Skip to content

Performance

Reuse Geometries and Materials

Each Geometry and Material consumes the GPU’s resources. If we know certain Geometries and/or Materials will repeat, we can reuse them

Imperative

We can have static geometries and materials as Component’s properties

1
@Component({
2
standalone: true,
3
template: `
4
<ngt-mesh [geometry]="sphere" [material]="redMaterial" [position]="[1, 1, 1]" />
5
<ngt-mesh [geometry]="sphere" [material]="redMaterial" [position]="[2, 2, 2]" />
6
`,
7
})
8
export class SceneGraph {
9
readonly sphere = new THREE.SphereGeometry(1, 32, 32);
10
readonly redMaterial = new THREE.MeshBasicMaterial({ color: 'red' });
11
}

We can also store these static objects in a Service to reuse across the application or turn them into Signals.

Declarative

We can put the Geometries and Materials declaratively on the template so they can react to Input changes; and still can reuse them

1
<ngt-sphere-geometry #sphere *args="[1, 32, 32]" attach="none" />
2
<ngt-mesh-basic-material #redMaterial color="red" attach="none" />
3
4
<ngt-mesh [geometry]="sphere" [material]="redMaterial" [position]="[1, 1, 1]" />
5
<ngt-mesh [geometry]="sphere" [material]="redMaterial" [position]="[2, 2, 2]" />

On-demand Rendering

Credit: React Three Fiber

The SceneGraph is usually rendered at 60 frames per second. This makes sense if the SceneGraph contains constantly moving parts (eg: game). Consequently, this drains the device’s resources.

If the SceneGraph has static entities, or entities that are allowed to come to a rest, constantly rendering at 60fps would be wasteful. In those cases, we can opt into on-demand rendering, which will only render when necessary. All we have to do is to set frameloop="demand" on the <ngt-canvas>

1
<ngt-canvas [sceneGraph]="SceneGraph" frameloop="demand" />

When using frameloop="demand", Angular Three will render: when properties of the entities change, when the camera moves via custom controls (from angular-three-soba) etc… To render, invalidate() function needs to be called and this is done automatically by Angular Three when necessary.

The consumers can also call invalidate() manually to render on demand.

1
@Component()
2
export class MyCmp {
3
private store = injectStore();
4
5
protected invalidate = this.store.select('invalidate');
6
7
constructor() {
8
effect(() => {
9
const invalidate = this.invalidate();
10
11
// do something
12
13
// ready to render
14
invalidate();
15
})
16
}
17
18
onSomething() {
19
// or use the invalidate() from the Store snapshot
20
this.store.snapshot.invalidate();
21
}
22
}