POV-Ray : Newsgroups : povray.pov4.discussion.general : Sphere Sweep Server Time
6 Nov 2025 02:55:54 EST (-0500)
  Sphere Sweep (Message 1 to 3 of 3)  
From: Bald Eagle
Subject: Sphere Sweep
Date: 30 Oct 2025 15:50:00
Message: <web.6903c050a549a6bd98de4e8625979125@news.povray.org>
"There have been long standing problems with reliably rendering the sphere_sweep
shape in povray.
https://github.com/POV-Ray/povray/blob/master/source/core/shape/spheresweep.h
https://github.com/POV-Ray/povray/blob/master/source/core/shape/spheresweep.cpp
Can you identify what the source of the problem is, and suggest fixes or
alternate, more modern methods for rendering this shape?"

Copilot said:


POV‑Ray. Looking at the current sources you linked (spheresweep.h/.cpp)

problems fall into a few concrete buckets: bounding errors, numerical robustness
and root‑finding pitfalls, and algorithmic assumptions that break in edge
cases (especially with cubic splines and transformations). Below is a concise
diagnosis and then practical fixes or modern alternatives that work reliably in
production.


1) Fragile/incorrect automatic bounding
Heuristic bounding that is too tight. The internal bounder grows each modeling

when the path spans a large extent while radii are small; rays get culled early


auto‑bounding was effectively always on, making the bad bounder
unavoidable; in 3.6 you could opt out.
github
User bounding control regression. A follow‑up PR restored 3.6‑style
user control (-MB/Bounding=off) precisely so troublesome sphere_sweeps could
render by disabling the bad auto‑bounder.
github
Transform bugs. With uniform negative scale (e.g., scale -1), the code
multiplied centers and radii by the scale without taking abs() for radii,
producing negative radii and a catastrophically wrong bounding box. The fix is
literally radius *= fabs(scale) in SphereSweep::Scale.
github

extending beyond control points, so the computed box can clip the real object;
recommendation: manually bound sphere_sweeps.
github

The implementation builds each sweep as segments with cubic polynomials for

routine (bezier_01), then assumes intersections come in pairs with normals

Intersect_Segment/Find_Valid_Points, which is brittle for tangencies, grazing
rays, self‑overlaps, or near‑degenerate data. When the pairing
invariant fails, valid hits get culled or bogus hits pass through.
github
The code pre‑allocates fixed‑size arrays based on SPHSWEEP_MAX_ISECT
= (Num_Spheres + Num_Segments)*2 + 64. In pathological cases (tight curvature +
large scene) you can exceed this estimate and silently drop

github

parts)

around the origin with cubic_spline; scaling sometimes just moves the artifacts.
The project tracked this for years (FS#81 → GH #147). Reports note
b_spline and linear_spline behave better, and cubic can slow the whole render

That aligns with the bad bounding + invalid intersection pairs story above.
povray
+1

sphere_sweep and approximate with cones + spheres (capsules); it renders faster
and avoids these artifacts.
povray

The tolerance keyword in SDL (and DEPTH_TOLERANCE/ZERO_TOLERANCE constants in
code) controls self‑shadowing and z‑fighting style issues, not the

povray
+1
The source shows those tolerances are tiny (1e‑6 to 1e‑4),
reasonable for biasing, but irrelevant if the bounder discards the ray or the
root finder mis‑classifies tangencies.
github
What I would change in the code (concrete, scoped fixes)
A) Make bounding safe by default, and controllable
Fix uniform negative scale (already proposed upstream): in SphereSweep::Scale,
multiply radii by fabs(scale) for the uniform case. This resolves the
disappearing/clipped object under scale -1.
github
Allow users to escape the auto‑bounder: keep the 3.6 behavior fully
restored (-MB, Bounding=off) so scenes can render correctly with manual

consistently respected everywhere intersections call Intersect_BBox.
github
Compute a conservative spline bound:
Sample the center/radius polynomials per segment using curvature‑aware
adaptive subdivision, and expand the box by max(r(t)) plus a small epsilon; or
Provide a user keyword (e.g., bound_inflate <factor>) to inflate
per‑segment bounds when the path extent ≫ radii (the exact heuristic

scenes.
github
B) Harden the intersection pipeline
Stop assuming perfect pairings. Update Find_Valid_Points to tolerate odd counts
from near‑tangencies by (a) classifying hits with sign of the surface
function or robust inside/outside tests and (b) merging roots within ε
along the ray. The header itself warns the current function requires paired

