Skip to content

Commit ca3d10d

Browse files
committed
docs: add cameras demo
1 parent 4322bec commit ca3d10d

File tree

6 files changed

+206
-17
lines changed

6 files changed

+206
-17
lines changed

apps/demo/src/app/animation-skinning-ik/animation-skinning-ik.component.ts

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,6 @@
11
import { NgIf } from '@angular/common';
22
import { Component, CUSTOM_ELEMENTS_SCHEMA, ElementRef, inject, ViewChild } from '@angular/core';
3-
import {
4-
applyProps,
5-
extend,
6-
injectBeforeRender,
7-
injectNgtLoader,
8-
NgtArgs,
9-
NgtCanvas,
10-
NgtPush,
11-
NgtState,
12-
NgtStore,
13-
} from 'angular-three';
3+
import { extend, injectBeforeRender, injectNgtLoader, NgtArgs, NgtCanvas, NgtPush, NgtStore } from 'angular-three';
144
import { map } from 'rxjs';
155
import * as THREE from 'three';
166
import { CCDIKHelper, CCDIKSolver, DRACOLoader, GLTFLoader, IKS, OrbitControls, TransformControls } from 'three-stdlib';
@@ -168,16 +158,11 @@ export class Scene {
168158
position: [0.9728517749133652, 1.1044765132727201, 0.7316689528482836]
169159
}"
170160
[gl]="{ logarithmicDepthBuffer: true }"
171-
(created)="onCreated($event)"
161+
(created)="$event.gl.physicallyCorrectLights = true; $event.camera.lookAt($event.scene.position)"
172162
/>
173163
`,
174164
imports: [NgtCanvas],
175165
})
176166
export default class DemoAnimationSkinningIK {
177167
readonly SceneGraph = Scene;
178-
179-
onCreated({ scene, camera, gl }: NgtState) {
180-
applyProps(gl, { physicallyCorrectLights: true });
181-
camera.lookAt(scene.position);
182-
}
183168
}

apps/demo/src/app/app.routes.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,14 @@ export const routes: Routes = [
4848
asset: 'assets/demo/animation-skinning-ik',
4949
},
5050
},
51+
52+
{
53+
path: 'camera',
54+
loadComponent: () => import('./camera/camera.component'),
55+
data: {
56+
description: 'THREE.js Cameras with helpers',
57+
link: '/camera',
58+
asset: 'assets/demo/camera',
59+
},
60+
},
5161
];
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
import {
2+
AfterViewInit,
3+
Component,
4+
CUSTOM_ELEMENTS_SCHEMA,
5+
ElementRef,
6+
HostListener,
7+
inject,
8+
ViewChild,
9+
} from '@angular/core';
10+
import { injectBeforeRender, injectNgtRef, NgtArgs, NgtCanvas, NgtState, NgtStore } from 'angular-three';
11+
import * as THREE from 'three';
12+
13+
@Component({
14+
standalone: true,
15+
template: `
16+
<ngt-group #cameras>
17+
<ngt-perspective-camera
18+
[ref]="cameraPerspectiveRef"
19+
[aspect]="store.get('viewport', 'aspect') * 0.5"
20+
[near]="150"
21+
[far]="1000"
22+
[rotation]="[0, Math.PI, 0]"
23+
/>
24+
<ngt-orthographic-camera
25+
[ref]="cameraOrthographicRef"
26+
[left]="(0.5 * 600 * store.get('viewport', 'aspect')) / -2"
27+
[right]="(0.5 * 600 * store.get('viewport', 'aspect')) / 2"
28+
[top]="300"
29+
[bottom]="-300"
30+
[near]="150"
31+
[far]="1000"
32+
[rotation]="[0, Math.PI, 0]"
33+
/>
34+
35+
<ngt-mesh [position]="[0, 0, 150]">
36+
<ngt-sphere-geometry *args="[5, 16, 8]" />
37+
<ngt-mesh-basic-material color="#0000ff" [wireframe]="true" />
38+
</ngt-mesh>
39+
</ngt-group>
40+
41+
<ngt-camera-helper #perspective *args="[cameraPerspectiveRef.nativeElement]" />
42+
<ngt-camera-helper #orthographic *args="[cameraOrthographicRef.nativeElement]" />
43+
44+
<ngt-mesh #whiteMesh>
45+
<ngt-sphere-geometry *args="[100, 16, 8]" />
46+
<ngt-mesh-basic-material [wireframe]="true" />
47+
48+
<ngt-mesh [position]="[0, 150, 0]">
49+
<ngt-sphere-geometry *args="[50, 16, 8]" />
50+
<ngt-mesh-basic-material color="#00ff00" [wireframe]="true" />
51+
</ngt-mesh>
52+
</ngt-mesh>
53+
54+
<ngt-points>
55+
<ngt-float32-buffer-attribute *args="[vertices, 3]" attach="geometry.attributes.position" />
56+
<ngt-points-material color="#888888" />
57+
</ngt-points>
58+
`,
59+
imports: [NgtArgs],
60+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
61+
})
62+
export class Scene implements AfterViewInit {
63+
readonly Math = Math;
64+
65+
readonly cameraPerspectiveRef = injectNgtRef<THREE.PerspectiveCamera>();
66+
readonly cameraOrthographicRef = injectNgtRef<THREE.OrthographicCamera>();
67+
68+
readonly store = inject(NgtStore);
69+
70+
@ViewChild('cameras', { static: true }) cameraGroup!: ElementRef<THREE.Group>;
71+
@ViewChild('perspective') cameraPerspectiveHelper?: ElementRef<THREE.CameraHelper>;
72+
@ViewChild('orthographic') cameraOrthographicHelper?: ElementRef<THREE.CameraHelper>;
73+
74+
@ViewChild('whiteMesh', { static: true }) whiteMesh!: ElementRef<THREE.Mesh>;
75+
76+
readonly vertices: number[] = [];
77+
78+
private activeCamera?: THREE.Camera;
79+
private activeCameraHelper?: THREE.CameraHelper;
80+
81+
constructor() {
82+
for (let i = 0; i < 10000; i++) {
83+
this.vertices.push(THREE.MathUtils.randFloatSpread(2000)); // x
84+
this.vertices.push(THREE.MathUtils.randFloatSpread(2000)); // y
85+
this.vertices.push(THREE.MathUtils.randFloatSpread(2000)); // z
86+
}
87+
injectBeforeRender(({ gl, size, scene, camera }) => {
88+
const r = Date.now() * 0.0005;
89+
const mesh = this.whiteMesh.nativeElement;
90+
const cameraGroup = this.cameraGroup.nativeElement;
91+
const cameraPerspective = this.cameraPerspectiveRef.nativeElement;
92+
const cameraPerspectiveHelper = this.cameraPerspectiveHelper?.nativeElement;
93+
const cameraOrthographic = this.cameraOrthographicRef.nativeElement;
94+
const cameraOrthographicHelper = this.cameraOrthographicHelper?.nativeElement;
95+
96+
mesh.position.x = 700 * Math.cos(r);
97+
mesh.position.z = 700 * Math.sin(r);
98+
mesh.position.y = 700 * Math.sin(r);
99+
100+
mesh.children[0].position.x = 70 * Math.cos(2 * r);
101+
mesh.children[0].position.z = 70 * Math.sin(r);
102+
103+
if (cameraPerspective && cameraOrthographic && cameraPerspectiveHelper && cameraOrthographicHelper) {
104+
if (this.activeCamera === cameraPerspective) {
105+
cameraPerspective.fov = 35 + 30 * Math.sin(0.5 * r);
106+
cameraPerspective.far = mesh.position.length();
107+
cameraPerspective.updateProjectionMatrix();
108+
109+
cameraPerspectiveHelper.update();
110+
cameraPerspectiveHelper.visible = true;
111+
112+
cameraOrthographicHelper.visible = false;
113+
} else {
114+
cameraOrthographic.far = mesh.position.length();
115+
cameraOrthographic.updateProjectionMatrix();
116+
117+
cameraOrthographicHelper.update();
118+
cameraOrthographicHelper.visible = true;
119+
120+
cameraPerspectiveHelper.visible = false;
121+
}
122+
}
123+
124+
cameraGroup.lookAt(mesh.position);
125+
126+
gl.clear();
127+
128+
this.activeCameraHelper!.visible = false;
129+
gl.setViewport(0, 0, size.width / 2, size.height);
130+
gl.render(scene, this.activeCamera!);
131+
132+
this.activeCameraHelper!.visible = true;
133+
134+
gl.setViewport(size.width / 2, 0, size.width / 2, size.height);
135+
gl.render(scene, camera);
136+
}, 1);
137+
}
138+
139+
ngAfterViewInit() {
140+
this.activeCamera = this.cameraPerspectiveRef.nativeElement;
141+
this.activeCameraHelper = this.cameraPerspectiveHelper?.nativeElement;
142+
}
143+
144+
@HostListener('document:keydown', ['$event'])
145+
onKeyDown(event: KeyboardEvent) {
146+
if (event.key.toLowerCase() === 'o') {
147+
this.activeCamera = this.cameraOrthographicRef.nativeElement;
148+
this.activeCameraHelper = this.cameraOrthographicHelper?.nativeElement;
149+
} else if (event.key.toLowerCase() === 'p') {
150+
this.activeCamera = this.cameraPerspectiveRef.nativeElement;
151+
this.activeCameraHelper = this.cameraPerspectiveHelper?.nativeElement;
152+
}
153+
}
154+
}
155+
156+
@Component({
157+
standalone: true,
158+
template: `
159+
<div class="block h-full w-full bg-black">
160+
<ngt-canvas
161+
[sceneGraph]="SceneGraph"
162+
[gl]="{ alpha: false }"
163+
[camera]="{
164+
fov: 50,
165+
near: 1,
166+
far: 10000,
167+
position: [0, 0, 2500]
168+
}"
169+
(created)="onCreated($event)"
170+
/>
171+
</div>
172+
<div class="absolute text-center text-white w-full top-0 left-0 text-xl">
173+
<a href="https://threejs.org" target="_blank" rel="noopener" class="underline">three.js</a> -<a
174+
href="https://angular-threejs.netlify.app"
175+
target="_blank"
176+
rel="noopener"
177+
class="underline"
178+
>Angular Three</a
179+
>
180+
- cameras
181+
<br />
182+
<b class="text-green-300">O</b> orthographic <b class="text-green-300">P</b> perspective
183+
</div>
184+
`,
185+
imports: [NgtCanvas],
186+
})
187+
export default class DemoCamera {
188+
readonly SceneGraph = Scene;
189+
190+
onCreated({ gl, camera, viewport }: NgtState) {
191+
gl.autoClear = false;
192+
(camera as THREE.PerspectiveCamera).aspect = viewport.aspect / 2;
193+
}
194+
}

apps/demo/src/assets/demo/camera.gif

893 KB
Loading

apps/demo/src/assets/demo/camera.mp4

1020 KB
Binary file not shown.

apps/demo/src/assets/demo/camera.webm

554 KB
Binary file not shown.

0 commit comments

Comments
 (0)