Lipschitz transform#89
Open
snowbldr wants to merge 2 commits into
Open
Conversation
TransformSDF3.Evaluate forwards the inner SDF at M⁻¹·p but doesn't
account for the linear map's stretch. When M is rotation+translation
(orthonormal) σ_max(M⁻¹) = 1 and the SDF stays Lipschitz-1; for any
matrix with non-uniform scaling, σ_max(M⁻¹) > 1 and the result
overstates true 3D distance by that factor. The octree marching-cubes
isEmpty check (|sdf(center)| ≥ half-diagonal) then skips cubes that
contain surface, producing holes.
Adds invStretch = 1/σ_max(M⁻¹_3x3) to TransformSDF3, computed at
construction via a closed-form symmetric-3×3 eigenvalue (Smith 1961).
Pure rotation/translation hits the diagonal short-circuit and gets
σ_max = 1 → invStretch = 1, no behavior change.
render/transform_test.go: watertight test with non-uniform scale
factors {2,2,2}, {3,1,1}, {1,1,3}, {2,3,4}, {5,1,5} on a unit sphere
at 80 cells; plus a rigid-transform distance-preservation pin so a
future tightening can't accidentally apply a < 1 factor to rotations.
…nfigs 3 inner SDFs (sphere, rounded box, cylinder) × 16 transform matrices: - pure scale: uniform 2x/3x, anisotropic, extreme ratios (10x, 0.5x) - reflection (negative scale on one or all axes) - rotation × scale composition (45° z, 30° y, oblique XY) - shear (single off-diagonal) - translation × scale composition Plus rigid-transform pin (rotation/translation only must give SDF exactly 1 at distance 1) across 7 rigid matrices, and an extruded-inner-SDF watertight pass. Each combination asserts zero boundary edges from the octree at cells=80.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix Transform3D Lipschitz under-correction for non-rigid matrices
Fixes one of the bugs in #85.
The bug
Transform3Devaluates by applyingM⁻¹to the query point andforwarding to the inner SDF. The inner SDF returns a distance in the
untransformed space; if
Mis non-orthonormal (any axis scaling),that distance is stretched by the largest singular value of
M⁻¹:so
Evaluateoverstates true 3D distance by up toσ_max(M⁻¹). Theoctree marching-cubes renderer's
|sdf(center)| ≥ half-diagonalpruning then skips cubes that contain surface, producing holes.
Pure rotation+translation has
σ_max = 1and the bug doesn't firethere; it only matters once you compose with
Scale3dor anynon-uniform scaling.
The fix
TransformSDF3growsinvStretch float64, set at construction:Evaluatemultiplies its result byinvStretchso the SDF stays avalid Lipschitz-1 distance estimator.
m44LinearSigmaMax2computesσ_max²of the 3×3 linear block via the closed-form symmetric-matrixeigenvalue formula (Smith 1961) — no iterative SVD on the construction
path.
Diagonal matrices (which pure scaling produces) hit the
p1 == 0short-circuit returning
max(a00, a11, a22). Pure rotation givesσ_max² = 1soinvStretch = 1(no behavior change).Tests
render/transform_test.go:Test_Transform3D_Watertight— non-uniform scales{2,2,2},{3,1,1},{1,1,3},{2,3,4},{5,1,5}on a unit sphere, octreeat 80 cells, asserts zero boundary edges.
Test_Transform3D_RigidPreservesDistance— pins that a rotatedsphere's SDF at distance 1 equals 1 to ≤ 1e-9, so a future tightening
of the σ_max calc can't accidentally apply a
< 1factor to rigidtransforms (which would be safe but slow).
Architecture-specific note
Same family of bug as the high-taper screw rendering issue from #84 —
non-1-Lipschitz SDF that the octree's
isEmptypruning rule wronglytrusts. Borderline configurations may render holes on x86_64 (FMA /
FTZ rounding differences) but not on Apple Silicon. The conservative
invStretchconstant is tight enough to absorb 1-ulp wobble either way.