Skip to content

Commit a6b5e78

Browse files
nartcclaude
andcommitted
feat(postprocessing): port missing effects from react-postprocessing
- add ramp, texture, ssao, autofocus effects - update lens-flare: replace minified shader with readable version, rename uniforms iTime→time, iResolution→screenRes - expose normalPass/downSamplingPass from effect-composer for ssao Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2699aac commit a6b5e78

7 files changed

Lines changed: 830 additions & 53 deletions

File tree

libs/postprocessing/src/lib/effect-composer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,8 @@ export class NgtpEffectComposer {
255255
* Can be used to access the composer directly for advanced use cases.
256256
*/
257257
effectComposer = pick(this.composerData, 'composer');
258+
normalPass = pick(this.composerData, 'normalPass');
259+
downSamplingPass = pick(this.composerData, 'downSamplingPass');
258260

259261
constructor() {
260262
extend({ Group });
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import {
2+
CUSTOM_ELEMENTS_SCHEMA,
3+
ChangeDetectionStrategy,
4+
Component,
5+
DestroyRef,
6+
ElementRef,
7+
computed,
8+
effect,
9+
inject,
10+
input,
11+
viewChild,
12+
} from '@angular/core';
13+
import { NgtArgs, NgtVector3, beforeRender, injectStore, pick, vector3 } from 'angular-three';
14+
import { easing } from 'maath';
15+
import { mergeInputs } from 'ngxtension/inject-inputs';
16+
import { CopyPass, DepthOfFieldEffect, DepthPickingPass } from 'postprocessing';
17+
import * as THREE from 'three';
18+
import { NgtpEffectComposer } from '../effect-composer';
19+
20+
type DOFOptions = NonNullable<ConstructorParameters<typeof DepthOfFieldEffect>[1]>;
21+
22+
export type AutofocusOptions = DOFOptions & {
23+
target?: NgtVector3;
24+
mouse?: boolean;
25+
debug?: number;
26+
manual?: boolean;
27+
smoothTime?: number;
28+
};
29+
30+
const defaultOptions: AutofocusOptions = {
31+
mouse: false,
32+
manual: false,
33+
smoothTime: 0.25,
34+
};
35+
36+
@Component({
37+
selector: 'ngtp-autofocus',
38+
template: `
39+
<ngt-primitive *args="[dofEffect()]" [dispose]="null" />
40+
@if (debugSize(); as debugSize) {
41+
<ngt-mesh #hitpointMesh>
42+
<ngt-sphere-geometry *args="[debugSize, 16, 16]" />
43+
<ngt-mesh-basic-material [color]="'#00ff00'" [opacity]="1" [transparent]="true" [depthWrite]="false" />
44+
</ngt-mesh>
45+
<ngt-mesh #targetMesh>
46+
<ngt-sphere-geometry *args="[debugSize / 2, 16, 16]" />
47+
<ngt-mesh-basic-material
48+
[color]="'#00ff00'"
49+
[opacity]="0.5"
50+
[transparent]="true"
51+
[depthWrite]="false"
52+
/>
53+
</ngt-mesh>
54+
}
55+
`,
56+
imports: [NgtArgs],
57+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
58+
changeDetection: ChangeDetectionStrategy.OnPush,
59+
})
60+
export class NgtpAutofocus {
61+
options = input(defaultOptions, { transform: mergeInputs(defaultOptions) });
62+
63+
private effectComposer = inject(NgtpEffectComposer);
64+
private store = injectStore();
65+
66+
private hitpoint = new THREE.Vector3(0, 0, 0);
67+
private ndc = new THREE.Vector3(0, 0, 0);
68+
69+
private depthPickingPass = new DepthPickingPass();
70+
private copyPass = new CopyPass();
71+
72+
debugSize = pick(this.options, 'debug');
73+
74+
private hitpointMeshRef = viewChild<ElementRef<THREE.Mesh>>('hitpointMesh');
75+
private targetMeshRef = viewChild<ElementRef<THREE.Mesh>>('targetMesh');
76+
77+
private target = vector3(this.options, 'target', true);
78+
79+
dofEffect = computed(() => {
80+
const [camera, options] = [this.effectComposer.camera(), this.options()];
81+
const { target: _, mouse: __, debug: ___, manual: ____, smoothTime: _____, ...dofOptions } = options;
82+
const dof = new DepthOfFieldEffect(camera, dofOptions);
83+
dof.target = new THREE.Vector3().copy(this.hitpoint);
84+
return dof;
85+
});
86+
87+
constructor() {
88+
// add passes to composer
89+
effect((onCleanup) => {
90+
const composer = this.effectComposer.effectComposer();
91+
if (!composer) return;
92+
93+
composer.addPass(this.depthPickingPass);
94+
composer.addPass(this.copyPass);
95+
96+
onCleanup(() => {
97+
composer.removePass(this.depthPickingPass);
98+
composer.removePass(this.copyPass);
99+
});
100+
});
101+
102+
inject(DestroyRef).onDestroy(() => {
103+
this.depthPickingPass.dispose();
104+
this.copyPass.dispose();
105+
});
106+
107+
// cleanup dof effect
108+
effect((onCleanup) => {
109+
const dof = this.dofEffect();
110+
onCleanup(() => dof.dispose());
111+
});
112+
113+
beforeRender(({ delta }) => {
114+
const dof = this.dofEffect();
115+
if (!dof?.target) return;
116+
117+
const { mouse: followMouse, smoothTime, manual } = this.options();
118+
if (manual) return;
119+
120+
const target = this.target();
121+
const camera = this.effectComposer.camera();
122+
123+
if (target) {
124+
this.hitpoint.copy(target);
125+
} else {
126+
const { x, y } = followMouse ? this.store.snapshot.pointer : { x: 0, y: 0 };
127+
this.ndc.x = x;
128+
this.ndc.y = y;
129+
130+
this.depthPickingPass.readDepth(this.ndc).then((depth) => {
131+
this.ndc.z = depth * 2.0 - 1.0;
132+
const hit = 1 - this.ndc.z > 0.0000001;
133+
if (hit) {
134+
const unprojected = this.ndc.clone().unproject(camera);
135+
this.hitpoint.copy(unprojected);
136+
}
137+
});
138+
}
139+
140+
if (smoothTime && smoothTime > 0 && delta > 0) {
141+
easing.damp3(dof.target, this.hitpoint, smoothTime, delta);
142+
} else {
143+
dof.target.copy(this.hitpoint);
144+
}
145+
146+
const hitpointMesh = this.hitpointMeshRef()?.nativeElement;
147+
if (hitpointMesh) hitpointMesh.position.copy(this.hitpoint);
148+
149+
const targetMesh = this.targetMeshRef()?.nativeElement;
150+
if (targetMesh) targetMesh.position.copy(dof.target);
151+
});
152+
}
153+
}

libs/postprocessing/src/lib/effects/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './ascii';
2+
export * from './autofocus';
23
export * from './bloom';
34
export * from './brightness-contrast';
45
export * from './chromatic-abberation';
@@ -17,11 +18,14 @@ export * from './lut';
1718
export * from './noise';
1819
export * from './outline';
1920
export * from './pixelation';
21+
export * from './ramp';
2022
export * from './scanline';
2123
export * from './selective-bloom';
2224
export * from './sepia';
25+
export * from './ssao';
2326
export * from './shock-wave';
2427
export * from './smaa';
28+
export * from './texture';
2529
export * from './tilt-shift';
2630
export * from './tilt-shift-2';
2731
export * from './tone-mapping';

0 commit comments

Comments
 (0)