From 4c81055610e1d2e2e7dc4fd49239e16c69e2e739 Mon Sep 17 00:00:00 2001 From: Nathan Mande Date: Sun, 19 Apr 2026 02:15:40 +0300 Subject: [PATCH] feat(rapier): full collider shapes support ### Description - `RigidBody` component now uses `RigidBodyCollidersShape` via the `collider` prop to generate auto colliders - Supported shapes: `cuboid`, `ball`, `capsule`, `cone`, `cylinder`, `convexHull`, `trimesh` - Full Collider Shapes support - Supported `ColliderShape`: `ball`, `capsule`, `cone`, `convexHull`, `convexMesh`, `cuboid`, `cylinder`, `heightfield`, `polyline`, `roundCone`, `roundConvexHull`, `roundConvexMesh`, `roundCuboid`, `roundCylinder`, `trimesh` - Align `Collider` components with `ColliderShape` - Code clean up and accessibility improvements. #### Breaking changes This integration was designed to be backwards compatible, but some changes were necessary to align with the new `ColliderShape`. - Old `Hull` collider no longer supported, use `convexHull` instead. --- .../src/pages/rapier/HeightfieldDemo.vue | 58 ++++++ .../src/pages/rapier/InstancedRigidBody.vue | 2 +- .../src/router/routes/rapier/index.ts | 5 + .../src/components/InstancedRigidBody.vue | 16 +- packages/rapier/src/components/Physics.vue | 28 +-- packages/rapier/src/components/RigidBody.vue | 9 +- .../colliders/{BallCollider.vue => Ball.vue} | 6 +- .../colliders/{BaseCollider.vue => Base.vue} | 0 .../src/components/colliders/Capsule.vue | 12 ++ .../components/colliders/CapsuleCollider.vue | 10 - .../rapier/src/components/colliders/Cone.vue | 12 ++ .../src/components/colliders/ConeCollider.vue | 10 - .../src/components/colliders/ConvexHull.vue | 12 ++ .../src/components/colliders/ConvexMesh.vue | 12 ++ .../src/components/colliders/Cuboid.vue | 12 ++ .../components/colliders/CuboidCollider.vue | 10 - .../src/components/colliders/Cylinder.vue | 12 ++ .../components/colliders/CylinderCollider.vue | 10 - .../src/components/colliders/Heightfield.vue | 14 ++ .../colliders/HeightfieldCollider.vue | 10 - .../src/components/colliders/HullCollider.vue | 10 - .../src/components/colliders/Polyline.vue | 12 ++ .../src/components/colliders/RoundCone.vue | 12 ++ .../components/colliders/RoundConvexHull.vue | 12 ++ .../components/colliders/RoundConvexMesh.vue | 12 ++ .../src/components/colliders/RoundCuboid.vue | 12 ++ .../components/colliders/RoundCylinder.vue | 12 ++ .../src/components/colliders/Trimesh.vue | 12 ++ .../components/colliders/TrimeshCollider.vue | 10 - .../rapier/src/components/colliders/index.ts | 41 +++- packages/rapier/src/core/collider.ts | 191 +++++++++--------- packages/rapier/src/core/rigid-body.ts | 88 ++++++++ packages/rapier/src/types/collider.ts | 29 +-- packages/rapier/src/types/rigid-body.ts | 26 ++- packages/rapier/src/utils/collisions.ts | 12 +- 35 files changed, 522 insertions(+), 229 deletions(-) create mode 100644 apps/playground/src/pages/rapier/HeightfieldDemo.vue rename packages/rapier/src/components/colliders/{BallCollider.vue => Ball.vue} (51%) rename packages/rapier/src/components/colliders/{BaseCollider.vue => Base.vue} (100%) create mode 100644 packages/rapier/src/components/colliders/Capsule.vue delete mode 100644 packages/rapier/src/components/colliders/CapsuleCollider.vue create mode 100644 packages/rapier/src/components/colliders/Cone.vue delete mode 100644 packages/rapier/src/components/colliders/ConeCollider.vue create mode 100644 packages/rapier/src/components/colliders/ConvexHull.vue create mode 100644 packages/rapier/src/components/colliders/ConvexMesh.vue create mode 100644 packages/rapier/src/components/colliders/Cuboid.vue delete mode 100644 packages/rapier/src/components/colliders/CuboidCollider.vue create mode 100644 packages/rapier/src/components/colliders/Cylinder.vue delete mode 100644 packages/rapier/src/components/colliders/CylinderCollider.vue create mode 100644 packages/rapier/src/components/colliders/Heightfield.vue delete mode 100644 packages/rapier/src/components/colliders/HeightfieldCollider.vue delete mode 100644 packages/rapier/src/components/colliders/HullCollider.vue create mode 100644 packages/rapier/src/components/colliders/Polyline.vue create mode 100644 packages/rapier/src/components/colliders/RoundCone.vue create mode 100644 packages/rapier/src/components/colliders/RoundConvexHull.vue create mode 100644 packages/rapier/src/components/colliders/RoundConvexMesh.vue create mode 100644 packages/rapier/src/components/colliders/RoundCuboid.vue create mode 100644 packages/rapier/src/components/colliders/RoundCylinder.vue create mode 100644 packages/rapier/src/components/colliders/Trimesh.vue delete mode 100644 packages/rapier/src/components/colliders/TrimeshCollider.vue diff --git a/apps/playground/src/pages/rapier/HeightfieldDemo.vue b/apps/playground/src/pages/rapier/HeightfieldDemo.vue new file mode 100644 index 000000000..40a24a80e --- /dev/null +++ b/apps/playground/src/pages/rapier/HeightfieldDemo.vue @@ -0,0 +1,58 @@ + + + diff --git a/apps/playground/src/pages/rapier/InstancedRigidBody.vue b/apps/playground/src/pages/rapier/InstancedRigidBody.vue index 11224e9b8..8f120cd7d 100644 --- a/apps/playground/src/pages/rapier/InstancedRigidBody.vue +++ b/apps/playground/src/pages/rapier/InstancedRigidBody.vue @@ -44,7 +44,7 @@ watch(torusInstancedMesh, (mesh) => { - + diff --git a/apps/playground/src/router/routes/rapier/index.ts b/apps/playground/src/router/routes/rapier/index.ts index 2c6359748..28f9ee74b 100644 --- a/apps/playground/src/router/routes/rapier/index.ts +++ b/apps/playground/src/router/routes/rapier/index.ts @@ -65,6 +65,11 @@ export const rapierRoutes = [ name: 'Solver Groups', component: () => import('@/pages/rapier/SolverGroupsDemo.vue'), }, + { + path: '/rapier/heightfield', + name: 'Heightfield', + component: () => import('@/pages/rapier/HeightfieldDemo.vue'), + }, { path: '/rapier/ragdoll', name: 'Basic Ragdoll', diff --git a/packages/rapier/src/components/InstancedRigidBody.vue b/packages/rapier/src/components/InstancedRigidBody.vue index 80e2bb27f..eadac1d8d 100644 --- a/packages/rapier/src/components/InstancedRigidBody.vue +++ b/packages/rapier/src/components/InstancedRigidBody.vue @@ -5,8 +5,12 @@ import { onUnmounted, onUpdated, shallowRef, watch } from 'vue' import { useRapierContext } from '../composables' import { MATRIX_ZERO, QUATERNION_ZERO, VECTOR_ZERO } from '../constants/' -import { createCollider, createRigidBody } from '../core' -import type { InstancedRigidBodyProps, RigidBodyContext, TresInstancedMesh } from '../types' +import { createCollider, createRigidBody, createRigidBodyAutoColliderPropsFromObject } from '../core' +import type { + InstancedRigidBodyProps, + RigidBodyContext, + TresInstancedMesh, +} from '../types' const props = withDefaults(defineProps>(), { type: 'dynamic', @@ -59,10 +63,14 @@ watch(bodyGroup, (group) => { rigidBodyInfo.rigidBody.setTranslation(position, true) rigidBodyInfo.rigidBody.setRotation(quaternion, true) + const colliderProps = createRigidBodyAutoColliderPropsFromObject( + object, + props.collider, + rigidBodyInfo.rigidBody, + ) const colliderInfo = { ...createCollider({ - object, - shape: props.collider, + ...colliderProps, rigidBody: rigidBodyInfo.rigidBody, world, }), diff --git a/packages/rapier/src/components/Physics.vue b/packages/rapier/src/components/Physics.vue index 2dd330d5c..adbe890f8 100644 --- a/packages/rapier/src/components/Physics.vue +++ b/packages/rapier/src/components/Physics.vue @@ -10,11 +10,11 @@ import { GRAVITY } from '../constants' import { collisionTrigger, emitIntersection, - getCollisionObjectFromSource, getCollisionSourceFromColliderHandle, + getNodeObjectsFromCollisionSource, } from '../utils' import Debug from './Debug.vue' -import type { PhysicsProps } from '../types' +import type { PhysicsProps, SourceTarget } from '../types' const props = withDefaults( defineProps>(), @@ -63,20 +63,24 @@ onBeforeRender(() => { eventQueue.drainCollisionEvents((handle1, handle2, started) => { const source1 = getCollisionSourceFromColliderHandle(world.value, handle1) const source2 = getCollisionSourceFromColliderHandle(world.value, handle2) - const object1 = getCollisionObjectFromSource(source1, scene) - const object2 = getCollisionObjectFromSource(source2, scene) + const [groupObject1, currentObject1] = getNodeObjectsFromCollisionSource(source1, scene) + const [groupObject2, currentObject2] = getNodeObjectsFromCollisionSource(source2, scene) - if (!object1 || !object2) { return } + if (!groupObject1 || !currentObject1 || !groupObject2 || !currentObject2) { return } - collisionTrigger( - { objects: object1, context: source1 }, - { objects: object2, context: source2 }, - started, - ) + const sourceTarget1: SourceTarget = { + objects: [groupObject1, currentObject1], + context: source1, + } + const sourceTarget2: SourceTarget = { + objects: [groupObject2, currentObject2], + context: source2, + } + collisionTrigger(sourceTarget1, sourceTarget2, started) emitIntersection( - { objects: object2, context: source2 }, - { objects: object1, context: source1 }, + sourceTarget2, + sourceTarget1, started && world.value.intersectionPair(source1.collider, source2.collider), ) }) diff --git a/packages/rapier/src/components/RigidBody.vue b/packages/rapier/src/components/RigidBody.vue index 4e736d5a6..892d16fcc 100644 --- a/packages/rapier/src/components/RigidBody.vue +++ b/packages/rapier/src/components/RigidBody.vue @@ -1,6 +1,6 @@