Debug
angular-three-cannon/debug
provides a debug experience for Cannon.js physics engine using cannon-es-debugger
. This
allows us to visualize how Cannon sees the 3D scene graph.
Installation
1npm install cannon-es-debugger2# yarn add cannon-es-debugger3# pnpm add cannon-es-debugger
Import NgtcDebug
from angular-three-cannon/debug
1import { NgtcDebug } from 'angular-three-cannon/debug';
Attach [debug]
to the ngtc-physics
component
1@Component({2 standalone: true,3 imports: [NgtcDebug, NgtcPhysics],4 template: `5 <ngtc-physics debug>6 <!-- objects that are subject to physics -->7 </ngtc-physics>8 `9})10export class SceneGraph {}
Passing options to NgtcDebug
We can pas options to NgtcDebug
by passing in an object to the debug
input
1@Component({2 standalone: true,3 imports: [NgtcDebug, NgtcPhysics],4 template: `5 <ngtc-physics6 [debug]="{ enabled: true, color: 'red', scale: 1.1 }"7 >8 <!-- objects that are subject to physics -->9 </ngtc-physics>10 `11})12export class SceneGraph {}
Example
1import {2 ChangeDetectionStrategy,3 Component,4 CUSTOM_ELEMENTS_SCHEMA,5 effect,6 type ElementRef,7 input,8 viewChild,9 viewChildren,10} from '@angular/core';11import type { Triplet } from '@pmndrs/cannon-worker-api';12import { extend, injectStore, NgtArgs, NgtCanvas, type NgtVector3 } from 'angular-three';13import { NgtcPhysics } from 'angular-three-cannon';14import { injectBox, injectPlane } from 'angular-three-cannon/body';15import { NgtcDebug } from 'angular-three-cannon/debug';16import type { Mesh } from 'three';17import * as THREE from 'three';18
19extend(THREE);20
21@Component({22 selector: 'app-plane',23 standalone: true,24 template: `25 <ngt-mesh #mesh [receiveShadow]="true">26 <ngt-plane-geometry *args="[1000, 1000]" />27 <ngt-shadow-material color="#171717" [transparent]="true" [opacity]="0.4" />28 </ngt-mesh>29 `,30 schemas: [CUSTOM_ELEMENTS_SCHEMA],31 changeDetection: ChangeDetectionStrategy.OnPush,32 imports: [NgtArgs],33})34export class Plane {35 meshRef = viewChild.required<ElementRef<Mesh>>('mesh');36 constructor() {37 injectPlane(() => ({ rotation: [-Math.PI / 2, 0, 0], position: [0, -2.5, 0] }), this.meshRef);38 }39}40
41@Component({42 selector: 'app-cube',43 standalone: true,44 template: `45 <ngt-mesh #mesh [receiveShadow]="true" [castShadow]="true">46 <ngt-box-geometry />47 <ngt-mesh-lambert-material color="hotpink" />48 </ngt-mesh>49 `,50 schemas: [CUSTOM_ELEMENTS_SCHEMA],51 changeDetection: ChangeDetectionStrategy.OnPush,52})53export class Cube {54 position = input<NgtVector3>([0, 5, 0]);55
56 meshRef = viewChild.required<ElementRef<Mesh>>('mesh');57
58 boxApi = injectBox(59 () => ({ mass: 1, position: this.position() as Triplet, rotation: [0.4, 0.2, 0.5], args: [1, 1, 1] }),60 this.meshRef,61 );62}63
64@Component({65 standalone: true,66 template: `67 <ngt-color attach="background" *args="['lightblue']" />68 <ngt-ambient-light />69 <ngt-directional-light [position]="10" [castShadow]="true">70 <ngt-vector2 *args="[2048, 2048]" attach="shadow.mapSize" />71 </ngt-directional-light>72 <ngtc-physics [debug]="{ enabled: true, color: 'red', scale: 1.1 }">73 <app-plane />74 @for (position of cubePositions; track $index) {75 <app-cube [position]="position" />76 }77 </ngtc-physics>78 `,79 imports: [Plane, Cube, NgtArgs, NgtcPhysics, NgtcDebug],80 schemas: [CUSTOM_ELEMENTS_SCHEMA],81 changeDetection: ChangeDetectionStrategy.OnPush,82})83export class SceneGraph {84 cubePositions: Triplet[] = [85 [0.1, 5, 0],86 [0, 10, -1],87 [0, 20, -2],88 ];89
90 cubes = viewChildren(Cube);91
92 constructor() {93 const store = injectStore();94
95 effect((onCleanup) => {96 const cubes = this.cubes();97 if (!cubes.length) return;98
99 const sub = store.snapshot.pointerMissed$.subscribe(() => {100 cubes.forEach((cube, index) => {101 cube.boxApi()?.position.set(...this.cubePositions[index]);102 cube.boxApi()?.rotation.set(0.4, 0.2, 0.5);103 });104 });105 onCleanup(() => sub.unsubscribe());106 });107 }108}109
110@Component({111 standalone: true,112 template: `113 <ngt-canvas114 [sceneGraph]="sceneGraph"115 [camera]="{ position: [-1, 5, 5], fov: 45 }"116 [shadows]="true"117 [dpr]="[1, 2]"118 [gl]="{ alpha: false }"119 />120 <span class="absolute bottom-0 right-0 font-mono text-black">* click to reset the cubes</span>121 `,122 changeDetection: ChangeDetectionStrategy.OnPush,123 imports: [NgtCanvas],124 host: { class: 'cannon-sample relative inline' },125})126export default class CannonSampleDebug {127 sceneGraph = SceneGraph;128}