attribute-aware-simplify.patch 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. diff --git a/thirdparty/meshoptimizer/meshoptimizer.h b/thirdparty/meshoptimizer/meshoptimizer.h
  2. index d95725dd71..46d28d3ea3 100644
  3. --- a/thirdparty/meshoptimizer/meshoptimizer.h
  4. +++ b/thirdparty/meshoptimizer/meshoptimizer.h
  5. @@ -321,6 +321,11 @@ enum
  6. meshopt_SimplifyLockBorder = 1 << 0,
  7. };
  8. +/**
  9. + * Experimental: Mesh simplifier with attribute metric; attributes follow xyz position data atm (vertex data must contain 3 + attribute_count floats per vertex)
  10. + */
  11. +MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, unsigned int options, float* result_error, const float* attributes, const float* attribute_weights, size_t attribute_count);
  12. +
  13. /**
  14. * Mesh simplifier
  15. * Reduces the number of triangles in the mesh, attempting to preserve mesh appearance as much as possible
  16. diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp
  17. index 5f0e9bac31..797329b010 100644
  18. --- a/thirdparty/meshoptimizer/simplifier.cpp
  19. +++ b/thirdparty/meshoptimizer/simplifier.cpp
  20. @@ -20,6 +20,8 @@
  21. #define TRACESTATS(i) (void)0
  22. #endif
  23. +#define ATTRIBUTES 8
  24. +
  25. // This work is based on:
  26. // Michael Garland and Paul S. Heckbert. Surface simplification using quadric error metrics. 1997
  27. // Michael Garland. Quadric-based polygonal surface simplification. 1999
  28. @@ -376,6 +378,10 @@ static void classifyVertices(unsigned char* result, unsigned int* loop, unsigned
  29. struct Vector3
  30. {
  31. float x, y, z;
  32. +
  33. +#if ATTRIBUTES
  34. + float a[ATTRIBUTES];
  35. +#endif
  36. };
  37. static float rescalePositions(Vector3* result, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride)
  38. @@ -432,6 +438,13 @@ struct Quadric
  39. float a10, a20, a21;
  40. float b0, b1, b2, c;
  41. float w;
  42. +
  43. +#if ATTRIBUTES
  44. + float gx[ATTRIBUTES];
  45. + float gy[ATTRIBUTES];
  46. + float gz[ATTRIBUTES];
  47. + float gw[ATTRIBUTES];
  48. +#endif
  49. };
  50. struct Collapse
  51. @@ -474,6 +487,16 @@ static void quadricAdd(Quadric& Q, const Quadric& R)
  52. Q.b2 += R.b2;
  53. Q.c += R.c;
  54. Q.w += R.w;
  55. +
  56. +#if ATTRIBUTES
  57. + for (int k = 0; k < ATTRIBUTES; ++k)
  58. + {
  59. + Q.gx[k] += R.gx[k];
  60. + Q.gy[k] += R.gy[k];
  61. + Q.gz[k] += R.gz[k];
  62. + Q.gw[k] += R.gw[k];
  63. + }
  64. +#endif
  65. }
  66. static float quadricError(const Quadric& Q, const Vector3& v)
  67. @@ -499,6 +522,17 @@ static float quadricError(const Quadric& Q, const Vector3& v)
  68. r += ry * v.y;
  69. r += rz * v.z;
  70. +#if ATTRIBUTES
  71. + // see quadricUpdateAttributes for general derivation; here we need to add the parts of (eval(pos) - attr)^2 that depend on attr
  72. + for (int k = 0; k < ATTRIBUTES; ++k)
  73. + {
  74. + float a = v.a[k];
  75. +
  76. + r += a * a * Q.w;
  77. + r -= 2 * a * (v.x * Q.gx[k] + v.y * Q.gy[k] + v.z * Q.gz[k] + Q.gw[k]);
  78. + }
  79. +#endif
  80. +
  81. float s = Q.w == 0.f ? 0.f : 1.f / Q.w;
  82. return fabsf(r) * s;
  83. @@ -522,6 +556,13 @@ static void quadricFromPlane(Quadric& Q, float a, float b, float c, float d, flo
  84. Q.b2 = c * dw;
  85. Q.c = d * dw;
  86. Q.w = w;
  87. +
  88. +#if ATTRIBUTES
  89. + memset(Q.gx, 0, sizeof(Q.gx));
  90. + memset(Q.gy, 0, sizeof(Q.gy));
  91. + memset(Q.gz, 0, sizeof(Q.gz));
  92. + memset(Q.gw, 0, sizeof(Q.gw));
  93. +#endif
  94. }
  95. static void quadricFromPoint(Quadric& Q, float x, float y, float z, float w)
  96. @@ -574,6 +615,84 @@ static void quadricFromTriangleEdge(Quadric& Q, const Vector3& p0, const Vector3
  97. quadricFromPlane(Q, normal.x, normal.y, normal.z, -distance, length * weight);
  98. }
  99. +#if ATTRIBUTES
  100. +static void quadricUpdateAttributes(Quadric& Q, const Vector3& p0, const Vector3& p1, const Vector3& p2, float w)
  101. +{
  102. + // for each attribute we want to encode the following function into the quadric:
  103. + // (eval(pos) - attr)^2
  104. + // where eval(pos) interpolates attribute across the triangle like so:
  105. + // eval(pos) = pos.x * gx + pos.y * gy + pos.z * gz + gw
  106. + // where gx/gy/gz/gw are gradients
  107. + Vector3 p10 = {p1.x - p0.x, p1.y - p0.y, p1.z - p0.z};
  108. + Vector3 p20 = {p2.x - p0.x, p2.y - p0.y, p2.z - p0.z};
  109. +
  110. + // we compute gradients using barycentric coordinates; barycentric coordinates can be computed as follows:
  111. + // v = (d11 * d20 - d01 * d21) / denom
  112. + // w = (d00 * d21 - d01 * d20) / denom
  113. + // u = 1 - v - w
  114. + // here v0, v1 are triangle edge vectors, v2 is a vector from point to triangle corner, and dij = dot(vi, vj)
  115. + const Vector3& v0 = p10;
  116. + const Vector3& v1 = p20;
  117. + float d00 = v0.x * v0.x + v0.y * v0.y + v0.z * v0.z;
  118. + float d01 = v0.x * v1.x + v0.y * v1.y + v0.z * v1.z;
  119. + float d11 = v1.x * v1.x + v1.y * v1.y + v1.z * v1.z;
  120. + float denom = d00 * d11 - d01 * d01;
  121. + float denomr = denom == 0 ? 0.f : 1.f / denom;
  122. +
  123. + // precompute gradient factors
  124. + // these are derived by directly computing derivative of eval(pos) = a0 * u + a1 * v + a2 * w and factoring out common factors that are shared between attributes
  125. + float gx1 = (d11 * v0.x - d01 * v1.x) * denomr;
  126. + float gx2 = (d00 * v1.x - d01 * v0.x) * denomr;
  127. + float gy1 = (d11 * v0.y - d01 * v1.y) * denomr;
  128. + float gy2 = (d00 * v1.y - d01 * v0.y) * denomr;
  129. + float gz1 = (d11 * v0.z - d01 * v1.z) * denomr;
  130. + float gz2 = (d00 * v1.z - d01 * v0.z) * denomr;
  131. +
  132. + for (int k = 0; k < ATTRIBUTES; ++k)
  133. + {
  134. + float a0 = p0.a[k], a1 = p1.a[k], a2 = p2.a[k];
  135. +
  136. + // compute gradient of eval(pos) for x/y/z/w
  137. + // the formulas below are obtained by directly computing derivative of eval(pos) = a0 * u + a1 * v + a2 * w
  138. + float gx = gx1 * (a1 - a0) + gx2 * (a2 - a0);
  139. + float gy = gy1 * (a1 - a0) + gy2 * (a2 - a0);
  140. + float gz = gz1 * (a1 - a0) + gz2 * (a2 - a0);
  141. + float gw = a0 - p0.x * gx - p0.y * gy - p0.z * gz;
  142. +
  143. + // quadric encodes (eval(pos)-attr)^2; this means that the resulting expansion needs to compute, for example, pos.x * pos.y * K
  144. + // since quadrics already encode factors for pos.x * pos.y, we can accumulate almost everything in basic quadric fields
  145. + Q.a00 += w * (gx * gx);
  146. + Q.a11 += w * (gy * gy);
  147. + Q.a22 += w * (gz * gz);
  148. +
  149. + Q.a10 += w * (gy * gx);
  150. + Q.a20 += w * (gz * gx);
  151. + Q.a21 += w * (gz * gy);
  152. +
  153. + Q.b0 += w * (gx * gw);
  154. + Q.b1 += w * (gy * gw);
  155. + Q.b2 += w * (gz * gw);
  156. +
  157. + Q.c += w * (gw * gw);
  158. +
  159. + // the only remaining sum components are ones that depend on attr; these will be addded during error evaluation, see quadricError
  160. + Q.gx[k] = w * gx;
  161. + Q.gy[k] = w * gy;
  162. + Q.gz[k] = w * gz;
  163. + Q.gw[k] = w * gw;
  164. +
  165. +#if TRACE > 2
  166. + printf("attr%d: %e %e %e\n",
  167. + k,
  168. + (gx * p0.x + gy * p0.y + gz * p0.z + gw - a0),
  169. + (gx * p1.x + gy * p1.y + gz * p1.z + gw - a1),
  170. + (gx * p2.x + gy * p2.y + gz * p2.z + gw - a2)
  171. + );
  172. +#endif
  173. + }
  174. +}
  175. +#endif
  176. +
  177. static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const unsigned int* remap)
  178. {
  179. for (size_t i = 0; i < index_count; i += 3)
  180. @@ -585,6 +704,9 @@ static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indic
  181. Quadric Q;
  182. quadricFromTriangle(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], 1.f);
  183. +#if ATTRIBUTES
  184. + quadricUpdateAttributes(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], Q.w);
  185. +#endif
  186. quadricAdd(vertex_quadrics[remap[i0]], Q);
  187. quadricAdd(vertex_quadrics[remap[i1]], Q);
  188. quadricAdd(vertex_quadrics[remap[i2]], Q);
  189. @@ -1278,14 +1400,20 @@ MESHOPTIMIZER_API unsigned int* meshopt_simplifyDebugLoopBack = 0;
  190. #endif
  191. 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)
  192. +{
  193. + return meshopt_simplifyWithAttributes(destination, indices, index_count, vertex_positions_data, vertex_count, vertex_positions_stride, target_index_count, target_error, options, out_result_error, 0, 0, 0);
  194. +}
  195. +
  196. +size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, unsigned int options, float* out_result_error, const float* attributes, const float* attribute_weights, size_t attribute_count)
  197. {
  198. using namespace meshopt;
  199. assert(index_count % 3 == 0);
  200. - assert(vertex_positions_stride >= 12 && vertex_positions_stride <= 256);
  201. - assert(vertex_positions_stride % sizeof(float) == 0);
  202. + assert(vertex_stride >= 12 && vertex_stride <= 256);
  203. + assert(vertex_stride % sizeof(float) == 0);
  204. assert(target_index_count <= index_count);
  205. assert((options & ~(meshopt_SimplifyLockBorder)) == 0);
  206. + assert(attribute_count <= ATTRIBUTES);
  207. meshopt_Allocator allocator;
  208. @@ -1299,7 +1427,7 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
  209. // build position remap that maps each vertex to the one with identical position
  210. unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
  211. unsigned int* wedge = allocator.allocate<unsigned int>(vertex_count);
  212. - buildPositionRemap(remap, wedge, vertex_positions_data, vertex_count, vertex_positions_stride, allocator);
  213. + buildPositionRemap(remap, wedge, vertex_data, vertex_count, vertex_stride, allocator);
  214. // classify vertices; vertex kind determines collapse rules, see kCanCollapse
  215. unsigned char* vertex_kind = allocator.allocate<unsigned char>(vertex_count);
  216. @@ -1323,7 +1451,21 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
  217. #endif
  218. Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count);
  219. - rescalePositions(vertex_positions, vertex_positions_data, vertex_count, vertex_positions_stride);
  220. + rescalePositions(vertex_positions, vertex_data, vertex_count, vertex_stride);
  221. +
  222. +#if ATTRIBUTES
  223. + for (size_t i = 0; i < vertex_count; ++i)
  224. + {
  225. + memset(vertex_positions[i].a, 0, sizeof(vertex_positions[i].a));
  226. +
  227. + for (size_t k = 0; k < attribute_count; ++k)
  228. + {
  229. + float a = attributes[i * attribute_count + k];
  230. +
  231. + vertex_positions[i].a[k] = a * attribute_weights[k];
  232. + }
  233. + }
  234. +#endif
  235. Quadric* vertex_quadrics = allocator.allocate<Quadric>(vertex_count);
  236. memset(vertex_quadrics, 0, vertex_count * sizeof(Quadric));
  237. @@ -1415,7 +1557,9 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
  238. // result_error is quadratic; we need to remap it back to linear
  239. if (out_result_error)
  240. + {
  241. *out_result_error = sqrtf(result_error);
  242. + }
  243. return result_count;
  244. }