Skip to content

Commit 49c1586

Browse files
committed
clusterizer: Use radii for extremum points in computeBoundingSphere
In cases where we need to find extremum points or expand the sphere to fit all points, we now incorporate a per-point radius into the computation. This math is *not* fully correct for, specifically, the initial bounding sphere and the sphere expansion as it doesn't fully account for the possibility that the points may have very different radii. To simplify the code, we require that the radii are always specified internally; using stride=0 allows to bypass that requirement.
1 parent 261e8ef commit 49c1586

File tree

1 file changed

+29
-17
lines changed

1 file changed

+29
-17
lines changed

src/clusterizer.cpp

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -141,11 +141,12 @@ static void buildTriangleAdjacencySparse(TriangleAdjacency2& adjacency, const un
141141
}
142142
}
143143

144-
static void computeBoundingSphere(float result[4], const float* points, size_t count, size_t points_stride)
144+
static void computeBoundingSphere(float result[4], const float* points, size_t count, size_t points_stride, const float* radii, size_t radii_stride)
145145
{
146146
assert(count > 0);
147147

148148
size_t points_stride_float = points_stride / sizeof(float);
149+
size_t radii_stride_float = radii_stride / sizeof(float);
149150

150151
// find extremum points along all 3 axes; for each axis we get a pair of points with min/max coordinates
151152
size_t pmin[3] = {0, 0, 0};
@@ -154,28 +155,35 @@ static void computeBoundingSphere(float result[4], const float* points, size_t c
154155
for (size_t i = 0; i < count; ++i)
155156
{
156157
const float* p = points + i * points_stride_float;
158+
float r = radii[i * radii_stride_float];
157159

158160
for (int axis = 0; axis < 3; ++axis)
159161
{
160-
pmin[axis] = (p[axis] < points[pmin[axis] * points_stride_float + axis]) ? i : pmin[axis];
161-
pmax[axis] = (p[axis] > points[pmax[axis] * points_stride_float + axis]) ? i : pmax[axis];
162+
float bmin = points[pmin[axis] * points_stride_float + axis] - radii[pmin[axis] * radii_stride_float];
163+
float bmax = points[pmax[axis] * points_stride_float + axis] + radii[pmax[axis] * radii_stride_float];
164+
165+
pmin[axis] = (p[axis] - r < bmin) ? i : pmin[axis];
166+
pmax[axis] = (p[axis] + r > bmax) ? i : pmax[axis];
162167
}
163168
}
164169

165170
// find the pair of points with largest distance
166-
float paxisd2 = 0;
167171
int paxis = 0;
172+
float paxisdr = 0;
168173

169174
for (int axis = 0; axis < 3; ++axis)
170175
{
171176
const float* p1 = points + pmin[axis] * points_stride_float;
172177
const float* p2 = points + pmax[axis] * points_stride_float;
178+
float r1 = radii[pmin[axis] * radii_stride_float];
179+
float r2 = radii[pmax[axis] * radii_stride_float];
173180

174181
float d2 = (p2[0] - p1[0]) * (p2[0] - p1[0]) + (p2[1] - p1[1]) * (p2[1] - p1[1]) + (p2[2] - p1[2]) * (p2[2] - p1[2]);
182+
float dr = sqrtf(d2) + r1 + r2;
175183

176-
if (d2 > paxisd2)
184+
if (dr > paxisdr)
177185
{
178-
paxisd2 = d2;
186+
paxisdr = dr;
179187
paxis = axis;
180188
}
181189
}
@@ -185,25 +193,25 @@ static void computeBoundingSphere(float result[4], const float* points, size_t c
185193
const float* p2 = points + pmax[paxis] * points_stride_float;
186194

187195
float center[3] = {(p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2, (p1[2] + p2[2]) / 2};
188-
float radius = sqrtf(paxisd2) / 2;
196+
float radius = paxisdr / 2;
189197

190198
// iteratively adjust the sphere up until all points fit
191199
for (size_t i = 0; i < count; ++i)
192200
{
193201
const float* p = points + i * points_stride_float;
202+
float r = radii[i * radii_stride_float];
203+
194204
float d2 = (p[0] - center[0]) * (p[0] - center[0]) + (p[1] - center[1]) * (p[1] - center[1]) + (p[2] - center[2]) * (p[2] - center[2]);
205+
float dr = sqrtf(d2) + r;
195206

196-
if (d2 > radius * radius)
207+
if (dr > radius)
197208
{
198-
float d = sqrtf(d2);
199-
assert(d > 0);
200-
201-
float k = 0.5f + (radius / d) / 2;
209+
float k = 0.5f + (radius / dr) / 2;
202210

203211
center[0] = center[0] * k + p[0] * (1 - k);
204212
center[1] = center[1] * k + p[1] * (1 - k);
205213
center[2] = center[2] * k + p[2] * (1 - k);
206-
radius = (radius + d) / 2;
214+
radius = (radius + dr) / 2;
207215
}
208216
}
209217

@@ -857,15 +865,17 @@ meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t
857865
if (triangles == 0)
858866
return bounds;
859867

868+
const float rzero = 0.f;
869+
860870
// compute cluster bounding sphere; we'll use the center to determine normal cone apex as well
861871
float psphere[4] = {};
862-
computeBoundingSphere(psphere, corners[0][0], triangles * 3, sizeof(float) * 3);
872+
computeBoundingSphere(psphere, corners[0][0], triangles * 3, sizeof(float) * 3, &rzero, 0);
863873

864874
float center[3] = {psphere[0], psphere[1], psphere[2]};
865875

866876
// treating triangle normals as points, find the bounding sphere - the sphere center determines the optimal cone axis
867877
float nsphere[4] = {};
868-
computeBoundingSphere(nsphere, normals[0], triangles, sizeof(float) * 3);
878+
computeBoundingSphere(nsphere, normals[0], triangles, sizeof(float) * 3, &rzero, 0);
869879

870880
float axis[3] = {nsphere[0], nsphere[1], nsphere[2]};
871881
float axislength = sqrtf(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);
@@ -981,16 +991,18 @@ meshopt_Bounds meshopt_computeSphereBounds(const float* positions, size_t count,
981991

982992
assert(positions_stride >= 12 && positions_stride <= 256);
983993
assert(positions_stride % sizeof(float) == 0);
984-
assert(radii == NULL || radii_stride >= 4);
994+
assert((radii_stride >= 4 && radii_stride <= 256) || radii == NULL);
985995
assert(radii_stride % sizeof(float) == 0);
986996

987997
meshopt_Bounds bounds = {};
988998

989999
if (count == 0)
9901000
return bounds;
9911001

1002+
const float rzero = 0.f;
1003+
9921004
float psphere[4] = {};
993-
computeBoundingSphere(psphere, positions, count, positions_stride);
1005+
computeBoundingSphere(psphere, positions, count, positions_stride, radii ? radii : &rzero, radii ? radii_stride : 0);
9941006

9951007
float pradius = 0;
9961008

0 commit comments

Comments
 (0)