feat(collision): shape-precise shielded-prism collision at the visible shell - #618
Open
gradies wants to merge 9 commits into
Open
feat(collision): shape-precise shielded-prism collision at the visible shell#618gradies wants to merge 9 commits into
gradies wants to merge 9 commits into
Conversation
…spec Robust build spec for shape-precise shielded-prism collision: keep the primitive box trigger but resize it to the shell AABB (no swap), add a signed-margin narrowphase (octahedron L1 / stella 4-form, already on-branch as ContainsPointLocal) at the ImpactorBase dispatch chokepoint, with a per-interaction threshold (skim = proximity band, pop = containment) and pending re-test. Fixes the two failure modes of the parallel tetrahedral branch (grazing skims rejected; pop-then-destroy from a collider swap) by construction. Point/sphere tiers are already realized (LOD cull + PrismSpatialIndex); this front-loads the bespoke-bounds tier. Includes exact contracts and the in-editor verification steps. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R78zS1KKCafHhXuebwgWmv
…nds narrowphase) Phase 0-1 of Docs/CollisionLOD/DESIGN.md. Shielded/super-shielded prisms keep the one primitive box trigger (never a mesh, never swapped) but resize it to the shell AABB (interactionShellScale, default = the 3x visual); a signed-margin analytic narrowphase then refines contacts down to the true octahedron / stella surface at the ImpactorBase dispatch chokepoint, with a per-interaction threshold (skim = a grazing proximity band, pop/damage = containment) and a pending re-test on OnTriggerStay for contacts that enter an AABB corner before reaching the shell. - SignedMarginLocal on both mesh generators (positive-inside; ContainsPointLocal redefined through it, one source of truth); IShieldContainmentGate; both shields implement it and publish Prism.ActiveShieldGate on settle, clear it on withdraw (ReferenceEquals-guarded for the shield<->super handoff) and on pool return. - Both tetrahedral-branch failure modes are avoided by construction: grazing skims pass (band, not containment), and the collider is resize-only (no enable/disable cycle) so a single continuous overlap cannot double-dispatch (no pop-then-destroy). Post-implementation adversarial review (fable-5) caught and this commit fixes: the impactee-side gate probed the prism's OWN box (returning the centre, margin always ~+1, gate never bit) -> now probes THIS impactor's own collider; and the pose methods force-enabled the collider (fighting the spawn window / collider-LOD) -> removed, poses are resize-only. Stella union math and compile verified clean. In-editor verification (DESIGN.md section 6) is the human gate and still pending. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R78zS1KKCafHhXuebwgWmv
Adversarial re-verify confirmed the lifecycle/compile fixes and stella math, but found shell-precision needs a real sphere-vs-shell margin (point sample toward the prism centre under-measures grazes -> dead zones, worst on the non-convex stella), a unified threshold (pop dispatches via the skimmer damage effect, so skim+pop share one threshold), and PhysX-timing handling for two pop-then-destroy paths (same-tick parked dispatch after gate clear; one-swing re-enter after the 3x->1x shrink). The last is a gameplay-feel fork. Shell-precision is not headless-verifiable; #617 (authored-size shielded skimming) remains the working baseline. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R78zS1KKCafHhXuebwgWmv
Shell-precise narrowphase for shielded/super-shielded prisms, on top of the #617 box-trigger baseline. The primitive box trigger resizes to the shell AABB (no swap), and impact dispatch refines it to the true octahedron/stella via an analytic signed-margin gate. - SignedMargin/SignedMarginSphere on both shells (octahedron L1, stella 4-form), reusing the on-branch ContainsPointLocal math. Sphere touchers gate on the sphere-vs-shell margin (centre + radius x world gradient) so grazes register without dead zones; point touchers use ClosestPoint. - Unified threshold 0 ("sphere reaches the shell") for skim and pop; removed the skim band that popped shields in thin air. - Parked-contact re-test drops on a null shell gate (impactee-side and self-side) so a pop cannot destroy the freshly-unshielded prism in its own tick. - Collider stays resize-only; enabled owned by spawn window / collider-LOD / destruction. One-swing pop+destroy left emergent (no bespoke grace). Reach is a per-shell config knob (interactionShellScale, default = the 3x visual). Not yet play-tested: the in-editor checklist in Docs/CollisionLOD/DESIGN.md sec 6 is the gate for feel/timing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R78zS1KKCafHhXuebwgWmv
…collision The shield's box trigger resizes to the shell AABB and dispatch refines to the true octahedron/stella via the analytic signed-margin narrowphase (no mesh collider); update the "planned follow-up" note to the shipped mechanism. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R78zS1KKCafHhXuebwgWmv
… tips First playtest: the 3x box reach is live but a vessel hull clipped through the pointy octahedron/stella tips because the non-sphere gate tested a SINGLE point (nearest approach to the prism centre), blind to the thin tips and the hull body. Only the sphere skimmer path was shape-aware. Make every collider shape-aware via ImpactorBase.ColliderReachesShell — the analytic equivalent of a convex octahedron/stella mesh collider: - Sphere: exact sphere-vs-shell margin (unchanged). - Any other convex/primitive collider: MAX shell margin over two support points - the collider's farthest point toward the shell interior (ClosestPoint(centre + ShellInwardNormal*big), catches the tips) and its nearest point to the prism centre (deep body). - New IShieldContainmentGate.ShellInwardNormal returns the nearest-facet inward normal (octahedron: octant L1 coefficients; stella: active linear form). - Impactee-side and self-side both route through the one helper. Needs the in-editor pass: hull should catch at the tips without over-reaching in open space. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R78zS1KKCafHhXuebwgWmv
…-vs-shell SAT Two confirmed root causes (5-agent diagnosis) of the Squirrel hull passing through shielded octahedron/stella tips: 1) The vessel's hull BoxColliders live on CHILD GameObjects (VesselImpactor sits on the root with the kinematic Rigidbody). ImpactorBase resolved the toucher collider via TryGetComponent on its OWN GameObject -> null -> the narrowphase fell back to a single point at the ship pivot, so the shape-aware test never ran on the vessel side (only the pivot-deep region interacted). Fix: cache the impactor's collider SET (own GO, else GetComponentsInChildren) and dispatch if ANY reaches the shell; pivot fallback only when no collider exists at all. 2) The two-point sample false-rejected ~18% of rotated-OBB tip overlaps. Fix: exact analytic OBB-vs-shell overlap via a Separating-Axis Test (IShieldContainmentGate.OverlapsWorldBox -> OverlapsBoxNormalized): octahedron as the L1 unit ball (25 axes); stella as the union of two tetrahedra, SAT per tet OR'd. BoxCollider touchers use it exactly; other colliders use a conservative world-AABB OBB; the sphere skimmer path is unchanged. The SAT is numerically proven against exact LP + dense-grid ground truth: 0/72751 false-reject on the octahedron, 0/94373 on the stella, 0% false-accept both, across 200k cases biased toward the tips/spikes. Still gated on the in-editor pass (cannot run Unity headless). Docs/CollisionLOD/DESIGN.md sec 7.3. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R78zS1KKCafHhXuebwgWmv
remove collider
…hase The exact OBB-vs-shell SAT was correct, but the authored hull box is a loose bounding box larger than the visible mesh, so it popped a shielded prism the instant the box EDGE reached the small octahedron shell — "the box outline pops it, not the octahedron." Add HullNarrowphaseScale (ImpactorBase, default 1) that uniformly shrinks the toucher's box half-edges / sphere radius about its own centre in the analytic shell test ONLY — never the physics broadphase trigger, so the parked-contact re-test window (and tunneling safety) is unchanged; the shrink only decides dispatch within an existing overlap. VesselImpactor exposes it as a live Range(0.2,1) inspector knob (hullNarrowphaseScale, default 0.7) so each vessel's effective hull hugs its visible silhouette; the skimmer sphere stays scale-1/exact to avoid a tangential-skim dead zone. Also remove the now-dead ShellInwardNormal (+ stella CoeffOf helper): the two-point support sample it fed was replaced by the SAT in a prior commit, leaving zero callers. Interface, both shields, and DESIGN.md §7.2 updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R78zS1KKCafHhXuebwgWmv
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 & why
#617 kept shielded prisms skimmable by keeping the primitive box trigger, but interaction happened at the bare prism size — the 3× visible shell was cosmetic. This delivers shape-precise interaction at the visible shell, without a mesh collider: the box trigger resizes to the shell AABB (no swap), and impact dispatch refines it to the true octahedron/stella via an analytic signed-margin gate. Reuses the on-branch
ContainsPointLocalmath, and fixes the two failure modes that sank the paralleltetrahedral-collider-costbranch — grazing skims rejected (a containment-only gate), and pop-then-destroy (a collider swap).Per-system summary
PrismOctahedronShield,PrismStellatedOctahedronShield) — implement the newIShieldContainmentGate:SignedMargin(octahedron L1 / stella 4-form, positive-inside) +SignedMarginSphere(centre, R) = SignedMargin(centre) + R·√((invA/sx)² + (invB/sy)² + (invC/sz)²)(sphere-vs-shell, conservative — never a dead zone). The shielded pose resizes the box toauthoredSize × interactionShellScale(config knob, default = the 3× visual), publishesPrism.SetActiveShieldGateon settle, restores + clears on withdraw. Box is resize-only, never swapped/disabled (enabledstays owned by the spawn window / collider-LOD / destruction).IShieldContainmentGate(new) —SignedMargin/SignedMarginSphere/ContainsWorldPoint.Prism—ActiveShieldGate(server-private) + internal setter, cleared on reset /OnDisable.ImpactorBase— narrowphase at theOnTriggerEnterchokepoint: sphere touchers gate onSignedMarginSphere(world centre + world radius), others on aClosestPointpoint margin, both vsShieldMarginThreshold(default 0 = "reaches the shell"). Contacts that enter the enlarged box outside the shell park and re-test onOnTriggerStay, and drop if their shell went null since parking — impactee-side (ActiveShieldGate == null) and self-side (HasOwnShieldGate) — closing the same-tick pop-then-destroy.SkimmerImpactor— dropped the_skimBand+ threshold override; skim and pop unify at threshold 0 (the sphere radius supplies the grazing reach, so "pop in thin air" is gone). Stay/Exit callbasefirst.SignedMarginLocalsiblings toContainsPointLocal.Docs/CollisionLOD/DESIGN.md(plan, exact contracts, the round-by-round findings, and the§6editor checklist); CLAUDE.md shield row updated to the shipped mechanism.Verification status
DESIGN.md §6):Physics.SendEvents/*.AcceptImpacteeat dense shielded mass.Follow-ups
DESIGN.md §7.1).OnTriggerStaynow delivers Stay callbacks to every impactor (previously only the skimmer). Cheap early-out when nothing is parked, but new per-frame callback volume on the prism hot path — profilePhysics.SendEvents; if material, restrict Stay to impactors that actually park.interactionShellScaleper shell if reach feels off.PrismSpatialIndexfor AOE); Phase 2 formalization is measure-first (DESIGN.md §4).Collider / perf impact (ecology gate)
No new physics queries, no mesh colliders, one trigger per prism (unchanged), still collider-LOD-cullable. The shielded box grows to 3× (more broadphase over-cover → more candidate
OnTriggercallbacks near a shielded prism), each resolved by a ~box-AABB analytic margin test. New per-frame cost: the baseOnTriggerStaydispatch to all impactors (see Follow-ups).🤖 Generated with Claude Code
Generated by Claude Code