github
Use robust bracketing for root finding on [0,1] with interval subdivision
(fallback to bisection/Newton only inside brackets). The existing bezier_01(...,
sturm, tolerance, ...) suggests a Sturm‑sequence option; always enable
Sturm for cubic segments, and add a per‑segment subdivision fallback when
the derivative is near zero (grazing).
github
Dynamic intersection storage. Replace the SPHSWEEP_MAX_ISECT fixed buffer with a
std::vector (thread‑local reused scratch if performance demands) and
gracefully grow when predicting too few hits. That prevents silent drops of
valid intersections.
github
Diagnostics. Emit a one‑time warning when (a) the per‑segment root
solver returns more roots than expected, (b) the pairing logic repairs odd
counts, or (c) the bounder is inflating beyond a heuristic threshold. This helps
users recognize problematic sweeps.

1) Approximate with capsules (cones/cylinders + end spheres)
Build a piecewise linear sweep: capped cylinder (or cone) between each pair of

and artifact‑free, and you can control resolution yourself.
povray




manual bounding helpers. It exists specifically because the native primitive is

github
+1

3) Render as an isosurface / SDF
Model the sweep as an implicit surface:

F
(
x
)
=
min
⁡
t
∈
[
0
,
1
]
∥
x
−
C
(
t
)
∥
−
r
(
t
)
=
0
F(x)=
t∈[0,1]
min
​
 ∥x−C(t)∥−r(t)=0
In POV‑Ray terms, implement an isosurface whose function returns the
minimum capsule distance over a polyline sampled from your spline. This is
robust and easy to bound (container box), just mind max_gradient. For modern
context and performance ideas, see SDF/sphere‑tracing literature.
povray
+2

4) Prefer b_spline or linear_spline over cubic_spline
Multiple reports show cubic is the worst offender (artifacts and performance),
whereas linear and b‑spline modes are much more stable. If you must use
the native primitive, this is the least painful path.
povray
+1

Practical scene‑side mitigations (when you must use the native primitive)

} and either set Remove_Bounds=off or a small Bounding_Threshold so


povray
Turn off auto‑bounding for that scene/object (-MB / Bounding=off) when you

internal bounder is buggy.
github

fabs() radius fix; otherwise you can get a shrunken/vanished object due to a bad
bounding box.
github

cure cubic halos; use it only for acne.
povray
Prefer POV‑Ray 3.8+ branches where possible: some sphere_sweep artifacts
seen in 3.6/3.7 were fixed in the 3.8 development line according to newsgroup
posts; still, the fundamental caveats above remain.
povray
Pointers in the current code that reflect these issues
Assumptions about intersection pairs and normal orientation are explicit in the
public comments for Intersect_Sphere, Intersect_Segment and Find_Valid_Points.

github
Tolerances and fixed intersection buffers (with SPHSWEEP_MAX_ISECT) are visible
in spheresweep.cpp; both are typical sources of robustness headaches in

github


Post a reply to this message

From: Bald Eagle
Subject: Re: Sphere Sweep
Date: 30 Oct 2025 16:05:00
Message: <web.6903c4d0c6f8e83298de4e8625979125@news.povray.org>
(a) C++ header for integrating into POV‑Ray
Download: cr_sweep_bounds.h
What it provides (header‑only, C++11):

centripetalKnots(P0,P1,P2,P3, alpha, T)
crSegmentToBezier(P0,P1,P2,P3, T, B) and crScalarToBezier(R0,R1,R2,R3, T, BR)
segmentAABB(B,BR) → AABB for one segment, inflated by r_max
sweepAABB(pts,rad,n, alpha=0.5) → global AABB for the entire sweep path


when you wire it into POV‑Ray, swap Vec3 for Vector3d and AABB for the


per‑segment bounding becomes tight and provably safe.


issues in each segment (a source of bad bounds and artifacts with

guarantees the curve lies inside the hull of its four control points;
axis‑aligned boxing that hull, then Minkowski‑inflating by a safe
r_max, yields a conservative bound for the swept volume.
[forums.dev...nvidia.com], [news.povray.org]


Post a reply to this message


Attachments:
Download 'cr_sweep_bounds.h.txt' (5 KB)

From: Bald Eagle
Subject: Re: Sphere Sweep
Date: 30 Oct 2025 16:25:00
Message: <web.6903c89ec6f8e83298de4e8625979125@news.povray.org>
What I'm also thinking here, is that if we can just map a multi-segment
centripetal Catmull-Rom spline onto whatever other spline that we want to
implement as a sphere_sweep, then we can just use the bounding cylinders that
I'm working on to bound each segment of the sphere_sweep.

I'm not sure what would happen if we try to do that with a spline that has cusps
or self-intersections - I guess it would just render like any other union {} of
objects.

In any event, it's worth a try.

- BE


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.