@@ -850,7 +850,7 @@ static void fillEdgeQuadrics(Quadric* vertex_quadrics, const unsigned int* indic
850
850
}
851
851
}
852
852
853
- 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, const unsigned int * remap )
853
+ 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)
854
854
{
855
855
for (size_t i = 0 ; i < index_count; i += 3 )
856
856
{
@@ -862,14 +862,13 @@ static void fillAttributeQuadrics(Quadric* attribute_quadrics, QuadricGrad* attr
862
862
QuadricGrad G[kMaxAttributes ];
863
863
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);
864
864
865
- // TODO: This blends together attribute weights across attribute discontinuities, which is probably not a great idea
866
- quadricAdd (attribute_quadrics[remap[i0]], QA);
867
- quadricAdd (attribute_quadrics[remap[i1]], QA);
868
- quadricAdd (attribute_quadrics[remap[i2]], QA);
865
+ quadricAdd (attribute_quadrics[i0], QA);
866
+ quadricAdd (attribute_quadrics[i1], QA);
867
+ quadricAdd (attribute_quadrics[i2], QA);
869
868
870
- quadricAdd (&attribute_gradients[remap[i0] * attribute_count], G, attribute_count);
871
- quadricAdd (&attribute_gradients[remap[i1] * attribute_count], G, attribute_count);
872
- quadricAdd (&attribute_gradients[remap[i2] * attribute_count], G, attribute_count);
869
+ quadricAdd (&attribute_gradients[i0 * attribute_count], G, attribute_count);
870
+ quadricAdd (&attribute_gradients[i1 * attribute_count], G, attribute_count);
871
+ quadricAdd (&attribute_gradients[i2 * attribute_count], G, attribute_count);
873
872
}
874
873
}
875
874
@@ -914,7 +913,13 @@ static bool hasTriangleFlips(const EdgeAdjacency& adjacency, const Vector3* vert
914
913
915
914
// early-out when at least one triangle flips due to a collapse
916
915
if (hasTriangleFlip (vertex_positions[a], vertex_positions[b], v0, v1))
916
+ {
917
+ #if TRACE >= 2
918
+ printf (" edge block %d -> %d: flip welded %d %d %d\n " , i0, i1, a, i0, b);
919
+ #endif
920
+
917
921
return true ;
922
+ }
918
923
}
919
924
920
925
return false ;
@@ -1017,16 +1022,31 @@ static void rankEdgeCollapses(Collapse* collapses, size_t collapse_count, const
1017
1022
float ei = quadricError (vertex_quadrics[remap[i0]], vertex_positions[i1]);
1018
1023
float ej = quadricError (vertex_quadrics[remap[j0 ]], vertex_positions[j1 ]);
1019
1024
1025
+ #if TRACE >= 2
1026
+ float di = ei, dj = ej;
1027
+ #endif
1028
+
1020
1029
if (attribute_count)
1021
1030
{
1022
- ei += quadricError (attribute_quadrics[remap[i0]], &attribute_gradients[remap[i0] * attribute_count], attribute_count, vertex_positions[i1], &vertex_attributes[i1 * attribute_count]);
1023
- ej += quadricError (attribute_quadrics[remap[j0 ]], &attribute_gradients[remap[j0 ] * attribute_count], attribute_count, vertex_positions[j1 ], &vertex_attributes[j1 * attribute_count]);
1031
+ // note: ideally we would evaluate max/avg of attribute errors for seam edges, but it's not clear if it's worth the extra cost
1032
+ ei += quadricError (attribute_quadrics[i0], &attribute_gradients[i0 * attribute_count], attribute_count, vertex_positions[i1], &vertex_attributes[i1 * attribute_count]);
1033
+ ej += quadricError (attribute_quadrics[j0 ], &attribute_gradients[j0 * attribute_count], attribute_count, vertex_positions[j1 ], &vertex_attributes[j1 * attribute_count]);
1024
1034
}
1025
1035
1026
1036
// pick edge direction with minimal error
1027
1037
c.v0 = ei <= ej ? i0 : j0 ;
1028
1038
c.v1 = ei <= ej ? i1 : j1 ;
1029
1039
c.error = ei <= ej ? ei : ej;
1040
+
1041
+ #if TRACE >= 2
1042
+ if (i0 == j0 ) // c.bidi has been overwritten
1043
+ printf (" edge eval %d -> %d: error %f (pos %f, attr %f)\n " , c.v0 , c.v1 ,
1044
+ sqrtf (c.error ), sqrtf (ei <= ej ? di : dj), sqrtf (ei <= ej ? ei - di : ej - dj));
1045
+ else
1046
+ printf (" edge eval %d -> %d: error %f (pos %f, attr %f); reverse %f (pos %f, attr %f)\n " , c.v0 , c.v1 ,
1047
+ sqrtf (ei <= ej ? ei : ej), sqrtf (ei <= ej ? di : dj), sqrtf (ei <= ej ? ei - di : ej - dj),
1048
+ sqrtf (ei <= ej ? ej : ei), sqrtf (ei <= ej ? dj : di), sqrtf (ei <= ej ? ej - dj : ei - di));
1049
+ #endif
1030
1050
}
1031
1051
}
1032
1052
@@ -1108,6 +1128,8 @@ static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char*
1108
1128
unsigned int r0 = remap[i0];
1109
1129
unsigned int r1 = remap[i1];
1110
1130
1131
+ unsigned char kind = vertex_kind[i0];
1132
+
1111
1133
// we don't collapse vertices that had source or target vertex involved in a collapse
1112
1134
// it's important to not move the vertices twice since it complicates the tracking/remapping logic
1113
1135
// it's important to not move other vertices towards a moved vertex to preserve error since we don't re-rank collapses mid-pass
@@ -1126,33 +1148,46 @@ static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char*
1126
1148
continue ;
1127
1149
}
1128
1150
1151
+ #if TRACE >= 2
1152
+ printf (" edge commit %d -> %d: kind %d->%d, error %f\n " , i0, i1, vertex_kind[i0], vertex_kind[i1], sqrtf (c.error ));
1153
+ #endif
1154
+
1129
1155
assert (collapse_remap[r0] == r0);
1130
1156
assert (collapse_remap[r1] == r1);
1131
1157
1132
1158
quadricAdd (vertex_quadrics[r1], vertex_quadrics[r0]);
1133
1159
1134
1160
if (attribute_count)
1135
1161
{
1136
- quadricAdd (attribute_quadrics[r1], attribute_quadrics[r0]);
1137
- quadricAdd (&attribute_gradients[r1 * attribute_count], &attribute_gradients[r0 * attribute_count], attribute_count);
1162
+ quadricAdd (attribute_quadrics[i1], attribute_quadrics[i0]);
1163
+ quadricAdd (&attribute_gradients[i1 * attribute_count], &attribute_gradients[i0 * attribute_count], attribute_count);
1164
+
1165
+ // note: this is intentionally missing handling for Kind_Complex; we assume that complex vertices have similar attribute values so just using the primary vertex is fine
1166
+ if (kind == Kind_Seam)
1167
+ {
1168
+ // seam collapses involve two edges so we need to update attribute quadrics for both target vertices; position quadrics are shared
1169
+ unsigned int s0 = wedge[i0], s1 = wedge[i1];
1170
+
1171
+ quadricAdd (attribute_quadrics[s1], attribute_quadrics[s0]);
1172
+ quadricAdd (&attribute_gradients[s1 * attribute_count], &attribute_gradients[s0 * attribute_count], attribute_count);
1173
+ }
1138
1174
}
1139
1175
1140
- if (vertex_kind[i0] == Kind_Complex)
1176
+ if (kind == Kind_Complex)
1141
1177
{
1178
+ // remap all vertices in the complex to the target vertex
1142
1179
unsigned int v = i0;
1143
1180
1144
1181
do
1145
1182
{
1146
- collapse_remap[v] = r1 ;
1183
+ collapse_remap[v] = i1 ;
1147
1184
v = wedge[v];
1148
1185
} while (v != i0);
1149
1186
}
1150
- else if (vertex_kind[i0] == Kind_Seam)
1187
+ else if (kind == Kind_Seam)
1151
1188
{
1152
1189
// remap v0 to v1 and seam pair of v0 to seam pair of v1
1153
- unsigned int s0 = wedge[i0];
1154
- unsigned int s1 = wedge[i1];
1155
-
1190
+ unsigned int s0 = wedge[i0], s1 = wedge[i1];
1156
1191
assert (s0 != i0 && s1 != i1);
1157
1192
assert (wedge[s0] == i0 && wedge[s1] == i1);
1158
1193
@@ -1170,7 +1205,7 @@ static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char*
1170
1205
collapse_locked[r1] = 1 ;
1171
1206
1172
1207
// border edges collapse 1 triangle, other edges collapse 2 or more
1173
- triangle_collapses += (vertex_kind[i0] == Kind_Border) ? 1 : 2 ;
1208
+ triangle_collapses += (kind == Kind_Border) ? 1 : 2 ;
1174
1209
edge_collapses++;
1175
1210
1176
1211
result_error = result_error < c.error ? c.error : result_error;
@@ -1641,7 +1676,7 @@ size_t meshopt_simplifyEdge(unsigned int* destination, const unsigned int* indic
1641
1676
fillEdgeQuadrics (vertex_quadrics, result, index_count, vertex_positions, remap, vertex_kind, loop, loopback);
1642
1677
1643
1678
if (attribute_count)
1644
- fillAttributeQuadrics (attribute_quadrics, attribute_gradients, result, index_count, vertex_positions, vertex_attributes, attribute_count, remap );
1679
+ fillAttributeQuadrics (attribute_quadrics, attribute_gradients, result, index_count, vertex_positions, vertex_attributes, attribute_count);
1645
1680
1646
1681
#if TRACE
1647
1682
size_t pass_count = 0 ;
@@ -1673,6 +1708,10 @@ size_t meshopt_simplifyEdge(unsigned int* destination, const unsigned int* indic
1673
1708
if (edge_collapse_count == 0 )
1674
1709
break ;
1675
1710
1711
+ #if TRACE
1712
+ printf (" pass %d:%c" , int (pass_count++), TRACE >= 2 ? ' \n ' : ' ' );
1713
+ #endif
1714
+
1676
1715
rankEdgeCollapses (edge_collapses, edge_collapse_count, vertex_positions, vertex_attributes, vertex_quadrics, attribute_quadrics, attribute_gradients, attribute_count, remap);
1677
1716
1678
1717
sortEdgeCollapses (collapse_order, edge_collapses, edge_collapse_count);
@@ -1684,10 +1723,6 @@ size_t meshopt_simplifyEdge(unsigned int* destination, const unsigned int* indic
1684
1723
1685
1724
memset (collapse_locked, 0 , vertex_count);
1686
1725
1687
- #if TRACE
1688
- printf (" pass %d: " , int (pass_count++));
1689
- #endif
1690
-
1691
1726
size_t collapses = performEdgeCollapses (collapse_remap, collapse_locked, vertex_quadrics, attribute_quadrics, attribute_gradients, attribute_count, edge_collapses, edge_collapse_count, collapse_order, remap, wedge, vertex_kind, vertex_positions, adjacency, triangle_collapse_goal, error_limit, result_error);
1692
1727
1693
1728
// no edges can be collapsed any more due to hitting the error limit or triangle collapse limit
0 commit comments