Skip to content

Commit d6a31d1

Browse files
committed
post-processing (wip)
1 parent f66cb79 commit d6a31d1

File tree

4 files changed

+73
-18
lines changed

4 files changed

+73
-18
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type {RenderPass} from 'three/addons/postprocessing/RenderPass.js';
2+
3+
export interface IGetRenderPass {
4+
getRenderPass(): RenderPass;
5+
}
6+
7+
export const hasGetRenderPass = (obj: object): obj is IGetRenderPass =>
8+
obj && typeof (obj as IGetRenderPass).getRenderPass === 'function';
+2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import type {Camera, Scene, WebGLRenderer} from 'three';
2+
import type {RenderPass} from 'three/addons/postprocessing/RenderPass.js';
23

34
export type RenderCmdFunc = (scene: Scene, camera: Camera, autoClear: boolean) => void;
45

56
export interface IStage {
67
resize(width: number, height: number): void;
78
renderFrame(renderer: WebGLRenderer, now: number, deltaTime: number, frameNo: number, renderCmd?: RenderCmdFunc): void;
9+
getRenderPass?(): RenderPass;
810
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type {WebGLRenderer} from 'three';
2-
import {EffectComposer} from 'three/addons/postprocessing/EffectComposer.js';
2+
import {EffectComposer, Pass} from 'three/addons/postprocessing/EffectComposer.js';
33
import {RenderPass} from 'three/addons/postprocessing/RenderPass.js';
44
import {
55
StageAdded,
@@ -9,30 +9,28 @@ import {
99
type StageAddedProps,
1010
type StageRemovedProps,
1111
} from '../events.js';
12+
import {hasGetRenderPass} from './IGetRenderPass.js';
1213
import type {IStage} from './IStage.js';
13-
import {Stage2D} from './Stage2D.js';
1414
import {StageRenderer} from './StageRenderer.js';
1515

16-
const isRenderPassable = (stage: IStage): stage is Stage2D => stage instanceof Stage2D;
17-
1816
export class PostProcessingRenderer extends StageRenderer implements IStageAdded, IStageRemoved {
1917
composer?: EffectComposer;
20-
renderPass: WeakMap<IStage, RenderPass> = new WeakMap();
18+
19+
renderPasses: WeakMap<IStage, RenderPass> = new WeakMap();
20+
passes: Pass[] = [];
2121

2222
constructor() {
2323
super();
2424
this.on([StageAdded, StageRemoved], this);
2525
}
2626

2727
override renderFrame(renderer: WebGLRenderer, now: number, deltaTime: number, frameNo: number): void {
28-
if (!this.composer) {
29-
this.composer = new EffectComposer(renderer);
30-
}
28+
const composer = this.getComposer(renderer);
3129

3230
this.stages.forEach((stage) => {
3331
this.resizeStage(stage, this.width, this.height);
3432
stage.stage.renderFrame(renderer, now, deltaTime, frameNo, (scene, camera, autoClear) => {
35-
const renderPass = this.renderPass.get(stage.stage);
33+
const renderPass = this.renderPasses.get(stage.stage);
3634
if (renderPass) {
3735
renderPass.clear = autoClear;
3836
renderPass.scene = scene;
@@ -41,22 +39,57 @@ export class PostProcessingRenderer extends StageRenderer implements IStageAdded
4139
});
4240
});
4341

44-
this.composer.render();
42+
composer.render();
43+
}
44+
45+
addPass(pass: Pass) {
46+
if (this.composer) {
47+
this.composer.addPass(pass);
48+
} else {
49+
this.passes.push(pass);
50+
}
51+
}
52+
53+
removePass(pass: Pass) {
54+
if (this.composer) {
55+
this.composer.removePass(pass);
56+
} else {
57+
const index = this.passes.indexOf(pass);
58+
if (index !== -1) {
59+
this.passes.splice(index, 1);
60+
}
61+
}
62+
}
63+
64+
getComposer(renderer: WebGLRenderer): EffectComposer {
65+
if (this.composer == null) {
66+
this.composer = new EffectComposer(renderer);
67+
this.passes.forEach((pass) => this.composer.addPass(pass));
68+
this.passes.length = 0;
69+
}
70+
return this.composer;
4571
}
4672

4773
stageAdded({stage}: StageAddedProps) {
48-
if (isRenderPassable(stage) && !this.renderPass.has(stage)) {
49-
this.renderPass.set(stage, new RenderPass(stage.scene, stage.camera));
50-
console.log('stageAdded as renderPass', {stage, postEffectsRenderer: this});
74+
if (hasGetRenderPass(stage) && !this.renderPasses.has(stage)) {
75+
const renderPass = stage.getRenderPass();
76+
this.renderPasses.set(stage, renderPass);
77+
this.addPass(renderPass);
78+
79+
console.log('stageAdded', {stage, renderPass, postProcessingRenderer: this});
5180
}
5281
}
5382

5483
stageRemoved({stage}: StageRemovedProps) {
55-
if (this.renderPass.has(stage)) {
56-
const renderPass = this.renderPass.get(stage)!;
57-
this.renderPass.delete(stage);
84+
if (this.renderPasses.has(stage)) {
85+
const renderPass = this.renderPasses.get(stage)!;
86+
this.renderPasses.delete(stage);
87+
this.removePass(renderPass);
5888
renderPass.dispose();
59-
console.log('stageRemoved as renderPass', {stage, postEffectsRenderer: this});
89+
90+
console.log('stageRemoved', {stage, renderPass, postProcessingRenderer: this});
6091
}
6192
}
93+
94+
// TODO dispose
6295
}

packages/twopoint5d/src/stage/Stage2D.ts

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {eventize, Eventize} from '@spearwolf/eventize';
22
import {Camera, Scene, WebGLRenderer} from 'three';
33

4+
import {RenderPass} from 'three/examples/jsm/postprocessing/RenderPass.js';
45
import {
56
FirstFrame,
67
StageAfterCameraChanged,
@@ -11,6 +12,7 @@ import {
1112
type Stage2DResizeProps,
1213
type StageAfterCameraChangedArgs,
1314
} from '../events.js';
15+
import type {IGetRenderPass} from './IGetRenderPass.js';
1416
import type {IProjection} from './IProjection.js';
1517
import type {IStage, RenderCmdFunc} from './IStage.js';
1618

@@ -31,7 +33,7 @@ export interface Stage2D extends Eventize {}
3133
*
3234
* After the camera is created the scene can be rendered with the method `renderFrame(renderer: THREE.WebGLRenderer)`
3335
*/
34-
export class Stage2D implements IStage {
36+
export class Stage2D implements IStage, IGetRenderPass {
3537
scene: Scene;
3638

3739
autoClear = true;
@@ -230,4 +232,14 @@ export class Stage2D implements IStage {
230232
);
231233
}
232234
}
235+
236+
#renderPass?: RenderPass;
237+
238+
getRenderPass(): RenderPass {
239+
if (this.#renderPass == null) {
240+
this.#renderPass = new RenderPass(this.scene, this.camera);
241+
this.#renderPass.clear = this.autoClear;
242+
}
243+
return this.#renderPass;
244+
}
233245
}

0 commit comments

Comments
 (0)