-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMeshDecimationTools.h
More file actions
405 lines (329 loc) · 14.7 KB
/
Copy pathMeshDecimationTools.h
File metadata and controls
405 lines (329 loc) · 14.7 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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
#pragma once
#ifndef MESHDECIMATIONTOOLS_H
#define MESHDECIMATIONTOOLS_H
#include <stdint.h>
#if defined(MDT_CONFIGURATION_FILE)
#include MDT_CONFIGURATION_FILE
#endif // defined(MDT_CONFIGURATION_FILE)
#if !defined(MDT_ASSERT)
#include <assert.h>
#define MDT_ASSERT(condition) assert(condition)
#endif // !defined(MDT_ASSERT)
#if !defined(MDT_MAX_ATTRIBUTE_STRIDE_DWORDS)
#define MDT_MAX_ATTRIBUTE_STRIDE_DWORDS 16
#endif // !defined(MDT_MAX_ATTRIBUTE_STRIDE_DWORDS)
#if !defined(MDT_MESHLET_GROUP_SIZE)
#define MDT_MESHLET_GROUP_SIZE 32
#endif // !defined(MDT_MESHLET_GROUP_SIZE)
#if !defined(MDT_ENABLE_ATTRIBUTE_SUPPORT)
#define MDT_ENABLE_ATTRIBUTE_SUPPORT 1
#endif // !defined(MDT_ENABLE_ATTRIBUTE_SUPPORT)
#define MDT_MAX_MESHLET_VERTEX_COUNT 254
#define MDT_MAX_MESHLET_FACE_COUNT 128
#define MDT_MAX_CLOD_LEVEL_COUNT 16
#if defined(__cplusplus)
extern "C" {
#endif // defined(__cplusplus)
struct MdtVector3 {
float x;
float y;
float z;
};
struct MdtSphereBounds {
struct MdtVector3 center;
float radius;
};
struct MdtErrorMetric {
struct MdtSphereBounds bounds;
float error;
};
//
// Memory reallocation function similar to C realloc():
// - Allocate a new memory block if (old_memory_block == NULL && size_bytes != 0).
// - Free the old memory block if (old_memory_block != NULL && size_bytes == 0).
// - Extend the old memory block or allocate a new memory block and memcpy the old contents to it if (old_memory_block != NULL && size_bytes != 0).
//
typedef void* (*MdtReallocCallback)(void* old_memory_block, uint64_t size_bytes, void* user_data);
struct MdtAllocatorCallbacks {
// Reallocation callback, see definition of MdtReallocCallback for reference.
MdtReallocCallback reallocate;
// User defined allocator state, passed to MdtReallocCallback as user_data argument.
void* user_data;
};
// Optional memory allocation callbacks. If they're not provided the system falls back to C realloc().
struct MdtSystemCallbacks {
//
// Temporary allocator that is used as a stack. Falls back to C realloc() if not provided.
// Memory blocks are allocated and freed from the end.
//
struct MdtAllocatorCallbacks temp_allocator;
//
// Heap allocator used for small number of growable arrays and all output allocations. Falls back to C realloc() if not provided.
// Memory blocks are allocated and freed in arbitrary order.
//
struct MdtAllocatorCallbacks heap_allocator;
};
// See normalize_vertex_attributes in MdtTriangleMeshDesc for reference.
typedef void (*MdtNormalizeVertexAttributes)(float* attributes);
struct MdtTriangleGeometryDesc {
// Array of vertex indices. 3 consecutive indices form a triangle.
const uint32_t* indices;
// Array of vertices. Stride is equal to 'vertex_stride_bytes' and provided via MdtTriangleMeshDesc.
const float* vertices;
// Size of the 'indices' array. Must be a multiple of 3.
uint32_t index_count;
// Size of the 'vertices' array, in vertices of size 'vertex_stride_bytes' (NOT in floats).
uint32_t vertex_count;
};
struct MdtTriangleMeshDesc {
//
// Array of geometry descriptions. One mesh may contain multiple geometries that get simplified
// without forming cracks in between. This is useful when different geometries use different
// materials or rendered using different techniques. For example a window might have transparent
// glass as one geometry and opaque wood frame as another geometry. This also matches the way
// raytracing acceleration structure build APIs work.
//
const struct MdtTriangleGeometryDesc* geometry_descs;
// Size of the 'geometry_descs' array.
uint32_t geometry_desc_count;
// Byte offset between individual vertices in geometries.
uint32_t vertex_stride_bytes;
//
// Vertex position error weight. Vertex positions are internally scaled such that the average face area is equal to geometric_weight^2.
// Values in range [0.25, 1.0] work well in most cases. Use 0.5 as the default for a good balance between quality and reported error.
//
float geometric_weight;
//
// Relative error weights of vertex attributes. Size must be equal to MDT_MAX_ATTRIBUTE_STRIDE_DWORDS
// or set to NULL for default weights==1.0.
// Default weights==1.0 work well in most cases (unit vectors, quaternions, UV coordinates, colors, etc).
//
float* attribute_weights;
//
// Vertex attribute normalization callback. Note that only attributes are passed in. Can be set to NULL.
// This callback is called when a new set of attributes is computed and can be used to normalize unit
// vectors and quaternions, or clamp coordinates or colors.
//
MdtNormalizeVertexAttributes normalize_vertex_attributes;
};
struct MdtContinuousLodBuildInputs {
// Source triangle mesh containing multiple geometries. See MdtTriangleMeshDesc definition for reference.
struct MdtTriangleMeshDesc mesh;
// Target triangle count for meshlet builder. It will try to get as close to this value,
// but never go above it. Internally clamped between 1 and MDT_MAX_MESHLET_FACE_COUNT=128 triangles.
uint32_t meshlet_target_triangle_count;
// Target vertex count for meshlet builder. It will try to get as close to this value,
// but never go above it. Internally clamped between 3 and MDT_MAX_MESHLET_VERTEX_COUNT=254 vertices.
uint32_t meshlet_target_vertex_count;
};
struct MdtLevelOfDetailTargetDesc {
// Target face count for decimated mesh. Decimation algorithm will terminate once face count is
// below or equal to the target face count.
uint32_t target_face_count;
// Target error limit for decimated mesh. Decimation algorithm will terminate before the limit is exceeded.
float target_error_limit;
};
struct MdtDiscreteLodBuildInputs {
// Source triangle mesh containing multiple geometries. See MdtTriangleMeshDesc definition for reference.
struct MdtTriangleMeshDesc mesh;
// Array of target limits for each level of detail.
struct MdtLevelOfDetailTargetDesc* level_of_detail_descs;
// Size of 'level_of_detail_descs' array.
uint32_t level_of_detail_count;
};
struct MdtMeshletTriangle {
// Three indices into meshlet_vertex_indices array. See MdtMeshlet and MdtContinuousLodBuildResult definitions for reference.
uint8_t i0;
uint8_t i1;
uint8_t i2;
};
struct MdtMeshlet {
// Bounding box over meshlet vertex positions.
struct MdtVector3 aabb_min;
struct MdtVector3 aabb_max;
// Bounding sphere over meshlet vertex positions.
struct MdtSphereBounds geometric_sphere_bounds;
//
// Error metric of this meshlet. Transferred from the group this meshlet was built from.
// For the first level meshlets the error is set to 0.
// Meshlet should be drawn if (EvaluateErrorMetric(meshlet.current_level_error_metric) <= target_error).
//
struct MdtErrorMetric current_level_error_metric;
//
// Index of a meshlet group from which this meshlet was built. Set to UINT32_MAX for the first level meshlets.
// current_level_error_metric is extracted from this meshlet group.
//
uint32_t current_level_meshlet_group_index;
//
// Error metric of one level coarser representation of this meshlet. Transferred from the group that was built using this meshlet.
// For the last level meshlet groups the error is set to FLT_MAX.
// Meshlet should be drawn if (EvaluateErrorMetric(meshlet.coarser_level_error_metric) > target_error).
//
struct MdtErrorMetric coarser_level_error_metric;
//
// Index of a meshlet group that was built from and contains this meshlet. This index is always valid, even for the last level meshlets.
// coarser_level_error_metric is extracted from this meshlet group.
//
uint32_t coarser_level_meshlet_group_index;
//
// Range of meshlet_vertex_indices for this meshlet.
// To iterate over all meshlet vertices use this loop:
// for (u32 i = meshlet.begin_vertex_indices_index; i < meshlet.end_vertex_indices_index; i += 1) {
// u32 vertex_index = result.meshlet_vertex_indices[i];
// float* vertex = &result.vertices[vertex_index * vertex_stride_dwords];
// }
//
uint32_t begin_vertex_indices_index;
uint32_t end_vertex_indices_index;
//
// Range of meshlet_triangles for this meshlet.
// To iterate over all meshlet triangles use this loop:
// for (u32 i = meshlet.begin_meshlet_triangles_index; i < meshlet.end_meshlet_triangles_index; i += 1) {
// MdtMeshletTriangle triangle = result.meshlet_triangles[i];
// u32 vertex_index0 = result.meshlet_vertex_indices[triangle.i0 + meshlet.begin_vertex_indices_index];
// u32 vertex_index1 = result.meshlet_vertex_indices[triangle.i1 + meshlet.begin_vertex_indices_index];
// u32 vertex_index2 = result.meshlet_vertex_indices[triangle.i2 + meshlet.begin_vertex_indices_index];
// float* vertex0 = &result.vertices[vertex_index0 * vertex_stride_dwords];
// float* vertex1 = &result.vertices[vertex_index1 * vertex_stride_dwords];
// float* vertex2 = &result.vertices[vertex_index2 * vertex_stride_dwords];
// }
//
uint32_t begin_meshlet_triangles_index;
uint32_t end_meshlet_triangles_index;
//
// Index of the source geometry. Each meshlet is built from faces and vertices of only one geometry.
// Note that meshlet groups may contain meshlets from different geometries. See definition of
// MdtTriangleMeshDesc for more information.
//
uint32_t geometry_index;
};
struct MdtMeshletGroup {
// Bounding box over source meshlet bounding boxes.
struct MdtVector3 aabb_min;
struct MdtVector3 aabb_max;
// Bounding sphere over source meshlet bounding spheres.
struct MdtSphereBounds geometric_sphere_bounds;
//
// Union of source meshlet current_level_error_metrics and decimation error for this meshlet group.
// Source meshlet current_level_error_metric is the same as this error_metric. For the last level
// meshlet groups the error is set to FLT_MAX.
//
// This error_metric can be used to accelerate LOD tests by first checking that it's error is
// larger than the target error, and only then checking source meshlets if their error is
// smaller than the target error:
// if (EvaluateErrorMetric(error_metric) > target_error) {
// for (u32 i = group.begin_meshlet_index; i < group.end_meshlet_index; i += 1) {
// if (EvaluateErrorMetric(meshlets[i].current_level_error_metric) <= target_error) {
// DrawMeshlet(i);
// }
// }
// }
//
struct MdtErrorMetric error_metric;
// Range of source meshlets for this meshlet group. Groups can contain up to 32 meshlets.
uint32_t begin_meshlet_index;
uint32_t end_meshlet_index;
//
// LOD of source meshlets in range [0, 16).
// Level 0 is the highest quality (i.e. source geometry), level 15 is the lowest quality.
//
uint32_t level_of_detail_index;
};
struct MdtContinuousLodLevel {
// Range of meshlet groups for this level of detail.
uint32_t begin_meshlet_groups_index;
uint32_t end_meshlet_groups_index;
// Range of meshlets for this level of detail.
uint32_t begin_meshlets_index;
uint32_t end_meshlets_index;
};
struct MdtContinuousLodBuildResult {
//
// Array of meshlet groups.
// Meshlet groups are the unit of mesh decimation.
// See definition of MdtMeshletGroup for more details.
//
struct MdtMeshletGroup* meshlet_groups;
//
// Array of meshlets.
// Meshlets are spatially and topologically small regions of a mesh. They have a limited
// number of faces and vertices. See definition of MdtMeshlet for more details.
//
struct MdtMeshlet* meshlets;
//
// Flattened arrays of vertex indices for each meshlet. Use [begin_vertex_indices_index, end_vertex_indices_index)
// range to extract vertex indices of a given meshlet. See definition of MdtMeshlet for more details.
//
uint32_t* meshlet_vertex_indices;
//
// Flattened arrays of triangles for each meshlet. Each triangle contains indices into meshlet_vertex_indices array.
// Use [begin_meshlet_triangles_index, end_meshlet_triangles_index) range to extract triangles of a given meshlet.
// See definition of MdtMeshlet for more details.
//
struct MdtMeshletTriangle* meshlet_triangles;
//
// Array of vertices shared by all meshlets across all levels. Indexed using elements from
// meshlet_vertex_indices array. Vertex stride matches the stride passed in MdtTriangleMeshDesc.
//
float* vertices;
// Meshlet and meshlet group ranges for each level of detail.
struct MdtContinuousLodLevel* levels;
//
// Sizes for each corresponding array defined above.
// Vertex count is in vertices of size 'vertex_stride_bytes' (NOT in floats).
//
uint32_t meshlet_group_count;
uint32_t meshlet_count;
uint32_t meshlet_vertex_index_count;
uint32_t meshlet_triangle_count;
uint32_t vertex_count;
uint32_t level_count;
};
struct MdtDiscreteLodLevel {
// Maximum edge collapse error encountered during simplification.
float max_error;
// Range of decimated geometry descs for this level of detail.
uint32_t begin_geometry_index;
uint32_t end_geometry_index;
};
struct MdtDecimatedGeometryDesc {
// Range of vertex indices corresponding to a single geometry.
uint32_t begin_indices_index;
uint32_t end_indices_index;
};
struct MdtDiscreteLodBuildResult {
// Array of level of detail descriptions.
struct MdtDiscreteLodLevel* level_of_detail_descs;
//
// Array of per geometry ranges of vertex indices across all levels of detail.
// Use 'level_of_detail_descs' to iterate over geometries of a specific level of detail.
//
struct MdtDecimatedGeometryDesc* geometry_descs;
//
// Array of vertex indices for all geometries across all levels of detail.
// Use 'geometry_descs' to iterate over index ranges for a specific geometries.
//
uint32_t* indices;
//
// Array of vertices for all geometries across all levels of detail. Vertices that are not changed between levels of detail are not duplicated.
// Vertex stride matches the stride passed in MdtTriangleMeshDesc.
//
float* vertices;
//
// Sizes for each corresponding array defined above.
// Vertex count is in vertices of size 'vertex_stride_bytes' (NOT in floats).
//
uint32_t level_of_detail_count;
uint32_t geometry_desc_count;
uint32_t index_count;
uint32_t vertex_count;
};
void MdtBuildContinuousLod(const struct MdtContinuousLodBuildInputs* inputs, struct MdtContinuousLodBuildResult* result, const struct MdtSystemCallbacks* callbacks);
void MdtBuildDiscreteLod(const struct MdtDiscreteLodBuildInputs* inputs, struct MdtDiscreteLodBuildResult* result, const struct MdtSystemCallbacks* callbacks);
void MdtFreeContinuousLodBuildResult(const struct MdtContinuousLodBuildResult* result, const struct MdtSystemCallbacks* callbacks);
void MdtFreeDiscreteLodBuildResult(const struct MdtDiscreteLodBuildResult* result, const struct MdtSystemCallbacks* callbacks);
struct MdtSphereBounds MdtComputeSphereBoundsUnion(const struct MdtSphereBounds* source_sphere_bounds, uint32_t source_sphere_bounds_count);
#if defined(__cplusplus)
} // extern "C"
#endif // defined(__cplusplus)
#endif // MESHDECIMATIONTOOLS_H