Rapier logo

Usage

Learn how to enable Physics in your TresJS scenes.

TLDR: A simple ball falling

<script setup lang="ts" >
import { TresCanvas } from '@tresjs/core'
import { Physics, RigidBody } from '@tresjs/rapier'
</script>

<template>
  <TresCanvas window-size>
    <TresPerspectiveCamera :position="[15, 15, 15]" :look-at="[0, 0, 0]" />
    <TresAmbientLight :intensity="0.5" />
    <TresDirectionalLight :position="[6, 8, 4]" />

    <Suspense>
      <Physics>
        <RigidBody collider="ball" :restitution="0.5">
          <TresMesh :position="[0, 8, 0]">
            <TresSphereGeometry />
            <TresMeshNormalMaterial />
          </TresMesh>
          </RigidBody>
          <RigidBody type="fixed" :restitution="0.5">
            <TresMesh :position="[0, 0, 0]">
              <TresPlaneGeometry :args="[20, 20, 20]" :rotate-x="-Math.PI / 2" />
              <TresMeshBasicMaterial color="#f4f4f4" />
            </TresMesh>
          </RigidBody>
      </Physics>
    </Suspense>
  </TresCanvas>
</template>
Note that in order to work the <Physics /> needs to be wrapped in a <Suspense > component
For a more detailed explanation please check how it works under the hood.

Props

Rapier components expose props that configure simulation behavior. All props are reactive (unless the docs specified), so you can drive them from refs.

<script setup lang="ts">
import { TresCanvas } from '@tresjs/core'
import { Physics, RigidBody } from '@tresjs/rapier'

const restitution = ref(0.5)
</script>

<template>
  <TresCanvas>
    <Suspense>
      <Physics>
        <RigidBody collider="ball" :restitution="restitution">
          <TresMesh>
            <TresSphereGeometry />
            <TresMeshNormalMaterial />
          </TresMesh>
        </RigidBody>
      </Physics>
    </Suspense>
  </TresCanvas>
</template>
See each API page for complete prop tables and defaults.

Events

RigidBody can emit events like collisions or intersections. You can use it as you would normally do using vue emits

<script setup lang="ts">
import { TresCanvas } from '@tresjs/core'
import { Physics, RigidBody } from '@tresjs/rapier'

const onCollisionEnter = (payload: unknown) => {
  console.log('collision-enter', payload)
}

const onCollisionExit = (payload: unknown) => {
  console.log('collision-exit', payload)
}
</script>

<template>
  <TresCanvas>
    <Suspense>
      <Physics>
        <RigidBody activeCollision @collision-enter="onCollisionEnter" @collision-exit="onCollisionExit">
          <TresMesh>
            <TresBoxGeometry />
            <TresMeshNormalMaterial />
          </TresMesh>
        </RigidBody>
      </Physics>
    </Suspense>
  </TresCanvas>
</template>

Exposed properties

Components expose useful objects through refs. For example, RigidBody exposes instance, which gives access to the underlying Rapier rigid-body API.

<script setup lang="ts">
import { shallowRef } from 'vue'
import { type ExposedRigidBody, RigidBody } from '@tresjs/rapier'

const rigidBodyRef = shallowRef<ExposedRigidBody | null>(null)

const logInstance = () => {
  console.log(rigidBodyRef.value?.instance)
}
</script>

<template>
  <RigidBody ref="rigidBodyRef">
    <TresMesh @click="logInstance">
      <TresBoxGeometry />
      <TresMeshNormalMaterial />
    </TresMesh>
  </RigidBody>
</template>
Some components expose additional objects, check each documentation.

Sleep/Awake

When a dynamic rigid-body doesn't move (or moves very slowly) during a few seconds, it will be marked as sleeping by the physics pipeline. Rigid-bodies marked as sleeping are no longer simulated by the physics engine until they are woken up. That way the physics engine doesn't waste any computational resources simulating objects that don't actually move. They are woken up automatically whenever another non-sleeping rigid-body starts interacting with them (either with a joint, or with one of its attached colliders generating contacts).

However, a sleeping rigid-body won't respond to any user action. This is why it is possible to wake-up the rigid-body manually with RigidBody.value.instance.wakeUp(). Some rigid-body methods take an additional wakeUp boolean argument that, if true, ensures that the rigid-body wakes up before the action takes place. For example:

<script setup lang="ts">
import { type ExposedRigidBody, RigidBody } from '@tresjs/rapier'
import { shallowRef } from 'vue'

const rigidCubeRef = shallowRef<ExposedRigidBody | null>(null)

const jumpCube = () => {
  // The second argument, the boolean is waking our rigidBody
  rigidCubeRef.value.instance.applyImpulse({ x: 0, y: 5, z: 0 }, true)
}
</script>

<template>
<RigidBody ref="rigidCubeRef">
  <TresMesh :position="[0, 5, 0]" @click="jumpCube">
    <TresBoxGeometry />
    <TresMeshNormalMaterial />
  </TresMesh>
</RigidBody>
</template>

Unless you want to achieve special effects, it is recommended to always set the wakeUp argument to true.

Caveats

  • Modifying the position/rotation property in a RigidBody instance in real-time causes teleport or "jump" weird behaviors, and is discouraged.