Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/meshoptimizer/simplifier.cpp
20837 views
1
// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
2
#include "meshoptimizer.h"
3
4
#include <assert.h>
5
#include <float.h>
6
#include <math.h>
7
#include <string.h>
8
9
#ifndef TRACE
10
#define TRACE 0
11
#endif
12
13
#if TRACE
14
#include <stdio.h>
15
#endif
16
17
#if TRACE
18
#define TRACESTATS(i) stats[i]++;
19
#else
20
#define TRACESTATS(i) (void)0
21
#endif
22
23
// This work is based on:
24
// Michael Garland and Paul S. Heckbert. Surface simplification using quadric error metrics. 1997
25
// Michael Garland. Quadric-based polygonal surface simplification. 1999
26
// Peter Lindstrom. Out-of-Core Simplification of Large Polygonal Models. 2000
27
// Matthias Teschner, Bruno Heidelberger, Matthias Mueller, Danat Pomeranets, Markus Gross. Optimized Spatial Hashing for Collision Detection of Deformable Objects. 2003
28
// Peter Van Sandt, Yannis Chronis, Jignesh M. Patel. Efficiently Searching In-Memory Sorted Arrays: Revenge of the Interpolation Search? 2019
29
// Hugues Hoppe. New Quadric Metric for Simplifying Meshes with Appearance Attributes. 1999
30
// Hugues Hoppe, Steve Marschner. Efficient Minimization of New Quadric Metric for Simplifying Meshes with Appearance Attributes. 2000
31
namespace meshopt
32
{
33
34
struct EdgeAdjacency
35
{
36
struct Edge
37
{
38
unsigned int next;
39
unsigned int prev;
40
};
41
42
unsigned int* offsets;
43
Edge* data;
44
};
45
46
static void prepareEdgeAdjacency(EdgeAdjacency& adjacency, size_t index_count, size_t vertex_count, meshopt_Allocator& allocator)
47
{
48
adjacency.offsets = allocator.allocate<unsigned int>(vertex_count + 1);
49
adjacency.data = allocator.allocate<EdgeAdjacency::Edge>(index_count);
50
}
51
52
static void updateEdgeAdjacency(EdgeAdjacency& adjacency, const unsigned int* indices, size_t index_count, size_t vertex_count, const unsigned int* remap)
53
{
54
size_t face_count = index_count / 3;
55
unsigned int* offsets = adjacency.offsets + 1;
56
EdgeAdjacency::Edge* data = adjacency.data;
57
58
// fill edge counts
59
memset(offsets, 0, vertex_count * sizeof(unsigned int));
60
61
for (size_t i = 0; i < index_count; ++i)
62
{
63
unsigned int v = remap ? remap[indices[i]] : indices[i];
64
assert(v < vertex_count);
65
66
offsets[v]++;
67
}
68
69
// fill offset table
70
unsigned int offset = 0;
71
72
for (size_t i = 0; i < vertex_count; ++i)
73
{
74
unsigned int count = offsets[i];
75
offsets[i] = offset;
76
offset += count;
77
}
78
79
assert(offset == index_count);
80
81
// fill edge data
82
for (size_t i = 0; i < face_count; ++i)
83
{
84
unsigned int a = indices[i * 3 + 0], b = indices[i * 3 + 1], c = indices[i * 3 + 2];
85
86
if (remap)
87
{
88
a = remap[a];
89
b = remap[b];
90
c = remap[c];
91
}
92
93
data[offsets[a]].next = b;
94
data[offsets[a]].prev = c;
95
offsets[a]++;
96
97
data[offsets[b]].next = c;
98
data[offsets[b]].prev = a;
99
offsets[b]++;
100
101
data[offsets[c]].next = a;
102
data[offsets[c]].prev = b;
103
offsets[c]++;
104
}
105
106
// finalize offsets
107
adjacency.offsets[0] = 0;
108
assert(adjacency.offsets[vertex_count] == index_count);
109
}
110
111
struct PositionHasher
112
{
113
const float* vertex_positions;
114
size_t vertex_stride_float;
115
const unsigned int* sparse_remap;
116
117
size_t hash(unsigned int index) const
118
{
119
unsigned int ri = sparse_remap ? sparse_remap[index] : index;
120
const unsigned int* key = reinterpret_cast<const unsigned int*>(vertex_positions + ri * vertex_stride_float);
121
122
unsigned int x = key[0], y = key[1], z = key[2];
123
124
// replace negative zero with zero
125
x = (x == 0x80000000) ? 0 : x;
126
y = (y == 0x80000000) ? 0 : y;
127
z = (z == 0x80000000) ? 0 : z;
128
129
// scramble bits to make sure that integer coordinates have entropy in lower bits
130
x ^= x >> 17;
131
y ^= y >> 17;
132
z ^= z >> 17;
133
134
// Optimized Spatial Hashing for Collision Detection of Deformable Objects
135
return (x * 73856093) ^ (y * 19349663) ^ (z * 83492791);
136
}
137
138
bool equal(unsigned int lhs, unsigned int rhs) const
139
{
140
unsigned int li = sparse_remap ? sparse_remap[lhs] : lhs;
141
unsigned int ri = sparse_remap ? sparse_remap[rhs] : rhs;
142
143
const float* lv = vertex_positions + li * vertex_stride_float;
144
const float* rv = vertex_positions + ri * vertex_stride_float;
145
146
return lv[0] == rv[0] && lv[1] == rv[1] && lv[2] == rv[2];
147
}
148
};
149
150
struct RemapHasher
151
{
152
unsigned int* remap;
153
154
size_t hash(unsigned int id) const
155
{
156
return id * 0x5bd1e995;
157
}
158
159
bool equal(unsigned int lhs, unsigned int rhs) const
160
{
161
return remap[lhs] == rhs;
162
}
163
};
164
165
static size_t hashBuckets2(size_t count)
166
{
167
size_t buckets = 1;
168
while (buckets < count + count / 4)
169
buckets *= 2;
170
171
return buckets;
172
}
173
174
template <typename T, typename Hash>
175
static T* hashLookup2(T* table, size_t buckets, const Hash& hash, const T& key, const T& empty)
176
{
177
assert(buckets > 0);
178
assert((buckets & (buckets - 1)) == 0);
179
180
size_t hashmod = buckets - 1;
181
size_t bucket = hash.hash(key) & hashmod;
182
183
for (size_t probe = 0; probe <= hashmod; ++probe)
184
{
185
T& item = table[bucket];
186
187
if (item == empty)
188
return &item;
189
190
if (hash.equal(item, key))
191
return &item;
192
193
// hash collision, quadratic probing
194
bucket = (bucket + probe + 1) & hashmod;
195
}
196
197
assert(false && "Hash table is full"); // unreachable
198
return NULL;
199
}
200
201
static void buildPositionRemap(unsigned int* remap, unsigned int* wedge, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, const unsigned int* sparse_remap, meshopt_Allocator& allocator)
202
{
203
PositionHasher hasher = {vertex_positions_data, vertex_positions_stride / sizeof(float), sparse_remap};
204
205
size_t table_size = hashBuckets2(vertex_count);
206
unsigned int* table = allocator.allocate<unsigned int>(table_size);
207
memset(table, -1, table_size * sizeof(unsigned int));
208
209
// build forward remap: for each vertex, which other (canonical) vertex does it map to?
210
// we use position equivalence for this, and remap vertices to other existing vertices
211
for (size_t i = 0; i < vertex_count; ++i)
212
{
213
unsigned int index = unsigned(i);
214
unsigned int* entry = hashLookup2(table, table_size, hasher, index, ~0u);
215
216
if (*entry == ~0u)
217
*entry = index;
218
219
remap[index] = *entry;
220
}
221
222
allocator.deallocate(table);
223
224
if (!wedge)
225
return;
226
227
// build wedge table: for each vertex, which other vertex is the next wedge that also maps to the same vertex?
228
// entries in table form a (cyclic) wedge loop per vertex; for manifold vertices, wedge[i] == remap[i] == i
229
for (size_t i = 0; i < vertex_count; ++i)
230
wedge[i] = unsigned(i);
231
232
for (size_t i = 0; i < vertex_count; ++i)
233
if (remap[i] != i)
234
{
235
unsigned int r = remap[i];
236
237
wedge[i] = wedge[r];
238
wedge[r] = unsigned(i);
239
}
240
}
241
242
static unsigned int* buildSparseRemap(unsigned int* indices, size_t index_count, size_t vertex_count, size_t* out_vertex_count, meshopt_Allocator& allocator)
243
{
244
// use a bit set to compute the precise number of unique vertices
245
unsigned char* filter = allocator.allocate<unsigned char>((vertex_count + 7) / 8);
246
247
for (size_t i = 0; i < index_count; ++i)
248
{
249
unsigned int index = indices[i];
250
assert(index < vertex_count);
251
filter[index / 8] = 0;
252
}
253
254
size_t unique = 0;
255
for (size_t i = 0; i < index_count; ++i)
256
{
257
unsigned int index = indices[i];
258
unique += (filter[index / 8] & (1 << (index % 8))) == 0;
259
filter[index / 8] |= 1 << (index % 8);
260
}
261
262
unsigned int* remap = allocator.allocate<unsigned int>(unique);
263
size_t offset = 0;
264
265
// temporary map dense => sparse; we allocate it last so that we can deallocate it
266
size_t revremap_size = hashBuckets2(unique);
267
unsigned int* revremap = allocator.allocate<unsigned int>(revremap_size);
268
memset(revremap, -1, revremap_size * sizeof(unsigned int));
269
270
// fill remap, using revremap as a helper, and rewrite indices in the same pass
271
RemapHasher hasher = {remap};
272
273
for (size_t i = 0; i < index_count; ++i)
274
{
275
unsigned int index = indices[i];
276
unsigned int* entry = hashLookup2(revremap, revremap_size, hasher, index, ~0u);
277
278
if (*entry == ~0u)
279
{
280
remap[offset] = index;
281
*entry = unsigned(offset);
282
offset++;
283
}
284
285
indices[i] = *entry;
286
}
287
288
allocator.deallocate(revremap);
289
290
assert(offset == unique);
291
*out_vertex_count = unique;
292
293
return remap;
294
}
295
296
enum VertexKind
297
{
298
Kind_Manifold, // not on an attribute seam, not on any boundary
299
Kind_Border, // not on an attribute seam, has exactly two open edges
300
Kind_Seam, // on an attribute seam with exactly two attribute seam edges
301
Kind_Complex, // none of the above; these vertices can move as long as all wedges move to the target vertex
302
Kind_Locked, // none of the above; these vertices can't move
303
304
Kind_Count
305
};
306
307
// manifold vertices can collapse onto anything
308
// border/seam vertices can collapse onto border/seam respectively, or locked
309
// complex vertices can collapse onto complex/locked
310
// a rule of thumb is that collapsing kind A into kind B preserves the kind B in the target vertex
311
// for example, while we could collapse Complex into Manifold, this would mean the target vertex isn't Manifold anymore
312
const unsigned char kCanCollapse[Kind_Count][Kind_Count] = {
313
{1, 1, 1, 1, 1},
314
{0, 1, 0, 0, 1},
315
{0, 0, 1, 0, 1},
316
{0, 0, 0, 1, 1},
317
{0, 0, 0, 0, 0},
318
};
319
320
// if a vertex is manifold or seam, adjoining edges are guaranteed to have an opposite edge
321
// note that for seam edges, the opposite edge isn't present in the attribute-based topology
322
// but is present if you consider a position-only mesh variant
323
// while many complex collapses have the opposite edge, since complex vertices collapse to the
324
// same wedge, keeping opposite edges separate improves the quality by considering both targets
325
const unsigned char kHasOpposite[Kind_Count][Kind_Count] = {
326
{1, 1, 1, 1, 1},
327
{1, 0, 1, 0, 0},
328
{1, 1, 1, 0, 1},
329
{1, 0, 0, 0, 0},
330
{1, 0, 1, 0, 0},
331
};
332
333
static bool hasEdge(const EdgeAdjacency& adjacency, unsigned int a, unsigned int b)
334
{
335
unsigned int count = adjacency.offsets[a + 1] - adjacency.offsets[a];
336
const EdgeAdjacency::Edge* edges = adjacency.data + adjacency.offsets[a];
337
338
for (size_t i = 0; i < count; ++i)
339
if (edges[i].next == b)
340
return true;
341
342
return false;
343
}
344
345
static bool hasEdge(const EdgeAdjacency& adjacency, unsigned int a, unsigned int b, const unsigned int* remap, const unsigned int* wedge)
346
{
347
unsigned int v = a;
348
349
do
350
{
351
unsigned int count = adjacency.offsets[v + 1] - adjacency.offsets[v];
352
const EdgeAdjacency::Edge* edges = adjacency.data + adjacency.offsets[v];
353
354
for (size_t i = 0; i < count; ++i)
355
if (remap[edges[i].next] == remap[b])
356
return true;
357
358
v = wedge[v];
359
} while (v != a);
360
361
return false;
362
}
363
364
static void classifyVertices(unsigned char* result, unsigned int* loop, unsigned int* loopback, size_t vertex_count, const EdgeAdjacency& adjacency, const unsigned int* remap, const unsigned int* wedge, const unsigned char* vertex_lock, const unsigned int* sparse_remap, unsigned int options)
365
{
366
memset(loop, -1, vertex_count * sizeof(unsigned int));
367
memset(loopback, -1, vertex_count * sizeof(unsigned int));
368
369
// incoming & outgoing open edges: ~0u if no open edges, i if there are more than 1
370
// note that this is the same data as required in loop[] arrays; loop[] data is only used for border/seam by default
371
// in permissive mode we also use it to guide complex-complex collapses, so we fill it for all vertices
372
unsigned int* openinc = loopback;
373
unsigned int* openout = loop;
374
375
for (size_t i = 0; i < vertex_count; ++i)
376
{
377
unsigned int vertex = unsigned(i);
378
379
unsigned int count = adjacency.offsets[vertex + 1] - adjacency.offsets[vertex];
380
const EdgeAdjacency::Edge* edges = adjacency.data + adjacency.offsets[vertex];
381
382
for (size_t j = 0; j < count; ++j)
383
{
384
unsigned int target = edges[j].next;
385
386
if (target == vertex)
387
{
388
// degenerate triangles have two distinct edges instead of three, and the self edge
389
// is bi-directional by definition; this can break border/seam classification by "closing"
390
// the open edge from another triangle and falsely marking the vertex as manifold
391
// instead we mark the vertex as having >1 open edges which turns it into locked/complex
392
openinc[vertex] = openout[vertex] = vertex;
393
}
394
else if (!hasEdge(adjacency, target, vertex))
395
{
396
openinc[target] = (openinc[target] == ~0u) ? vertex : target;
397
openout[vertex] = (openout[vertex] == ~0u) ? target : vertex;
398
}
399
}
400
}
401
402
#if TRACE
403
size_t stats[4] = {};
404
#endif
405
406
for (size_t i = 0; i < vertex_count; ++i)
407
{
408
if (remap[i] == i)
409
{
410
if (wedge[i] == i)
411
{
412
// no attribute seam, need to check if it's manifold
413
unsigned int openi = openinc[i], openo = openout[i];
414
415
// note: we classify any vertices with no open edges as manifold
416
// this is technically incorrect - if 4 triangles share an edge, we'll classify vertices as manifold
417
// it's unclear if this is a problem in practice
418
if (openi == ~0u && openo == ~0u)
419
{
420
result[i] = Kind_Manifold;
421
}
422
else if (openi != ~0u && openo != ~0u && remap[openi] == remap[openo] && openi != i)
423
{
424
// classify half-seams as seams (the branch below would mis-classify them as borders)
425
// half-seam is a single vertex that connects to both vertices of a potential seam
426
// treating these as seams allows collapsing the "full" seam vertex onto them
427
result[i] = Kind_Seam;
428
}
429
else if (openi != i && openo != i)
430
{
431
result[i] = Kind_Border;
432
}
433
else
434
{
435
result[i] = Kind_Locked;
436
TRACESTATS(0);
437
}
438
}
439
else if (wedge[wedge[i]] == i)
440
{
441
// attribute seam; need to distinguish between Seam and Locked
442
unsigned int w = wedge[i];
443
unsigned int openiv = openinc[i], openov = openout[i];
444
unsigned int openiw = openinc[w], openow = openout[w];
445
446
// seam should have one open half-edge for each vertex, and the edges need to "connect" - point to the same vertex post-remap
447
if (openiv != ~0u && openiv != i && openov != ~0u && openov != i &&
448
openiw != ~0u && openiw != w && openow != ~0u && openow != w)
449
{
450
if (remap[openiv] == remap[openow] && remap[openov] == remap[openiw] && remap[openiv] != remap[openov])
451
{
452
result[i] = Kind_Seam;
453
}
454
else
455
{
456
result[i] = Kind_Locked;
457
TRACESTATS(1);
458
}
459
}
460
else
461
{
462
result[i] = Kind_Locked;
463
TRACESTATS(2);
464
}
465
}
466
else
467
{
468
// more than one vertex maps to this one; we don't have classification available
469
result[i] = Kind_Locked;
470
TRACESTATS(3);
471
}
472
}
473
else
474
{
475
assert(remap[i] < i);
476
477
result[i] = result[remap[i]];
478
}
479
}
480
481
if (options & meshopt_SimplifyPermissive)
482
for (size_t i = 0; i < vertex_count; ++i)
483
if (result[i] == Kind_Seam || result[i] == Kind_Locked)
484
{
485
if (remap[i] != i)
486
{
487
// only process primary vertices; wedges will be updated to match the primary vertex
488
result[i] = result[remap[i]];
489
continue;
490
}
491
492
bool protect = false;
493
494
// vertex_lock may protect any wedge, not just the primary vertex, so we switch to complex only if no wedges are protected
495
unsigned int v = unsigned(i);
496
do
497
{
498
unsigned int rv = sparse_remap ? sparse_remap[v] : v;
499
protect |= vertex_lock && (vertex_lock[rv] & meshopt_SimplifyVertex_Protect) != 0;
500
v = wedge[v];
501
} while (v != i);
502
503
// protect if any adjoining edge doesn't have an opposite edge (indicating vertex is on the border)
504
do
505
{
506
const EdgeAdjacency::Edge* edges = &adjacency.data[adjacency.offsets[v]];
507
size_t count = adjacency.offsets[v + 1] - adjacency.offsets[v];
508
509
for (size_t j = 0; j < count; ++j)
510
protect |= !hasEdge(adjacency, edges[j].next, v, remap, wedge);
511
v = wedge[v];
512
} while (v != i);
513
514
result[i] = protect ? result[i] : int(Kind_Complex);
515
}
516
517
if (vertex_lock)
518
{
519
// vertex_lock may lock any wedge, not just the primary vertex, so we need to lock the primary vertex and relock any wedges
520
for (size_t i = 0; i < vertex_count; ++i)
521
{
522
unsigned int ri = sparse_remap ? sparse_remap[i] : unsigned(i);
523
524
if (vertex_lock[ri] & meshopt_SimplifyVertex_Lock)
525
result[remap[i]] = Kind_Locked;
526
}
527
528
for (size_t i = 0; i < vertex_count; ++i)
529
if (result[remap[i]] == Kind_Locked)
530
result[i] = Kind_Locked;
531
}
532
533
if (options & meshopt_SimplifyLockBorder)
534
for (size_t i = 0; i < vertex_count; ++i)
535
if (result[i] == Kind_Border)
536
result[i] = Kind_Locked;
537
538
#if TRACE
539
printf("locked: many open edges %d, disconnected seam %d, many seam edges %d, many wedges %d\n",
540
int(stats[0]), int(stats[1]), int(stats[2]), int(stats[3]));
541
#endif
542
}
543
544
struct Vector3
545
{
546
float x, y, z;
547
};
548
549
static float rescalePositions(Vector3* result, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, const unsigned int* sparse_remap = NULL, float* out_offset = NULL)
550
{
551
size_t vertex_stride_float = vertex_positions_stride / sizeof(float);
552
553
float minv[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
554
float maxv[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
555
556
for (size_t i = 0; i < vertex_count; ++i)
557
{
558
unsigned int ri = sparse_remap ? sparse_remap[i] : unsigned(i);
559
const float* v = vertex_positions_data + ri * vertex_stride_float;
560
561
if (result)
562
{
563
result[i].x = v[0];
564
result[i].y = v[1];
565
result[i].z = v[2];
566
}
567
568
for (int j = 0; j < 3; ++j)
569
{
570
float vj = v[j];
571
572
minv[j] = minv[j] > vj ? vj : minv[j];
573
maxv[j] = maxv[j] < vj ? vj : maxv[j];
574
}
575
}
576
577
float extent = 0.f;
578
579
extent = (maxv[0] - minv[0]) < extent ? extent : (maxv[0] - minv[0]);
580
extent = (maxv[1] - minv[1]) < extent ? extent : (maxv[1] - minv[1]);
581
extent = (maxv[2] - minv[2]) < extent ? extent : (maxv[2] - minv[2]);
582
583
if (result)
584
{
585
float scale = extent == 0 ? 0.f : 1.f / extent;
586
587
for (size_t i = 0; i < vertex_count; ++i)
588
{
589
result[i].x = (result[i].x - minv[0]) * scale;
590
result[i].y = (result[i].y - minv[1]) * scale;
591
result[i].z = (result[i].z - minv[2]) * scale;
592
}
593
}
594
595
if (out_offset)
596
{
597
out_offset[0] = minv[0];
598
out_offset[1] = minv[1];
599
out_offset[2] = minv[2];
600
}
601
602
return extent;
603
}
604
605
static void rescaleAttributes(float* result, const float* vertex_attributes_data, size_t vertex_count, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, const unsigned int* attribute_remap, const unsigned int* sparse_remap)
606
{
607
size_t vertex_attributes_stride_float = vertex_attributes_stride / sizeof(float);
608
609
for (size_t i = 0; i < vertex_count; ++i)
610
{
611
unsigned int ri = sparse_remap ? sparse_remap[i] : unsigned(i);
612
613
for (size_t k = 0; k < attribute_count; ++k)
614
{
615
unsigned int rk = attribute_remap[k];
616
float a = vertex_attributes_data[ri * vertex_attributes_stride_float + rk];
617
618
result[i * attribute_count + k] = a * attribute_weights[rk];
619
}
620
}
621
}
622
623
static void finalizeVertices(float* vertex_positions_data, size_t vertex_positions_stride, float* vertex_attributes_data, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, size_t vertex_count, const Vector3* vertex_positions, const float* vertex_attributes, const unsigned int* sparse_remap, const unsigned int* attribute_remap, float vertex_scale, const float* vertex_offset, const unsigned char* vertex_kind, const unsigned char* vertex_update, const unsigned char* vertex_lock)
624
{
625
size_t vertex_positions_stride_float = vertex_positions_stride / sizeof(float);
626
size_t vertex_attributes_stride_float = vertex_attributes_stride / sizeof(float);
627
628
for (size_t i = 0; i < vertex_count; ++i)
629
{
630
if (!vertex_update[i])
631
continue;
632
633
unsigned int ri = sparse_remap ? sparse_remap[i] : unsigned(i);
634
635
// updating externally locked vertices is not allowed
636
if (vertex_lock && (vertex_lock[ri] & meshopt_SimplifyVertex_Lock) != 0)
637
continue;
638
639
// moving locked vertices may result in floating point drift
640
if (vertex_kind[i] != Kind_Locked)
641
{
642
const Vector3& p = vertex_positions[i];
643
float* v = vertex_positions_data + ri * vertex_positions_stride_float;
644
645
v[0] = p.x * vertex_scale + vertex_offset[0];
646
v[1] = p.y * vertex_scale + vertex_offset[1];
647
v[2] = p.z * vertex_scale + vertex_offset[2];
648
}
649
650
if (attribute_count)
651
{
652
const float* sa = vertex_attributes + i * attribute_count;
653
float* va = vertex_attributes_data + ri * vertex_attributes_stride_float;
654
655
for (size_t k = 0; k < attribute_count; ++k)
656
{
657
unsigned int rk = attribute_remap[k];
658
659
va[rk] = sa[k] / attribute_weights[rk];
660
}
661
}
662
}
663
}
664
665
static const size_t kMaxAttributes = 32;
666
667
struct Quadric
668
{
669
// a00*x^2 + a11*y^2 + a22*z^2 + 2*a10*xy + 2*a20*xz + 2*a21*yz + 2*b0*x + 2*b1*y + 2*b2*z + c
670
float a00, a11, a22;
671
float a10, a20, a21;
672
float b0, b1, b2, c;
673
float w;
674
};
675
676
struct QuadricGrad
677
{
678
// gx*x + gy*y + gz*z + gw
679
float gx, gy, gz, gw;
680
};
681
682
struct Reservoir
683
{
684
float x, y, z;
685
float r, g, b;
686
float w;
687
};
688
689
struct Collapse
690
{
691
unsigned int v0;
692
unsigned int v1;
693
694
union
695
{
696
unsigned int bidi;
697
float error;
698
unsigned int errorui;
699
};
700
};
701
702
static float normalize(Vector3& v)
703
{
704
float length = sqrtf(v.x * v.x + v.y * v.y + v.z * v.z);
705
706
if (length > 0)
707
{
708
v.x /= length;
709
v.y /= length;
710
v.z /= length;
711
}
712
713
return length;
714
}
715
716
static void quadricAdd(Quadric& Q, const Quadric& R)
717
{
718
Q.a00 += R.a00;
719
Q.a11 += R.a11;
720
Q.a22 += R.a22;
721
Q.a10 += R.a10;
722
Q.a20 += R.a20;
723
Q.a21 += R.a21;
724
Q.b0 += R.b0;
725
Q.b1 += R.b1;
726
Q.b2 += R.b2;
727
Q.c += R.c;
728
Q.w += R.w;
729
}
730
731
static void quadricAdd(QuadricGrad& G, const QuadricGrad& R)
732
{
733
G.gx += R.gx;
734
G.gy += R.gy;
735
G.gz += R.gz;
736
G.gw += R.gw;
737
}
738
739
static void quadricAdd(QuadricGrad* G, const QuadricGrad* R, size_t attribute_count)
740
{
741
for (size_t k = 0; k < attribute_count; ++k)
742
{
743
G[k].gx += R[k].gx;
744
G[k].gy += R[k].gy;
745
G[k].gz += R[k].gz;
746
G[k].gw += R[k].gw;
747
}
748
}
749
750
static float quadricEval(const Quadric& Q, const Vector3& v)
751
{
752
float rx = Q.b0;
753
float ry = Q.b1;
754
float rz = Q.b2;
755
756
rx += Q.a10 * v.y;
757
ry += Q.a21 * v.z;
758
rz += Q.a20 * v.x;
759
760
rx *= 2;
761
ry *= 2;
762
rz *= 2;
763
764
rx += Q.a00 * v.x;
765
ry += Q.a11 * v.y;
766
rz += Q.a22 * v.z;
767
768
float r = Q.c;
769
r += rx * v.x;
770
r += ry * v.y;
771
r += rz * v.z;
772
773
return r;
774
}
775
776
static float quadricError(const Quadric& Q, const Vector3& v)
777
{
778
float r = quadricEval(Q, v);
779
float s = Q.w == 0.f ? 0.f : 1.f / Q.w;
780
781
return fabsf(r) * s;
782
}
783
784
static float quadricError(const Quadric& Q, const QuadricGrad* G, size_t attribute_count, const Vector3& v, const float* va)
785
{
786
float r = quadricEval(Q, v);
787
788
// see quadricFromAttributes for general derivation; here we need to add the parts of (eval(pos) - attr)^2 that depend on attr
789
for (size_t k = 0; k < attribute_count; ++k)
790
{
791
float a = va[k];
792
float g = v.x * G[k].gx + v.y * G[k].gy + v.z * G[k].gz + G[k].gw;
793
794
r += a * (a * Q.w - 2 * g);
795
}
796
797
// note: unlike position error, we do not normalize by Q.w to retain edge scaling as described in quadricFromAttributes
798
return fabsf(r);
799
}
800
801
static void quadricFromPlane(Quadric& Q, float a, float b, float c, float d, float w)
802
{
803
float aw = a * w;
804
float bw = b * w;
805
float cw = c * w;
806
float dw = d * w;
807
808
Q.a00 = a * aw;
809
Q.a11 = b * bw;
810
Q.a22 = c * cw;
811
Q.a10 = a * bw;
812
Q.a20 = a * cw;
813
Q.a21 = b * cw;
814
Q.b0 = a * dw;
815
Q.b1 = b * dw;
816
Q.b2 = c * dw;
817
Q.c = d * dw;
818
Q.w = w;
819
}
820
821
static void quadricFromPoint(Quadric& Q, float x, float y, float z, float w)
822
{
823
Q.a00 = Q.a11 = Q.a22 = w;
824
Q.a10 = Q.a20 = Q.a21 = 0;
825
Q.b0 = -x * w;
826
Q.b1 = -y * w;
827
Q.b2 = -z * w;
828
Q.c = (x * x + y * y + z * z) * w;
829
Q.w = w;
830
}
831
832
static void quadricFromTriangle(Quadric& Q, const Vector3& p0, const Vector3& p1, const Vector3& p2, float weight)
833
{
834
Vector3 p10 = {p1.x - p0.x, p1.y - p0.y, p1.z - p0.z};
835
Vector3 p20 = {p2.x - p0.x, p2.y - p0.y, p2.z - p0.z};
836
837
// normal = cross(p1 - p0, p2 - p0)
838
Vector3 normal = {p10.y * p20.z - p10.z * p20.y, p10.z * p20.x - p10.x * p20.z, p10.x * p20.y - p10.y * p20.x};
839
float area = normalize(normal);
840
841
float distance = normal.x * p0.x + normal.y * p0.y + normal.z * p0.z;
842
843
// we use sqrtf(area) so that the error is scaled linearly; this tends to improve silhouettes
844
quadricFromPlane(Q, normal.x, normal.y, normal.z, -distance, sqrtf(area) * weight);
845
}
846
847
static void quadricFromTriangleEdge(Quadric& Q, const Vector3& p0, const Vector3& p1, const Vector3& p2, float weight)
848
{
849
Vector3 p10 = {p1.x - p0.x, p1.y - p0.y, p1.z - p0.z};
850
851
// edge length; keep squared length around for projection correction
852
float lengthsq = p10.x * p10.x + p10.y * p10.y + p10.z * p10.z;
853
float length = sqrtf(lengthsq);
854
855
// p20p = length of projection of p2-p0 onto p1-p0; note that p10 is unnormalized so we need to correct it later
856
Vector3 p20 = {p2.x - p0.x, p2.y - p0.y, p2.z - p0.z};
857
float p20p = p20.x * p10.x + p20.y * p10.y + p20.z * p10.z;
858
859
// perp = perpendicular vector from p2 to line segment p1-p0
860
// note: since p10 is unnormalized we need to correct the projection; we scale p20 instead to take advantage of normalize below
861
Vector3 perp = {p20.x * lengthsq - p10.x * p20p, p20.y * lengthsq - p10.y * p20p, p20.z * lengthsq - p10.z * p20p};
862
normalize(perp);
863
864
float distance = perp.x * p0.x + perp.y * p0.y + perp.z * p0.z;
865
866
// note: the weight is scaled linearly with edge length; this has to match the triangle weight
867
quadricFromPlane(Q, perp.x, perp.y, perp.z, -distance, length * weight);
868
}
869
870
static void quadricFromAttributes(Quadric& Q, QuadricGrad* G, const Vector3& p0, const Vector3& p1, const Vector3& p2, const float* va0, const float* va1, const float* va2, size_t attribute_count)
871
{
872
// for each attribute we want to encode the following function into the quadric:
873
// (eval(pos) - attr)^2
874
// where eval(pos) interpolates attribute across the triangle like so:
875
// eval(pos) = pos.x * gx + pos.y * gy + pos.z * gz + gw
876
// where gx/gy/gz/gw are gradients
877
Vector3 p10 = {p1.x - p0.x, p1.y - p0.y, p1.z - p0.z};
878
Vector3 p20 = {p2.x - p0.x, p2.y - p0.y, p2.z - p0.z};
879
880
// normal = cross(p1 - p0, p2 - p0)
881
Vector3 normal = {p10.y * p20.z - p10.z * p20.y, p10.z * p20.x - p10.x * p20.z, p10.x * p20.y - p10.y * p20.x};
882
float area = sqrtf(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z) * 0.5f;
883
884
// quadric is weighted with the square of edge length (= area)
885
// this equalizes the units with the positional error (which, after normalization, is a square of distance)
886
// as a result, a change in weighted attribute of 1 along distance d is approximately equivalent to a change in position of d
887
float w = area;
888
889
// we compute gradients using barycentric coordinates; barycentric coordinates can be computed as follows:
890
// v = (d11 * d20 - d01 * d21) / denom
891
// w = (d00 * d21 - d01 * d20) / denom
892
// u = 1 - v - w
893
// here v0, v1 are triangle edge vectors, v2 is a vector from point to triangle corner, and dij = dot(vi, vj)
894
// note: v2 and d20/d21 can not be evaluated here as v2 is effectively an unknown variable; we need these only as variables for derivation of gradients
895
const Vector3& v0 = p10;
896
const Vector3& v1 = p20;
897
float d00 = v0.x * v0.x + v0.y * v0.y + v0.z * v0.z;
898
float d01 = v0.x * v1.x + v0.y * v1.y + v0.z * v1.z;
899
float d11 = v1.x * v1.x + v1.y * v1.y + v1.z * v1.z;
900
float denom = d00 * d11 - d01 * d01;
901
float denomr = denom == 0 ? 0.f : 1.f / denom;
902
903
// precompute gradient factors
904
// these are derived by directly computing derivative of eval(pos) = a0 * u + a1 * v + a2 * w and factoring out expressions that are shared between attributes
905
float gx1 = (d11 * v0.x - d01 * v1.x) * denomr;
906
float gx2 = (d00 * v1.x - d01 * v0.x) * denomr;
907
float gy1 = (d11 * v0.y - d01 * v1.y) * denomr;
908
float gy2 = (d00 * v1.y - d01 * v0.y) * denomr;
909
float gz1 = (d11 * v0.z - d01 * v1.z) * denomr;
910
float gz2 = (d00 * v1.z - d01 * v0.z) * denomr;
911
912
memset(&Q, 0, sizeof(Quadric));
913
914
Q.w = w;
915
916
for (size_t k = 0; k < attribute_count; ++k)
917
{
918
float a0 = va0[k], a1 = va1[k], a2 = va2[k];
919
920
// compute gradient of eval(pos) for x/y/z/w
921
// the formulas below are obtained by directly computing derivative of eval(pos) = a0 * u + a1 * v + a2 * w
922
float gx = gx1 * (a1 - a0) + gx2 * (a2 - a0);
923
float gy = gy1 * (a1 - a0) + gy2 * (a2 - a0);
924
float gz = gz1 * (a1 - a0) + gz2 * (a2 - a0);
925
float gw = a0 - p0.x * gx - p0.y * gy - p0.z * gz;
926
927
// quadric encodes (eval(pos)-attr)^2; this means that the resulting expansion needs to compute, for example, pos.x * pos.y * K
928
// since quadrics already encode factors for pos.x * pos.y, we can accumulate almost everything in basic quadric fields
929
// note: for simplicity we scale all factors by weight here instead of outside the loop
930
Q.a00 += w * (gx * gx);
931
Q.a11 += w * (gy * gy);
932
Q.a22 += w * (gz * gz);
933
934
Q.a10 += w * (gy * gx);
935
Q.a20 += w * (gz * gx);
936
Q.a21 += w * (gz * gy);
937
938
Q.b0 += w * (gx * gw);
939
Q.b1 += w * (gy * gw);
940
Q.b2 += w * (gz * gw);
941
942
Q.c += w * (gw * gw);
943
944
// the only remaining sum components are ones that depend on attr; these will be addded during error evaluation, see quadricError
945
G[k].gx = w * gx;
946
G[k].gy = w * gy;
947
G[k].gz = w * gz;
948
G[k].gw = w * gw;
949
}
950
}
951
952
static void quadricVolumeGradient(QuadricGrad& G, const Vector3& p0, const Vector3& p1, const Vector3& p2)
953
{
954
Vector3 p10 = {p1.x - p0.x, p1.y - p0.y, p1.z - p0.z};
955
Vector3 p20 = {p2.x - p0.x, p2.y - p0.y, p2.z - p0.z};
956
957
// normal = cross(p1 - p0, p2 - p0)
958
Vector3 normal = {p10.y * p20.z - p10.z * p20.y, p10.z * p20.x - p10.x * p20.z, p10.x * p20.y - p10.y * p20.x};
959
float area = normalize(normal) * 0.5f;
960
961
G.gx = normal.x * area;
962
G.gy = normal.y * area;
963
G.gz = normal.z * area;
964
G.gw = (-p0.x * normal.x - p0.y * normal.y - p0.z * normal.z) * area;
965
}
966
967
static bool quadricSolve(Vector3& p, const Quadric& Q, const QuadricGrad& GV)
968
{
969
// solve A*p = -b where A is the quadric matrix and b is the linear term
970
float a00 = Q.a00, a11 = Q.a11, a22 = Q.a22;
971
float a10 = Q.a10, a20 = Q.a20, a21 = Q.a21;
972
float x0 = -Q.b0, x1 = -Q.b1, x2 = -Q.b2;
973
974
float eps = 1e-6f * Q.w;
975
976
// LDL decomposition: A = LDL^T
977
float d0 = a00;
978
float l10 = a10 / d0;
979
float l20 = a20 / d0;
980
981
float d1 = a11 - a10 * l10;
982
float dl21 = a21 - a20 * l10;
983
float l21 = dl21 / d1;
984
985
float d2 = a22 - a20 * l20 - dl21 * l21;
986
987
// solve L*y = x
988
float y0 = x0;
989
float y1 = x1 - l10 * y0;
990
float y2 = x2 - l20 * y0 - l21 * y1;
991
992
// solve D*z = y
993
float z0 = y0 / d0;
994
float z1 = y1 / d1;
995
float z2 = y2 / d2;
996
997
// augment system with linear constraint GV using Lagrange multiplier
998
float a30 = GV.gx, a31 = GV.gy, a32 = GV.gz;
999
float x3 = -GV.gw;
1000
1001
float l30 = a30 / d0;
1002
float dl31 = a31 - a30 * l10;
1003
float l31 = dl31 / d1;
1004
float dl32 = a32 - a30 * l20 - dl31 * l21;
1005
float l32 = dl32 / d2;
1006
float d3 = 0.f - a30 * l30 - dl31 * l31 - dl32 * l32;
1007
1008
float y3 = x3 - l30 * y0 - l31 * y1 - l32 * y2;
1009
float z3 = fabsf(d3) > eps ? y3 / d3 : 0.f; // if d3 is zero, we can ignore the constraint
1010
1011
// substitute L^T*p = z
1012
float lambda = z3;
1013
float pz = z2 - l32 * lambda;
1014
float py = z1 - l21 * pz - l31 * lambda;
1015
float px = z0 - l10 * py - l20 * pz - l30 * lambda;
1016
1017
p.x = px;
1018
p.y = py;
1019
p.z = pz;
1020
1021
return fabsf(d0) > eps && fabsf(d1) > eps && fabsf(d2) > eps;
1022
}
1023
1024
static void quadricReduceAttributes(Quadric& Q, const Quadric& A, const QuadricGrad* G, size_t attribute_count)
1025
{
1026
// update vertex quadric with attribute quadric; multiply by vertex weight to minimize normalized error
1027
Q.a00 += A.a00 * Q.w;
1028
Q.a11 += A.a11 * Q.w;
1029
Q.a22 += A.a22 * Q.w;
1030
Q.a10 += A.a10 * Q.w;
1031
Q.a20 += A.a20 * Q.w;
1032
Q.a21 += A.a21 * Q.w;
1033
Q.b0 += A.b0 * Q.w;
1034
Q.b1 += A.b1 * Q.w;
1035
Q.b2 += A.b2 * Q.w;
1036
1037
float iaw = A.w == 0 ? 0.f : Q.w / A.w;
1038
1039
// update linear system based on attribute gradients (BB^T/a)
1040
for (size_t k = 0; k < attribute_count; ++k)
1041
{
1042
const QuadricGrad& g = G[k];
1043
1044
Q.a00 -= (g.gx * g.gx) * iaw;
1045
Q.a11 -= (g.gy * g.gy) * iaw;
1046
Q.a22 -= (g.gz * g.gz) * iaw;
1047
Q.a10 -= (g.gx * g.gy) * iaw;
1048
Q.a20 -= (g.gx * g.gz) * iaw;
1049
Q.a21 -= (g.gy * g.gz) * iaw;
1050
1051
Q.b0 -= (g.gx * g.gw) * iaw;
1052
Q.b1 -= (g.gy * g.gw) * iaw;
1053
Q.b2 -= (g.gz * g.gw) * iaw;
1054
}
1055
}
1056
1057
static void fillFaceQuadrics(Quadric* vertex_quadrics, QuadricGrad* volume_gradients, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const unsigned int* remap)
1058
{
1059
for (size_t i = 0; i < index_count; i += 3)
1060
{
1061
unsigned int i0 = indices[i + 0];
1062
unsigned int i1 = indices[i + 1];
1063
unsigned int i2 = indices[i + 2];
1064
1065
Quadric Q;
1066
quadricFromTriangle(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], 1.f);
1067
1068
quadricAdd(vertex_quadrics[remap[i0]], Q);
1069
quadricAdd(vertex_quadrics[remap[i1]], Q);
1070
quadricAdd(vertex_quadrics[remap[i2]], Q);
1071
1072
if (volume_gradients)
1073
{
1074
QuadricGrad GV;
1075
quadricVolumeGradient(GV, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2]);
1076
1077
quadricAdd(volume_gradients[remap[i0]], GV);
1078
quadricAdd(volume_gradients[remap[i1]], GV);
1079
quadricAdd(volume_gradients[remap[i2]], GV);
1080
}
1081
}
1082
}
1083
1084
static void fillVertexQuadrics(Quadric* vertex_quadrics, const Vector3* vertex_positions, size_t vertex_count, const unsigned int* remap, unsigned int options)
1085
{
1086
// by default, we use a very small weight to improve triangulation and numerical stability without affecting the shape or error
1087
float factor = (options & meshopt_SimplifyRegularize) ? 1e-1f : 1e-7f;
1088
1089
for (size_t i = 0; i < vertex_count; ++i)
1090
{
1091
if (remap[i] != i)
1092
continue;
1093
1094
const Vector3& p = vertex_positions[i];
1095
float w = vertex_quadrics[i].w * factor;
1096
1097
Quadric Q;
1098
quadricFromPoint(Q, p.x, p.y, p.z, w);
1099
1100
quadricAdd(vertex_quadrics[i], Q);
1101
}
1102
}
1103
1104
static void fillEdgeQuadrics(Quadric* vertex_quadrics, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const unsigned int* remap, const unsigned char* vertex_kind, const unsigned int* loop, const unsigned int* loopback)
1105
{
1106
for (size_t i = 0; i < index_count; i += 3)
1107
{
1108
static const int next[4] = {1, 2, 0, 1};
1109
1110
for (int e = 0; e < 3; ++e)
1111
{
1112
unsigned int i0 = indices[i + e];
1113
unsigned int i1 = indices[i + next[e]];
1114
1115
unsigned char k0 = vertex_kind[i0];
1116
unsigned char k1 = vertex_kind[i1];
1117
1118
// check that either i0 or i1 are border/seam and are on the same edge loop
1119
// note that we need to add the error even for edged that connect e.g. border & locked
1120
// if we don't do that, the adjacent border->border edge won't have correct errors for corners
1121
if (k0 != Kind_Border && k0 != Kind_Seam && k1 != Kind_Border && k1 != Kind_Seam)
1122
continue;
1123
1124
if ((k0 == Kind_Border || k0 == Kind_Seam) && loop[i0] != i1)
1125
continue;
1126
1127
if ((k1 == Kind_Border || k1 == Kind_Seam) && loopback[i1] != i0)
1128
continue;
1129
1130
unsigned int i2 = indices[i + next[e + 1]];
1131
1132
// we try hard to maintain border edge geometry; seam edges can move more freely
1133
// due to topological restrictions on collapses, seam quadrics slightly improves collapse structure but aren't critical
1134
const float kEdgeWeightSeam = 0.5f; // applied twice due to opposite edges
1135
const float kEdgeWeightBorder = 10.f;
1136
1137
float edgeWeight = (k0 == Kind_Border || k1 == Kind_Border) ? kEdgeWeightBorder : kEdgeWeightSeam;
1138
1139
Quadric Q;
1140
quadricFromTriangleEdge(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], edgeWeight);
1141
1142
Quadric QT;
1143
quadricFromTriangle(QT, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], edgeWeight);
1144
1145
// mix edge quadric with triangle quadric to stabilize collapses in both directions; both quadrics inherit edge weight so that their error is added
1146
QT.w = 0;
1147
quadricAdd(Q, QT);
1148
1149
quadricAdd(vertex_quadrics[remap[i0]], Q);
1150
quadricAdd(vertex_quadrics[remap[i1]], Q);
1151
}
1152
}
1153
}
1154
1155
static void fillAttributeQuadrics(Quadric* attribute_quadrics, QuadricGrad* attribute_gradients, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const float* vertex_attributes, size_t attribute_count)
1156
{
1157
for (size_t i = 0; i < index_count; i += 3)
1158
{
1159
unsigned int i0 = indices[i + 0];
1160
unsigned int i1 = indices[i + 1];
1161
unsigned int i2 = indices[i + 2];
1162
1163
Quadric QA;
1164
QuadricGrad G[kMaxAttributes];
1165
quadricFromAttributes(QA, G, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], &vertex_attributes[i0 * attribute_count], &vertex_attributes[i1 * attribute_count], &vertex_attributes[i2 * attribute_count], attribute_count);
1166
1167
quadricAdd(attribute_quadrics[i0], QA);
1168
quadricAdd(attribute_quadrics[i1], QA);
1169
quadricAdd(attribute_quadrics[i2], QA);
1170
1171
quadricAdd(&attribute_gradients[i0 * attribute_count], G, attribute_count);
1172
quadricAdd(&attribute_gradients[i1 * attribute_count], G, attribute_count);
1173
quadricAdd(&attribute_gradients[i2 * attribute_count], G, attribute_count);
1174
}
1175
}
1176
1177
// does triangle ABC flip when C is replaced with D?
1178
static bool hasTriangleFlip(const Vector3& a, const Vector3& b, const Vector3& c, const Vector3& d)
1179
{
1180
Vector3 eb = {b.x - a.x, b.y - a.y, b.z - a.z};
1181
Vector3 ec = {c.x - a.x, c.y - a.y, c.z - a.z};
1182
Vector3 ed = {d.x - a.x, d.y - a.y, d.z - a.z};
1183
1184
Vector3 nbc = {eb.y * ec.z - eb.z * ec.y, eb.z * ec.x - eb.x * ec.z, eb.x * ec.y - eb.y * ec.x};
1185
Vector3 nbd = {eb.y * ed.z - eb.z * ed.y, eb.z * ed.x - eb.x * ed.z, eb.x * ed.y - eb.y * ed.x};
1186
1187
float ndp = nbc.x * nbd.x + nbc.y * nbd.y + nbc.z * nbd.z;
1188
float abc = nbc.x * nbc.x + nbc.y * nbc.y + nbc.z * nbc.z;
1189
float abd = nbd.x * nbd.x + nbd.y * nbd.y + nbd.z * nbd.z;
1190
1191
// scale is cos(angle); somewhat arbitrarily set to ~75 degrees
1192
// note that the "pure" check is ndp <= 0 (90 degree cutoff) but that allows flipping through a series of close-to-90 collapses
1193
return ndp <= 0.25f * sqrtf(abc * abd);
1194
}
1195
1196
static bool hasTriangleFlips(const EdgeAdjacency& adjacency, const Vector3* vertex_positions, const unsigned int* collapse_remap, unsigned int i0, unsigned int i1)
1197
{
1198
assert(collapse_remap[i0] == i0);
1199
assert(collapse_remap[i1] == i1);
1200
1201
const Vector3& v0 = vertex_positions[i0];
1202
const Vector3& v1 = vertex_positions[i1];
1203
1204
const EdgeAdjacency::Edge* edges = &adjacency.data[adjacency.offsets[i0]];
1205
size_t count = adjacency.offsets[i0 + 1] - adjacency.offsets[i0];
1206
1207
for (size_t i = 0; i < count; ++i)
1208
{
1209
unsigned int a = collapse_remap[edges[i].next];
1210
unsigned int b = collapse_remap[edges[i].prev];
1211
1212
// skip triangles that will get collapsed by i0->i1 collapse or already got collapsed previously
1213
if (a == i1 || b == i1 || a == b)
1214
continue;
1215
1216
// early-out when at least one triangle flips due to a collapse
1217
if (hasTriangleFlip(vertex_positions[a], vertex_positions[b], v0, v1))
1218
{
1219
#if TRACE >= 2
1220
printf("edge block %d -> %d: flip welded %d %d %d\n", i0, i1, a, i0, b);
1221
#endif
1222
1223
return true;
1224
}
1225
}
1226
1227
return false;
1228
}
1229
1230
static bool hasTriangleFlips(const EdgeAdjacency& adjacency, const Vector3* vertex_positions, unsigned int i0, const Vector3& v1)
1231
{
1232
const Vector3& v0 = vertex_positions[i0];
1233
1234
const EdgeAdjacency::Edge* edges = &adjacency.data[adjacency.offsets[i0]];
1235
size_t count = adjacency.offsets[i0 + 1] - adjacency.offsets[i0];
1236
1237
for (size_t i = 0; i < count; ++i)
1238
{
1239
unsigned int a = edges[i].next, b = edges[i].prev;
1240
1241
if (hasTriangleFlip(vertex_positions[a], vertex_positions[b], v0, v1))
1242
return true;
1243
}
1244
1245
return false;
1246
}
1247
1248
static float getNeighborhoodRadius(const EdgeAdjacency& adjacency, const Vector3* vertex_positions, unsigned int i0)
1249
{
1250
const Vector3& v0 = vertex_positions[i0];
1251
1252
const EdgeAdjacency::Edge* edges = &adjacency.data[adjacency.offsets[i0]];
1253
size_t count = adjacency.offsets[i0 + 1] - adjacency.offsets[i0];
1254
1255
float result = 0.f;
1256
1257
for (size_t i = 0; i < count; ++i)
1258
{
1259
unsigned int a = edges[i].next, b = edges[i].prev;
1260
1261
const Vector3& va = vertex_positions[a];
1262
const Vector3& vb = vertex_positions[b];
1263
1264
float da = (va.x - v0.x) * (va.x - v0.x) + (va.y - v0.y) * (va.y - v0.y) + (va.z - v0.z) * (va.z - v0.z);
1265
float db = (vb.x - v0.x) * (vb.x - v0.x) + (vb.y - v0.y) * (vb.y - v0.y) + (vb.z - v0.z) * (vb.z - v0.z);
1266
1267
result = result < da ? da : result;
1268
result = result < db ? db : result;
1269
}
1270
1271
return sqrtf(result);
1272
}
1273
1274
static unsigned int getComplexTarget(unsigned int v, unsigned int target, const unsigned int* remap, const unsigned int* loop, const unsigned int* loopback)
1275
{
1276
unsigned int r = remap[target];
1277
1278
// use loop metadata to guide complex collapses towards the correct wedge
1279
// this works for edges on attribute discontinuities because loop/loopback track the single half-edge without a pair, similar to seams
1280
if (loop[v] != ~0u && remap[loop[v]] == r)
1281
return loop[v];
1282
else if (loopback[v] != ~0u && remap[loopback[v]] == r)
1283
return loopback[v];
1284
else
1285
return target;
1286
}
1287
1288
static size_t boundEdgeCollapses(const EdgeAdjacency& adjacency, size_t vertex_count, size_t index_count, unsigned char* vertex_kind)
1289
{
1290
size_t dual_count = 0;
1291
1292
for (size_t i = 0; i < vertex_count; ++i)
1293
{
1294
unsigned char k = vertex_kind[i];
1295
unsigned int e = adjacency.offsets[i + 1] - adjacency.offsets[i];
1296
1297
dual_count += (k == Kind_Manifold || k == Kind_Seam) ? e : 0;
1298
}
1299
1300
assert(dual_count <= index_count);
1301
1302
// pad capacity by 3 so that we can check for overflow once per triangle instead of once per edge
1303
return (index_count - dual_count / 2) + 3;
1304
}
1305
1306
static size_t pickEdgeCollapses(Collapse* collapses, size_t collapse_capacity, const unsigned int* indices, size_t index_count, const unsigned int* remap, const unsigned char* vertex_kind, const unsigned int* loop, const unsigned int* loopback)
1307
{
1308
size_t collapse_count = 0;
1309
1310
for (size_t i = 0; i < index_count; i += 3)
1311
{
1312
static const int next[3] = {1, 2, 0};
1313
1314
// this should never happen as boundEdgeCollapses should give an upper bound for the collapse count, but in an unlikely event it does we can just drop extra collapses
1315
if (collapse_count + 3 > collapse_capacity)
1316
break;
1317
1318
for (int e = 0; e < 3; ++e)
1319
{
1320
unsigned int i0 = indices[i + e];
1321
unsigned int i1 = indices[i + next[e]];
1322
1323
// this can happen either when input has a zero-length edge, or when we perform collapses for complex
1324
// topology w/seams and collapse a manifold vertex that connects to both wedges onto one of them
1325
// we leave edges like this alone since they may be important for preserving mesh integrity
1326
if (remap[i0] == remap[i1])
1327
continue;
1328
1329
unsigned char k0 = vertex_kind[i0];
1330
unsigned char k1 = vertex_kind[i1];
1331
1332
// the edge has to be collapsible in at least one direction
1333
if (!(kCanCollapse[k0][k1] | kCanCollapse[k1][k0]))
1334
continue;
1335
1336
// manifold and seam edges should occur twice (i0->i1 and i1->i0) - skip redundant edges
1337
if (kHasOpposite[k0][k1] && remap[i1] > remap[i0])
1338
continue;
1339
1340
// two vertices are on a border or a seam, but there's no direct edge between them
1341
// this indicates that they belong to two different edge loops and we should not collapse this edge
1342
// loop[] and loopback[] track half edges so we only need to check one of them
1343
if ((k0 == Kind_Border || k0 == Kind_Seam) && k1 != Kind_Manifold && loop[i0] != i1)
1344
continue;
1345
if ((k1 == Kind_Border || k1 == Kind_Seam) && k0 != Kind_Manifold && loopback[i1] != i0)
1346
continue;
1347
1348
// edge can be collapsed in either direction - we will pick the one with minimum error
1349
// note: we evaluate error later during collapse ranking, here we just tag the edge as bidirectional
1350
if (kCanCollapse[k0][k1] & kCanCollapse[k1][k0])
1351
{
1352
Collapse c = {i0, i1, {/* bidi= */ 1}};
1353
collapses[collapse_count++] = c;
1354
}
1355
else
1356
{
1357
// edge can only be collapsed in one direction
1358
unsigned int e0 = kCanCollapse[k0][k1] ? i0 : i1;
1359
unsigned int e1 = kCanCollapse[k0][k1] ? i1 : i0;
1360
1361
Collapse c = {e0, e1, {/* bidi= */ 0}};
1362
collapses[collapse_count++] = c;
1363
}
1364
}
1365
}
1366
1367
return collapse_count;
1368
}
1369
1370
static void rankEdgeCollapses(Collapse* collapses, size_t collapse_count, const Vector3* vertex_positions, const float* vertex_attributes, const Quadric* vertex_quadrics, const Quadric* attribute_quadrics, const QuadricGrad* attribute_gradients, size_t attribute_count, const unsigned int* remap, const unsigned int* wedge, const unsigned char* vertex_kind, const unsigned int* loop, const unsigned int* loopback)
1371
{
1372
for (size_t i = 0; i < collapse_count; ++i)
1373
{
1374
Collapse& c = collapses[i];
1375
1376
unsigned int i0 = c.v0;
1377
unsigned int i1 = c.v1;
1378
bool bidi = c.bidi;
1379
1380
float ei = quadricError(vertex_quadrics[remap[i0]], vertex_positions[i1]);
1381
float ej = bidi ? quadricError(vertex_quadrics[remap[i1]], vertex_positions[i0]) : FLT_MAX;
1382
1383
#if TRACE >= 3
1384
float di = ei, dj = ej;
1385
#endif
1386
1387
if (attribute_count)
1388
{
1389
ei += quadricError(attribute_quadrics[i0], &attribute_gradients[i0 * attribute_count], attribute_count, vertex_positions[i1], &vertex_attributes[i1 * attribute_count]);
1390
ej += bidi ? quadricError(attribute_quadrics[i1], &attribute_gradients[i1 * attribute_count], attribute_count, vertex_positions[i0], &vertex_attributes[i0 * attribute_count]) : 0;
1391
1392
// seam edges need to aggregate attribute errors between primary and secondary edges, as attribute quadrics are separate
1393
if (vertex_kind[i0] == Kind_Seam)
1394
{
1395
// for seam collapses we need to find the seam pair; this is a bit tricky since we need to rely on edge loops as target vertex may be locked (and thus have more than two wedges)
1396
unsigned int s0 = wedge[i0];
1397
unsigned int s1 = loop[i0] == i1 ? loopback[s0] : loop[s0];
1398
1399
assert(wedge[s0] == i0); // s0 may be equal to i0 for half-seams
1400
assert(s1 != ~0u && remap[s1] == remap[i1]);
1401
1402
// note: this should never happen due to the assertion above, but when disabled if we ever hit this case we'll get a memory safety issue; for now play it safe
1403
s1 = (s1 != ~0u) ? s1 : wedge[i1];
1404
1405
ei += quadricError(attribute_quadrics[s0], &attribute_gradients[s0 * attribute_count], attribute_count, vertex_positions[s1], &vertex_attributes[s1 * attribute_count]);
1406
ej += bidi ? quadricError(attribute_quadrics[s1], &attribute_gradients[s1 * attribute_count], attribute_count, vertex_positions[s0], &vertex_attributes[s0 * attribute_count]) : 0;
1407
}
1408
else
1409
{
1410
// complex edges can have multiple wedges, so we need to aggregate errors for all wedges based on the selected target
1411
if (vertex_kind[i0] == Kind_Complex)
1412
for (unsigned int v = wedge[i0]; v != i0; v = wedge[v])
1413
{
1414
unsigned int t = getComplexTarget(v, i1, remap, loop, loopback);
1415
1416
ei += quadricError(attribute_quadrics[v], &attribute_gradients[v * attribute_count], attribute_count, vertex_positions[t], &vertex_attributes[t * attribute_count]);
1417
}
1418
1419
if (vertex_kind[i1] == Kind_Complex && bidi)
1420
for (unsigned int v = wedge[i1]; v != i1; v = wedge[v])
1421
{
1422
unsigned int t = getComplexTarget(v, i0, remap, loop, loopback);
1423
1424
ej += quadricError(attribute_quadrics[v], &attribute_gradients[v * attribute_count], attribute_count, vertex_positions[t], &vertex_attributes[t * attribute_count]);
1425
}
1426
}
1427
}
1428
1429
// pick edge direction with minimal error (branchless)
1430
bool rev = bidi & (ej < ei);
1431
1432
c.v0 = rev ? i1 : i0;
1433
c.v1 = rev ? i0 : i1;
1434
c.error = ej < ei ? ej : ei;
1435
1436
#if TRACE >= 3
1437
if (bidi)
1438
printf("edge eval %d -> %d: error %f (pos %f, attr %f); reverse %f (pos %f, attr %f)\n",
1439
rev ? i1 : i0, rev ? i0 : i1,
1440
sqrtf(rev ? ej : ei), sqrtf(rev ? dj : di), sqrtf(rev ? ej - dj : ei - di),
1441
sqrtf(rev ? ei : ej), sqrtf(rev ? di : dj), sqrtf(rev ? ei - di : ej - dj));
1442
else
1443
printf("edge eval %d -> %d: error %f (pos %f, attr %f)\n", i0, i1, sqrtf(c.error), sqrtf(di), sqrtf(ei - di));
1444
#endif
1445
}
1446
}
1447
1448
static void sortEdgeCollapses(unsigned int* sort_order, const Collapse* collapses, size_t collapse_count)
1449
{
1450
// we use counting sort to order collapses by error; since the exact sort order is not as critical,
1451
// only top 12 bits of exponent+mantissa (8 bits of exponent and 4 bits of mantissa) are used.
1452
// to avoid excessive stack usage, we clamp the exponent range as collapses with errors much higher than 1 are not useful.
1453
const unsigned int sort_bits = 12;
1454
const unsigned int sort_bins = 2048 + 512; // exponent range [-127, 32)
1455
1456
// fill histogram for counting sort
1457
unsigned int histogram[sort_bins];
1458
memset(histogram, 0, sizeof(histogram));
1459
1460
for (size_t i = 0; i < collapse_count; ++i)
1461
{
1462
// skip sign bit since error is non-negative
1463
unsigned int error = collapses[i].errorui;
1464
unsigned int key = (error << 1) >> (32 - sort_bits);
1465
key = key < sort_bins ? key : sort_bins - 1;
1466
1467
histogram[key]++;
1468
}
1469
1470
// compute offsets based on histogram data
1471
size_t histogram_sum = 0;
1472
1473
for (size_t i = 0; i < sort_bins; ++i)
1474
{
1475
size_t count = histogram[i];
1476
histogram[i] = unsigned(histogram_sum);
1477
histogram_sum += count;
1478
}
1479
1480
assert(histogram_sum == collapse_count);
1481
1482
// compute sort order based on offsets
1483
for (size_t i = 0; i < collapse_count; ++i)
1484
{
1485
// skip sign bit since error is non-negative
1486
unsigned int error = collapses[i].errorui;
1487
unsigned int key = (error << 1) >> (32 - sort_bits);
1488
key = key < sort_bins ? key : sort_bins - 1;
1489
1490
sort_order[histogram[key]++] = unsigned(i);
1491
}
1492
}
1493
1494
static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char* collapse_locked, const Collapse* collapses, size_t collapse_count, const unsigned int* collapse_order, const unsigned int* remap, const unsigned int* wedge, const unsigned char* vertex_kind, const unsigned int* loop, const unsigned int* loopback, const Vector3* vertex_positions, const EdgeAdjacency& adjacency, size_t triangle_collapse_goal, float error_limit, float& result_error)
1495
{
1496
size_t edge_collapses = 0;
1497
size_t triangle_collapses = 0;
1498
1499
// most collapses remove 2 triangles; use this to establish a bound on the pass in terms of error limit
1500
// note that edge_collapse_goal is an estimate; triangle_collapse_goal will be used to actually limit collapses
1501
size_t edge_collapse_goal = triangle_collapse_goal / 2;
1502
1503
#if TRACE
1504
size_t stats[7] = {};
1505
#endif
1506
1507
for (size_t i = 0; i < collapse_count; ++i)
1508
{
1509
const Collapse& c = collapses[collapse_order[i]];
1510
1511
TRACESTATS(0);
1512
1513
if (c.error > error_limit)
1514
{
1515
TRACESTATS(4);
1516
break;
1517
}
1518
1519
if (triangle_collapses >= triangle_collapse_goal)
1520
{
1521
TRACESTATS(5);
1522
break;
1523
}
1524
1525
// we limit the error in each pass based on the error of optimal last collapse; since many collapses will be locked
1526
// as they will share vertices with other successfull collapses, we need to increase the acceptable error by some factor
1527
float error_goal = edge_collapse_goal < collapse_count ? 1.5f * collapses[collapse_order[edge_collapse_goal]].error : FLT_MAX;
1528
1529
// on average, each collapse is expected to lock 6 other collapses; to avoid degenerate passes on meshes with odd
1530
// topology, we only abort if we got over 1/6 collapses accordingly.
1531
if (c.error > error_goal && c.error > result_error && triangle_collapses > triangle_collapse_goal / 6)
1532
{
1533
TRACESTATS(6);
1534
break;
1535
}
1536
1537
unsigned int i0 = c.v0;
1538
unsigned int i1 = c.v1;
1539
1540
unsigned int r0 = remap[i0];
1541
unsigned int r1 = remap[i1];
1542
1543
unsigned char kind = vertex_kind[i0];
1544
1545
// we don't collapse vertices that had source or target vertex involved in a collapse
1546
// it's important to not move the vertices twice since it complicates the tracking/remapping logic
1547
// it's important to not move other vertices towards a moved vertex to preserve error since we don't re-rank collapses mid-pass
1548
if (collapse_locked[r0] | collapse_locked[r1])
1549
{
1550
TRACESTATS(1);
1551
continue;
1552
}
1553
1554
if (hasTriangleFlips(adjacency, vertex_positions, collapse_remap, r0, r1))
1555
{
1556
// adjust collapse goal since this collapse is invalid and shouldn't factor into error goal
1557
edge_collapse_goal++;
1558
1559
TRACESTATS(2);
1560
continue;
1561
}
1562
1563
#if TRACE >= 2
1564
printf("edge commit %d -> %d: kind %d->%d, error %f\n", i0, i1, vertex_kind[i0], vertex_kind[i1], sqrtf(c.error));
1565
#endif
1566
1567
assert(collapse_remap[r0] == r0);
1568
assert(collapse_remap[r1] == r1);
1569
1570
if (kind == Kind_Complex)
1571
{
1572
// remap all vertices in the complex to the target vertex
1573
unsigned int v = i0;
1574
1575
do
1576
{
1577
unsigned int t = getComplexTarget(v, i1, remap, loop, loopback);
1578
1579
collapse_remap[v] = t;
1580
v = wedge[v];
1581
} while (v != i0);
1582
}
1583
else if (kind == Kind_Seam)
1584
{
1585
// for seam collapses we need to move the seam pair together; this is a bit tricky since we need to rely on edge loops as target vertex may be locked (and thus have more than two wedges)
1586
unsigned int s0 = wedge[i0];
1587
unsigned int s1 = loop[i0] == i1 ? loopback[s0] : loop[s0];
1588
assert(wedge[s0] == i0); // s0 may be equal to i0 for half-seams
1589
assert(s1 != ~0u && remap[s1] == r1);
1590
1591
// additional asserts to verify that the seam pair is consistent
1592
assert(kind != vertex_kind[i1] || s1 == wedge[i1]);
1593
assert(loop[i0] == i1 || loopback[i0] == i1);
1594
assert(loop[s0] == s1 || loopback[s0] == s1);
1595
1596
// note: this should never happen due to the assertion above, but when disabled if we ever hit this case we'll get a memory safety issue; for now play it safe
1597
s1 = (s1 != ~0u) ? s1 : wedge[i1];
1598
1599
collapse_remap[i0] = i1;
1600
collapse_remap[s0] = s1;
1601
}
1602
else
1603
{
1604
assert(wedge[i0] == i0);
1605
1606
collapse_remap[i0] = i1;
1607
}
1608
1609
// note: we technically don't need to lock r1 if it's a locked vertex, as it can't move and its quadric won't be used
1610
// however, this results in slightly worse error on some meshes because the locked collapses get an unfair advantage wrt scheduling
1611
collapse_locked[r0] = 1;
1612
collapse_locked[r1] = 1;
1613
1614
// border edges collapse 1 triangle, other edges collapse 2 or more
1615
triangle_collapses += (kind == Kind_Border) ? 1 : 2;
1616
edge_collapses++;
1617
1618
result_error = result_error < c.error ? c.error : result_error;
1619
}
1620
1621
#if TRACE
1622
float error_goal_last = edge_collapse_goal < collapse_count ? 1.5f * collapses[collapse_order[edge_collapse_goal]].error : FLT_MAX;
1623
float error_goal_limit = error_goal_last < error_limit ? error_goal_last : error_limit;
1624
1625
printf("removed %d triangles, error %e (goal %e); evaluated %d/%d collapses (done %d, skipped %d, invalid %d); %s\n",
1626
int(triangle_collapses), sqrtf(result_error), sqrtf(error_goal_limit),
1627
int(stats[0]), int(collapse_count), int(edge_collapses), int(stats[1]), int(stats[2]),
1628
stats[4] ? "error limit" : (stats[5] ? "count limit" : (stats[6] ? "error goal" : "out of collapses")));
1629
#endif
1630
1631
return edge_collapses;
1632
}
1633
1634
static void updateQuadrics(const unsigned int* collapse_remap, size_t vertex_count, Quadric* vertex_quadrics, QuadricGrad* volume_gradients, Quadric* attribute_quadrics, QuadricGrad* attribute_gradients, size_t attribute_count, const Vector3* vertex_positions, const unsigned int* remap, float& vertex_error)
1635
{
1636
for (size_t i = 0; i < vertex_count; ++i)
1637
{
1638
if (collapse_remap[i] == i)
1639
continue;
1640
1641
unsigned int i0 = unsigned(i);
1642
unsigned int i1 = collapse_remap[i];
1643
1644
unsigned int r0 = remap[i0];
1645
unsigned int r1 = remap[i1];
1646
1647
// ensure we only update vertex_quadrics once: primary vertex must be moved if any wedge is moved
1648
if (i0 == r0)
1649
{
1650
quadricAdd(vertex_quadrics[r1], vertex_quadrics[r0]);
1651
1652
if (volume_gradients)
1653
quadricAdd(volume_gradients[r1], volume_gradients[r0]);
1654
}
1655
1656
if (attribute_count)
1657
{
1658
quadricAdd(attribute_quadrics[i1], attribute_quadrics[i0]);
1659
quadricAdd(&attribute_gradients[i1 * attribute_count], &attribute_gradients[i0 * attribute_count], attribute_count);
1660
1661
if (i0 == r0)
1662
{
1663
// when attributes are used, distance error needs to be recomputed as collapses don't track it; it is safe to do this after the quadric adjustment
1664
float derr = quadricError(vertex_quadrics[r0], vertex_positions[r1]);
1665
vertex_error = vertex_error < derr ? derr : vertex_error;
1666
}
1667
}
1668
}
1669
}
1670
1671
static void solvePositions(Vector3* vertex_positions, size_t vertex_count, const Quadric* vertex_quadrics, const QuadricGrad* volume_gradients, const Quadric* attribute_quadrics, const QuadricGrad* attribute_gradients, size_t attribute_count, const unsigned int* remap, const unsigned int* wedge, const EdgeAdjacency& adjacency, const unsigned char* vertex_kind, const unsigned char* vertex_update)
1672
{
1673
#if TRACE
1674
size_t stats[6] = {};
1675
#endif
1676
1677
for (size_t i = 0; i < vertex_count; ++i)
1678
{
1679
if (!vertex_update[i])
1680
continue;
1681
1682
// moving vertices on an attribute discontinuity may result in extrapolating UV outside of the chart bounds
1683
// moving vertices on a border requires a stronger edge quadric to preserve the border geometry
1684
if (vertex_kind[i] == Kind_Locked || vertex_kind[i] == Kind_Seam || vertex_kind[i] == Kind_Border)
1685
continue;
1686
1687
if (remap[i] != i)
1688
{
1689
vertex_positions[i] = vertex_positions[remap[i]];
1690
continue;
1691
}
1692
1693
TRACESTATS(0);
1694
1695
const Vector3& vp = vertex_positions[i];
1696
1697
Quadric Q = vertex_quadrics[i];
1698
QuadricGrad GV = {};
1699
1700
// add a point quadric for regularization to stabilize the solution
1701
Quadric R;
1702
quadricFromPoint(R, vp.x, vp.y, vp.z, Q.w * 1e-4f);
1703
quadricAdd(Q, R);
1704
1705
if (attribute_count)
1706
{
1707
// optimal point simultaneously minimizes attribute quadrics for all wedges
1708
unsigned int v = unsigned(i);
1709
do
1710
{
1711
quadricReduceAttributes(Q, attribute_quadrics[v], &attribute_gradients[v * attribute_count], attribute_count);
1712
v = wedge[v];
1713
} while (v != i);
1714
1715
// minimizing attribute quadrics results in volume loss so we incorporate volume gradient as a constraint
1716
if (volume_gradients)
1717
GV = volume_gradients[i];
1718
}
1719
1720
Vector3 p;
1721
if (!quadricSolve(p, Q, GV))
1722
{
1723
TRACESTATS(2);
1724
continue;
1725
}
1726
1727
// reject updates that move the vertex too far from its neighborhood
1728
// this detects and fixes most cases when the quadric is not well-defined
1729
float nr = getNeighborhoodRadius(adjacency, vertex_positions, unsigned(i));
1730
float dp = (p.x - vp.x) * (p.x - vp.x) + (p.y - vp.y) * (p.y - vp.y) + (p.z - vp.z) * (p.z - vp.z);
1731
1732
if (dp > nr * nr)
1733
{
1734
TRACESTATS(3);
1735
continue;
1736
}
1737
1738
// reject updates that would flip a neighboring triangle, as we do for edge collapse
1739
if (hasTriangleFlips(adjacency, vertex_positions, unsigned(i), p))
1740
{
1741
TRACESTATS(4);
1742
continue;
1743
}
1744
1745
// reject updates that increase positional error too much; allow some tolerance to improve attribute quality
1746
if (quadricError(vertex_quadrics[i], p) > quadricError(vertex_quadrics[i], vp) * 1.5f + 1e-6f)
1747
{
1748
TRACESTATS(5);
1749
continue;
1750
}
1751
1752
TRACESTATS(1);
1753
vertex_positions[i] = p;
1754
}
1755
1756
#if TRACE
1757
printf("updated %d/%d positions; failed solve %d bounds %d flip %d error %d\n", int(stats[1]), int(stats[0]), int(stats[2]), int(stats[3]), int(stats[4]), int(stats[5]));
1758
#endif
1759
}
1760
1761
static void solveAttributes(Vector3* vertex_positions, float* vertex_attributes, size_t vertex_count, const Quadric* attribute_quadrics, const QuadricGrad* attribute_gradients, size_t attribute_count, const unsigned int* remap, const unsigned int* wedge, const unsigned char* vertex_kind, const unsigned char* vertex_update)
1762
{
1763
for (size_t i = 0; i < vertex_count; ++i)
1764
{
1765
if (!vertex_update[i])
1766
continue;
1767
1768
if (remap[i] != i)
1769
continue;
1770
1771
for (size_t k = 0; k < attribute_count; ++k)
1772
{
1773
unsigned int shared = ~0u;
1774
1775
// for complex vertices, preserve attribute continuity and use highest weight wedge if values were shared
1776
if (vertex_kind[i] == Kind_Complex)
1777
{
1778
shared = unsigned(i);
1779
1780
for (unsigned int v = wedge[i]; v != i; v = wedge[v])
1781
if (vertex_attributes[v * attribute_count + k] != vertex_attributes[i * attribute_count + k])
1782
shared = ~0u;
1783
else if (shared != ~0u && attribute_quadrics[v].w > attribute_quadrics[shared].w)
1784
shared = v;
1785
}
1786
1787
// update attributes for all wedges
1788
unsigned int v = unsigned(i);
1789
do
1790
{
1791
unsigned int r = (shared == ~0u) ? v : shared;
1792
1793
const Vector3& p = vertex_positions[i]; // same for all wedges
1794
const Quadric& A = attribute_quadrics[r];
1795
const QuadricGrad& G = attribute_gradients[r * attribute_count + k];
1796
1797
float iw = A.w == 0 ? 0.f : 1.f / A.w;
1798
float av = (G.gx * p.x + G.gy * p.y + G.gz * p.z + G.gw) * iw;
1799
1800
vertex_attributes[v * attribute_count + k] = av;
1801
v = wedge[v];
1802
} while (v != i);
1803
}
1804
}
1805
}
1806
1807
static size_t remapIndexBuffer(unsigned int* indices, size_t index_count, const unsigned int* collapse_remap, const unsigned int* remap)
1808
{
1809
size_t write = 0;
1810
1811
for (size_t i = 0; i < index_count; i += 3)
1812
{
1813
unsigned int v0 = collapse_remap[indices[i + 0]];
1814
unsigned int v1 = collapse_remap[indices[i + 1]];
1815
unsigned int v2 = collapse_remap[indices[i + 2]];
1816
1817
// we never move the vertex twice during a single pass
1818
assert(collapse_remap[v0] == v0);
1819
assert(collapse_remap[v1] == v1);
1820
assert(collapse_remap[v2] == v2);
1821
1822
// collapse zero area triangles even if they are not topologically degenerate
1823
// this is required to cleanup manifold->seam collapses when a vertex is collapsed onto a seam pair
1824
// as well as complex collapses and some other cases where cross wedge collapses are performed
1825
unsigned int r0 = remap[v0];
1826
unsigned int r1 = remap[v1];
1827
unsigned int r2 = remap[v2];
1828
1829
if (r0 != r1 && r0 != r2 && r1 != r2)
1830
{
1831
indices[write + 0] = v0;
1832
indices[write + 1] = v1;
1833
indices[write + 2] = v2;
1834
write += 3;
1835
}
1836
}
1837
1838
return write;
1839
}
1840
1841
static void remapEdgeLoops(unsigned int* loop, size_t vertex_count, const unsigned int* collapse_remap)
1842
{
1843
for (size_t i = 0; i < vertex_count; ++i)
1844
{
1845
// note: this is a no-op for vertices that were remapped
1846
// ideally we would clear the loop entries for those for consistency, even though they aren't going to be used
1847
// however, the remapping process needs loop information for remapped vertices, so this would require a separate pass
1848
if (loop[i] != ~0u)
1849
{
1850
unsigned int l = loop[i];
1851
unsigned int r = collapse_remap[l];
1852
1853
// i == r is a special case when the seam edge is collapsed in a direction opposite to where loop goes
1854
if (i == r)
1855
loop[i] = (loop[l] != ~0u) ? collapse_remap[loop[l]] : ~0u;
1856
else
1857
loop[i] = r;
1858
}
1859
}
1860
}
1861
1862
static unsigned int follow(unsigned int* parents, unsigned int index)
1863
{
1864
while (index != parents[index])
1865
{
1866
unsigned int parent = parents[index];
1867
parents[index] = parents[parent];
1868
index = parent;
1869
}
1870
1871
return index;
1872
}
1873
1874
static size_t buildComponents(unsigned int* components, size_t vertex_count, const unsigned int* indices, size_t index_count, const unsigned int* remap)
1875
{
1876
for (size_t i = 0; i < vertex_count; ++i)
1877
components[i] = unsigned(i);
1878
1879
// compute a unique (but not sequential!) index for each component via union-find
1880
for (size_t i = 0; i < index_count; i += 3)
1881
{
1882
static const int next[4] = {1, 2, 0, 1};
1883
1884
for (int e = 0; e < 3; ++e)
1885
{
1886
unsigned int i0 = indices[i + e];
1887
unsigned int i1 = indices[i + next[e]];
1888
1889
unsigned int r0 = remap[i0];
1890
unsigned int r1 = remap[i1];
1891
1892
r0 = follow(components, r0);
1893
r1 = follow(components, r1);
1894
1895
// merge components with larger indices into components with smaller indices
1896
// this guarantees that the root of the component is always the one with the smallest index
1897
if (r0 != r1)
1898
components[r0 < r1 ? r1 : r0] = r0 < r1 ? r0 : r1;
1899
}
1900
}
1901
1902
// make sure each element points to the component root *before* we renumber the components
1903
for (size_t i = 0; i < vertex_count; ++i)
1904
if (remap[i] == i)
1905
components[i] = follow(components, unsigned(i));
1906
1907
unsigned int next_component = 0;
1908
1909
// renumber components using sequential indices
1910
// a sequential pass is sufficient because component root always has the smallest index
1911
// note: it is unsafe to use follow() in this pass because we're replacing component links with sequential indices inplace
1912
for (size_t i = 0; i < vertex_count; ++i)
1913
{
1914
if (remap[i] == i)
1915
{
1916
unsigned int root = components[i];
1917
assert(root <= i); // make sure we already computed the component for non-roots
1918
components[i] = (root == i) ? next_component++ : components[root];
1919
}
1920
else
1921
{
1922
assert(remap[i] < i); // make sure we already computed the component
1923
components[i] = components[remap[i]];
1924
}
1925
}
1926
1927
return next_component;
1928
}
1929
1930
static void measureComponents(float* component_errors, size_t component_count, const unsigned int* components, const Vector3* vertex_positions, size_t vertex_count)
1931
{
1932
memset(component_errors, 0, component_count * 4 * sizeof(float));
1933
1934
// compute approximate sphere center for each component as an average
1935
for (size_t i = 0; i < vertex_count; ++i)
1936
{
1937
unsigned int c = components[i];
1938
assert(components[i] < component_count);
1939
1940
Vector3 v = vertex_positions[i]; // copy avoids aliasing issues
1941
1942
component_errors[c * 4 + 0] += v.x;
1943
component_errors[c * 4 + 1] += v.y;
1944
component_errors[c * 4 + 2] += v.z;
1945
component_errors[c * 4 + 3] += 1; // weight
1946
}
1947
1948
// complete the center computation, and reinitialize [3] as a radius
1949
for (size_t i = 0; i < component_count; ++i)
1950
{
1951
float w = component_errors[i * 4 + 3];
1952
float iw = w == 0.f ? 0.f : 1.f / w;
1953
1954
component_errors[i * 4 + 0] *= iw;
1955
component_errors[i * 4 + 1] *= iw;
1956
component_errors[i * 4 + 2] *= iw;
1957
component_errors[i * 4 + 3] = 0; // radius
1958
}
1959
1960
// compute squared radius for each component
1961
for (size_t i = 0; i < vertex_count; ++i)
1962
{
1963
unsigned int c = components[i];
1964
1965
float dx = vertex_positions[i].x - component_errors[c * 4 + 0];
1966
float dy = vertex_positions[i].y - component_errors[c * 4 + 1];
1967
float dz = vertex_positions[i].z - component_errors[c * 4 + 2];
1968
float r = dx * dx + dy * dy + dz * dz;
1969
1970
component_errors[c * 4 + 3] = component_errors[c * 4 + 3] < r ? r : component_errors[c * 4 + 3];
1971
}
1972
1973
// we've used the output buffer as scratch space, so we need to move the results to proper indices
1974
for (size_t i = 0; i < component_count; ++i)
1975
{
1976
#if TRACE >= 2
1977
printf("component %d: center %f %f %f, error %e\n", int(i),
1978
component_errors[i * 4 + 0], component_errors[i * 4 + 1], component_errors[i * 4 + 2], sqrtf(component_errors[i * 4 + 3]));
1979
#endif
1980
// note: we keep the squared error to make it match quadric error metric
1981
component_errors[i] = component_errors[i * 4 + 3];
1982
}
1983
}
1984
1985
static size_t pruneComponents(unsigned int* indices, size_t index_count, const unsigned int* components, const float* component_errors, size_t component_count, float error_cutoff, float& nexterror)
1986
{
1987
(void)component_count;
1988
1989
size_t write = 0;
1990
float min_error = FLT_MAX;
1991
1992
for (size_t i = 0; i < index_count; i += 3)
1993
{
1994
unsigned int v0 = indices[i + 0], v1 = indices[i + 1], v2 = indices[i + 2];
1995
unsigned int c = components[v0];
1996
assert(c == components[v1] && c == components[v2]);
1997
1998
if (component_errors[c] > error_cutoff)
1999
{
2000
min_error = min_error > component_errors[c] ? component_errors[c] : min_error;
2001
2002
indices[write + 0] = v0;
2003
indices[write + 1] = v1;
2004
indices[write + 2] = v2;
2005
write += 3;
2006
}
2007
}
2008
2009
#if TRACE
2010
size_t pruned_components = 0;
2011
for (size_t i = 0; i < component_count; ++i)
2012
pruned_components += (component_errors[i] >= nexterror && component_errors[i] <= error_cutoff);
2013
2014
printf("pruned %d triangles in %d components (goal %e); next %e\n", int((index_count - write) / 3), int(pruned_components), sqrtf(error_cutoff), min_error < FLT_MAX ? sqrtf(min_error) : min_error * 2);
2015
#endif
2016
2017
// update next error with the smallest error of the remaining components
2018
nexterror = min_error;
2019
return write;
2020
}
2021
2022
struct CellHasher
2023
{
2024
const unsigned int* vertex_ids;
2025
2026
size_t hash(unsigned int i) const
2027
{
2028
unsigned int h = vertex_ids[i];
2029
2030
// MurmurHash2 finalizer
2031
h ^= h >> 13;
2032
h *= 0x5bd1e995;
2033
h ^= h >> 15;
2034
return h;
2035
}
2036
2037
bool equal(unsigned int lhs, unsigned int rhs) const
2038
{
2039
return vertex_ids[lhs] == vertex_ids[rhs];
2040
}
2041
};
2042
2043
struct IdHasher
2044
{
2045
size_t hash(unsigned int id) const
2046
{
2047
unsigned int h = id;
2048
2049
// MurmurHash2 finalizer
2050
h ^= h >> 13;
2051
h *= 0x5bd1e995;
2052
h ^= h >> 15;
2053
return h;
2054
}
2055
2056
bool equal(unsigned int lhs, unsigned int rhs) const
2057
{
2058
return lhs == rhs;
2059
}
2060
};
2061
2062
struct TriangleHasher
2063
{
2064
const unsigned int* indices;
2065
2066
size_t hash(unsigned int i) const
2067
{
2068
const unsigned int* tri = indices + i * 3;
2069
2070
// Optimized Spatial Hashing for Collision Detection of Deformable Objects
2071
return (tri[0] * 73856093) ^ (tri[1] * 19349663) ^ (tri[2] * 83492791);
2072
}
2073
2074
bool equal(unsigned int lhs, unsigned int rhs) const
2075
{
2076
const unsigned int* lt = indices + lhs * 3;
2077
const unsigned int* rt = indices + rhs * 3;
2078
2079
return lt[0] == rt[0] && lt[1] == rt[1] && lt[2] == rt[2];
2080
}
2081
};
2082
2083
static void computeVertexIds(unsigned int* vertex_ids, const Vector3* vertex_positions, const unsigned char* vertex_lock, size_t vertex_count, int grid_size)
2084
{
2085
assert(grid_size >= 1 && grid_size <= 1024);
2086
float cell_scale = float(grid_size - 1);
2087
2088
for (size_t i = 0; i < vertex_count; ++i)
2089
{
2090
const Vector3& v = vertex_positions[i];
2091
2092
int xi = int(v.x * cell_scale + 0.5f);
2093
int yi = int(v.y * cell_scale + 0.5f);
2094
int zi = int(v.z * cell_scale + 0.5f);
2095
2096
if (vertex_lock && (vertex_lock[i] & meshopt_SimplifyVertex_Lock))
2097
vertex_ids[i] = (1 << 30) | unsigned(i);
2098
else
2099
vertex_ids[i] = (xi << 20) | (yi << 10) | zi;
2100
}
2101
}
2102
2103
static size_t countTriangles(const unsigned int* vertex_ids, const unsigned int* indices, size_t index_count)
2104
{
2105
size_t result = 0;
2106
2107
for (size_t i = 0; i < index_count; i += 3)
2108
{
2109
unsigned int id0 = vertex_ids[indices[i + 0]];
2110
unsigned int id1 = vertex_ids[indices[i + 1]];
2111
unsigned int id2 = vertex_ids[indices[i + 2]];
2112
2113
result += (id0 != id1) & (id0 != id2) & (id1 != id2);
2114
}
2115
2116
return result;
2117
}
2118
2119
static size_t fillVertexCells(unsigned int* table, size_t table_size, unsigned int* vertex_cells, const unsigned int* vertex_ids, size_t vertex_count)
2120
{
2121
CellHasher hasher = {vertex_ids};
2122
2123
memset(table, -1, table_size * sizeof(unsigned int));
2124
2125
size_t result = 0;
2126
2127
for (size_t i = 0; i < vertex_count; ++i)
2128
{
2129
unsigned int* entry = hashLookup2(table, table_size, hasher, unsigned(i), ~0u);
2130
2131
if (*entry == ~0u)
2132
{
2133
*entry = unsigned(i);
2134
vertex_cells[i] = unsigned(result++);
2135
}
2136
else
2137
{
2138
vertex_cells[i] = vertex_cells[*entry];
2139
}
2140
}
2141
2142
return result;
2143
}
2144
2145
static size_t countVertexCells(unsigned int* table, size_t table_size, const unsigned int* vertex_ids, size_t vertex_count)
2146
{
2147
IdHasher hasher;
2148
2149
memset(table, -1, table_size * sizeof(unsigned int));
2150
2151
size_t result = 0;
2152
2153
for (size_t i = 0; i < vertex_count; ++i)
2154
{
2155
unsigned int id = vertex_ids[i];
2156
unsigned int* entry = hashLookup2(table, table_size, hasher, id, ~0u);
2157
2158
result += (*entry == ~0u);
2159
*entry = id;
2160
}
2161
2162
return result;
2163
}
2164
2165
static void fillCellQuadrics(Quadric* cell_quadrics, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const unsigned int* vertex_cells)
2166
{
2167
for (size_t i = 0; i < index_count; i += 3)
2168
{
2169
unsigned int i0 = indices[i + 0];
2170
unsigned int i1 = indices[i + 1];
2171
unsigned int i2 = indices[i + 2];
2172
2173
unsigned int c0 = vertex_cells[i0];
2174
unsigned int c1 = vertex_cells[i1];
2175
unsigned int c2 = vertex_cells[i2];
2176
2177
int single_cell = (c0 == c1) & (c0 == c2);
2178
2179
Quadric Q;
2180
quadricFromTriangle(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], single_cell ? 3.f : 1.f);
2181
2182
if (single_cell)
2183
{
2184
quadricAdd(cell_quadrics[c0], Q);
2185
}
2186
else
2187
{
2188
quadricAdd(cell_quadrics[c0], Q);
2189
quadricAdd(cell_quadrics[c1], Q);
2190
quadricAdd(cell_quadrics[c2], Q);
2191
}
2192
}
2193
}
2194
2195
static void fillCellReservoirs(Reservoir* cell_reservoirs, size_t cell_count, const Vector3* vertex_positions, const float* vertex_colors, size_t vertex_colors_stride, size_t vertex_count, const unsigned int* vertex_cells)
2196
{
2197
static const float dummy_color[] = {0.f, 0.f, 0.f};
2198
2199
size_t vertex_colors_stride_float = vertex_colors_stride / sizeof(float);
2200
2201
for (size_t i = 0; i < vertex_count; ++i)
2202
{
2203
unsigned int cell = vertex_cells[i];
2204
const Vector3& v = vertex_positions[i];
2205
Reservoir& r = cell_reservoirs[cell];
2206
2207
const float* color = vertex_colors ? &vertex_colors[i * vertex_colors_stride_float] : dummy_color;
2208
2209
r.x += v.x;
2210
r.y += v.y;
2211
r.z += v.z;
2212
r.r += color[0];
2213
r.g += color[1];
2214
r.b += color[2];
2215
r.w += 1.f;
2216
}
2217
2218
for (size_t i = 0; i < cell_count; ++i)
2219
{
2220
Reservoir& r = cell_reservoirs[i];
2221
2222
float iw = r.w == 0.f ? 0.f : 1.f / r.w;
2223
2224
r.x *= iw;
2225
r.y *= iw;
2226
r.z *= iw;
2227
r.r *= iw;
2228
r.g *= iw;
2229
r.b *= iw;
2230
}
2231
}
2232
2233
static void fillCellRemap(unsigned int* cell_remap, float* cell_errors, size_t cell_count, const unsigned int* vertex_cells, const Quadric* cell_quadrics, const Vector3* vertex_positions, size_t vertex_count)
2234
{
2235
memset(cell_remap, -1, cell_count * sizeof(unsigned int));
2236
2237
for (size_t i = 0; i < vertex_count; ++i)
2238
{
2239
unsigned int cell = vertex_cells[i];
2240
float error = quadricError(cell_quadrics[cell], vertex_positions[i]);
2241
2242
if (cell_remap[cell] == ~0u || cell_errors[cell] > error)
2243
{
2244
cell_remap[cell] = unsigned(i);
2245
cell_errors[cell] = error;
2246
}
2247
}
2248
}
2249
2250
static void fillCellRemap(unsigned int* cell_remap, float* cell_errors, size_t cell_count, const unsigned int* vertex_cells, const Reservoir* cell_reservoirs, const Vector3* vertex_positions, const float* vertex_colors, size_t vertex_colors_stride, float color_weight, size_t vertex_count)
2251
{
2252
static const float dummy_color[] = {0.f, 0.f, 0.f};
2253
2254
size_t vertex_colors_stride_float = vertex_colors_stride / sizeof(float);
2255
2256
memset(cell_remap, -1, cell_count * sizeof(unsigned int));
2257
2258
for (size_t i = 0; i < vertex_count; ++i)
2259
{
2260
unsigned int cell = vertex_cells[i];
2261
const Vector3& v = vertex_positions[i];
2262
const Reservoir& r = cell_reservoirs[cell];
2263
2264
const float* color = vertex_colors ? &vertex_colors[i * vertex_colors_stride_float] : dummy_color;
2265
2266
float pos_error = (v.x - r.x) * (v.x - r.x) + (v.y - r.y) * (v.y - r.y) + (v.z - r.z) * (v.z - r.z);
2267
float col_error = (color[0] - r.r) * (color[0] - r.r) + (color[1] - r.g) * (color[1] - r.g) + (color[2] - r.b) * (color[2] - r.b);
2268
float error = pos_error + color_weight * col_error;
2269
2270
if (cell_remap[cell] == ~0u || cell_errors[cell] > error)
2271
{
2272
cell_remap[cell] = unsigned(i);
2273
cell_errors[cell] = error;
2274
}
2275
}
2276
}
2277
2278
static size_t filterTriangles(unsigned int* destination, unsigned int* tritable, size_t tritable_size, const unsigned int* indices, size_t index_count, const unsigned int* vertex_cells, const unsigned int* cell_remap)
2279
{
2280
TriangleHasher hasher = {destination};
2281
2282
memset(tritable, -1, tritable_size * sizeof(unsigned int));
2283
2284
size_t result = 0;
2285
2286
for (size_t i = 0; i < index_count; i += 3)
2287
{
2288
unsigned int c0 = vertex_cells[indices[i + 0]];
2289
unsigned int c1 = vertex_cells[indices[i + 1]];
2290
unsigned int c2 = vertex_cells[indices[i + 2]];
2291
2292
if (c0 != c1 && c0 != c2 && c1 != c2)
2293
{
2294
unsigned int a = cell_remap[c0];
2295
unsigned int b = cell_remap[c1];
2296
unsigned int c = cell_remap[c2];
2297
2298
if (b < a && b < c)
2299
{
2300
unsigned int t = a;
2301
a = b, b = c, c = t;
2302
}
2303
else if (c < a && c < b)
2304
{
2305
unsigned int t = c;
2306
c = b, b = a, a = t;
2307
}
2308
2309
destination[result * 3 + 0] = a;
2310
destination[result * 3 + 1] = b;
2311
destination[result * 3 + 2] = c;
2312
2313
unsigned int* entry = hashLookup2(tritable, tritable_size, hasher, unsigned(result), ~0u);
2314
2315
if (*entry == ~0u)
2316
*entry = unsigned(result++);
2317
}
2318
}
2319
2320
return result * 3;
2321
}
2322
2323
static float interpolate(float y, float x0, float y0, float x1, float y1, float x2, float y2)
2324
{
2325
// three point interpolation from "revenge of interpolation search" paper
2326
float num = (y1 - y) * (x1 - x2) * (x1 - x0) * (y2 - y0);
2327
float den = (y2 - y) * (x1 - x2) * (y0 - y1) + (y0 - y) * (x1 - x0) * (y1 - y2);
2328
return x1 + (den == 0.f ? 0.f : num / den);
2329
}
2330
2331
} // namespace meshopt
2332
2333
// Note: this is only exposed for development purposes; do *not* use
2334
enum
2335
{
2336
meshopt_SimplifyInternalSolve = 1 << 29,
2337
meshopt_SimplifyInternalDebug = 1 << 30
2338
};
2339
2340
size_t meshopt_simplifyEdge(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes_data, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, const unsigned char* vertex_lock, size_t target_index_count, float target_error, unsigned int options, float* out_result_error)
2341
{
2342
using namespace meshopt;
2343
2344
assert(index_count % 3 == 0);
2345
assert(vertex_positions_stride >= 12 && vertex_positions_stride <= 256);
2346
assert(vertex_positions_stride % sizeof(float) == 0);
2347
assert(target_index_count <= index_count);
2348
assert(target_error >= 0);
2349
assert((options & ~(meshopt_SimplifyLockBorder | meshopt_SimplifySparse | meshopt_SimplifyErrorAbsolute | meshopt_SimplifyPrune | meshopt_SimplifyRegularize | meshopt_SimplifyPermissive | meshopt_SimplifyInternalSolve | meshopt_SimplifyInternalDebug)) == 0);
2350
assert(vertex_attributes_stride >= attribute_count * sizeof(float) && vertex_attributes_stride <= 256);
2351
assert(vertex_attributes_stride % sizeof(float) == 0);
2352
assert(attribute_count <= kMaxAttributes);
2353
for (size_t i = 0; i < attribute_count; ++i)
2354
assert(attribute_weights[i] >= 0);
2355
2356
meshopt_Allocator allocator;
2357
2358
unsigned int* result = destination;
2359
if (result != indices)
2360
memcpy(result, indices, index_count * sizeof(unsigned int));
2361
2362
// build an index remap and update indices/vertex_count to minimize the subsequent work
2363
// note: as a consequence, errors will be computed relative to the subset extent
2364
unsigned int* sparse_remap = NULL;
2365
if (options & meshopt_SimplifySparse)
2366
sparse_remap = buildSparseRemap(result, index_count, vertex_count, &vertex_count, allocator);
2367
2368
// build adjacency information
2369
EdgeAdjacency adjacency = {};
2370
prepareEdgeAdjacency(adjacency, index_count, vertex_count, allocator);
2371
updateEdgeAdjacency(adjacency, result, index_count, vertex_count, NULL);
2372
2373
// build position remap that maps each vertex to the one with identical position
2374
// wedge table stores next vertex with identical position for each vertex
2375
unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
2376
unsigned int* wedge = allocator.allocate<unsigned int>(vertex_count);
2377
buildPositionRemap(remap, wedge, vertex_positions_data, vertex_count, vertex_positions_stride, sparse_remap, allocator);
2378
2379
// classify vertices; vertex kind determines collapse rules, see kCanCollapse
2380
unsigned char* vertex_kind = allocator.allocate<unsigned char>(vertex_count);
2381
unsigned int* loop = allocator.allocate<unsigned int>(vertex_count);
2382
unsigned int* loopback = allocator.allocate<unsigned int>(vertex_count);
2383
classifyVertices(vertex_kind, loop, loopback, vertex_count, adjacency, remap, wedge, vertex_lock, sparse_remap, options);
2384
2385
#if TRACE
2386
size_t unique_positions = 0;
2387
for (size_t i = 0; i < vertex_count; ++i)
2388
unique_positions += remap[i] == i;
2389
2390
printf("position remap: %d vertices => %d positions\n", int(vertex_count), int(unique_positions));
2391
2392
size_t kinds[Kind_Count] = {};
2393
for (size_t i = 0; i < vertex_count; ++i)
2394
kinds[vertex_kind[i]] += remap[i] == i;
2395
2396
printf("kinds: manifold %d, border %d, seam %d, complex %d, locked %d\n",
2397
int(kinds[Kind_Manifold]), int(kinds[Kind_Border]), int(kinds[Kind_Seam]), int(kinds[Kind_Complex]), int(kinds[Kind_Locked]));
2398
#endif
2399
2400
Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count);
2401
float vertex_offset[3] = {};
2402
float vertex_scale = rescalePositions(vertex_positions, vertex_positions_data, vertex_count, vertex_positions_stride, sparse_remap, vertex_offset);
2403
2404
float* vertex_attributes = NULL;
2405
unsigned int attribute_remap[kMaxAttributes];
2406
2407
if (attribute_count)
2408
{
2409
// remap attributes to only include ones with weight > 0 to minimize memory/compute overhead for quadrics
2410
size_t attributes_used = 0;
2411
for (size_t i = 0; i < attribute_count; ++i)
2412
if (attribute_weights[i] > 0)
2413
attribute_remap[attributes_used++] = unsigned(i);
2414
2415
attribute_count = attributes_used;
2416
vertex_attributes = allocator.allocate<float>(vertex_count * attribute_count);
2417
rescaleAttributes(vertex_attributes, vertex_attributes_data, vertex_count, vertex_attributes_stride, attribute_weights, attribute_count, attribute_remap, sparse_remap);
2418
}
2419
2420
Quadric* vertex_quadrics = allocator.allocate<Quadric>(vertex_count);
2421
memset(vertex_quadrics, 0, vertex_count * sizeof(Quadric));
2422
2423
Quadric* attribute_quadrics = NULL;
2424
QuadricGrad* attribute_gradients = NULL;
2425
QuadricGrad* volume_gradients = NULL;
2426
2427
if (attribute_count)
2428
{
2429
attribute_quadrics = allocator.allocate<Quadric>(vertex_count);
2430
memset(attribute_quadrics, 0, vertex_count * sizeof(Quadric));
2431
2432
attribute_gradients = allocator.allocate<QuadricGrad>(vertex_count * attribute_count);
2433
memset(attribute_gradients, 0, vertex_count * attribute_count * sizeof(QuadricGrad));
2434
2435
if (options & meshopt_SimplifyInternalSolve)
2436
{
2437
volume_gradients = allocator.allocate<QuadricGrad>(vertex_count);
2438
memset(volume_gradients, 0, vertex_count * sizeof(QuadricGrad));
2439
}
2440
}
2441
2442
fillFaceQuadrics(vertex_quadrics, volume_gradients, result, index_count, vertex_positions, remap);
2443
fillVertexQuadrics(vertex_quadrics, vertex_positions, vertex_count, remap, options);
2444
fillEdgeQuadrics(vertex_quadrics, result, index_count, vertex_positions, remap, vertex_kind, loop, loopback);
2445
2446
if (attribute_count)
2447
fillAttributeQuadrics(attribute_quadrics, attribute_gradients, result, index_count, vertex_positions, vertex_attributes, attribute_count);
2448
2449
unsigned int* components = NULL;
2450
float* component_errors = NULL;
2451
size_t component_count = 0;
2452
float component_nexterror = 0;
2453
2454
if (options & meshopt_SimplifyPrune)
2455
{
2456
components = allocator.allocate<unsigned int>(vertex_count);
2457
component_count = buildComponents(components, vertex_count, result, index_count, remap);
2458
2459
component_errors = allocator.allocate<float>(component_count * 4); // overallocate for temporary use inside measureComponents
2460
measureComponents(component_errors, component_count, components, vertex_positions, vertex_count);
2461
2462
component_nexterror = FLT_MAX;
2463
for (size_t i = 0; i < component_count; ++i)
2464
component_nexterror = component_nexterror > component_errors[i] ? component_errors[i] : component_nexterror;
2465
2466
#if TRACE
2467
printf("components: %d (min error %e)\n", int(component_count), sqrtf(component_nexterror));
2468
#endif
2469
}
2470
2471
#if TRACE
2472
size_t pass_count = 0;
2473
#endif
2474
2475
size_t collapse_capacity = boundEdgeCollapses(adjacency, vertex_count, index_count, vertex_kind);
2476
2477
Collapse* edge_collapses = allocator.allocate<Collapse>(collapse_capacity);
2478
unsigned int* collapse_order = allocator.allocate<unsigned int>(collapse_capacity);
2479
unsigned int* collapse_remap = allocator.allocate<unsigned int>(vertex_count);
2480
unsigned char* collapse_locked = allocator.allocate<unsigned char>(vertex_count);
2481
2482
size_t result_count = index_count;
2483
float result_error = 0;
2484
float vertex_error = 0;
2485
2486
// target_error input is linear; we need to adjust it to match quadricError units
2487
float error_scale = (options & meshopt_SimplifyErrorAbsolute) ? vertex_scale : 1.f;
2488
float error_limit = (target_error * target_error) / (error_scale * error_scale);
2489
2490
while (result_count > target_index_count)
2491
{
2492
// note: throughout the simplification process adjacency structure reflects welded topology for result-in-progress
2493
updateEdgeAdjacency(adjacency, result, result_count, vertex_count, remap);
2494
2495
size_t edge_collapse_count = pickEdgeCollapses(edge_collapses, collapse_capacity, result, result_count, remap, vertex_kind, loop, loopback);
2496
assert(edge_collapse_count <= collapse_capacity);
2497
2498
// no edges can be collapsed any more due to topology restrictions
2499
if (edge_collapse_count == 0)
2500
break;
2501
2502
#if TRACE
2503
printf("pass %d:%c", int(pass_count++), TRACE >= 2 ? '\n' : ' ');
2504
#endif
2505
2506
rankEdgeCollapses(edge_collapses, edge_collapse_count, vertex_positions, vertex_attributes, vertex_quadrics, attribute_quadrics, attribute_gradients, attribute_count, remap, wedge, vertex_kind, loop, loopback);
2507
2508
sortEdgeCollapses(collapse_order, edge_collapses, edge_collapse_count);
2509
2510
size_t triangle_collapse_goal = (result_count - target_index_count) / 3;
2511
2512
for (size_t i = 0; i < vertex_count; ++i)
2513
collapse_remap[i] = unsigned(i);
2514
2515
memset(collapse_locked, 0, vertex_count);
2516
2517
size_t collapses = performEdgeCollapses(collapse_remap, collapse_locked, edge_collapses, edge_collapse_count, collapse_order, remap, wedge, vertex_kind, loop, loopback, vertex_positions, adjacency, triangle_collapse_goal, error_limit, result_error);
2518
2519
// no edges can be collapsed any more due to hitting the error limit or triangle collapse limit
2520
if (collapses == 0)
2521
break;
2522
2523
updateQuadrics(collapse_remap, vertex_count, vertex_quadrics, volume_gradients, attribute_quadrics, attribute_gradients, attribute_count, vertex_positions, remap, vertex_error);
2524
2525
// updateQuadrics will update vertex error if we use attributes, but if we don't then result_error and vertex_error are equivalent
2526
vertex_error = attribute_count == 0 ? result_error : vertex_error;
2527
2528
// note: we update loops following edge collapses, but after this we might still have stale loop data
2529
// this can happen when a triangle with a loop edge gets collapsed along a non-loop edge
2530
// that works since a loop that points to a vertex that is no longer connected is not affecting collapse logic
2531
remapEdgeLoops(loop, vertex_count, collapse_remap);
2532
remapEdgeLoops(loopback, vertex_count, collapse_remap);
2533
2534
result_count = remapIndexBuffer(result, result_count, collapse_remap, remap);
2535
2536
if ((options & meshopt_SimplifyPrune) && result_count > target_index_count && component_nexterror <= vertex_error)
2537
result_count = pruneComponents(result, result_count, components, component_errors, component_count, vertex_error, component_nexterror);
2538
}
2539
2540
// at this point, component_nexterror might be stale: component it references may have been removed through a series of edge collapses
2541
bool component_nextstale = true;
2542
2543
// we're done with the regular simplification but we're still short of the target; try pruning more aggressively towards error_limit
2544
while ((options & meshopt_SimplifyPrune) && result_count > target_index_count && component_nexterror <= error_limit)
2545
{
2546
#if TRACE
2547
printf("pass %d: cleanup; ", int(pass_count++));
2548
#endif
2549
2550
float component_cutoff = component_nexterror * 1.5f < error_limit ? component_nexterror * 1.5f : error_limit;
2551
2552
// track maximum error in eligible components as we are increasing resulting error
2553
float component_maxerror = 0;
2554
for (size_t i = 0; i < component_count; ++i)
2555
if (component_errors[i] > component_maxerror && component_errors[i] <= component_cutoff)
2556
component_maxerror = component_errors[i];
2557
2558
size_t new_count = pruneComponents(result, result_count, components, component_errors, component_count, component_cutoff, component_nexterror);
2559
if (new_count == result_count && !component_nextstale)
2560
break;
2561
2562
component_nextstale = false; // pruneComponents guarantees next error is up to date
2563
result_count = new_count;
2564
result_error = result_error < component_maxerror ? component_maxerror : result_error;
2565
vertex_error = vertex_error < component_maxerror ? component_maxerror : vertex_error;
2566
}
2567
2568
#if TRACE
2569
printf("result: %d triangles, error: %e (pos %.3e); total %d passes\n", int(result_count / 3), sqrtf(result_error), sqrtf(vertex_error), int(pass_count));
2570
#endif
2571
2572
// if solve is requested, update input buffers destructively from internal data
2573
if (options & meshopt_SimplifyInternalSolve)
2574
{
2575
unsigned char* vertex_update = collapse_locked; // reuse as scratch space
2576
memset(vertex_update, 0, vertex_count);
2577
2578
// limit quadric solve to vertices that are still used in the result
2579
for (size_t i = 0; i < result_count; ++i)
2580
{
2581
unsigned int v = result[i];
2582
2583
// mark the vertex for finalizeVertices and root vertex for solve*
2584
vertex_update[remap[v]] = vertex_update[v] = 1;
2585
}
2586
2587
// edge adjacency may be stale as we haven't updated it after last series of edge collapses
2588
updateEdgeAdjacency(adjacency, result, result_count, vertex_count, remap);
2589
2590
solvePositions(vertex_positions, vertex_count, vertex_quadrics, volume_gradients, attribute_quadrics, attribute_gradients, attribute_count, remap, wedge, adjacency, vertex_kind, vertex_update);
2591
2592
if (attribute_count)
2593
solveAttributes(vertex_positions, vertex_attributes, vertex_count, attribute_quadrics, attribute_gradients, attribute_count, remap, wedge, vertex_kind, vertex_update);
2594
2595
finalizeVertices(const_cast<float*>(vertex_positions_data), vertex_positions_stride, const_cast<float*>(vertex_attributes_data), vertex_attributes_stride, attribute_weights, attribute_count, vertex_count, vertex_positions, vertex_attributes, sparse_remap, attribute_remap, vertex_scale, vertex_offset, vertex_kind, vertex_update, vertex_lock);
2596
}
2597
2598
// if debug visualization data is requested, fill it instead of index data; for simplicity, this doesn't work with sparsity
2599
if ((options & meshopt_SimplifyInternalDebug) && !sparse_remap)
2600
{
2601
assert(Kind_Count <= 8 && vertex_count < (1 << 28)); // 3 bit kind, 1 bit loop
2602
2603
for (size_t i = 0; i < result_count; i += 3)
2604
{
2605
unsigned int a = result[i + 0], b = result[i + 1], c = result[i + 2];
2606
2607
result[i + 0] |= (vertex_kind[a] << 28) | (unsigned(loop[a] == b || loopback[b] == a) << 31);
2608
result[i + 1] |= (vertex_kind[b] << 28) | (unsigned(loop[b] == c || loopback[c] == b) << 31);
2609
result[i + 2] |= (vertex_kind[c] << 28) | (unsigned(loop[c] == a || loopback[a] == c) << 31);
2610
}
2611
}
2612
2613
// convert resulting indices back into the dense space of the larger mesh
2614
if (sparse_remap)
2615
for (size_t i = 0; i < result_count; ++i)
2616
result[i] = sparse_remap[result[i]];
2617
2618
// result_error is quadratic; we need to remap it back to linear
2619
if (out_result_error)
2620
*out_result_error = sqrtf(result_error) * error_scale;
2621
2622
return result_count;
2623
}
2624
2625
size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, unsigned int options, float* out_result_error)
2626
{
2627
assert((options & meshopt_SimplifyInternalSolve) == 0); // use meshopt_simplifyWithUpdate instead
2628
2629
return meshopt_simplifyEdge(destination, indices, index_count, vertex_positions_data, vertex_count, vertex_positions_stride, NULL, 0, NULL, 0, NULL, target_index_count, target_error, options, out_result_error);
2630
}
2631
2632
size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes_data, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, const unsigned char* vertex_lock, size_t target_index_count, float target_error, unsigned int options, float* out_result_error)
2633
{
2634
assert((options & meshopt_SimplifyInternalSolve) == 0); // use meshopt_simplifyWithUpdate instead
2635
2636
return meshopt_simplifyEdge(destination, indices, index_count, vertex_positions_data, vertex_count, vertex_positions_stride, vertex_attributes_data, vertex_attributes_stride, attribute_weights, attribute_count, vertex_lock, target_index_count, target_error, options, out_result_error);
2637
}
2638
2639
size_t meshopt_simplifyWithUpdate(unsigned int* indices, size_t index_count, float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, float* vertex_attributes_data, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, const unsigned char* vertex_lock, size_t target_index_count, float target_error, unsigned int options, float* out_result_error)
2640
{
2641
return meshopt_simplifyEdge(indices, indices, index_count, vertex_positions_data, vertex_count, vertex_positions_stride, vertex_attributes_data, vertex_attributes_stride, attribute_weights, attribute_count, vertex_lock, target_index_count, target_error, options | meshopt_SimplifyInternalSolve, out_result_error);
2642
}
2643
2644
size_t meshopt_simplifySloppy(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, const unsigned char* vertex_lock, size_t target_index_count, float target_error, float* out_result_error)
2645
{
2646
using namespace meshopt;
2647
2648
assert(index_count % 3 == 0);
2649
assert(vertex_positions_stride >= 12 && vertex_positions_stride <= 256);
2650
assert(vertex_positions_stride % sizeof(float) == 0);
2651
assert(target_index_count <= index_count);
2652
2653
// we expect to get ~2 triangles/vertex in the output
2654
size_t target_cell_count = target_index_count / 6;
2655
2656
meshopt_Allocator allocator;
2657
2658
Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count);
2659
rescalePositions(vertex_positions, vertex_positions_data, vertex_count, vertex_positions_stride);
2660
2661
// find the optimal grid size using guided binary search
2662
#if TRACE
2663
printf("source: %d vertices, %d triangles\n", int(vertex_count), int(index_count / 3));
2664
printf("target: %d cells, %d triangles\n", int(target_cell_count), int(target_index_count / 3));
2665
#endif
2666
2667
unsigned int* vertex_ids = allocator.allocate<unsigned int>(vertex_count);
2668
2669
const int kInterpolationPasses = 5;
2670
2671
// invariant: # of triangles in min_grid <= target_count
2672
int min_grid = int(1.f / (target_error < 1e-3f ? 1e-3f : (target_error < 1.f ? target_error : 1.f)));
2673
int max_grid = 1025;
2674
size_t min_triangles = 0;
2675
size_t max_triangles = index_count / 3;
2676
2677
// when we're error-limited, we compute the triangle count for the min. size; this accelerates convergence and provides the correct answer when we can't use a larger grid
2678
if (min_grid > 1 || vertex_lock)
2679
{
2680
computeVertexIds(vertex_ids, vertex_positions, vertex_lock, vertex_count, min_grid);
2681
min_triangles = countTriangles(vertex_ids, indices, index_count);
2682
}
2683
2684
// instead of starting in the middle, let's guess as to what the answer might be! triangle count usually grows as a square of grid size...
2685
int next_grid_size = int(sqrtf(float(target_cell_count)) + 0.5f);
2686
2687
for (int pass = 0; pass < 10 + kInterpolationPasses; ++pass)
2688
{
2689
if (min_triangles >= target_index_count / 3 || max_grid - min_grid <= 1)
2690
break;
2691
2692
// we clamp the prediction of the grid size to make sure that the search converges
2693
int grid_size = next_grid_size;
2694
grid_size = (grid_size <= min_grid) ? min_grid + 1 : (grid_size >= max_grid ? max_grid - 1 : grid_size);
2695
2696
computeVertexIds(vertex_ids, vertex_positions, vertex_lock, vertex_count, grid_size);
2697
size_t triangles = countTriangles(vertex_ids, indices, index_count);
2698
2699
#if TRACE
2700
printf("pass %d (%s): grid size %d, triangles %d, %s\n",
2701
pass, (pass == 0) ? "guess" : (pass <= kInterpolationPasses ? "lerp" : "binary"),
2702
grid_size, int(triangles),
2703
(triangles <= target_index_count / 3) ? "under" : "over");
2704
#endif
2705
2706
float tip = interpolate(float(size_t(target_index_count / 3)), float(min_grid), float(min_triangles), float(grid_size), float(triangles), float(max_grid), float(max_triangles));
2707
2708
if (triangles <= target_index_count / 3)
2709
{
2710
min_grid = grid_size;
2711
min_triangles = triangles;
2712
}
2713
else
2714
{
2715
max_grid = grid_size;
2716
max_triangles = triangles;
2717
}
2718
2719
// we start by using interpolation search - it usually converges faster
2720
// however, interpolation search has a worst case of O(N) so we switch to binary search after a few iterations which converges in O(logN)
2721
next_grid_size = (pass < kInterpolationPasses) ? int(tip + 0.5f) : (min_grid + max_grid) / 2;
2722
}
2723
2724
if (min_triangles == 0)
2725
{
2726
if (out_result_error)
2727
*out_result_error = 1.f;
2728
2729
return 0;
2730
}
2731
2732
// build vertex->cell association by mapping all vertices with the same quantized position to the same cell
2733
size_t table_size = hashBuckets2(vertex_count);
2734
unsigned int* table = allocator.allocate<unsigned int>(table_size);
2735
2736
unsigned int* vertex_cells = allocator.allocate<unsigned int>(vertex_count);
2737
2738
computeVertexIds(vertex_ids, vertex_positions, vertex_lock, vertex_count, min_grid);
2739
size_t cell_count = fillVertexCells(table, table_size, vertex_cells, vertex_ids, vertex_count);
2740
2741
// build a quadric for each target cell
2742
Quadric* cell_quadrics = allocator.allocate<Quadric>(cell_count);
2743
memset(cell_quadrics, 0, cell_count * sizeof(Quadric));
2744
2745
fillCellQuadrics(cell_quadrics, indices, index_count, vertex_positions, vertex_cells);
2746
2747
// for each target cell, find the vertex with the minimal error
2748
unsigned int* cell_remap = allocator.allocate<unsigned int>(cell_count);
2749
float* cell_errors = allocator.allocate<float>(cell_count);
2750
2751
fillCellRemap(cell_remap, cell_errors, cell_count, vertex_cells, cell_quadrics, vertex_positions, vertex_count);
2752
2753
// compute error
2754
float result_error = 0.f;
2755
2756
for (size_t i = 0; i < cell_count; ++i)
2757
result_error = result_error < cell_errors[i] ? cell_errors[i] : result_error;
2758
2759
// vertex collapses often result in duplicate triangles; we need a table to filter them out
2760
size_t tritable_size = hashBuckets2(min_triangles);
2761
unsigned int* tritable = allocator.allocate<unsigned int>(tritable_size);
2762
2763
// note: this is the first and last write to destination, which allows aliasing destination with indices
2764
size_t write = filterTriangles(destination, tritable, tritable_size, indices, index_count, vertex_cells, cell_remap);
2765
2766
#if TRACE
2767
printf("result: grid size %d, %d cells, %d triangles (%d unfiltered), error %e\n", min_grid, int(cell_count), int(write / 3), int(min_triangles), sqrtf(result_error));
2768
#endif
2769
2770
if (out_result_error)
2771
*out_result_error = sqrtf(result_error);
2772
2773
return write;
2774
}
2775
2776
size_t meshopt_simplifyPrune(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, float target_error)
2777
{
2778
using namespace meshopt;
2779
2780
assert(index_count % 3 == 0);
2781
assert(vertex_positions_stride >= 12 && vertex_positions_stride <= 256);
2782
assert(vertex_positions_stride % sizeof(float) == 0);
2783
assert(target_error >= 0);
2784
2785
meshopt_Allocator allocator;
2786
2787
unsigned int* result = destination;
2788
if (result != indices)
2789
memcpy(result, indices, index_count * sizeof(unsigned int));
2790
2791
// build position remap that maps each vertex to the one with identical position
2792
unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
2793
buildPositionRemap(remap, NULL, vertex_positions_data, vertex_count, vertex_positions_stride, NULL, allocator);
2794
2795
Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count);
2796
rescalePositions(vertex_positions, vertex_positions_data, vertex_count, vertex_positions_stride, NULL);
2797
2798
unsigned int* components = allocator.allocate<unsigned int>(vertex_count);
2799
size_t component_count = buildComponents(components, vertex_count, indices, index_count, remap);
2800
2801
float* component_errors = allocator.allocate<float>(component_count * 4); // overallocate for temporary use inside measureComponents
2802
measureComponents(component_errors, component_count, components, vertex_positions, vertex_count);
2803
2804
float component_nexterror = 0;
2805
size_t result_count = pruneComponents(result, index_count, components, component_errors, component_count, target_error * target_error, component_nexterror);
2806
2807
return result_count;
2808
}
2809
2810
size_t meshopt_simplifyPoints(unsigned int* destination, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_colors, size_t vertex_colors_stride, float color_weight, size_t target_vertex_count)
2811
{
2812
using namespace meshopt;
2813
2814
assert(vertex_positions_stride >= 12 && vertex_positions_stride <= 256);
2815
assert(vertex_positions_stride % sizeof(float) == 0);
2816
assert(vertex_colors_stride == 0 || (vertex_colors_stride >= 12 && vertex_colors_stride <= 256));
2817
assert(vertex_colors_stride % sizeof(float) == 0);
2818
assert(vertex_colors == NULL || vertex_colors_stride != 0);
2819
assert(target_vertex_count <= vertex_count);
2820
2821
size_t target_cell_count = target_vertex_count;
2822
2823
if (target_cell_count == 0)
2824
return 0;
2825
2826
meshopt_Allocator allocator;
2827
2828
Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count);
2829
rescalePositions(vertex_positions, vertex_positions_data, vertex_count, vertex_positions_stride);
2830
2831
// find the optimal grid size using guided binary search
2832
#if TRACE
2833
printf("source: %d vertices\n", int(vertex_count));
2834
printf("target: %d cells\n", int(target_cell_count));
2835
#endif
2836
2837
unsigned int* vertex_ids = allocator.allocate<unsigned int>(vertex_count);
2838
2839
size_t table_size = hashBuckets2(vertex_count);
2840
unsigned int* table = allocator.allocate<unsigned int>(table_size);
2841
2842
const int kInterpolationPasses = 5;
2843
2844
// invariant: # of vertices in min_grid <= target_count
2845
int min_grid = 0;
2846
int max_grid = 1025;
2847
size_t min_vertices = 0;
2848
size_t max_vertices = vertex_count;
2849
2850
// instead of starting in the middle, let's guess as to what the answer might be! triangle count usually grows as a square of grid size...
2851
int next_grid_size = int(sqrtf(float(target_cell_count)) + 0.5f);
2852
2853
for (int pass = 0; pass < 10 + kInterpolationPasses; ++pass)
2854
{
2855
assert(min_vertices < target_vertex_count);
2856
assert(max_grid - min_grid > 1);
2857
2858
// we clamp the prediction of the grid size to make sure that the search converges
2859
int grid_size = next_grid_size;
2860
grid_size = (grid_size <= min_grid) ? min_grid + 1 : (grid_size >= max_grid ? max_grid - 1 : grid_size);
2861
2862
computeVertexIds(vertex_ids, vertex_positions, NULL, vertex_count, grid_size);
2863
size_t vertices = countVertexCells(table, table_size, vertex_ids, vertex_count);
2864
2865
#if TRACE
2866
printf("pass %d (%s): grid size %d, vertices %d, %s\n",
2867
pass, (pass == 0) ? "guess" : (pass <= kInterpolationPasses ? "lerp" : "binary"),
2868
grid_size, int(vertices),
2869
(vertices <= target_vertex_count) ? "under" : "over");
2870
#endif
2871
2872
float tip = interpolate(float(target_vertex_count), float(min_grid), float(min_vertices), float(grid_size), float(vertices), float(max_grid), float(max_vertices));
2873
2874
if (vertices <= target_vertex_count)
2875
{
2876
min_grid = grid_size;
2877
min_vertices = vertices;
2878
}
2879
else
2880
{
2881
max_grid = grid_size;
2882
max_vertices = vertices;
2883
}
2884
2885
if (vertices == target_vertex_count || max_grid - min_grid <= 1)
2886
break;
2887
2888
// we start by using interpolation search - it usually converges faster
2889
// however, interpolation search has a worst case of O(N) so we switch to binary search after a few iterations which converges in O(logN)
2890
next_grid_size = (pass < kInterpolationPasses) ? int(tip + 0.5f) : (min_grid + max_grid) / 2;
2891
}
2892
2893
if (min_vertices == 0)
2894
return 0;
2895
2896
// build vertex->cell association by mapping all vertices with the same quantized position to the same cell
2897
unsigned int* vertex_cells = allocator.allocate<unsigned int>(vertex_count);
2898
2899
computeVertexIds(vertex_ids, vertex_positions, NULL, vertex_count, min_grid);
2900
size_t cell_count = fillVertexCells(table, table_size, vertex_cells, vertex_ids, vertex_count);
2901
2902
// accumulate points into a reservoir for each target cell
2903
Reservoir* cell_reservoirs = allocator.allocate<Reservoir>(cell_count);
2904
memset(cell_reservoirs, 0, cell_count * sizeof(Reservoir));
2905
2906
fillCellReservoirs(cell_reservoirs, cell_count, vertex_positions, vertex_colors, vertex_colors_stride, vertex_count, vertex_cells);
2907
2908
// for each target cell, find the vertex with the minimal error
2909
unsigned int* cell_remap = allocator.allocate<unsigned int>(cell_count);
2910
float* cell_errors = allocator.allocate<float>(cell_count);
2911
2912
// we scale the color weight to bring it to the same scale as position so that error addition makes sense
2913
float color_weight_scaled = color_weight * (min_grid == 1 ? 1.f : 1.f / (min_grid - 1));
2914
2915
fillCellRemap(cell_remap, cell_errors, cell_count, vertex_cells, cell_reservoirs, vertex_positions, vertex_colors, vertex_colors_stride, color_weight_scaled * color_weight_scaled, vertex_count);
2916
2917
// copy results to the output
2918
assert(cell_count <= target_vertex_count);
2919
memcpy(destination, cell_remap, sizeof(unsigned int) * cell_count);
2920
2921
#if TRACE
2922
// compute error
2923
float result_error = 0.f;
2924
2925
for (size_t i = 0; i < cell_count; ++i)
2926
result_error = result_error < cell_errors[i] ? cell_errors[i] : result_error;
2927
2928
printf("result: %d cells, %e error\n", int(cell_count), sqrtf(result_error));
2929
#endif
2930
2931
return cell_count;
2932
}
2933
2934
float meshopt_simplifyScale(const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
2935
{
2936
using namespace meshopt;
2937
2938
assert(vertex_positions_stride >= 12 && vertex_positions_stride <= 256);
2939
assert(vertex_positions_stride % sizeof(float) == 0);
2940
2941
float extent = rescalePositions(NULL, vertex_positions, vertex_count, vertex_positions_stride);
2942
2943
return extent;
2944
}
2945
2946