threlte logo

Terrain with Rapier physics

This example shows how to include user-generated random terrain as a fixed <RigidBody>, within a Rapier world.

This is an adaption of Rapier’s own demo (select “Demo: triangle mesh”).

<script lang="ts">
  import { Canvas } from '@threlte/core'
  import { World } from '@threlte/rapier'
  import Scene from './Scene.svelte'
  import { Pane, Button } from 'svelte-tweakpane-ui'

  let reset: () => any | undefined
  let toggleDebug: () => any | undefined
</script>

<Pane
  title=""
  position="fixed"
>
  <Button
    title="Reset"
    on:click={reset}
  />
  <Button
    title="Toggle Debug"
    on:click={toggleDebug}
  />
</Pane>

<div>
  <Canvas>
    <World>
      <Scene
        bind:reset
        bind:toggleDebug
      />
    </World>
  </Canvas>
</div>

<style>
  div {
    height: 100%;
  }
</style>

How does it work

  1. Similar to the 3D noise example, loop over the vertices of a PlaneGeometry, and use a noise map to create a heightfield array heights.
  2. Attach the heightfield to a rapier <Collider>
<Collider
  shape={'heightfield'}
  args={[nsubdivs, nsubdivs, heights, scale]}
/>
  1. Wrap in a fixed <RigidBody>. We don’t want this terrain to respond to gravity and fall downwards when rapier physics simulation begins.
<RigidBody type={'fixed'}>
  <Collider ... />
</RigidBody>
  1. Add some falling random shapes to the scene to prove that the terrain is functioning properly (see “FallingShapes.svelte”)
  • define some shapes in an array

    • geometry
    • <AutoCollider> type
    • color
  • fill an array of 50 items with a random shape, with a random position and rotation, and loop over it in markup

  • add a <T.Mesh> to the scene, provide it with the chosen geometry, and a material with the chosen color

  • wrap that in an <AutoColliders> with the chosen AutoCollider

  • wrap in a 'dynamic' <RigidBody>. Dynamic because we want these shapes to fall in the scene according to gravity.

  • finally, wrap in a <T.Group> to set our random position and rotation