Skip to content

Commit 4f8fd8c

Browse files
committed
docs: bruno simons 20k challenge ported from r3f
1 parent 7c73755 commit 4f8fd8c

File tree

5 files changed

+215
-0
lines changed

5 files changed

+215
-0
lines changed
Binary file not shown.
Binary file not shown.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { ChangeDetectionStrategy, Component } from '@angular/core';
2+
import { NgtCanvas } from 'angular-three';
3+
import { Experience } from './experience';
4+
5+
@Component({
6+
standalone: true,
7+
template: `
8+
<ngt-canvas
9+
[sceneGraph]="sceneGraph"
10+
flat
11+
shadows
12+
[gl]="{ antialias: false }"
13+
[camera]="{ position: [-30, 35, -15], near: 30, far: 55, fov: 12 }"
14+
/>
15+
<pre class="absolute top-2 right-2">
16+
Credits: <a class="underline" href="https://pmndrs.github.io/examples/demos/bruno-simons-20k-challenge" target="_blank">Bruno Simons 20K Challenge with R3F</a>
17+
</pre>
18+
`,
19+
changeDetection: ChangeDetectionStrategy.OnPush,
20+
host: { class: 'bruno-simons-2k-soba' },
21+
imports: [NgtCanvas],
22+
})
23+
export default class BrunoSimons20k {
24+
protected sceneGraph = Experience;
25+
}
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, input, Signal } from '@angular/core';
2+
import { NgtArgs, NgtEuler, NgtVector3 } from 'angular-three';
3+
import { NgtpDepthOfField, NgtpEffectComposer, NgtpToneMapping } from 'angular-three-postprocessing';
4+
import { NgtpN8AO } from 'angular-three-postprocessing/n8ao';
5+
import { NgtrCuboidCollider, NgtrInstancedRigidBodies, NgtrPhysics, NgtrRigidBody } from 'angular-three-rapier';
6+
import { NgtsOrbitControls } from 'angular-three-soba/controls';
7+
import { injectGLTF } from 'angular-three-soba/loaders';
8+
import {
9+
NgtsAccumulativeShadows,
10+
NgtsEnvironment,
11+
NgtsLightformer,
12+
NgtsRandomizedLights,
13+
} from 'angular-three-soba/staging';
14+
import { MathUtils, Mesh, MeshStandardMaterial } from 'three';
15+
import { GLTF } from 'three-stdlib';
16+
17+
type HatGLTF = GLTF & {
18+
nodes: { Plane006: Mesh; Plane006_1: Mesh };
19+
materials: { Material: MeshStandardMaterial; boxCap: MeshStandardMaterial };
20+
};
21+
22+
@Component({
23+
selector: 'app-hats',
24+
standalone: true,
25+
template: `
26+
@if (gltf(); as gltf) {
27+
<ngt-object3D [ngtrInstancedRigidBodies]="instances" [options]="{ colliders: 'hull' }">
28+
<ngt-instanced-mesh
29+
*args="[gltf.nodes.Plane006_1.geometry, gltf.materials.boxCap, 80]"
30+
[dispose]="null"
31+
[receiveShadow]="true"
32+
[castShadow]="true"
33+
/>
34+
</ngt-object3D>
35+
}
36+
`,
37+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
38+
changeDetection: ChangeDetectionStrategy.OnPush,
39+
imports: [NgtrInstancedRigidBodies, NgtArgs],
40+
})
41+
export class Hats {
42+
protected gltf = injectGLTF(() => './blender-threejs-journey-20k-hat-transformed.glb') as Signal<HatGLTF | null>;
43+
44+
protected instances = Array.from({ length: 80 }, (_, index) => ({
45+
key: index,
46+
position: [MathUtils.randFloatSpread(2) + 1, 10 + index / 2, MathUtils.randFloatSpread(2) - 2] as NgtVector3,
47+
rotation: [Math.random(), Math.random(), Math.random()] as NgtEuler,
48+
}));
49+
50+
// NOTE: GLTF of the hat has 2 parts: the cap and the tassel. InstancedMesh
51+
// can only have 1 geometry, so we need something like CSG to merge the geometries into one.
52+
// Angular Three does not have this yet.
53+
// <Geometry useGroups>
54+
// <Base geometry={nodes.Plane006.geometry} material={materials.Material} />
55+
// <Addition geometry={nodes.Plane006_1.geometry} material={materials.boxCap} />
56+
// </Geometry>
57+
}
58+
59+
type ModelGLTF = GLTF & {
60+
nodes: { boxBase: Mesh; boxBack: Mesh; Text: Mesh };
61+
materials: { boxBase: MeshStandardMaterial; inside: MeshStandardMaterial };
62+
};
63+
64+
@Component({
65+
selector: 'app-model',
66+
standalone: true,
67+
template: `
68+
@if (gltf(); as gltf) {
69+
<ngt-group [position]="position()" [dispose]="null">
70+
<ngt-object3D ngtrRigidBody="fixed" [options]="{ colliders: 'trimesh' }">
71+
<ngt-mesh
72+
[castShadow]="true"
73+
[receiveShadow]="true"
74+
[geometry]="gltf.nodes.boxBase.geometry"
75+
[material]="gltf.materials.boxBase"
76+
/>
77+
<ngt-mesh
78+
[receiveShadow]="true"
79+
[geometry]="gltf.nodes.boxBack.geometry"
80+
[material]="gltf.materials.inside"
81+
/>
82+
<ngt-mesh
83+
[castShadow]="true"
84+
[receiveShadow]="true"
85+
[geometry]="gltf.nodes.Text.geometry"
86+
[material]="gltf.materials.boxBase"
87+
/>
88+
</ngt-object3D>
89+
</ngt-group>
90+
}
91+
`,
92+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
93+
changeDetection: ChangeDetectionStrategy.OnPush,
94+
imports: [NgtrRigidBody],
95+
})
96+
export class Model {
97+
position = input<NgtVector3>([0, 0, 0]);
98+
99+
protected gltf = injectGLTF(() => './blender-threejs-journey-20k-transformed.glb') as Signal<ModelGLTF | null>;
100+
}
101+
102+
@Component({
103+
standalone: true,
104+
template: `
105+
<ngt-color attach="background" *args="['#f0f0f0']" />
106+
<ngt-ambient-light [intensity]="0.5" />
107+
<ngt-directional-light [position]="[-10, 10, 5]" [castShadow]="true">
108+
<ngt-value [rawValue]="-0.0001" attach="shadow.bias" />
109+
<ngt-vector2 *args="[256, 256]" attach="shadow.mapSize" />
110+
<ngt-orthographic-camera *args="[-10, 10, -10, 10]" attach="shadow.camera" />
111+
</ngt-directional-light>
112+
113+
<ngts-environment [options]="{ resolution: 32 }">
114+
<ng-template>
115+
<ngts-lightformer [options]="{ position: [10, 10, 10], scale: 10, intensity: 4 }" />
116+
<ngts-lightformer [options]="{ position: [10, 0, -10], scale: 10, color: 'red', intensity: 6 }" />
117+
<ngts-lightformer [options]="{ position: [-10, -10, -10], scale: 10, intensity: 4 }" />
118+
</ng-template>
119+
</ngts-environment>
120+
121+
<ngtr-physics [options]="{ gravity: [0, -4, 0] }">
122+
<app-model [position]="[1, 0, -1.5]" />
123+
<app-hats />
124+
<ngt-object3D ngtrRigidBody="fixed" [options]="{ colliders: false }" [position]="[0, -1, 0]">
125+
<ngt-object3D ngtrCuboidCollider [args]="[1000, 1, 1000]" />
126+
</ngt-object3D>
127+
</ngtr-physics>
128+
129+
<ngts-accumulative-shadows
130+
[options]="{
131+
temporal: true,
132+
frames: Infinity,
133+
alphaTest: 1,
134+
blend: 200,
135+
limit: 1500,
136+
scale: 25,
137+
position: [0, -0.05, 0],
138+
}"
139+
>
140+
<ngts-randomized-lights
141+
[options]="{ amount: 1, mapSize: 512, radius: 5, ambient: 0.5, position: [-10, 10, 5], size: 10, bias: 0.001 }"
142+
/>
143+
</ngts-accumulative-shadows>
144+
145+
<ngtp-effect-composer>
146+
<ngtp-n8ao [options]="{ aoRadius: 0.5, intensity: 1 }" />
147+
<ngtp-depth-of-field [options]="{ target: [0, 0, -2.5], focusRange: 0.1, bokehScale: 10 }" />
148+
<ngtp-tone-mapping />
149+
</ngtp-effect-composer>
150+
151+
<ngts-orbit-controls
152+
[options]="{
153+
autoRotate: true,
154+
autoRotateSpeed: 0.1,
155+
enablePan: false,
156+
enableZoom: false,
157+
minPolarAngle: Math.PI / 4,
158+
maxPolarAngle: Math.PI / 4,
159+
}"
160+
/>
161+
`,
162+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
163+
changeDetection: ChangeDetectionStrategy.OnPush,
164+
host: { class: 'bruno-simons-2k-soba-experience' },
165+
imports: [
166+
NgtArgs,
167+
NgtsEnvironment,
168+
NgtsLightformer,
169+
NgtrPhysics,
170+
Model,
171+
NgtrRigidBody,
172+
NgtrCuboidCollider,
173+
NgtsAccumulativeShadows,
174+
NgtsRandomizedLights,
175+
NgtpEffectComposer,
176+
NgtpN8AO,
177+
NgtpDepthOfField,
178+
NgtsOrbitControls,
179+
NgtpToneMapping,
180+
Hats,
181+
],
182+
})
183+
export class Experience {
184+
protected readonly Infinity = Infinity;
185+
protected readonly Math = Math;
186+
}

apps/kitchen-sink/src/app/soba/soba.routes.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ const routes: Routes = [
6161
path: 'starbucks',
6262
loadComponent: () => import('./starbucks/starbucks'),
6363
},
64+
{
65+
path: 'bruno-simons-20k',
66+
loadComponent: () => import('./bruno-simons-20k/bruno-simons-20k'),
67+
},
6468
{
6569
path: '',
6670
redirectTo: 'stars',

0 commit comments

Comments
 (0)