Skip to content

Commit 06469c5

Browse files
committed
More sphere sweep changes.
- Revert most of commit be3225d, which was based on a misunderstanding of the code. - Eliminate a bit more unnecessary copying around of data along the way. - Fix some inside texture inconsistencies when using control points with negative radii. - Document some of the insight gained into the workings of the sphere sweep code.
1 parent 887467e commit 06469c5

File tree

3 files changed

+151
-25
lines changed

3 files changed

+151
-25
lines changed

changes.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ Fixed or Mitigated Bugs
3535
Miscellaneous:
3636

3737
- Fixed a bug in the new `cubic_spline` sphere sweep bounding code.
38+
- Reverted most of the sphere sweep performance and memory footprint
39+
improvements introduced in the previous beta, as they caused artifacts.
40+
- Fixed some sphere sweep inside texture inconsistencies when using
41+
control points with negative radius.
3842

3943

4044
Changes between 3.7.1-beta.5 and 3.7.1-beta.6

source/core/shape/spheresweep.cpp

Lines changed: 123 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -192,28 +192,12 @@ bool SphereSweep::All_Intersections(const Ray& ray, IStack& Depth_Stack, TraceTh
192192
// Intersections with single spheres
193193
for(i = 0; i < Num_Spheres; i++)
194194
{
195-
// Are there intersections with this sphere?
196-
if(Intersect_Sphere(New_Ray, &Sphere[i], Sphere_Isect))
195+
// Test for end of vector
196+
if (Num_Isect + 2 <= SPHSWEEP_MAX_ISECT)
197197
{
198-
// Test for end of vector
199-
if(Num_Isect + 2 <= SPHSWEEP_MAX_ISECT)
200-
{
201-
// Valid intersection at Sphere_Isect[0]?
202-
if((Sphere_Isect[0].t > -MAX_DISTANCE) && (Sphere_Isect[0].t < MAX_DISTANCE))
203-
{
204-
// Add intersection
205-
Isect[Num_Isect] = Sphere_Isect[0];
206-
Num_Isect++;
207-
}
208-
209-
// Valid intersection at Sphere_Isect[1]?
210-
if((Sphere_Isect[1].t > -MAX_DISTANCE) && (Sphere_Isect[1].t < MAX_DISTANCE))
211-
{
212-
// Add intersection
213-
Isect[Num_Isect] = Sphere_Isect[1];
214-
Num_Isect++;
215-
}
216-
}
198+
// Are there intersections with this sphere?
199+
if (Intersect_Sphere(New_Ray, &Sphere[i], Isect + Num_Isect))
200+
Num_Isect += 2;
217201
}
218202
}
219203

@@ -349,7 +333,7 @@ bool SphereSweep::Intersect_Sphere(const BasicRay &ray, const SPHSWEEP_SPH *Sphe
349333
Inter[0].Point = ray.Evaluate(Inter[0].t);
350334

351335
// Calculate normal
352-
Inter[0].Normal = (Inter[0].Point - Sphere->Center) / Sphere->Radius;
336+
Inter[0].Normal = (Inter[0].Point - Sphere->Center) / fabs(Sphere->Radius);
353337

354338
// Calculate bigger depth
355339
Inter[1].t = t_Closest_Approach + Half_Chord;
@@ -358,7 +342,7 @@ bool SphereSweep::Intersect_Sphere(const BasicRay &ray, const SPHSWEEP_SPH *Sphe
358342
Inter[1].Point = ray.Evaluate(Inter[1].t);
359343

360344
// Calculate normal
361-
Inter[1].Normal = (Inter[1].Point - Sphere->Center) / Sphere->Radius;
345+
Inter[1].Normal = (Inter[1].Point - Sphere->Center) / fabs(Sphere->Radius);
362346

363347
return true;
364348
}
@@ -410,7 +394,12 @@ bool SphereSweep::Intersect_Sphere(const BasicRay &ray, const SPHSWEEP_SPH *Sphe
410394
int SphereSweep::Intersect_Segment(const BasicRay &ray, const SPHSWEEP_SEG *Segment, SPHSWEEP_INT *Isect, TraceThreadData *Thread)
411395
{
412396
int Isect_Count;
397+
DBL Dot1, Dot2;
398+
DBL t1, t2;
413399
Vector3d Vector;
400+
Vector3d IPoint;
401+
Vector3d DCenter;
402+
DBL DCenterDot;
414403
DBL temp;
415404
DBL b, c, d, e, f, g, h, i, j, k, l;
416405
DBL Coef[11];
@@ -423,6 +412,79 @@ int SphereSweep::Intersect_Segment(const BasicRay &ray, const SPHSWEEP_SEG *Segm
423412

424413
Isect_Count = 0;
425414

415+
// Calculate intersections with closing discs near the ends of the spline segment.
416+
// Note that the positions of the closing discs account for the rate of change in radius
417+
// at the respective end of the spline segment.
418+
419+
// We need to compute these intersections even though we will inevitably discard them later,
420+
// because the algorithm downstream expects intersections to always come in pairs, one entering
421+
// the segment and the other one exiting it. The intersections with the closing discs will
422+
// take the place of any intersections we discard because they fall outside the interval [0,1].
423+
// (Also, if the spline happens to be parallel to the ray direction, we will get no roots
424+
// at all but still need to have these intersections.)
425+
426+
// Closing disk near u=1.
427+
Dot1 = dot(ray.Direction, Segment->Center_Deriv[0]);
428+
if(fabs(Dot1) > EPSILON)
429+
{
430+
Vector = ray.Origin - Segment->Closing_Sphere[0].Center;
431+
Dot2 = dot(Vector, Segment->Center_Deriv[0]);
432+
t1 = -(Dot2 + Segment->Closing_Sphere[0].Radius * Segment->Radius_Deriv[0]) / Dot1;
433+
if ((t1 > -MAX_DISTANCE) && (t1 < MAX_DISTANCE))
434+
{
435+
// Calculate point
436+
IPoint = ray.Evaluate(t1);
437+
438+
// Is the point inside the closing sphere?
439+
DCenter = IPoint - Segment->Closing_Sphere[0].Center;
440+
DCenterDot = DCenter.lengthSqr();
441+
if(DCenterDot < Sqr(Segment->Closing_Sphere[0].Radius))
442+
{
443+
// Add intersection
444+
Isect[Isect_Count].t = t1;
445+
446+
// Copy point
447+
Isect[Isect_Count].Point = IPoint;
448+
449+
// Calculate normal
450+
Isect[Isect_Count].Normal = -Segment->Center_Deriv[0].normalized();
451+
452+
Isect_Count++;
453+
}
454+
}
455+
}
456+
457+
// Closing disk near u=1.
458+
Dot1 = dot(ray.Direction, Segment->Center_Deriv[1]);
459+
if(fabs(Dot1) > EPSILON)
460+
{
461+
Vector = ray.Origin - Segment->Closing_Sphere[1].Center;
462+
Dot2 = dot(Vector, Segment->Center_Deriv[1]);
463+
t2 = -(Dot2 + Segment->Closing_Sphere[1].Radius * Segment->Radius_Deriv[1]) / Dot1;
464+
if((t2 > -MAX_DISTANCE) && (t2 < MAX_DISTANCE))
465+
{
466+
// Calculate point
467+
IPoint = ray.Evaluate(t2);
468+
469+
// Is the point inside the closing sphere?
470+
DCenter = IPoint - Segment->Closing_Sphere[1].Center;
471+
DCenterDot = DCenter.lengthSqr();
472+
if(DCenterDot < Sqr(Segment->Closing_Sphere[1].Radius))
473+
{
474+
// Add intersection
475+
Isect[Isect_Count].t = t2;
476+
477+
// Copy point
478+
Isect[Isect_Count].Point = IPoint;
479+
480+
// Calculate normal
481+
Isect[Isect_Count].Normal = Segment->Center_Deriv[1].normalized();
482+
483+
Isect_Count++;
484+
}
485+
}
486+
}
487+
426488
// Calculate intersections with sides of the segment
427489

428490
switch (Segment->Num_Coefs)
@@ -537,7 +599,10 @@ int SphereSweep::Intersect_Segment(const BasicRay &ray, const SPHSWEEP_SEG *Segm
537599
break;
538600
}
539601

540-
// Remove roots not in interval [0, 1]
602+
// Remove roots not in interval [0, 1].
603+
604+
// Note that the corresponding intersections are either removed in balanced pairs, or are
605+
// balanced by intersections with the closing discs.
541606

542607
m = 0;
543608
while(m < Num_Poly_Roots)
@@ -1474,6 +1539,16 @@ void SphereSweep::Compute()
14741539

14751540
for(i = 0; i < Num_Segments; i++)
14761541
{
1542+
// Calculate closing sphere for u = 0
1543+
1544+
// Center
1545+
Segment[i].Closing_Sphere[0].Center =
1546+
Segment[i].Center_Coef[0];
1547+
1548+
// Radius
1549+
Segment[i].Closing_Sphere[0].Radius =
1550+
Segment[i].Radius_Coef[0];
1551+
14771552
// Calculate derivatives for u = 0
14781553

14791554
// Center
@@ -1484,6 +1559,27 @@ void SphereSweep::Compute()
14841559
Segment[i].Radius_Deriv[0] =
14851560
Segment[i].Radius_Coef[1];
14861561

1562+
// Calculate closing sphere for u = 1
1563+
1564+
// Center
1565+
Segment[i].Closing_Sphere[1].Center =
1566+
Segment[i].Center_Coef[0];
1567+
1568+
// Radius
1569+
Segment[i].Closing_Sphere[1].Radius =
1570+
Segment[i].Radius_Coef[0];
1571+
1572+
for(coef = 1; coef < Segment[i].Num_Coefs; coef++)
1573+
{
1574+
// Center
1575+
Segment[i].Closing_Sphere[1].Center +=
1576+
Segment[i].Center_Coef[coef];
1577+
1578+
// Radius
1579+
Segment[i].Closing_Sphere[1].Radius +=
1580+
Segment[i].Radius_Coef[coef];
1581+
}
1582+
14871583
// Calculate derivatives for u = 1
14881584

14891585
// Center
@@ -1592,9 +1688,11 @@ int SphereSweep::Find_Valid_Points(SPHSWEEP_INT *Inter, int Num_Inter, const Bas
15921688
int i;
15931689
int j;
15941690
int Inside;
1595-
int Keep;
1691+
bool Keep;
15961692
DBL NormalDotDirection;
15971693

1694+
// NB: First intersection point always enters, last one always leaves, so we're not explicitly testing them.
1695+
15981696
Inside = 1;
15991697
i = 1;
16001698
while(i < Num_Inter - 1)

source/core/shape/spheresweep.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ struct Sphere_Sweep_Sphere_Struct
9797
/* One segment of the sphere sweep */
9898
struct Sphere_Sweep_Segment_Struct
9999
{
100+
SPHSWEEP_SPH Closing_Sphere[2]; /* Spheres closing the segment */
100101
Vector3d Center_Deriv[2]; /* Derivatives of center funcs for 0 and 1 */
101102
DBL Radius_Deriv[2]; /* Derivatives of radius funcs for 0 and 1 */
102103
int Num_Coefs; /* Number of coefficients */
@@ -141,9 +142,32 @@ class SphereSweep : public ObjectBase
141142

142143
void Compute();
143144
protected:
145+
146+
/// @note
147+
/// This function is quasi-guaranteed to always compute a pair of intersection points
148+
/// (if any), even in the case of a "glancing blow", and with surface normals oriented
149+
/// away from the spline "backbone".
150+
///
144151
static bool Intersect_Sphere(const BasicRay &ray, const SPHSWEEP_SPH *Sphere, SPHSWEEP_INT *Isect);
152+
153+
/// @note
154+
/// This function is quasi-guaranteed to always compute pairs of intersection points
155+
/// (if any), even in the case of a "glancing blow", and with surface normals oriented
156+
/// away from the spline "backbone".
157+
///
145158
static int Intersect_Segment(const BasicRay &ray, const SPHSWEEP_SEG *Segment, SPHSWEEP_INT *Isect, TraceThreadData *Thread);
159+
160+
/// Eliminate interior surfaces.
161+
///
162+
/// This function cleans up the intersections found, discarding any that lie inside other
163+
/// portions of the sphere sweep.
164+
///
165+
/// @note
166+
/// This function requires that intersections always come in pairs, with surface
167+
/// normals oriented away from the spline "backbone".
168+
///
146169
static int Find_Valid_Points(SPHSWEEP_INT *Inter, int Num_Inter, const BasicRay &ray);
170+
147171
static int Comp_Isects(const void *Intersection_1, const void *Intersection_2);
148172
static int bezier_01(int degree, const DBL* Coef, DBL* Roots, bool sturm, DBL tolerance, TraceThreadData *Thread);
149173
};

0 commit comments

Comments
 (0)