Stop the section plane deleting the half of the model it is meant to show - #138
Draft
kmatzen wants to merge 1 commit into
Draft
Stop the section plane deleting the half of the model it is meant to show#138kmatzen wants to merge 1 commit into
kmatzen wants to merge 1 commit into
Conversation
…show Enabling the clipping plane and orbiting to look at the kept side edge-on, or from behind it, thinned the model out and then dropped it entirely. On the reported project, looking up at the kept half from 60 degrees below the plane, the viewport drew nothing at all where the equivalent cut solid covers a third of the frame. Two faults, both in how the marcher handled the plane. It tested every sample against the plane and, on the cut-away side, jumped to the plane by dividing by the ray's component along the clip axis. That division has no guard: a view grazing the plane drives the component to zero and the quotient to an infinity, and a camera sitting on the plane makes it 0/0. NaN > 0.0 is false, so those rays fell through to a fallback that advanced by the hit threshold — about half a pixel — and the clipped branch never checked whether the ray had left the bounding box, so it could not terminate. Such a ray spent all 1024 of its iterations creeping, and rays with real surface still ahead of them ran out of budget before reaching it. Solving the crossing in closed form instead then exposed the second fault. Ending the march at the crossing is wrong, because over-relaxed sphere tracing deliberately overshoots and corrects on the next iteration: the step that finds a surface routinely lands past it first. Cutting the ray off the moment it passes the plane throws that pending correction away, so a surface just short of the plane is lost — and that is the usual case, since the plane gets placed against the feature being inspected. The plane now bounds which hits count rather than how far the march may travel, and the ray is abandoned only from a step where Keinert's condition has just certified that nothing was skipped. Also drops the cross-section shading test, which painted any marched hit landing within three hit-thresholds of the plane as cut face. That measured proximity rather than causation, so a real face lying flat against the plane was tinted across its whole extent. Whether a ray starts on the cut face is already known exactly from its own entry point. The test states the requirement without a reference image: intersecting the tree with a half-space of ordinary geometry produces exactly the solid the plane should reveal, so rendering both and comparing silhouettes needs no golden file and survives the GPU differences that sank golden images in #52. It fails on the old marcher at 0.00% against 32.24%. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
🚀 Preview deployed: https://worktree-clip-grazing-fix.sinter.pages.dev (updates on every push to this PR) |
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.
What you saw
Turning on the clipping plane (the scissors tool) and orbiting to a grazing view made the scene render wrong — and orbiting further, to look at the kept half from below the plane, made it disappear entirely.
Measured on the reported project, looking up at the kept half from 60° below the plane: the viewport drew 0.00% of the frame where the equivalent cut solid covers 32.24%.
Views from the cut side (positive elevations) were already correct, which is why this reads as "it breaks when I rotate".
Two faults
The plane crossing was solved by an unguarded division. The marcher tested every sample against the plane and, on the cut-away side, jumped to it via
(u_clipPos - ro.a) / rd.a. Grazing views driverd.ato zero and the quotient to an infinity; a camera sitting on the plane makes it0/0. SinceNaN > 0.0is false, those rays fell into a fallback that advanced by the hit threshold — roughly half a pixel — and the clipped branch never checked whether the ray had left the bounding box, so it could never terminate. Such a ray burned all 1024 iterations creeping, and rays with real surface still ahead of them ran out of budget before reaching it.Ending the march at the crossing loses surfaces just short of it. Solving the crossing in closed form exposed this. Over-relaxed sphere tracing (Keinert et al., already used here for #76) deliberately overshoots and corrects on the following iteration, so the step that finds a surface routinely lands past it first. Cutting the ray off the moment it passes the plane discards that pending correction. A surface just short of the plane is exactly the common case, since the plane gets positioned against the feature being inspected — so the model vanished wholesale rather than in patches.
The plane now bounds which hits count, not how far the march may travel. The ray is abandoned only from a step where Keinert's condition has just certified that nothing was skipped, which is also what keeps a hit on the cut-away side from being accepted.
Also fixed
The cross-section was shaded by testing whether a marched hit landed within three hit-thresholds of the plane — proximity rather than causation, so a genuine face lying flat against the plane was painted as cut face across its whole extent. Whether a ray starts on the cut face is already known exactly from its own entry point.
Removing the per-step clip branch also removed the budget-burning crawl: the probe run that produced these numbers went from 51s to 20s.
Test
e2e/clip-plane.spec.tsstates the requirement without a reference image: intersecting the tree with a half-space of ordinary CSG geometry produces exactly the solid the plane should reveal, so rendering both and comparing silhouettes needs no golden file and survives the GPU and driver differences that sank golden images in #52 — both sides are rendered by the same marcher on the same machine, and only their agreement is asserted. Both clip directions are covered.Fails on the old marcher (0.00% vs 32.24%); passes here with every angle agreeing to within 0.25 percentage points.
Verification
vitest run— 503 passed, 3 skippedviewport-frames.spec.ts— 10/10 in isolationNote: this machine flakes on the full e2e suite under load regardless of this change — HEAD alone produces the same
viewport-framesfailures under--workers=1, and every one of them passes when run serially in isolation.🤖 Generated with Claude Code