Cogs.Core
UniformGridSystem_isosurf_ref.cpp
1#include "Resources/Resources.h"
2#include "Resources/MeshManager.h"
3#include "Resources/VertexFormats.h"
4
5#include "Context.h"
6
7#include "../../../IsoSurfaces/MarchingCubesTables.h"
8
9#include "Foundation/Logging/Logger.h"
10#include "Foundation/Memory/MemoryBuffer.h"
11#include "Foundation/Platform/Timer.h"
12
13#include <glm/glm.hpp>
14
15//#include "C:\utils\iaca-win64\iacaMarks.h"
16namespace {
17 using namespace Cogs::Core;
18
19 Cogs::Logging::Log logger = Cogs::Logging::getLogger("UniformGridSystem");
20
21 struct Vertex
22 {
23 glm::vec3 pos;
24 glm::vec3 nrm;
25 glm::vec2 tex;
26 };
27 typedef uint16_t Idx;
28
29 void analyzeRef(uint8_t* tmp,
30 unsigned& vertexCount_,
31 unsigned& occupiedCells_,
32 unsigned& indexCount_,
33 const float* values,
34 const glm::uvec3 gridLayout,
35 const unsigned T_n,
36 const float* thresholds)
37 {
38 const auto cellLayout = gridLayout - glm::uvec3(1, 1, 1);
39 const auto * vertexCountTable = MarchingCubes::vertexCountTable().data();
41
42 unsigned vertexCount = 0;
43 unsigned occupiedCells = 0;
44 unsigned indexCount = 0;
45 for (unsigned l = 0; l < T_n; l++) {
46 auto * offsets = (uint32_t*)(tmp + gridLayout.x*gridLayout.y*gridLayout.z * sizeof(uint32_t)*l);
47 auto * codes = tmp + gridLayout.x*gridLayout.y*gridLayout.z*(sizeof(uint32_t)*T_n + l);
48
49 const auto T = thresholds[l];
50
51 auto * c = codes;
52 auto * o = offsets;
53 const auto * v = values;
54 for (unsigned k = 0; k < gridLayout.z; k++) {
55 for (unsigned j = 0; j < gridLayout.y; j++) {
56 for (unsigned i = 0; i < gridLayout.x; i++) {
57
58 auto ii = i < cellLayout.x ? 1 : 0;
59 auto jj = j < cellLayout.y ? gridLayout.x : 0;
60 auto kk = k < cellLayout.z ? gridLayout.x * gridLayout.y : 0;
61
62 unsigned code =
63 (v[0] < T ? 1 : 0) |
64 (v[ii] < T ? 2 : 0) |
65 (v[jj] < T ? 4 : 0) |
66 (v[jj + ii] < T ? 8 : 0) |
67 (v[kk + 0] < T ? 16 : 0) |
68 (v[kk + ii] < T ? 32 : 0) |
69 (v[kk + jj] < T ? 64 : 0) |
70 (v[kk + jj + ii] < T ? 128 : 0);
71 v++;
72
73 if (code == 255) code = 0;
74 *o++ = vertexCount;
75 if (code) {
76 vertexCount += vertexCountTable[code];
77 if (i < cellLayout.x && j < cellLayout.y && k < cellLayout.z) {
78 occupiedCells++;
79 indexCount += indexCountTable[code];
80 }
81 }
82 *c++ = uint8_t(code);
83 }
84 }
85 }
86 }
87 vertexCount_ = vertexCount;
88 occupiedCells_ = occupiedCells;
89 indexCount_ = indexCount;
90 }
91
92 void analyzeSomewhatOptimized(uint8_t* tmp,
93 unsigned& vertexCount_,
94 unsigned& occupiedCells_,
95 unsigned& indexCount_,
96 const float* values,
97 const glm::uvec3 gridLayout,
98 const unsigned T_n,
99 const float* thresholds)
100 {
101 assert((gridLayout.x & 7) == 0 && (gridLayout.y & 7) == 0 && (gridLayout.z & 7) == 0);
102 assert((gridLayout.y*gridLayout.x & 31) == 0);
103
104 const auto cellLayout = gridLayout - glm::uvec3(1, 1, 1);
105 const auto * vertexCountTable = MarchingCubes::vertexCountTable().data();
107
108 unsigned vertexCount = 0;
109 unsigned occupiedCells = 0;
110 unsigned indexCount = 0;
111 for (unsigned l = 0; l < T_n; l++) {
112 auto * offsets = (uint32_t*)(tmp + gridLayout.x*gridLayout.y*gridLayout.z * sizeof(uint32_t)*l);
113 auto * codes = (tmp + gridLayout.x*gridLayout.y*gridLayout.z*(sizeof(uint32_t)*T_n + l));
114 const auto T = thresholds[l];
115 for (unsigned k = 0; k < gridLayout.z*gridLayout.y*gridLayout.x; k++) {
116 codes[k] = values[k] < T ? 1 : 0;
117 }
118
119 auto * c = codes;
120 const auto m = gridLayout.y*gridLayout.x;
121 for (unsigned k = 0; k < cellLayout.z; k++) {
122 for (unsigned j = 0; j < gridLayout.y*gridLayout.x; j++) {
123 unsigned code = (c[0] << 0) | (c[m] << 4);
124 *c++ = uint8_t(code);
125 }
126 }
127 for (unsigned j = 0; j < gridLayout.y* gridLayout.x; j++) {
128 unsigned code = (c[0] << 0) | (c[0] << 4);
129 *c++ = uint8_t(code);
130 }
131
132 c = codes;
133 for (unsigned k = 0; k < gridLayout.z; k++) {
134 for (unsigned i = 0; i < cellLayout.y*gridLayout.x; i++) {
135 c[0] = c[0] | (c[gridLayout.x] << 2);
136 c++;
137 }
138 for (unsigned i = 0; i < gridLayout.x; i++) {
139 c[0] = c[0] | (c[0] << 2);
140 c++;
141 }
142 }
143
144 c = codes;
145 auto * o = offsets;
146 for (unsigned k = 0; k < gridLayout.z; k++) {
147 for (unsigned j = 0; j < gridLayout.y; j++) {
148 for (unsigned i = 0; i < cellLayout.x; i++) {
149 unsigned code = (c[0] << 0) | (c[1] << 1);
150 if (code == 255) code = 0;
151 *o++ = vertexCount;
152 *c++ = uint8_t(code);
153 if (code == 0) continue;
154
155 vertexCount += vertexCountTable[code];
156 if (i < cellLayout.x && j < cellLayout.y && k < cellLayout.z) {
157 occupiedCells++;
158 indexCount += indexCountTable[code];
159 }
160 }
161 unsigned code = (c[0] << 0) | (c[0] << 1);
162 if (code == 255) code = 0;
163 *o++ = vertexCount;
164 if (code) {
165 vertexCount += vertexCountTable[code];
166 }
167 *c++ = uint8_t(code);
168 }
169 }
170 }
171
172 vertexCount_ = vertexCount;
173 occupiedCells_ = occupiedCells;
174 indexCount_ = indexCount;
175 }
176
177 unsigned vertexExtractRef(Cogs::Core::MappedStream<Vertex>& vertices,
178 uint8_t* tmp,
179 const float* values,
180 const glm::uvec3 gridLayout,
181 const unsigned T_n,
182 const float* thresholds)
183 {
184 unsigned vix = 0;
185 const auto cellLayout = gridLayout - glm::uvec3(1, 1, 1);
186 const auto * axesTable = MarchingCubes::axesTable().data();
187 for (unsigned l = 0; l < T_n; l++) {
188 //auto * offsets = (uint32_t*)(tmp + gridLayout.x*gridLayout.y*gridLayout.z * sizeof(uint32_t)*l);
189 auto * codes = tmp + gridLayout.x*gridLayout.y*gridLayout.z*(sizeof(uint32_t)*T_n + l);
190 auto * c = codes;
191 const auto tp = (l + 0.5f) * (1.0f / 4.f);
192 const auto T = thresholds[l];
193 for (unsigned k = 0; k < gridLayout.z; k++) {
194 for (unsigned j = 0; j < gridLayout.y; j++) {
195 for (unsigned i = 0; i < gridLayout.x; i++) {
196 auto code = *c++;
197 if (code == 0) continue;
198
199 auto axes = axesTable[code];
200 unsigned ll = 0;
201 if (axes) {
202 auto ip = std::min(cellLayout.x, i + 1);
203 auto jp = std::min(cellLayout.y, j + 1);
204 auto kp = std::min(cellLayout.z, k + 1);
205
206 float a = values[(k*gridLayout.y + j)*gridLayout.x + i];
207
208 float ax = values[(k*gridLayout.y + j)*gridLayout.x + ip] - a; // gradient via forward differences
209 float ay = values[(k*gridLayout.y + jp)*gridLayout.x + i] - a;
210 float az = values[(kp*gridLayout.y + j)*gridLayout.x + i] - a;
211
212 if (axes & 4) {
213 ll++;
214 auto kk = k + 1;
215 auto kkp = std::min(cellLayout.z, kk + 1);
216 //assert(kk < gridLayout.z);
217
218 float b = values[(kk*gridLayout.y + j)*gridLayout.x + i];
219 float bx = values[(kk*gridLayout.y + j)*gridLayout.x + ip] - b;
220 float by = values[(kk*gridLayout.y + jp)*gridLayout.x + i] - b;
221 float bz = values[(kkp*gridLayout.y + j)*gridLayout.x + i] - b;
222
223 float t = (T - a) / (b - a); // solve linear eq
224 //assert(0 <= t && t <= 1.f);
225 float s = 1.f - t;
226 vertices[vix++] = Vertex{ glm::vec3(i, j, k + t),
227 -glm::vec3(s*ax + t * bx, s*ay + t * by, s*az + t * bz),
228 glm::vec2(tp, 0.5) };
229 }
230
231 if (axes & 2) {
232 ll++;
233 auto jj = j + 1;
234 auto jjp = std::min(cellLayout.y, jj + 1);
235 //assert(jj < gridLayout.y);
236
237 float b = values[(k*gridLayout.y + jj)*gridLayout.x + i];
238 float bx = values[(k*gridLayout.y + jj)*gridLayout.x + ip] - b;
239 float by = values[(k*gridLayout.y + jjp)*gridLayout.x + i] - b;
240 float bz = values[(kp*gridLayout.y + jj)*gridLayout.x + i] - b;
241
242 float t = (T - a) / (b - a);
243 //assert(0 <= t && t <= 1.f);
244 float s = 1.f - t;
245 vertices[vix++] = Vertex{ glm::vec3(i, j + t, k),
246 -glm::vec3(s*ax + t * bx, s*ay + t * by, s*az + t * bz),
247 glm::vec2(tp, 0.5) };
248 }
249 if (axes & 1) {
250 ll++;
251 auto ii = i + 1;
252 auto iip = std::min(cellLayout.y, ii + 1);
253 //assert(ii < gridLayout.x);
254
255 float b = values[(k*gridLayout.y + j)*gridLayout.x + ii];
256 float bx = values[(k*gridLayout.y + j)*gridLayout.x + iip] - b;
257 float by = values[(k*gridLayout.y + jp)*gridLayout.x + ii] - b;
258 float bz = values[(kp*gridLayout.y + j)*gridLayout.x + ii] - b;
259
260 float t = (T - a) / (b - a);
261 //assert(0 <= t && t <= 1.f);
262 float s = 1.f - t;
263 vertices[vix++] = Vertex{ glm::vec3(i, j + t, k),
264 -glm::vec3(s*ax + t * bx, s*ay + t * by, s*az + t * bz),
265 glm::vec2(tp, 0.5) };
266 }
267 //auto q = vertexCountTable[code];
268 //assert(l == q);
269 }
270
271 }
272 }
273 }
274 }
275
276 return vix;
277 }
278
279}
280
281namespace Cogs::Core::EchoSounder {
282
283
284//#pragma optimize( "", off )
285 MeshHandle createIsoSurfacesReference(Context* context,
286 uint64_t& analyze,
287 uint64_t& vtx,
288 uint64_t& idx,
290 const float* values,
291 const glm::uvec3 gridLayout,
292 const glm::vec3 /*minCorner*/,
293 const glm::vec3 /*maxCorner*/,
294 const float *thresholds, size_t count)
295 {
296 assert(gridLayout.x != 0 && gridLayout.y != 0 && gridLayout.z != 0);
297
298 const uint32_t T_n = (uint32_t)count;
299
300 // grid layout is the layout of sample positions
301 // a cell must be surrounded by samples, so cell layout is one less along each dimension
302 //const auto indexCountTable = MarchingCubes::indexCountTable();
303
304 //const auto * vertexCountTable = MarchingCubes::vertexCountTable().data();
305 const auto * axesTable = MarchingCubes::axesTable().data();
306 const auto * indexTable = MarchingCubes::indexTable().data();
307
308 const auto cellLayout = gridLayout - glm::uvec3(1, 1, 1);
309
310 scratch.resize(T_n*(sizeof(uint32_t) + sizeof(uint8_t) + 3*sizeof(uint32_t))*gridLayout.x*gridLayout.y*gridLayout.z, false);
311 auto * tmp = (uint8_t*)scratch.data();
312
313
314 unsigned occupiedCells = 0;
315 unsigned indexCount = 0;
316 unsigned vertexCount = 0;
317
318 auto timer = Timer::startNew();
319 //analyzeRef(tmp, vertexCount, occupiedCells, indexCount, values, gridLayout, T_n, thresholds);
320 analyzeSomewhatOptimized(tmp, vertexCount, occupiedCells, indexCount, values, gridLayout,
321 static_cast<const unsigned>(T_n), thresholds);
322 analyze = timer.elapsedMicroseconds();
323
324 if (occupiedCells == 0) {
325 vtx = 0;
326 idx = 0;
328 }
329
330 auto mesh = context->meshManager->createLocked();
331 //mesh->setBounds(Cogs::Geometry::BoundingBox{ glm::vec3(0,0,0), glm::vec3(gridLayout.x, gridLayout.y, gridLayout.z) });
332 mesh->setMeshFlag(MeshFlags::ClockwiseWinding);
333 mesh->primitiveType = PrimitiveType::TriangleList;
334
335 auto vertices = mesh->map<Vertex>(VertexDataType::Interleaved0, VertexFormats::Pos3fNorm3fTex2f, vertexCount);
336
337 // Extract vertices
338 timer = Timer::startNew();
339 auto vix = vertexExtractRef(vertices, tmp, values, gridLayout,
340 static_cast<const unsigned>(T_n), thresholds);
341 vtx = timer.elapsedMicroseconds();
342
343 // extract indices
344 std::vector<uint32_t> sub_mesh(T_n+1, 0);
345 mesh->clearIndexes();
346 Idx *indices = (Idx*)mesh->mapStream(VertexDataType::Indexes, 0, indexCount, sizeof(Idx), true);
347
348 unsigned iix = 0;
349 timer = Timer::startNew();
350 for (unsigned l = 0; l < T_n; l++) {
351 auto * offsets = (uint32_t*)(tmp + gridLayout.x*gridLayout.y*gridLayout.z * sizeof(uint32_t)*l);
352 auto * codes = tmp + gridLayout.x*gridLayout.y*gridLayout.z*(sizeof(uint32_t)*T_n + l);
353 auto * c = codes;
354 for (unsigned k = 0; k < cellLayout.z; k++) {
355 for (unsigned j = 0; j < cellLayout.y; j++) {
356 for (unsigned i = 0; i < cellLayout.x; i++) {
357 auto code = *c++;
358 if (code == 0) continue;
359
360 auto * axisShifts = indexTable + 16 * code;
361 while(true)
362 {
363 auto axisShift = *axisShifts++;
364 if (axisShift == 255) break;
365
366 auto ii = i + (axisShift & 8 ? 1 : 0);
367 auto jj = j + (axisShift & 16 ? 1 : 0);
368 auto kk = k + (axisShift & 32 ? 1 : 0);
369
370 auto shiftedCell = (kk*gridLayout.y + jj)*gridLayout.x + ii;
371
372 const auto shiftedCode = codes[shiftedCell];
373 const auto axes = axesTable[shiftedCode] & axisShift;
374
375 const auto ix = offsets[shiftedCell] + ((axes & 4) ? 1 : 0) + ((axes & 2) ? 1 : 0);
376 assert(ix < vertexCount);
377
378 assert(sizeof(Idx)!=2 || ix < 0xffff);
379 indices[iix++] = (Idx)ix;
380 }
381 }
382
383 c++;
384 }
385 c += gridLayout.x;
386 }
387 sub_mesh[l+1] = iix;
388 }
389 assert(vix == vertexCount);
390 assert(iix == indexCount);
391
392 mesh->setMeshFlag(MeshFlags::Indexed);
393 mesh->setMeshFlag(MeshFlags::IndexesChanged);
394
395 auto subMeshes = mesh->mapSubMeshes(T_n);
396 for (unsigned l = 0; l < T_n; l++) {
397 uint32_t start = sub_mesh[l];
398 uint32_t size = sub_mesh[l+1]-sub_mesh[l];
399 subMeshes[l] = {start, size, PrimitiveType::TriangleList};
400 }
401 mesh->setCount(indexCount);
402
403 auto box = Geometry::makeEmptyBoundingBox<Geometry::BoundingBox>();
404 for(unsigned i=0; i<vertexCount; i++){
405 glm::vec3 pos = vertices[i].pos;
406 box.min = glm::min(box.min, pos);
407 box.max = glm::max(box.max, pos);
408 }
409 mesh->setBounds(box);
410
411 idx = timer.elapsedMicroseconds();
412 return mesh.getHandle();
413 }
414//#pragma optimize( "", on )
415
416}
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
Log implementation class.
Definition: LogManager.h:139
COGSCORE_DLL_API const std::vector< unsigned char > & indexCountTable()
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
Wrapper for mapped stream data automatically updating the Mesh resource mapped from when destructed.
Definition: Mesh.h:126
@ IndexesChanged
The index data of the mesh changed.
Definition: Mesh.h:61
@ Indexed
The mesh should be drawn indexed, using index data to order the triangle vertexes.
Definition: Mesh.h:65
@ ClockwiseWinding
The mesh uses clockwise winding order for it's triangles as opposed to the counter-clockwise default.
Definition: Mesh.h:63
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
@ TriangleList
List of triangles.
Definition: Common.h:116