Skip to content

Commit

Permalink
feat: base of instanced mesh support
Browse files Browse the repository at this point in the history
  • Loading branch information
Neosoulink committed Jun 20, 2024
1 parent 3b366f6 commit d68dd43
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 24 deletions.
13 changes: 10 additions & 3 deletions playground/src/pages/basics/RigidBodyDemo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { TresCanvas } from '@tresjs/core'
import { OrbitControls } from '@tresjs/cientos'
import { Physics, RigidBody } from '@tresjs/rapier'
import { ACESFilmicToneMapping, SRGBColorSpace } from 'three'
import { ACESFilmicToneMapping, MeshNormalMaterial, SRGBColorSpace, TorusKnotGeometry } from 'three'
const gl = {
clearColor: '#82DBC5',
Expand All @@ -11,6 +11,9 @@ const gl = {
outputColorSpace: SRGBColorSpace,
toneMapping: ACESFilmicToneMapping,
}
const torusKnots = new TorusKnotGeometry()
const torusKnotsMaterial = new MeshNormalMaterial()
</script>

<template>
Expand All @@ -19,7 +22,11 @@ const gl = {
<OrbitControls />
<Suspense>
<Physics debug>
<RigidBody>
<RigidBody instanced>
<TresInstancedMesh :args="[torusKnots, torusKnotsMaterial, 3]" />
</RigidBody>

<RigidBody collider="hull">
<TresMesh :position="[0, 8, 0]">
<TresTorusGeometry />
<TresMeshNormalMaterial />
Expand All @@ -37,7 +44,7 @@ const gl = {
</TresMesh>
</RigidBody>
<RigidBody type="fixed">
<TresMesh>
<TresMesh :position="[0, -5, 0]">
<TresPlaneGeometry :args="[20, 20, 20]" :rotate-x="-Math.PI / 2" />
<TresMeshBasicMaterial color="#f4f4f4" />
</TresMesh>
Expand Down
97 changes: 85 additions & 12 deletions src/components/RigidBody.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,116 @@
import { shallowRef, watch } from 'vue'
import { type TresObject, useLoop } from '@tresjs/core'
import { InstancedMesh } from 'three'
import { useRapierContext } from '../composables/useRapier'
import { createRigiBody } from '../utils/rigid-body.util'
import { createColliderFromChildren } from '../utils/collider.util'
import { createCollider, createCollidersFromChildren } from '../utils/collider.util'
import { MATRIX_ZERO, QUATERNION_ZERO, VECTOR_ZERO } from '../constants/object.constant'
import type { RigidBodyProps } from '../types/rigid-body.type'
const props = withDefaults(defineProps<Partial<RigidBodyProps>>(), {
type: 'dynamic',
collider: 'cuboid',
instanced: false,
})
const { world } = await useRapierContext()
const { onBeforeRender } = useLoop()
const rigidObject = shallowRef<TresObject>()
const rigidBodyInfo = shallowRef<ReturnType<typeof createRigiBody>>()
const rigidColliders = shallowRef<ReturnType<typeof createColliderFromChildren>>()
const parentObject = shallowRef<TresObject>()
const rigidBodyInfos = shallowRef<ReturnType<typeof createRigiBody>[]>()
const colliderInfos = shallowRef<ReturnType<typeof createCollidersFromChildren>>()
watch(rigidObject, (object) => {
watch(parentObject, (object) => {
if (!object) { return }
rigidBodyInfo.value = createRigiBody({
if (props.instanced) {
const child = parentObject.value?.children[0]
if (
!(child instanceof InstancedMesh)
|| typeof parentObject.value?.children?.length !== 'number'
|| parentObject.value.children.length > 1
) {
throw new Error('Incorrect data assignment detected! #RigidBody support only one #InstancedMesh')
}
// const array = child.instanceMatrix.array
const rigidBodies = []
const colliders = []
for (let i = 0; i < child.count; i++) {
// const position = VECTOR_ZERO.fromArray(array, i * 16 + 12)
rigidBodies.push(createRigiBody({
object: child,
rigidBodyType: props.type,
world,
}))
colliders.push(createCollider({
object: child,
colliderShape: props.collider,
rigidBody: rigidBodies[i].rigidBody,
world,
}))
}
rigidBodyInfos.value = rigidBodies
colliderInfos.value = colliders
return
}
rigidBodyInfos.value = [createRigiBody({
object,
rigidBodyType: props.type,
world,
})
rigidColliders.value = createColliderFromChildren({
})]
colliderInfos.value = createCollidersFromChildren({
colliderShape: props.collider,
rigidBody: rigidBodyInfo.value.rigidBody,
rigidBody: rigidBodyInfos.value[0].rigidBody,
object,
world,
})
})
onBeforeRender(() => {
if (!rigidColliders.value) { return }
if (!colliderInfos.value || !rigidBodyInfos.value) { return }
if (props.instanced) {
const child: InstancedMesh = parentObject.value?.children[0]
const array = child.instanceMatrix.array
for (let i = 0; i < child.count; i++) {
let position = VECTOR_ZERO.clone()
let quaternion = QUATERNION_ZERO.clone()
let scale = VECTOR_ZERO.clone()
child.getMatrixAt(i, MATRIX_ZERO)
MATRIX_ZERO.decompose(position, quaternion, scale)
position = VECTOR_ZERO.copy(
rigidBodyInfos.value[i].rigidBody.translation(),
)
quaternion = QUATERNION_ZERO.copy(
rigidBodyInfos.value[i].rigidBody.rotation(),
)
scale = VECTOR_ZERO.clone().copy(scale)
MATRIX_ZERO
.compose(position, quaternion, scale)
.toArray(array, i * 16)
}
child.instanceMatrix.needsUpdate = true
child.computeBoundingSphere()
return
}
rigidColliders.value.forEach((item) => {
colliderInfos.value.forEach((item) => {
const position = item.collider.translation()
item.child.position.set(position.x, position.y, position.z)
Expand All @@ -49,7 +122,7 @@ onBeforeRender(() => {
</script>

<template>
<TresGroup ref="rigidObject">
<TresGroup ref="parentObject">
<slot></slot>
</TresGroup>
</template>
5 changes: 4 additions & 1 deletion src/constants/object.constant.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { Vector3 } from 'three'
import { Euler, Matrix4, Quaternion, Vector3 } from 'three'

export const VECTOR_ZERO = new Vector3()
export const EULER_ZERO = new Euler()
export const QUATERNION_ZERO = new Quaternion()
export const MATRIX_ZERO = new Matrix4()
7 changes: 5 additions & 2 deletions src/types/collider.type.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { RigidBody, World } from '@dimforge/rapier3d-compat'
import type { TresObject } from '@tresjs/core'
import type { InstancedMesh } from 'three'

/** @description Tres Rapier supported Collider shapes. */
export type ColliderShape =
Expand All @@ -14,7 +15,7 @@ export type ColliderShape =

export interface CreateColliderDescProps {
/** @description The parent object. (@link TresObject}. */
object: TresObject
object: TresObject | InstancedMesh
/** @description The `Collider` shape. {@link ColliderShape}. */
colliderShape?: ColliderShape
}
Expand All @@ -30,4 +31,6 @@ export interface CreateColliderProps extends CreateColliderDescProps {
world: World
}

export interface CreateColliderFromChildrenProps extends CreateColliderProps {}
export interface CreateCollidersFromChildrenProps extends CreateColliderProps {}

export interface CreateCollidersFromInstancedProps extends CreateColliderProps {}
5 changes: 4 additions & 1 deletion src/types/rigid-body.type.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { TresObject } from '@tresjs/core'
import type { World } from '@dimforge/rapier3d-compat'
import type { InstancedMesh } from 'three'

import type { ColliderShape } from './collider.type'

Expand All @@ -15,11 +16,13 @@ export interface RigidBodyProps {
type: RigidBodyType
/** @description Set the `RigidBody` collider shape. */
collider: ColliderShape
/** @description Make the **RigidBody** support `instancedMesh` */
instanced: boolean
}

export interface CreateRigidBodyDescProps {
/** @description The parent object. (@link TresObject}. */
object: TresObject
object: TresObject | InstancedMesh
/** @description The `rigidBody` type. {@link RigidBodyType}. */
rigidBodyType: RigidBodyType
}
Expand Down
10 changes: 5 additions & 5 deletions src/utils/collider.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import type { TresObject } from '@tresjs/core'

import { VECTOR_ZERO } from '../constants/object.constant'
import type {
CreateColliderFromChildrenProps,
CreateColliderProps,
CreateCollidersFromChildrenProps,
} from '../types/collider.type'
import type { CreateColliderDescProps } from './../types/collider.type'

Expand Down Expand Up @@ -101,15 +101,15 @@ export const createCollider = (props: CreateColliderProps) => {
}

/**
* @description Create a {@link Collider} shapes for each child in the object
* based on the given {@link CreateColliderFromChildrenProps}
* @description Create a list of {@link Collider} shapes for each child in the object
* based on the given {@link CreateCollidersFromChildrenProps}
*
* @param props {@link CreateColliderFromChildrenProps}
* @param props {@link CreateCollidersFromChildrenProps}
*
* @see https://rapier.rs/javascript3d/classes/Collider.html
* @see https://rapier.rs/docs/user_guides/javascript/colliders
*/
export const createColliderFromChildren = (props: CreateColliderFromChildrenProps) => {
export const createCollidersFromChildren = (props: CreateCollidersFromChildrenProps) => {
return ((props?.object?.children ?? []) as TresObject[]).map((child) => {
return {
...createCollider({ ...props, object: child }),
Expand Down

0 comments on commit d68dd43

Please sign in to comment.