Skip to content

Commit 02fd9f1

Browse files
committed
spotlight
1 parent a176665 commit 02fd9f1

File tree

11 files changed

+699
-1
lines changed

11 files changed

+699
-1
lines changed
498 KB
Loading
340 KB
Loading
548 KB
Loading
137 KB
Loading
87.4 KB
Loading

libs/soba/misc/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ export * from './lib/animations';
22
export * from './lib/bake-shadows';
33
export * from './lib/constants';
44
export * from './lib/deprecated';
5+
export * from './lib/depth-buffer';
56
export * from './lib/fbo';
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { computed, Injector } from '@angular/core';
2+
import { injectBeforeRender, injectStore, pick } from 'angular-three';
3+
import { injectFBO } from 'angular-three-soba/misc';
4+
import { assertInjector } from 'ngxtension/assert-injector';
5+
import { DepthFormat, DepthTexture, UnsignedShortType } from 'three';
6+
7+
export function injectDepthBuffer(
8+
params: () => { size?: number; frames?: number } = () => ({}),
9+
{ injector }: { injector?: Injector } = {},
10+
) {
11+
return assertInjector(injectDepthBuffer, injector, () => {
12+
const size = computed(() => params().size || 256);
13+
const frames = computed(() => params().frames || Infinity);
14+
15+
const store = injectStore();
16+
const width = store.select('size', 'width');
17+
const height = store.select('size', 'height');
18+
const dpr = store.select('viewport', 'dpr');
19+
20+
const w = computed(() => size() || width() * dpr());
21+
const h = computed(() => size() || height() * dpr());
22+
23+
const depthConfig = computed(() => {
24+
const depthTexture = new DepthTexture(w(), h());
25+
depthTexture.format = DepthFormat;
26+
depthTexture.type = UnsignedShortType;
27+
return { depthTexture };
28+
});
29+
30+
const depthFBO = injectFBO(() => ({
31+
width: w(),
32+
height: h(),
33+
settings: depthConfig(),
34+
}));
35+
36+
let count = 0;
37+
injectBeforeRender(({ gl, scene, camera }) => {
38+
if (frames() === Infinity || count < frames()) {
39+
gl.setRenderTarget(depthFBO());
40+
gl.render(scene, camera);
41+
gl.setRenderTarget(null);
42+
count++;
43+
}
44+
});
45+
46+
return pick(depthFBO, 'depthTexture');
47+
});
48+
}
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
import { ChangeDetectionStrategy, Component, computed, CUSTOM_ELEMENTS_SCHEMA, input } from '@angular/core';
2+
import { Meta } from '@storybook/angular';
3+
import { NgtArgs } from 'angular-three';
4+
import { NgtsPerspectiveCamera } from 'angular-three-soba/cameras';
5+
import { NgtsOrbitControls } from 'angular-three-soba/controls';
6+
import { injectTexture } from 'angular-three-soba/loaders';
7+
import { injectDepthBuffer } from 'angular-three-soba/misc';
8+
import { NgtsEnvironment, NgtsSpotLight, NgtsSpotLightOptions, NgtsSpotLightShadow } from 'angular-three-soba/staging';
9+
import { MathUtils, RepeatWrapping } from 'three';
10+
import { makeDecorators, makeStoryObject } from '../setup-canvas';
11+
12+
@Component({
13+
standalone: true,
14+
template: `
15+
<ngts-orbit-controls
16+
[options]="{ makeDefault: true, autoRotate: true, autoRotateSpeed: 0.5, minDistance: 2, maxDistance: 10 }"
17+
/>
18+
<ngts-perspective-camera [options]="{ makeDefault: true, near: 0.01, far: 50, position: [1, 3, 1], fov: 60 }" />
19+
<ngts-environment [options]="{ preset: 'sunset' }" />
20+
21+
<ngt-hemisphere-light *args="['#ffffbb', '#080820', Math.PI]" />
22+
23+
<ngt-mesh [rotation]="[-Math.PI / 2, 0, 0]" [receiveShadow]="true">
24+
<ngt-circle-geometry *args="[5, 64, 64]" />
25+
<ngt-mesh-standard-material
26+
[map]="textures()?.diffuse"
27+
[normalMap]="textures()?.normal"
28+
[roughnessMap]="textures()?.roughness"
29+
[aoMap]="textures()?.ao"
30+
[envMapIntensity]="0.2"
31+
/>
32+
</ngt-mesh>
33+
34+
<ngts-spot-light [options]="options()">
35+
<ngts-spot-light-shadow
36+
[shader]="shader()"
37+
[options]="{
38+
scale: 4,
39+
distance: 0.4,
40+
width: 2048,
41+
height: 2048,
42+
map: leafTexture(),
43+
}"
44+
/>
45+
</ngts-spot-light>
46+
`,
47+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
48+
changeDetection: ChangeDetectionStrategy.OnPush,
49+
imports: [NgtsOrbitControls, NgtsPerspectiveCamera, NgtsEnvironment, NgtArgs, NgtsSpotLight, NgtsSpotLightShadow],
50+
})
51+
class SpotLightShadowStory {
52+
protected readonly Math = Math;
53+
54+
wind = input(false);
55+
options = input({} as NgtsSpotLightOptions);
56+
57+
textures = injectTexture(
58+
() => ({
59+
diffuse: './textures/grassy_cobble/grassy_cobblestone_diff_2k.jpg',
60+
normal: './textures/grassy_cobble/grassy_cobblestone_nor_gl_2k.jpg',
61+
roughness: './textures/grassy_cobble/grassy_cobblestone_rough_2k.jpg',
62+
ao: './textures/grassy_cobble/grassy_cobblestone_ao_2k.jpg',
63+
}),
64+
{
65+
onLoad: (textures) => {
66+
textures.forEach((texture) => {
67+
texture.wrapS = texture.wrapT = RepeatWrapping;
68+
texture.repeat.set(2, 2);
69+
});
70+
},
71+
},
72+
);
73+
leafTexture = injectTexture(() => './textures/other/leaves.jpg');
74+
shader = computed(() => {
75+
if (!this.wind()) return undefined;
76+
return /* glsl */ `
77+
varying vec2 vUv;
78+
uniform sampler2D uShadowMap;
79+
uniform float uTime;
80+
void main() {
81+
// material.repeat.set(2.5) - Since repeat is a shader feature not texture
82+
// we need to implement it manually
83+
vec2 uv = mod(vUv, 0.4) * 2.5;
84+
// Fake wind distortion
85+
uv.x += sin(uv.y * 10.0 + uTime * 0.5) * 0.02;
86+
uv.y += sin(uv.x * 10.0 + uTime * 0.5) * 0.02;
87+
vec3 color = texture2D(uShadowMap, uv).xyz;
88+
gl_FragColor = vec4(color, 1.);
89+
}
90+
`;
91+
});
92+
}
93+
94+
@Component({
95+
standalone: true,
96+
template: `
97+
<ngts-spot-light [options]="spotLightOneOptions()" />
98+
<ngts-spot-light [options]="spotLightTwoOptions()" />
99+
100+
<ngt-mesh [position]="[0, 0.5, 0]" [castShadow]="true">
101+
<ngt-box-geometry />
102+
<ngt-mesh-phong-material />
103+
</ngt-mesh>
104+
105+
<ngt-mesh [receiveShadow]="true" [rotation]="[-Math.PI / 2, 0, 0]">
106+
<ngt-plane-geometry *args="[100, 100]" />
107+
<ngt-mesh-phong-material />
108+
</ngt-mesh>
109+
`,
110+
imports: [NgtsSpotLight, NgtArgs],
111+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
112+
changeDetection: ChangeDetectionStrategy.OnPush,
113+
})
114+
class DefaultSpotLightStory {
115+
protected readonly Math = Math;
116+
117+
options = input({} as NgtsSpotLightOptions);
118+
119+
depthBuffer = injectDepthBuffer();
120+
121+
spotLightOneOptions = computed(() => ({
122+
depthBuffer: this.depthBuffer(),
123+
position: [3, 2, 0],
124+
color: '#ff005b',
125+
...this.options(),
126+
}));
127+
spotLightTwoOptions = computed(() => ({
128+
depthBuffer: this.depthBuffer(),
129+
position: [-3, 2, 0],
130+
color: '#0EEC82',
131+
...this.options(),
132+
}));
133+
}
134+
135+
export default {
136+
title: 'Staging/SpotLight',
137+
decorators: makeDecorators(),
138+
} as Meta;
139+
140+
export const Default = makeStoryObject(DefaultSpotLightStory, {
141+
canvasOptions: { lights: false },
142+
argsOptions: {
143+
options: {
144+
penumbra: 0.5,
145+
intensity: 0.5 * Math.PI,
146+
decay: 0,
147+
angle: 0.5,
148+
castShadow: true,
149+
},
150+
},
151+
});
152+
153+
export const Shadows = makeStoryObject(SpotLightShadowStory, {
154+
canvasOptions: { controls: false, lights: false },
155+
argsOptions: {
156+
wind: true,
157+
options: {
158+
distance: 20,
159+
intensity: 5 * Math.PI,
160+
decay: 0,
161+
angle: MathUtils.degToRad(45),
162+
color: '#fadcb9',
163+
position: [5, 7, -2],
164+
volumetric: false,
165+
debug: false,
166+
},
167+
},
168+
});

libs/soba/staging/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ export * from './lib/normal-texture';
1313
export * from './lib/randomized-lights';
1414
export * from './lib/render-texture';
1515
export * from './lib/sky';
16+
export { NgtsSpotLight, NgtsSpotLightOptions, NgtsSpotLightShadow } from './lib/spot-light';
1617
export * from './lib/stage';

0 commit comments

Comments
 (0)