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 @@
diff --git a/packages/rapier/src/components/colliders/BaseCollider.vue b/packages/rapier/src/components/colliders/Base.vue
similarity index 100%
rename from packages/rapier/src/components/colliders/BaseCollider.vue
rename to packages/rapier/src/components/colliders/Base.vue
diff --git a/packages/rapier/src/components/colliders/Capsule.vue b/packages/rapier/src/components/colliders/Capsule.vue
new file mode 100644
index 000000000..8b86bc8d3
--- /dev/null
+++ b/packages/rapier/src/components/colliders/Capsule.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/packages/rapier/src/components/colliders/CapsuleCollider.vue b/packages/rapier/src/components/colliders/CapsuleCollider.vue
deleted file mode 100644
index 18491246d..000000000
--- a/packages/rapier/src/components/colliders/CapsuleCollider.vue
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
diff --git a/packages/rapier/src/components/colliders/Cone.vue b/packages/rapier/src/components/colliders/Cone.vue
new file mode 100644
index 000000000..93fd2797f
--- /dev/null
+++ b/packages/rapier/src/components/colliders/Cone.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/packages/rapier/src/components/colliders/ConeCollider.vue b/packages/rapier/src/components/colliders/ConeCollider.vue
deleted file mode 100644
index 9a0820528..000000000
--- a/packages/rapier/src/components/colliders/ConeCollider.vue
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
diff --git a/packages/rapier/src/components/colliders/ConvexHull.vue b/packages/rapier/src/components/colliders/ConvexHull.vue
new file mode 100644
index 000000000..7ed395040
--- /dev/null
+++ b/packages/rapier/src/components/colliders/ConvexHull.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/packages/rapier/src/components/colliders/ConvexMesh.vue b/packages/rapier/src/components/colliders/ConvexMesh.vue
new file mode 100644
index 000000000..2d23352ed
--- /dev/null
+++ b/packages/rapier/src/components/colliders/ConvexMesh.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/packages/rapier/src/components/colliders/Cuboid.vue b/packages/rapier/src/components/colliders/Cuboid.vue
new file mode 100644
index 000000000..e7ac34e4c
--- /dev/null
+++ b/packages/rapier/src/components/colliders/Cuboid.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/packages/rapier/src/components/colliders/CuboidCollider.vue b/packages/rapier/src/components/colliders/CuboidCollider.vue
deleted file mode 100644
index 6364ac3ea..000000000
--- a/packages/rapier/src/components/colliders/CuboidCollider.vue
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
diff --git a/packages/rapier/src/components/colliders/Cylinder.vue b/packages/rapier/src/components/colliders/Cylinder.vue
new file mode 100644
index 000000000..d47e8d66d
--- /dev/null
+++ b/packages/rapier/src/components/colliders/Cylinder.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/packages/rapier/src/components/colliders/CylinderCollider.vue b/packages/rapier/src/components/colliders/CylinderCollider.vue
deleted file mode 100644
index 68b02551b..000000000
--- a/packages/rapier/src/components/colliders/CylinderCollider.vue
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
diff --git a/packages/rapier/src/components/colliders/Heightfield.vue b/packages/rapier/src/components/colliders/Heightfield.vue
new file mode 100644
index 000000000..bebc92061
--- /dev/null
+++ b/packages/rapier/src/components/colliders/Heightfield.vue
@@ -0,0 +1,14 @@
+
+
+
+
+
diff --git a/packages/rapier/src/components/colliders/HeightfieldCollider.vue b/packages/rapier/src/components/colliders/HeightfieldCollider.vue
deleted file mode 100644
index 2aaaaa592..000000000
--- a/packages/rapier/src/components/colliders/HeightfieldCollider.vue
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
diff --git a/packages/rapier/src/components/colliders/HullCollider.vue b/packages/rapier/src/components/colliders/HullCollider.vue
deleted file mode 100644
index 58e70de35..000000000
--- a/packages/rapier/src/components/colliders/HullCollider.vue
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
diff --git a/packages/rapier/src/components/colliders/Polyline.vue b/packages/rapier/src/components/colliders/Polyline.vue
new file mode 100644
index 000000000..cdee9c9ec
--- /dev/null
+++ b/packages/rapier/src/components/colliders/Polyline.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/packages/rapier/src/components/colliders/RoundCone.vue b/packages/rapier/src/components/colliders/RoundCone.vue
new file mode 100644
index 000000000..6d244ec8d
--- /dev/null
+++ b/packages/rapier/src/components/colliders/RoundCone.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/packages/rapier/src/components/colliders/RoundConvexHull.vue b/packages/rapier/src/components/colliders/RoundConvexHull.vue
new file mode 100644
index 000000000..3ac610d14
--- /dev/null
+++ b/packages/rapier/src/components/colliders/RoundConvexHull.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/packages/rapier/src/components/colliders/RoundConvexMesh.vue b/packages/rapier/src/components/colliders/RoundConvexMesh.vue
new file mode 100644
index 000000000..192ac5eab
--- /dev/null
+++ b/packages/rapier/src/components/colliders/RoundConvexMesh.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/packages/rapier/src/components/colliders/RoundCuboid.vue b/packages/rapier/src/components/colliders/RoundCuboid.vue
new file mode 100644
index 000000000..576b803cd
--- /dev/null
+++ b/packages/rapier/src/components/colliders/RoundCuboid.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/packages/rapier/src/components/colliders/RoundCylinder.vue b/packages/rapier/src/components/colliders/RoundCylinder.vue
new file mode 100644
index 000000000..898fc9909
--- /dev/null
+++ b/packages/rapier/src/components/colliders/RoundCylinder.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/packages/rapier/src/components/colliders/Trimesh.vue b/packages/rapier/src/components/colliders/Trimesh.vue
new file mode 100644
index 000000000..a1856dfce
--- /dev/null
+++ b/packages/rapier/src/components/colliders/Trimesh.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/packages/rapier/src/components/colliders/TrimeshCollider.vue b/packages/rapier/src/components/colliders/TrimeshCollider.vue
deleted file mode 100644
index c21fa8e23..000000000
--- a/packages/rapier/src/components/colliders/TrimeshCollider.vue
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
diff --git a/packages/rapier/src/components/colliders/index.ts b/packages/rapier/src/components/colliders/index.ts
index 2713b01d6..555fa8bb7 100644
--- a/packages/rapier/src/components/colliders/index.ts
+++ b/packages/rapier/src/components/colliders/index.ts
@@ -1,26 +1,47 @@
/** @description `Collider` with the shape set to `ball` */
-export { default as BallCollider } from './BallCollider.vue'
+export { default as BallCollider } from './Ball.vue'
/** @description `Collider` with no shape set */
-export { default as Collider } from './BaseCollider.vue'
+export { default as Collider } from './Base.vue'
/** @description `Collider` with the shape set to `capsule` */
-export { default as CapsuleCollider } from './CapsuleCollider.vue'
+export { default as CapsuleCollider } from './Capsule.vue'
/** @description `Collider` with the shape set to `cone` */
-export { default as ConeCollider } from './ConeCollider.vue'
+export { default as ConeCollider } from './Cone.vue'
+
+/** @description `Collider` with the shape set to `hull` */
+export { default as ConvexHullCollider } from './ConvexHull.vue'
+
+/** @description `Collider` with the shape set to `convexMesh` */
+export { default as ConvexMeshCollider } from './ConvexMesh.vue'
/** @description `Collider` with the shape set to `cuboid` */
-export { default as CuboidCollider } from './CuboidCollider.vue'
+export { default as CuboidCollider } from './Cuboid.vue'
/** @description `Collider` with the shape set to `cylinder` */
-export { default as CylinderCollider } from './CylinderCollider.vue'
+export { default as CylinderCollider } from './Cylinder.vue'
/** @description `Collider` with the shape set to `heightfield` */
-export { default as HeightfieldCollider } from './HeightfieldCollider.vue'
+export { default as HeightfieldCollider } from './Heightfield.vue'
-/** @description `Collider` with the shape set to `hull` */
-export { default as HullCollider } from './HullCollider.vue'
+/** @description `Collider` with the shape set to `polyline` */
+export { default as PolylineCollider } from './Polyline.vue'
+
+/** @description `Collider` with the shape set to `roundCone` */
+export { default as RoundConeCollider } from './RoundCone.vue'
+
+/** @description `Collider` with the shape set to `roundConeConvexHull` */
+export { default as RoundConvexHullCollider } from './RoundConvexHull.vue'
+
+/** @description `Collider` with the shape set to `roundConeConvexMesh` */
+export { default as RoundConvexMeshCollider } from './RoundConvexMesh.vue'
+
+/** @description `Collider` with the shape set to `roundCuboid` */
+export { default as RoundCuboidCollider } from './RoundCuboid.vue'
+
+/** @description `Collider` with the shape set to `roundCylinder` */
+export { default as RoundCylinderCollider } from './RoundCylinder.vue'
/** @description `Collider` with the shape set to `trimesh` */
-export { default as TrimeshCollider } from './TrimeshCollider.vue'
+export { default as TrimeshCollider } from './Trimesh.vue'
diff --git a/packages/rapier/src/core/collider.ts b/packages/rapier/src/core/collider.ts
index cb90be85f..64631ef03 100644
--- a/packages/rapier/src/core/collider.ts
+++ b/packages/rapier/src/core/collider.ts
@@ -1,18 +1,9 @@
-import { ColliderDesc } from '@dimforge/rapier3d-compat'
-import {
- BufferGeometry,
- IcosahedronGeometry,
- Mesh,
- SphereGeometry,
-} from 'three'
-import { mergeVertices } from 'three/examples/jsm/utils/BufferGeometryUtils.js'
-import type { TresObject3D } from '@tresjs/core'
-import type { QuaternionLike, Vector3Like } from 'three'
+import { ColliderDesc, type Quaternion, type Vector3 } from '@dimforge/rapier3d-compat'
+import { Vector3 as ThreeVector3 } from 'three'
import { QUATERNION_ZERO, VECTOR_ZERO } from '../constants'
import { getColliderSizingsFromObject } from '../utils'
import type {
- ColliderProps,
ColliderShape,
CreateColliderDescProps,
CreateColliderProps,
@@ -20,15 +11,53 @@ import type {
} from '../types/collider'
import { parsePosition, parseRotation } from '../utils/common'
+/** @internal */
+const _scaleVertices = (vertices: ArrayLike, scale: Vector3) => {
+ const scaledVertices = Array.from(vertices)
+
+ for (let i = 0; i < vertices.length / 3; i++) {
+ scaledVertices[i * 3] *= scale.x
+ scaledVertices[i * 3 + 1] *= scale.y
+ scaledVertices[i * 3 + 2] *= scale.z
+ }
+
+ return scaledVertices
+}
+
+/** @internal */
+const _scaleColliderArgs = (
+ shape: ColliderShape,
+ args: (number | ArrayLike | { x: number, y: number, z: number })[],
+ scale: Vector3,
+) => {
+ const newArgs = args.slice()
+
+ if (shape === 'heightfield') {
+ const s = newArgs[3] as { x: number, y: number, z: number }
+ s.x *= scale.x
+ s.x *= scale.y
+ s.x *= scale.z
+
+ return newArgs
+ }
+
+ if (shape === 'trimesh' || shape === 'convexHull') {
+ newArgs[0] = _scaleVertices(newArgs[0] as ArrayLike, scale)
+ return newArgs
+ }
+
+ const scaleArray = [scale.x, scale.y, scale.z, scale.x, scale.x]
+ return newArgs.map((arg, index) => scaleArray[index] * (arg as number))
+}
+
/**
* @description
*
- * Create a {@link ColliderDesc} shape based on the given properties.
- *
- * If the shape or sizes are not specified,
- * it will try to create a shape based on the object's geometry or the bounding-box.
+ * Create a {@link ColliderDesc} based on the received properties.
*
- * Will create a {@link ColliderDesc.cuboid Cuboid} by default.
+ * If the shape is not specified,
+ * it will fallback to a {@link ColliderDesc.cuboid Cuboid} shape,
+ * using the object geometry bounding-box.
*
* @param props {@link CreateColliderDescProps}
*
@@ -36,76 +65,67 @@ import { parsePosition, parseRotation } from '../utils/common'
* @see https://rapier.rs/docs/user_guides/javascript/colliders
*/
export const createColliderDesc = (props: CreateColliderDescProps) => {
- const { object, args, shape, scale, rigidBody } = props
- const position: Vector3Like
- = (props.position && parsePosition(props.position))
- ?? (object?.position && parsePosition(object?.position))
- ?? rigidBody.translation()
- ?? VECTOR_ZERO
- const rotation: QuaternionLike
- = (props.rotation && parseRotation(props.rotation))
- ?? (object?.quaternion && parseRotation(object?.quaternion))
- ?? rigidBody.rotation()
- ?? QUATERNION_ZERO.clone()
- const sizes = getColliderSizingsFromObject(object as TresObject3D)
- const halfWidth = (args?.[0] ?? sizes.halfWidth) * (scale?.[0] ?? 1)
- const halfHeight = (args?.[1] ?? sizes.halfHeight) * (scale?.[1] ?? 1)
- const halfDepth = (args?.[2] ?? sizes.halfDepth) * (scale?.[2] ?? 1)
- const radius = (args?.[0] ?? sizes.radius) * (scale?.[0] ?? 1)
-
- let colliderDesc = ColliderDesc.cuboid(
- halfWidth ?? 1,
- halfHeight ?? 1,
- halfDepth ?? 1,
+ const { shape, object, args, position, rotation, rigidBody, scale } = props
+ const { halfWidth, halfHeight, halfDepth } = getColliderSizingsFromObject(object)
+ const colliderDescMethod = ColliderDesc[shape || 'cuboid']
+ const safeScale = new ThreeVector3(
+ scale?.[0] ?? 1,
+ scale?.[1] ?? 1,
+ scale?.[2] ?? 1,
)
+ const safeArgs = [
+ args?.[0] ?? 1,
+ args?.[1] ?? 1,
+ args?.[2] ?? 1,
+ args?.[3] ?? 1,
+ ...(args?.slice(4) ?? []),
+ ]
+ const scaledArgs = _scaleColliderArgs(shape || 'cuboid', safeArgs, safeScale) as Parameters<(typeof ColliderDesc)[
+ ColliderShape
+ ]>
- if (
- shape === 'ball'
- || (shape === undefined
- && object instanceof Mesh
- && (object.geometry instanceof SphereGeometry
- || object.geometry instanceof IcosahedronGeometry))
- ) {
- colliderDesc = ColliderDesc.ball(radius ?? 1)
- }
- else if (shape === 'capsule') {
- colliderDesc = ColliderDesc.capsule(halfWidth ?? 1, halfHeight ?? 1)
- }
- else if (shape === 'cone') {
- colliderDesc = ColliderDesc.cone(halfWidth ?? 1, halfHeight ?? 1)
- }
- else if (shape === 'cylinder') {
- colliderDesc = ColliderDesc.cylinder(halfWidth ?? 1, halfHeight ?? 1)
+ let colliderDesc: ColliderDesc | null
+
+ const getSafeColliderDesc = () => {
+ return ColliderDesc.cuboid(halfWidth, halfHeight, halfDepth)
}
- else if (object?.geometry instanceof BufferGeometry) {
- if (shape === 'trimesh') {
- const clonedGeometry = mergeVertices(object.geometry)
- const triMeshMap = clonedGeometry.attributes.position
- .array as Float32Array
- const triMeshUnit = clonedGeometry.index?.array as Uint32Array
-
- colliderDesc = ColliderDesc.trimesh(triMeshMap, triMeshUnit)
+
+ try {
+ if (!colliderDescMethod) {
+ throw new Error(`Invalid collider shape: ${shape}.`)
}
- else if (shape === 'hull') {
- const triMeshMap = mergeVertices(object.geometry).attributes.position.array as Float32Array
- colliderDesc = ColliderDesc.convexHull(triMeshMap) ?? colliderDesc
+ colliderDesc = colliderDescMethod?.(...scaledArgs as [any, any, any, any, any])
+
+ if (!colliderDesc) {
+ throw new Error(`Invalid collider shape: ${shape}. Switching to cuboid.`)
}
- // TODO: Unable to retrieve the subdivision number & the Matrix of the given object for #heightfield
- // else if (shape === 'heightfield') {
- // colliderDesc = ColliderDesc.heightfield(object.geometry)
- // }
+ }
+ catch (error) {
+ console.warn(`Error creating collider: ${error instanceof Error ? error.message : 'Unknown error'}. Switching to cuboid.`)
+ colliderDesc = getSafeColliderDesc()
}
+ const newPosition: Vector3
+ = (position && parsePosition(position))
+ ?? (object?.position && parsePosition(object?.position))
+ ?? rigidBody.translation()
+ ?? VECTOR_ZERO
+ const newRotation: Quaternion
+ = (rotation && parseRotation(rotation))
+ ?? (object?.quaternion && parseRotation(object?.quaternion))
+ ?? rigidBody.rotation()
+ ?? QUATERNION_ZERO.clone()
+
colliderDesc
- .setTranslation(position.x, position.y, position.z)
- .setRotation(rotation)
+ .setTranslation(newPosition.x, newPosition.y, newPosition.z)
+ .setRotation(newRotation)
return colliderDesc
}
/**
- * @description Create a {@link Collider} shape based on the given
+ * @description Create a {@link Collider} shape based on the received
* {@link CreateColliderProps}
*
* @param props {@link CreateColliderDescProps}
@@ -126,30 +146,3 @@ export const createCollider = (
object,
}
}
-
-/**
- * @description Create a {@link ColliderProps} from the given object.
- *
- * @param object {@link TresObject3D}
- * @param shape {@link ColliderShape}
- */
-export const createColliderPropsFromObject = (
- object: TresObject3D,
- shape: ColliderShape,
-): ColliderProps => {
- const { position } = object
- const rotation = object?.quaternion
- const sizes = getColliderSizingsFromObject(object)
-
- return {
- shape,
- object,
- args:
- shape === 'ball'
- ? [sizes.radius]
- : [sizes.halfWidth, sizes.halfHeight, sizes.halfDepth],
- position: [position.x, position.y, position.z],
- rotation: [rotation.x, rotation.y, rotation.z, rotation.w],
- scale: [object.scale.x ?? 1, object.scale.y ?? 1, object.scale.z ?? 1],
- }
-}
diff --git a/packages/rapier/src/core/rigid-body.ts b/packages/rapier/src/core/rigid-body.ts
index 2b10c3fab..08f4d75e5 100644
--- a/packages/rapier/src/core/rigid-body.ts
+++ b/packages/rapier/src/core/rigid-body.ts
@@ -1,11 +1,71 @@
import { type RigidBody, RigidBodyDesc } from '@dimforge/rapier3d-compat'
import type {
+ ColliderProps,
+ ColliderShape,
CreateRigidBodyDescProps,
CreateRigidBodyProps,
CreateRigidBodyReturnType,
+ RigidBodyCollidersShape,
RigidBodyUserData,
} from '../types'
+import { BufferGeometry, IcosahedronGeometry, Mesh, SphereGeometry } from 'three'
+import { mergeVertices } from 'three/examples/jsm/utils/BufferGeometryUtils.js'
+import type { TresObject3D } from '@tresjs/core'
+import { getColliderSizingsFromObject } from '../utils'
+
+/**
+ * @description
+ */
+export const createRigidBodyAutoColliderArgs: (props: {
+ rigidBody: RigidBody
+ shape: RigidBodyCollidersShape
+ object: TresObject3D
+}) => any[] = (props) => {
+ const { object, shape } = props
+ const geometry = object?.geometry?.clone()
+ const sizes = getColliderSizingsFromObject(object as TresObject3D)
+ const halfWidth = (sizes.halfWidth)
+ const halfHeight = (sizes.halfHeight)
+ const halfDepth = (sizes.halfDepth)
+ const radius = (sizes.radius)
+
+ let args: any[] = [
+ halfWidth,
+ halfHeight,
+ halfDepth,
+ ]
+
+ if (
+ shape === 'ball'
+ || (shape === undefined
+ && object instanceof Mesh
+ && (geometry instanceof SphereGeometry
+ || geometry instanceof IcosahedronGeometry))
+ ) {
+ args = [(radius ?? 1)]
+ }
+ else if (shape === 'capsule' || shape === 'cone' || shape === 'cylinder') {
+ args = [halfWidth, halfHeight]
+ }
+ else if (geometry instanceof BufferGeometry) {
+ if (shape === 'trimesh') {
+ const clonedGeometry = mergeVertices(geometry)
+ const triMeshMap = clonedGeometry.attributes.position
+ .array as Float32Array
+ const triMeshUnit = clonedGeometry.index?.array as Uint32Array
+
+ args = [triMeshMap, triMeshUnit]
+ }
+ else if (shape === 'convexHull') {
+ const triMeshMap = mergeVertices(geometry).attributes.position.array as Float32Array
+
+ args = [triMeshMap]
+ }
+ }
+
+ return args
+}
/**
* @description Create a {@link RigidBodyDesc} based on the given
@@ -43,6 +103,34 @@ export const createRigidBodyDesc = (props: CreateRigidBodyDescProps) => {
return rigidBodyDesc
}
+/**
+ * @description Create {@link ColliderProps} based on the received object and shape.
+ *
+ * @param object {@link TresObject3D}
+ * @param shape {@link RigidBodyCollidersShape}
+ * @param rigidBody {@link RigidBody}
+ */
+export const createRigidBodyAutoColliderPropsFromObject = (
+ object: TresObject3D,
+ shape: RigidBodyCollidersShape,
+ rigidBody: RigidBody,
+): ColliderProps => {
+ const { position, quaternion, scale } = object
+
+ return {
+ shape: shape as ColliderShape,
+ object,
+ args: createRigidBodyAutoColliderArgs({
+ rigidBody,
+ shape,
+ object,
+ }),
+ position: [position.x, position.y, position.z],
+ rotation: [quaternion.x, quaternion.y, quaternion.z, quaternion.w],
+ scale: [scale.x ?? 1, scale.y ?? 1, scale.z ?? 1],
+ }
+}
+
/**
* @description Create a {@link RigidBody} based on the given
* {@link CreateRigidBodyProps}
diff --git a/packages/rapier/src/types/collider.ts b/packages/rapier/src/types/collider.ts
index a6c3f0199..d99a879d5 100644
--- a/packages/rapier/src/types/collider.ts
+++ b/packages/rapier/src/types/collider.ts
@@ -14,39 +14,42 @@ import type { RigidBodyColliderContext } from './rigid-body'
export type TresInstancedMesh = InstancedMesh & TresObject3D
/** @description Tres Rapier supported Collider shapes. */
-export type ColliderShape =
- | 'cuboid'
+export type ColliderShape = keyof Pick<
+ typeof ColliderDesc,
| 'ball'
| 'capsule'
| 'cone'
+ | 'convexHull'
+ | 'convexMesh'
+ | 'cuboid'
| 'cylinder'
- | 'hull'
- | 'trimesh'
| 'heightfield'
+ | 'polyline'
+ | 'roundCone'
+ | 'roundConvexHull'
+ | 'roundConvexMesh'
+ | 'roundCuboid'
+ | 'roundCylinder'
+ | 'trimesh'
+>
export interface ColliderProps {
/**
* @description Set the {@link Collider} shape.
- *
* @default undefined
*/
shape?: ColliderShape
/**
* @description Shape based {@link TresObject3D}.
- *
* @important Required for certain shapes like `trimesh`, `hull`, `heightfield`.
- *
* @default undefined
*/
object?: TresObject3D
/**
- * @description The half-sizes of the collider shapes.
- * @important Only radius is required for `ball` shape.
- * @default [x: 1, y: 1, z: 1]
+ * @description The arguments for the collider shape.
+ * @default undefined
*/
- args?:
- | [halfWidth: number, halfHeight: number, HalfDepth: number]
- | [radius: number]
+ args?: Array
/**
* @description {@link Collider} position.
* @default [x: 0, y: 0, z: 0]
diff --git a/packages/rapier/src/types/rigid-body.ts b/packages/rapier/src/types/rigid-body.ts
index a9682b887..f92af682c 100644
--- a/packages/rapier/src/types/rigid-body.ts
+++ b/packages/rapier/src/types/rigid-body.ts
@@ -8,7 +8,7 @@ import type {
import type { TresObject3D, TresVector3, VectorCoordinates } from '@tresjs/core'
import type { Ref } from 'vue'
-import type { ColliderProps, ColliderShape } from './collider'
+import type { ColliderProps } from './collider'
export interface RigidBodyUserData {
[key: string]: any
@@ -24,6 +24,18 @@ export type RigidBodyType =
| 'kinematicVelocity'
| 'fixed'
+/** @description `RigidBody` auto generated colliders shape. */
+export type RigidBodyCollidersShape = keyof Pick<
+typeof ColliderDesc,
+| 'cuboid'
+| 'ball'
+| 'capsule'
+| 'cone'
+| 'cylinder'
+| 'convexHull'
+| 'trimesh'
+>
+
export interface RigidBodyProps extends Pick<
ColliderProps,
// Auto generated colliders properties.
@@ -40,10 +52,10 @@ export interface RigidBodyProps extends Pick<
/** @description Set the `RigidBody` type. */
type: RigidBodyType
/**
- * @description Set the `RigidBody` collider shape.
+ * @description `RigidBody` auto generated colliders shape.
* @note Pass `false` to disable the auto generated colliders.
*/
- collider?: ColliderShape | false
+ collider?: RigidBodyCollidersShape | false
/**
* @description Set the gravity of the`RigidBody`.
* @default 1
@@ -121,8 +133,8 @@ export interface ExposedRigidBody {
}
export interface InstancedRigidBodyProps extends RigidBodyProps {
- /** @description Set the `RigidBody` collider shape. */
- collider: ColliderShape
+ /** @description Set the `RigidBody` colliders shape. */
+ collider?: RigidBodyCollidersShape
}
export interface RigidBodyColliderContext {
@@ -155,7 +167,9 @@ export interface CreateRigidBodyDescProps {
* @description The rigid-body based object. (@link TresObject3D}.
*/
object: TresObject3D
- /** @description The `rigidBody` type. {@link RigidBodyType}. */
+ /**
+ * @description The `rigidBody` type. {@link RigidBodyType}.
+ */
rigidBodyType: RigidBodyType
/**
* @description The Rapier {@link World} context.
diff --git a/packages/rapier/src/utils/collisions.ts b/packages/rapier/src/utils/collisions.ts
index af94704df..cc01fce71 100644
--- a/packages/rapier/src/utils/collisions.ts
+++ b/packages/rapier/src/utils/collisions.ts
@@ -5,11 +5,7 @@ import type { CollisionSource, CollisionType, RigidBodyUserData, SourceTarget, T
export const getCollisionSourceFromColliderHandle = (world: World, handle: ColliderHandle) => {
const collider = world.getCollider(handle)
- const rigidBodyHandle = collider?.parent()?.handle
- const rigidBody
- = rigidBodyHandle !== undefined
- ? world.getRigidBody(rigidBodyHandle)
- : undefined
+ const rigidBody = collider?.parent() ?? undefined
const source: CollisionSource = {
collider,
rigidBody,
@@ -18,17 +14,17 @@ export const getCollisionSourceFromColliderHandle = (world: World, handle: Colli
return source
}
-export const getCollisionObjectFromSource = (source: CollisionSource, scene: Ref): SourceTarget['objects'] => {
+export const getNodeObjectsFromCollisionSource = (source: CollisionSource, scene: Ref) => {
const rigidBody = source.rigidBody
const collider = source.collider
const groupUserData = rigidBody?.userData as RigidBodyUserData | undefined
const groupUuid = groupUserData?.uuid
- const groupObject = scene.value.getObjectByProperty('uuid', groupUuid) as TresVNodeObject
+ const groupObject = scene.value.getObjectByProperty('uuid', groupUuid) as TresVNodeObject | undefined
const currentUserData = collider.userData as RigidBodyUserData | undefined
const currentUuid = currentUserData?.uuid
- const currentObject = scene.value.getObjectByProperty('uuid', currentUuid) as TresVNodeObject
+ const currentObject = scene.value.getObjectByProperty('uuid', currentUuid) as TresVNodeObject | undefined
return [groupObject, currentObject]
}