-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLOD.cpp
More file actions
179 lines (158 loc) · 4.21 KB
/
Copy pathLOD.cpp
File metadata and controls
179 lines (158 loc) · 4.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include "template.h"
#include "scene.h"
#include "LOD.h"
LOD::LOD(int depth)
: m_depth(depth)
{
assert(depth > 0 && depth < 10);
m_side = 1 << depth; // 2^depth
m_count = size_t(m_side) * m_side * m_side;
m_mask.resize(m_count, false);
m_sphereIDs.resize(m_count);
}
void Scene::BuildChunks()
{
m_LODDepth_cache = GetSettingsR().m_LODDepth;
m_lods.clear();
for (int d = 0; d < m_LODDepth_cache; ++d)
{
m_lods.emplace_back(d + 1); // depth grows from 1 to m_LODDepth
}
for (int d = m_LODDepth_cache; d >= 1; --d) // we build LODs from the last (finest) to the first (roughest)
{
LOD& lod = m_lods[d - 1];
if (d == m_LODDepth_cache)
{
lod.BuildFromScene(*this);
}
else
{
lod.BuildFromPrevious(m_lods[d]);
}
}
}
void LOD::ClearAll()
{
std::fill(m_mask.begin(), m_mask.end(), false);
}
void LOD::BuildFromScene(const Scene& scene)
{
ClearAll();
const Level* const level = scene.GetCurrentLevelR();
const int blockSize = WORLDSIZE / m_side;
for (int z = 0; z < m_side; z++)
{
for (int y = 0; y < m_side; y++)
{
for (int x = 0; x < m_side; x++)
{
bool occupied = false;
int startX = x * blockSize;
int startY = y * blockSize;
int startZ = z * blockSize;
for (int bz = 0; bz < blockSize && !occupied; bz++)
{
for (int by = 0; by < blockSize && !occupied; by++)
{
for (int bx = 0; bx < blockSize; bx++)
{
if (scene.GetVoxelAt(
startX + bx,
startY + by,
startZ + bz).IsEmpty() == false)
{
occupied = true;
break;
}
}
}
}
if (occupied)
Set(x, y, z);
}
}
}
// spheres
float3 side3f = float3(static_cast<float>(m_side));
int3 side3i = int3(m_side);
static constexpr float RADIUS_EPS = 0.025f;
for (size_t id = 0; id < level->m_spheres.objects.size(); ++id)
{
assert(id <= 0xffff && "Only unsigned short number of spheres is supported");
const Sphere& sphere = level->m_spheres.objects[id];
const float3 center = sphere.m_center;
const float radius = sphere.m_radius;
const float sqrRadius = radius * radius;
const int3 minCell = clamp(int3((center - float3(radius + RADIUS_EPS)) * float(m_side)), int3(0), side3i);
const int3 maxCell = clamp(int3((center + float3(radius + RADIUS_EPS)) * float(m_side)) + int3(1 /*to ensure round up*/), int3(0), side3i);
for (int x = minCell.x; x < maxCell.x; ++x)
{
for (int y = minCell.y; y < maxCell.y; ++y)
{
for (int z = minCell.z; z < maxCell.z; ++z)
{
const float3 posf = float3(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
const float3 cellMin = posf / side3f;
const float3 cellMax = (posf + float3(1.0f)) / side3f;
// Closest point on the cell AABB to the sphere center
const float3 closest = clamp(center, cellMin, cellMax);
if (sqrLength(closest - center) <= sqrRadius)
{
MarkSphere(x, y, z, static_cast<unsigned short>(id));
}
}
}
}
}
}
void LOD::BuildFromPrevious(const LOD& finer)
{
assert(finer.m_side == m_side * 2);
ClearAll();
for (int z = 0; z < m_side; z++)
{
for (int y = 0; y < m_side; y++)
{
for (int x = 0; x < m_side; x++)
{
const int fx = x * 2;
const int fy = y * 2;
const int fz = z * 2;
const size_t index = Index(x, y, z);
const size_t base = finer.Index(fx, fy, fz);
const size_t offsetY = finer.m_side;
const size_t offsetZ = finer.m_side * finer.m_side;
const size_t finerIndices[8]{
base,
base + 1,
base + offsetY,
base + offsetY + 1,
base + offsetZ,
base + offsetZ + 1,
base + offsetZ + offsetY,
base + offsetZ + offsetY + 1
};
for (int i = 0; i < 8; i++)
{
const size_t finerIndex = finerIndices[i];
if (finer.m_mask[finerIndex])
{
Set(x, y, z);
}
std::vector<unsigned short>& thisIDs = m_sphereIDs[index];
const std::vector<unsigned short>& finerIDs = finer.m_sphereIDs[finerIndex];
if (!finerIDs.empty())
{
for (auto sphereid : finer.m_sphereIDs[finerIndex])
{
if (std::find(thisIDs.begin(), thisIDs.end(), sphereid) == thisIDs.end()) // avoid repetitions
{
thisIDs.push_back(sphereid);
}
}
}
}
}
}
}
}