Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🔫 Remove autoUpdate option #22

Merged
merged 1 commit into from
Dec 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 28 additions & 14 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This is a debugger for use with [cannon-es](https://github.com/pmndrs/cannon-es). It was adapted from the [original cannon.js debugger](https://github.com/schteppe/cannon.js/blob/master/tools/threejs/CannonDebugRenderer.js) written by Stefan Hedman [@schteppe](https://github.com/schteppe).

**Note:** This debugger is implemented within [use-cannon](https://github.com/pmndrs/use-cannon#debug) directly.
**Note:** This debugger is included in [use-cannon](https://github.com/pmndrs/use-cannon#debug) directly.

### Installation

Expand All @@ -18,25 +18,36 @@ yarn add three cannon-es

### Usage

Give `cannon-es-debugger` references to your Three scene object and Cannon physics bodies:
Give `cannon-es-debugger` references to your three.js scene object and cannon-es world:

```js
import { Scene } from 'three'
import { World } from 'cannon-es'
import cannonDebugger from 'cannon-es-debugger'
import CannonDebugger from 'cannon-es-debugger'

const scene = new Scene()
const world = new World()
cannonDebugger(scene, world.bodies, options)
const cannonDebugger = new CannonDebugger(scene, world, {
// options...
})

// ...

function animate() {
requestAnimationFrame(animate)

world.step(timeStep) // Update cannon-es physics
cannonDebugger.update() // Update the CannonDebugger meshes
renderer.render(scene, camera) // Render the three.js scene
}
animate()
```

New meshes with wireframe textures will be generated from your physics body geometries and added into the scene. A mesh will be created for every shape in the physics body. The position of the meshes will be synched with the Cannon physics body simulation on every animation frame.
New meshes with wireframe material will be generated from your physics body shapes and added into the scene. The position of the meshes will be synched with the Cannon physics body simulation on every animation frame.

### API

The available properties of the `options` object are listed below.

```typescript
```ts
import type { Scene, Color } from 'three'
import type { Body } from 'cannon-es'

Expand All @@ -45,20 +56,23 @@ type DebugOptions = {
scale?: number
onInit?: (body: Body, mesh: Mesh, shape: Shape) => void
onUpdate?: (body: Body, mesh: Mesh, shape: Shape) => void
autoUpdate?: Boolean
}

export default function cannonDebugger(scene: Scene, bodies: Body[], options: DebugOptions): void
export default class CannonDebugger {
constructor(scene: Scene, world: World, options: DebugOptions): void

update(): void
}
```

The available properties of the `options` object are:

- **`color`** - a [Three Color](https://threejs.org/docs/#api/en/math/Color) argument that sets the wireframe color, defaults to `0x00ff00`

- **`scale`** - scale factor, defaults to 1
- **`scale`** - scale factor for all the wireframe meshes, defaults to 1

- **`onInit`** - callback function that runs once, right after a new wireframe mesh is added

- **`onUpdate`** - callback function that runs on every subsequent animation frame

- **`autoUpdate`** - wheter or not the debugger should update by itself (default: `true`)

If you set `autoUpdate: false`, then you can use the `update()` method included in the returned object to update the debugger manually.
The `update()` method needs to be called in a `requestAnimationFrame` loop to keep updating the wireframe meshes after the bodies have been updated.
19 changes: 8 additions & 11 deletions src/cannon-es-debugger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
BufferGeometry,
Float32BufferAttribute,
} from 'three'
import type { Body } from 'cannon-es'
import type { Body, World } from 'cannon-es'
import type { Scene, Color } from 'three'

type ComplexShape = Shape & { geometryId?: number }
Expand All @@ -30,13 +30,12 @@ export type DebugOptions = {
scale?: number
onInit?: (body: Body, mesh: Mesh, shape: Shape) => void
onUpdate?: (body: Body, mesh: Mesh, shape: Shape) => void
autoUpdate?: Boolean
}

export default function cannonDebugger(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not match what is in the README:

export default class CannonDebugger {
  constructor(scene: Scene, world: World, options: DebugOptions): void
  update(): void
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're using this pattern because we don't want to expose the private variables, we can switch to a class when we can ship private class fields

scene: Scene,
bodies: Body[],
{ color = 0x00ff00, scale = 1, onInit, onUpdate, autoUpdate }: DebugOptions = {}
world: World,
{ color = 0x00ff00, scale = 1, onInit, onUpdate }: DebugOptions = {}
) {
const _meshes: Mesh[] = []
const _material = new MeshBasicMaterial({ color: color ?? 0x00ff00, wireframe: true })
Expand Down Expand Up @@ -179,7 +178,7 @@ export default function cannonDebugger(
break
}
case BOX: {
mesh.scale.copy(((shape as Box).halfExtents as unknown) as ThreeVector3)
mesh.scale.copy((shape as Box).halfExtents as unknown as ThreeVector3)
mesh.scale.multiplyScalar(2 * scale)
break
}
Expand All @@ -195,7 +194,7 @@ export default function cannonDebugger(
break
}
case TRIMESH: {
mesh.scale.copy(((shape as Trimesh).scale as unknown) as ThreeVector3).multiplyScalar(scale)
mesh.scale.copy((shape as Trimesh).scale as unknown as ThreeVector3).multiplyScalar(scale)
break
}
case HEIGHTFIELD: {
Expand Down Expand Up @@ -240,7 +239,7 @@ export default function cannonDebugger(

let meshIndex = 0

for (const body of bodies) {
for (const body of world.bodies) {
Copy link
Member

@bjornstar bjornstar Dec 31, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering that you only use the world to access the bodies, it seems a bit overkill to bring the entire world into the debugger.

In use-cannon the world lives in a worker and we don't have direct access to it so it's quite difficult to have this as a requirement for using the debugger.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I preferred matching the signature to the original CannonDebugRenderer.

We can just mock the world (like we're doing now) in use-cannon.

for (let i = 0; i !== body.shapes.length; i++) {
const shape = body.shapes[i]
const didCreateNewMesh = updateMesh(meshIndex, shape)
Expand All @@ -255,8 +254,8 @@ export default function cannonDebugger(
body.quaternion.mult(body.shapeOrientations[i], shapeWorldQuaternion)

// Copy to meshes
mesh.position.copy((shapeWorldPosition as unknown) as ThreeVector3)
mesh.quaternion.copy((shapeWorldQuaternion as unknown) as ThreeQuaternion)
mesh.position.copy(shapeWorldPosition as unknown as ThreeVector3)
mesh.quaternion.copy(shapeWorldQuaternion as unknown as ThreeQuaternion)

if (didCreateNewMesh && onInit instanceof Function) onInit(body, mesh, shape)
if (!didCreateNewMesh && onUpdate instanceof Function) onUpdate(body, mesh, shape)
Expand All @@ -272,9 +271,7 @@ export default function cannonDebugger(
}

meshes.length = meshIndex
if (autoUpdate !== false) requestAnimationFrame(update)
}

if (autoUpdate !== false) requestAnimationFrame(update)
return { update }
}