Add a hitBackFaces raycast option to skip mesh collider back faces - #9506
Merged
Merged
Conversation
raycastFirst and raycastAll take a new hitBackFaces option. Setting it to false sets Bullet's kF_FilterBackfaces flag on the ray callback, so rays skip the triangles of mesh colliders that face away from them: the far side of a closed mesh, and the first surface a ray starting inside one meets. It defaults to true, keeping the current behavior. Ammo builds without ray callback flags warn once and ignore the option. Fixes #2516 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Public API reportThis PR changes the public API surface (+2 / −2), per the docs' rules (@ignore / @Private / undocumented are excluded). Show API diff-RigidBodyComponentSystem.raycastAll(start: Vec3, end: Vec3, options?: { filterCallback: Function; filterCollisionGroup: number; filterCollisionMask: number; filterTags: any[]; sort: boolean }): RaycastResult[]
-RigidBodyComponentSystem.raycastFirst(start: Vec3, end: Vec3, options?: { filterCallback: Function; filterCollisionGroup: number; filterCollisionMask: number; filterTags: any[] }): RaycastResult | null
+RigidBodyComponentSystem.raycastAll(start: Vec3, end: Vec3, options?: { filterCallback: Function; filterCollisionGroup: number; filterCollisionMask: number; filterTags: any[]; hitBackFaces: boolean; sort: boolean }): RaycastResult[]
+RigidBodyComponentSystem.raycastFirst(start: Vec3, end: Vec3, options?: { filterCallback: Function; filterCollisionGroup: number; filterCollisionMask: number; filterTags: any[]; hitBackFaces: boolean }): RaycastResult | nullInformational only — this never fails the build. |
Build size reportThis PR changes the size of the minified bundles.
|
Contributor
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
No unresolved blocking issues were identified.
Review effort: Lite
Findings: None
What changed in this PR
Adds optional hitBackFaces filtering for rigid-body raycasts, implemented for Ammo while preserving existing behavior by default.
Changes:
- Documents the
hitBackFacesraycast option. - Applies Ammo back-face filtering with compatibility handling.
- Adds comprehensive regression tests.
| File | Description |
|---|---|
test/framework/physics/ammo/ammo-physics-world.test.mjs |
Tests filtering, defaults, primitives, and compatibility behavior. |
src/framework/physics/physics-world.js |
Documents the backend raycast option. |
src/framework/physics/ammo/ammo-physics-world.js |
Applies back-face filtering and fallback warning. |
src/framework/components/rigid-body/system.js |
Exposes and documents the public API. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
LeXXik
reviewed
Sep 23, 2026
Contributor
|
Looks good 👍 |
This branch was successfully deployed
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.
Fixes #2516
Problem
raycastAllthrough a mesh collider reports two hits, one on the way in and one on the way out.raycastFirsthas the same problem when the ray starts inside a mesh: it hits the inside of the far wall. There was no way to exclude these back-face hits, and it couldn't be done in user code either. Bullet flips a back-face hit's normal to face the ray, so every hit looks front-facing and a dot-product check can't tell them apart.Box, sphere, convex hull and other primitive colliders never report back-face hits, so only mesh colliders are affected.
Change
raycastFirstandraycastAllonRigidBodyComponentSystemtake a newhitBackFacesoption:falsesets Bullet'skF_FilterBackfacesflag on the ray callback. The binding for it has been in ammo.js since Expose m_flags in RayResultCallback kripken/ammo.js#368 (2021), and the build shipped with the examples has it.true, so existing behavior is unchanged.PhysicsWorldbackend base class, so other backends are expected to honor it. Jolt (mBackFaceModeTriangles) and PhysX (PxHitFlag::eMESH_BOTH_SIDES) both have a native per-query equivalent, although both default to ignoring back faces.Tests
New
raycast back facesblock intest/framework/physics/ammo/ammo-physics-world.test.mjs, run against real Ammo:hitBackFaces: falsethe same ray hits only the entry face.raycastFirstfrom inside a mesh hits the far wall by default and misses withhitBackFaces: false.raycastFirstgoes through the filteredraycastAllpath.Without the source change, the four tests that set
hitBackFaces: falsefail. The full suite matches the local baseline, whose 37 failures come from the missing canvas binary and are not related to this change.build:types,test:types, lint and the docs build (warnings as errors) all pass.🤖 Generated with Claude Code