@needle-tools/engine 4.6.0 → 4.6.1-next.20d54cd
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/generateMeshBVH.worker-BaNp_Xtp.js +25 -0
- package/dist/{gltf-progressive-Bm9eEfgu.min.js → gltf-progressive-Bl4okF1b.min.js} +1 -1
- package/dist/{gltf-progressive-GjIqwSG3.js → gltf-progressive-DSpdn0QT.js} +2 -2
- package/dist/{gltf-progressive-Dn6o99rH.umd.cjs → gltf-progressive-P8b8a0qY.umd.cjs} +1 -1
- package/dist/needle-engine.bundle-BVrLqIyi.umd.cjs +1575 -0
- package/dist/{needle-engine.bundle-DsrPZ9gj.js → needle-engine.bundle-BonYthMO.js} +8850 -8678
- package/dist/needle-engine.bundle-CokaG-YG.min.js +1575 -0
- package/dist/needle-engine.js +352 -351
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/{postprocessing-CRQa6Qxn.umd.cjs → postprocessing-CjW23fio.umd.cjs} +18 -18
- package/dist/{postprocessing-D6W1EyZ-.js → postprocessing-DYLNOL3W.js} +4 -3
- package/dist/{postprocessing-DF8AlRgW.min.js → postprocessing-xYQWCHFu.min.js} +26 -26
- package/dist/{three-DMrv-4ar.umd.cjs → three-B_hneGZr.umd.cjs} +4 -4
- package/dist/{three-Bz6X1mrw.js → three-DrqIzZTH.js} +4198 -4198
- package/dist/{three-Boa-jOq-.min.js → three-DuDKwKB8.min.js} +33 -33
- package/dist/{three-examples-GggCDHv0.js → three-examples-B50TT3Iu.js} +5 -5
- package/dist/{three-examples-DuVhxqft.min.js → three-examples-DaDLBuy6.min.js} +14 -14
- package/dist/{three-examples-C7ryg8vN.umd.cjs → three-examples-X3OadjXB.umd.cjs} +3 -3
- package/dist/{three-mesh-ui-CY6Izc7C.min.js → three-mesh-ui-B3p3gyUz.min.js} +1 -1
- package/dist/{three-mesh-ui-CwlN0FUC.umd.cjs → three-mesh-ui-CQiIQIlA.umd.cjs} +1 -1
- package/dist/{three-mesh-ui-CLNOfsWn.js → three-mesh-ui-CxuWt7m-.js} +1 -1
- package/dist/{vendor-zxXa3Dmr.min.js → vendor-BlSxe9JJ.min.js} +3 -3
- package/dist/{vendor-BSD1RQIh.js → vendor-BmYIgaS1.js} +3 -3
- package/dist/{vendor-DHr4aqIZ.umd.cjs → vendor-Cavtu3CP.umd.cjs} +3 -3
- package/lib/engine/engine_assetdatabase.js +3 -1
- package/lib/engine/engine_assetdatabase.js.map +1 -1
- package/lib/engine/engine_context.d.ts +6 -3
- package/lib/engine/engine_context.js +20 -12
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_three_utils.d.ts +17 -14
- package/lib/engine/engine_three_utils.js +106 -53
- package/lib/engine/engine_three_utils.js.map +1 -1
- package/lib/engine/engine_tonemapping.d.ts +4 -0
- package/lib/engine/engine_tonemapping.js +21 -18
- package/lib/engine/engine_tonemapping.js.map +1 -1
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine/engine_utils_screenshot.d.ts +1 -1
- package/lib/engine/engine_utils_screenshot.js +11 -2
- package/lib/engine/engine_utils_screenshot.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.d.ts +4 -1
- package/lib/engine/webcomponents/needle-engine.extras.js +3 -3
- package/lib/engine/webcomponents/needle-engine.extras.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.js +11 -21
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine-components/CameraUtils.js.map +1 -1
- package/lib/engine-components/ReflectionProbe.d.ts +2 -1
- package/lib/engine-components/ReflectionProbe.js +4 -1
- package/lib/engine-components/ReflectionProbe.js.map +1 -1
- package/lib/engine-components/Renderer.js +9 -5
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/postprocessing/Effects/Antialiasing.js +3 -1
- package/lib/engine-components/postprocessing/Effects/Antialiasing.js.map +1 -1
- package/lib/engine-components/postprocessing/Effects/BloomEffect.d.ts +2 -2
- package/lib/engine-components/postprocessing/Effects/BloomEffect.js +5 -2
- package/lib/engine-components/postprocessing/Effects/BloomEffect.js.map +1 -1
- package/lib/engine-components/postprocessing/Effects/ColorAdjustments.d.ts +8 -0
- package/lib/engine-components/postprocessing/Effects/ColorAdjustments.js +27 -8
- package/lib/engine-components/postprocessing/Effects/ColorAdjustments.js.map +1 -1
- package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.js +1 -0
- package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.js.map +1 -1
- package/lib/engine-components/postprocessing/Effects/Sharpening.d.ts +1 -0
- package/lib/engine-components/postprocessing/Effects/Sharpening.js +4 -0
- package/lib/engine-components/postprocessing/Effects/Sharpening.js.map +1 -1
- package/lib/engine-components/postprocessing/Effects/Tonemapping.d.ts +2 -9
- package/lib/engine-components/postprocessing/Effects/Tonemapping.js +29 -73
- package/lib/engine-components/postprocessing/Effects/Tonemapping.js.map +1 -1
- package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.d.ts +13 -0
- package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.js +52 -0
- package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.js.map +1 -0
- package/lib/engine-components/postprocessing/PostProcessingEffect.d.ts +18 -0
- package/lib/engine-components/postprocessing/PostProcessingEffect.js +22 -3
- package/lib/engine-components/postprocessing/PostProcessingEffect.js.map +1 -1
- package/lib/engine-components/postprocessing/PostProcessingHandler.d.ts +21 -4
- package/lib/engine-components/postprocessing/PostProcessingHandler.js +237 -125
- package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
- package/lib/engine-components/postprocessing/Volume.d.ts +2 -1
- package/lib/engine-components/postprocessing/Volume.js +51 -33
- package/lib/engine-components/postprocessing/Volume.js.map +1 -1
- package/lib/engine-components/postprocessing/index.d.ts +1 -0
- package/lib/engine-components/postprocessing/index.js +1 -0
- package/lib/engine-components/postprocessing/index.js.map +1 -1
- package/lib/engine-components/postprocessing/utils.d.ts +43 -0
- package/lib/engine-components/postprocessing/utils.js +82 -0
- package/lib/engine-components/postprocessing/utils.js.map +1 -1
- package/package.json +2 -2
- package/plugins/vite/dependency-watcher.js +8 -2
- package/src/engine/engine_assetdatabase.ts +3 -1
- package/src/engine/engine_context.ts +27 -15
- package/src/engine/engine_three_utils.ts +134 -58
- package/src/engine/engine_tonemapping.ts +23 -24
- package/src/engine/engine_utils.ts +2 -2
- package/src/engine/engine_utils_screenshot.ts +13 -3
- package/src/engine/webcomponents/needle-engine.extras.ts +3 -3
- package/src/engine/webcomponents/needle-engine.ts +14 -25
- package/src/engine-components/CameraUtils.ts +3 -3
- package/src/engine-components/ReflectionProbe.ts +5 -1
- package/src/engine-components/Renderer.ts +10 -7
- package/src/engine-components/postprocessing/Effects/Antialiasing.ts +3 -1
- package/src/engine-components/postprocessing/Effects/BloomEffect.ts +6 -4
- package/src/engine-components/postprocessing/Effects/ColorAdjustments.ts +24 -13
- package/src/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.ts +1 -0
- package/src/engine-components/postprocessing/Effects/Sharpening.ts +5 -0
- package/src/engine-components/postprocessing/Effects/Tonemapping.ts +29 -81
- package/src/engine-components/postprocessing/Effects/Tonemapping.utils.ts +60 -0
- package/src/engine-components/postprocessing/PostProcessingEffect.ts +23 -3
- package/src/engine-components/postprocessing/PostProcessingHandler.ts +268 -132
- package/src/engine-components/postprocessing/Volume.ts +54 -38
- package/src/engine-components/postprocessing/index.ts +2 -1
- package/src/engine-components/postprocessing/utils.ts +102 -2
- package/dist/generateMeshBVH.worker-Cdfpaq5W.js +0 -25
- package/dist/needle-engine.bundle-BDO_N7gN.min.js +0 -1559
- package/dist/needle-engine.bundle-CoJqbtmp.umd.cjs +0 -1559
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
import type { Effect, EffectComposer, Pass, ToneMappingEffect as _TonemappingEffect } from "postprocessing";
|
|
2
|
-
import { HalfFloatType, NoToneMapping } from "three";
|
|
2
|
+
import { Camera as Camera3, DepthTexture, HalfFloatType, LinearFilter, NoToneMapping, Scene, Texture, ToneMapping, WebGLRenderTarget } from "three";
|
|
3
3
|
|
|
4
4
|
import { showBalloonWarning } from "../../engine/debug/index.js";
|
|
5
5
|
// import { internal_SetSharpeningEffectModule } from "./Effects/Sharpening.js";
|
|
6
6
|
import { MODULES } from "../../engine/engine_modules.js";
|
|
7
7
|
import { Context } from "../../engine/engine_setup.js";
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
8
|
+
import { Graphics } from "../../engine/engine_three_utils.js";
|
|
9
|
+
import { getParam } from "../../engine/engine_utils.js";
|
|
10
10
|
import { Camera } from "../Camera.js";
|
|
11
|
+
import { threeToneMappingToEffectMode } from "./Effects/Tonemapping.utils.js";
|
|
11
12
|
import { PostProcessingEffect, PostProcessingEffectContext } from "./PostProcessingEffect.js";
|
|
13
|
+
import { orderEffects, PostprocessingEffectData, PostProcessingEffectOrder } from "./utils.js";
|
|
12
14
|
|
|
13
15
|
declare const NEEDLE_USE_POSTPROCESSING: boolean;
|
|
14
16
|
globalThis["NEEDLE_USE_POSTPROCESSING"] = globalThis["NEEDLE_USE_POSTPROCESSING"] !== undefined ? globalThis["NEEDLE_USE_POSTPROCESSING"] : true;
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
const debug = getParam("debugpost");
|
|
18
|
-
const dontMergePasses = getParam("debugpostpasses");
|
|
19
20
|
|
|
20
21
|
const activeKey = Symbol("needle:postprocessing-handler");
|
|
21
22
|
const autoclearSetting = Symbol("needle:previous-autoclear-state");
|
|
23
|
+
const previousToneMapping = Symbol("needle:previous-tone-mapping");
|
|
22
24
|
|
|
23
25
|
/**
|
|
24
26
|
* PostProcessingHandler is responsible for applying post processing effects to the scene. It is internally used by the {@link Volume} component
|
|
@@ -27,7 +29,15 @@ export class PostProcessingHandler {
|
|
|
27
29
|
|
|
28
30
|
private _composer: EffectComposer | null = null;
|
|
29
31
|
private _lastVolumeComponents?: PostProcessingEffect[];
|
|
30
|
-
private _effects: Array<
|
|
32
|
+
private readonly _effects: Array<PostprocessingEffectData> = [];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Returns true if a specific effect is currently active in the post processing stack.
|
|
36
|
+
*/
|
|
37
|
+
getEffectIsActive(effect: Effect): boolean {
|
|
38
|
+
if (!effect) return false;
|
|
39
|
+
return this._isActive && this._effects.some(e => e.effect === effect);
|
|
40
|
+
}
|
|
31
41
|
|
|
32
42
|
get isActive() {
|
|
33
43
|
return this._isActive;
|
|
@@ -44,7 +54,7 @@ export class PostProcessingHandler {
|
|
|
44
54
|
this.context = context;
|
|
45
55
|
}
|
|
46
56
|
|
|
47
|
-
apply(components: PostProcessingEffect[])
|
|
57
|
+
apply(components: PostProcessingEffect[]): Promise<void> {
|
|
48
58
|
if ("env" in import.meta && import.meta.env.VITE_NEEDLE_USE_POSTPROCESSING === "false") {
|
|
49
59
|
if (debug) console.warn("Postprocessing is disabled via vite env setting");
|
|
50
60
|
else console.debug("Postprocessing is disabled via vite env setting");
|
|
@@ -60,7 +70,7 @@ export class PostProcessingHandler {
|
|
|
60
70
|
return this.onApply(this.context, components);
|
|
61
71
|
}
|
|
62
72
|
|
|
63
|
-
unapply() {
|
|
73
|
+
unapply(dispose: boolean = true) {
|
|
64
74
|
if (debug) console.log("Unapplying postprocessing effects");
|
|
65
75
|
this._isActive = false;
|
|
66
76
|
if (this._lastVolumeComponents) {
|
|
@@ -73,21 +83,29 @@ export class PostProcessingHandler {
|
|
|
73
83
|
const active = context[activeKey] as PostProcessingHandler | null;
|
|
74
84
|
if (active === this) {
|
|
75
85
|
delete context[activeKey];
|
|
86
|
+
|
|
87
|
+
// Restore the auto clear setting
|
|
88
|
+
if (typeof context.renderer[autoclearSetting] === "boolean") {
|
|
89
|
+
context.renderer.autoClear = context.renderer[autoclearSetting];
|
|
90
|
+
}
|
|
91
|
+
if (typeof context.renderer[previousToneMapping] === "number") {
|
|
92
|
+
context.renderer.toneMapping = context.renderer[previousToneMapping] as ToneMapping;
|
|
93
|
+
}
|
|
76
94
|
}
|
|
95
|
+
|
|
96
|
+
this._composer?.removeAllPasses();
|
|
97
|
+
if (dispose) this._composer?.dispose();
|
|
98
|
+
|
|
77
99
|
if (context.composer === this._composer) {
|
|
78
|
-
context.composer?.dispose();
|
|
79
100
|
context.composer = null;
|
|
80
101
|
}
|
|
81
|
-
if (typeof context.renderer[autoclearSetting] === "boolean") {
|
|
82
|
-
context.renderer.autoClear = context.renderer[autoclearSetting];
|
|
83
|
-
}
|
|
84
102
|
}
|
|
85
103
|
|
|
86
104
|
dispose() {
|
|
87
|
-
this.unapply();
|
|
105
|
+
this.unapply(true);
|
|
88
106
|
|
|
89
107
|
for (const effect of this._effects) {
|
|
90
|
-
effect.dispose();
|
|
108
|
+
effect.effect.dispose();
|
|
91
109
|
}
|
|
92
110
|
this._effects.length = 0;
|
|
93
111
|
this._composer = null;
|
|
@@ -105,6 +123,7 @@ export class PostProcessingHandler {
|
|
|
105
123
|
// import("./Effects/Sharpening.effect")
|
|
106
124
|
]);
|
|
107
125
|
|
|
126
|
+
|
|
108
127
|
// try {
|
|
109
128
|
// internal_SetSharpeningEffectModule(modules[2]);
|
|
110
129
|
// }
|
|
@@ -141,10 +160,22 @@ export class PostProcessingHandler {
|
|
|
141
160
|
// apply or collect effects
|
|
142
161
|
const res = component.apply(ctx);
|
|
143
162
|
if (!res) continue;
|
|
163
|
+
|
|
164
|
+
|
|
144
165
|
if (Array.isArray(res)) {
|
|
145
|
-
|
|
166
|
+
for (const effect of res) {
|
|
167
|
+
this._effects.push({
|
|
168
|
+
effect,
|
|
169
|
+
priority: component.order
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
this._effects.push({
|
|
175
|
+
effect: res,
|
|
176
|
+
priority: component.order
|
|
177
|
+
});
|
|
146
178
|
}
|
|
147
|
-
else this._effects.push(res);
|
|
148
179
|
}
|
|
149
180
|
}
|
|
150
181
|
else {
|
|
@@ -153,24 +184,40 @@ export class PostProcessingHandler {
|
|
|
153
184
|
}
|
|
154
185
|
}
|
|
155
186
|
|
|
156
|
-
// Ensure that we have a tonemapping effect if the renderer is set to use a tone mapping
|
|
157
|
-
if (this.context.renderer.toneMapping != NoToneMapping) {
|
|
158
|
-
if (!this._effects.find(e => e instanceof MODULES.POSTPROCESSING.MODULE.ToneMappingEffect)) {
|
|
159
|
-
const tonemapping = new MODULES.POSTPROCESSING.MODULE.ToneMappingEffect();
|
|
160
|
-
this._effects.push(tonemapping);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
187
|
this.applyEffects(context);
|
|
165
188
|
}
|
|
166
189
|
|
|
190
|
+
private _anyPassHasDepth = false;
|
|
191
|
+
private _anyPassHasNormal = false;
|
|
192
|
+
private _hasSmaaEffect = false;
|
|
193
|
+
|
|
194
|
+
get anyPassHasDepth() { return this._anyPassHasDepth; }
|
|
195
|
+
get anyPassHasNormal() { return this._anyPassHasNormal; }
|
|
196
|
+
get hasSmaaEffect() { return this._hasSmaaEffect; }
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
private _customInputBuffer: WebGLRenderTarget<Texture> | null = null;
|
|
201
|
+
private _customInputBufferId = 0;
|
|
202
|
+
private _multisampling: number = 0;
|
|
203
|
+
set multisampling(value: number) {
|
|
204
|
+
this._multisampling = value;
|
|
205
|
+
}
|
|
206
|
+
get multisampling() {
|
|
207
|
+
return this._multisampling;
|
|
208
|
+
}
|
|
209
|
+
|
|
167
210
|
|
|
168
211
|
/** Build composer passes */
|
|
169
212
|
private applyEffects(context: Context) {
|
|
213
|
+
// Reset state
|
|
214
|
+
this._anyPassHasDepth = false;
|
|
215
|
+
this._anyPassHasNormal = false;
|
|
216
|
+
this._hasSmaaEffect = false;
|
|
170
217
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
218
|
+
if (this._effects.length <= 0) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
174
221
|
|
|
175
222
|
const camera = context.mainCameraComponent as Camera;
|
|
176
223
|
const renderer = context.renderer;
|
|
@@ -180,8 +227,27 @@ export class PostProcessingHandler {
|
|
|
180
227
|
// Store the auto clear setting because the postprocessing composer just disables it
|
|
181
228
|
// and when we disable postprocessing we want to restore the original setting
|
|
182
229
|
// https://github.com/pmndrs/postprocessing/blob/271944b74b543a5b743a62803a167b60cc6bb4ee/src/core/EffectComposer.js#L230C12-L230C12
|
|
230
|
+
// First we need to get the previously set autoClear setting, if it exists
|
|
231
|
+
if (typeof renderer[autoclearSetting] === "boolean") {
|
|
232
|
+
renderer.autoClear = renderer[autoclearSetting];
|
|
233
|
+
}
|
|
183
234
|
renderer[autoclearSetting] = renderer.autoClear;
|
|
184
235
|
|
|
236
|
+
if (typeof renderer[previousToneMapping] === "number") {
|
|
237
|
+
renderer.toneMapping = renderer[previousToneMapping] as ToneMapping;
|
|
238
|
+
}
|
|
239
|
+
renderer[previousToneMapping] = renderer.toneMapping;
|
|
240
|
+
|
|
241
|
+
// Ensure that we have a tonemapping effect if the renderer is set to use a tone mapping
|
|
242
|
+
if (renderer.toneMapping != NoToneMapping) {
|
|
243
|
+
if (!this._effects.find(e => e instanceof MODULES.POSTPROCESSING.MODULE.ToneMappingEffect)) {
|
|
244
|
+
const tonemapping = new MODULES.POSTPROCESSING.MODULE.ToneMappingEffect();
|
|
245
|
+
tonemapping.name = `ToneMapping (${renderer.toneMapping})`;
|
|
246
|
+
tonemapping.mode = threeToneMappingToEffectMode(renderer.toneMapping);
|
|
247
|
+
this._effects.push({ effect: tonemapping, priority: PostProcessingEffectOrder.ToneMapping });
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
185
251
|
// create composer and set active on context
|
|
186
252
|
if (!this._composer) {
|
|
187
253
|
// const hdrRenderTarget = new WebGLRenderTarget(window.innerWidth, window.innerHeight, { type: HalfFloatType });
|
|
@@ -194,11 +260,14 @@ export class PostProcessingHandler {
|
|
|
194
260
|
if (context.composer && context.composer !== this._composer) {
|
|
195
261
|
console.warn("There's already an active EffectComposer in your scene: replacing it with a new one. This might cause unexpected behaviour. Make sure to only use one PostprocessingManager/Volume in your scene.");
|
|
196
262
|
}
|
|
263
|
+
|
|
197
264
|
context.composer = this._composer;
|
|
198
265
|
const composer = context.composer;
|
|
199
266
|
composer.setMainCamera(cam);
|
|
200
267
|
composer.setRenderer(renderer);
|
|
201
268
|
composer.setMainScene(scene);
|
|
269
|
+
composer.autoRenderToScreen = true; // Must be enabled because it might be disabled during addPass by the composer itself (depending on the effect's settings or order)
|
|
270
|
+
composer.multisampling = 0; // Disable multisampling by default
|
|
202
271
|
|
|
203
272
|
for (const prev of composer.passes)
|
|
204
273
|
prev.dispose();
|
|
@@ -206,68 +275,197 @@ export class PostProcessingHandler {
|
|
|
206
275
|
|
|
207
276
|
// Render to screen pass
|
|
208
277
|
const screenpass = new MODULES.POSTPROCESSING.MODULE.RenderPass(scene, cam);
|
|
209
|
-
screenpass.name = "
|
|
278
|
+
screenpass.name = "RenderPass";
|
|
210
279
|
screenpass.mainScene = scene;
|
|
211
280
|
composer.addPass(screenpass);
|
|
212
281
|
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
282
|
+
const screenPassRender = screenpass.render;
|
|
283
|
+
this._customInputBuffer?.dispose();
|
|
284
|
+
this._customInputBuffer = null;
|
|
285
|
+
screenpass.render = (renderer, inputBuffer, outputBuffer, deltaTime, stencilTest) => {
|
|
286
|
+
if (!inputBuffer) return;
|
|
217
287
|
|
|
218
|
-
|
|
288
|
+
// screenPassRender.call(screenpass, renderer, inputBuffer, outputBuffer, deltaTime, stencilTest);
|
|
289
|
+
// return;
|
|
219
290
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}
|
|
226
|
-
else {
|
|
227
|
-
// seems some effects are not correctly typed, but three can deal with them,
|
|
228
|
-
// so we might need to just pass them through
|
|
229
|
-
composer.addPass(ef);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
291
|
+
// Make sure multisampling is disabled on the composer buffers. Technically a user could still set multisampling directly on the composer so this is to override that and make sure these textures do NOT use multisampling
|
|
292
|
+
inputBuffer.samples = 0;
|
|
293
|
+
if (outputBuffer) {
|
|
294
|
+
outputBuffer.samples = 0;
|
|
295
|
+
}
|
|
232
296
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
297
|
+
// Make sure the input buffer is a WebGLRenderTarget with the correct settings
|
|
298
|
+
if (!this._customInputBuffer
|
|
299
|
+
|| this._customInputBuffer.width !== inputBuffer.width
|
|
300
|
+
|| this._customInputBuffer.height !== inputBuffer.height
|
|
301
|
+
|| this._customInputBuffer.samples !== this._multisampling
|
|
302
|
+
|| this._customInputBuffer.texture.format !== inputBuffer.texture.format
|
|
303
|
+
|| this._customInputBuffer.texture.type !== HalfFloatType
|
|
304
|
+
) {
|
|
305
|
+
this._customInputBuffer?.dispose();
|
|
306
|
+
|
|
307
|
+
this._customInputBuffer = new WebGLRenderTarget(inputBuffer.width, inputBuffer.height, {
|
|
308
|
+
format: inputBuffer.texture.format,
|
|
309
|
+
type: HalfFloatType,
|
|
310
|
+
depthBuffer: inputBuffer.depthBuffer,
|
|
311
|
+
depthTexture: inputBuffer.depthTexture
|
|
312
|
+
? new DepthTexture(inputBuffer.width, inputBuffer.height)
|
|
313
|
+
: undefined,
|
|
314
|
+
stencilBuffer: inputBuffer.stencilBuffer,
|
|
315
|
+
samples: Math.max(0, this._multisampling),
|
|
316
|
+
minFilter: inputBuffer.texture.minFilter ?? LinearFilter,
|
|
317
|
+
magFilter: inputBuffer.texture.magFilter ?? LinearFilter,
|
|
318
|
+
generateMipmaps: inputBuffer.texture.generateMipmaps,
|
|
319
|
+
});
|
|
320
|
+
this._customInputBufferId++;
|
|
321
|
+
this._customInputBuffer.texture.name = `CustomInputBuffer-${this._customInputBufferId}`;
|
|
322
|
+
if (this._customInputBuffer.depthTexture && inputBuffer.depthTexture) {
|
|
323
|
+
this._customInputBuffer.depthTexture.format = inputBuffer.depthTexture.format;
|
|
324
|
+
this._customInputBuffer.depthTexture.type = inputBuffer.depthTexture.type;
|
|
240
325
|
}
|
|
326
|
+
// https://github.com/pmndrs/postprocessing/blob/ad338df710ef41fee4e5d10ad2c2c299030d46ef/src/core/EffectComposer.js#L366
|
|
327
|
+
if (this._customInputBuffer.samples > 0)
|
|
328
|
+
(this._customInputBuffer as any).ignoreDepthForMultisampleCopy = false;
|
|
329
|
+
|
|
330
|
+
if (debug) console.warn(`[PostProcessing] Input buffer created with size ${this._customInputBuffer.width}x${this._customInputBuffer.height} and samples ${this._customInputBuffer.samples}`);
|
|
241
331
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
332
|
+
// Calling the original render function with the input buffer
|
|
333
|
+
screenPassRender.call(screenpass, renderer, this._customInputBuffer, outputBuffer, deltaTime, stencilTest);
|
|
334
|
+
// Blit the resulting buffer to the input buffer passed in by the composer so it's used for subsequent effects
|
|
335
|
+
Graphics.blit(this._customInputBuffer.texture, inputBuffer, {
|
|
336
|
+
renderer,
|
|
337
|
+
depthTexture: this._customInputBuffer.depthTexture,
|
|
338
|
+
depthWrite: true,
|
|
339
|
+
depthTest: true,
|
|
340
|
+
});
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
try {
|
|
345
|
+
orderEffects(this._effects);
|
|
346
|
+
|
|
347
|
+
let foundTonemappingEffect = false;
|
|
348
|
+
let activeTonemappingEffect: _TonemappingEffect | null = null;
|
|
349
|
+
for (let i = this._effects.length - 1; i >= 0; i--) {
|
|
350
|
+
const ef = this._effects[i].effect;
|
|
351
|
+
if (ef instanceof MODULES.POSTPROCESSING.MODULE.ToneMappingEffect) {
|
|
352
|
+
// If we already have a tonemapping effect, we can skip this one
|
|
353
|
+
if (foundTonemappingEffect) {
|
|
354
|
+
if (debug) console.warn(`[PostProcessing] Found multiple tonemapping effects in the scene: ${ef.name} and ${activeTonemappingEffect?.name}. Only the last one added will be used.`);
|
|
355
|
+
this._effects.splice(i, 1);
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
activeTonemappingEffect = ef;
|
|
359
|
+
foundTonemappingEffect = true;
|
|
360
|
+
}
|
|
245
361
|
}
|
|
246
|
-
}
|
|
247
|
-
else {
|
|
248
|
-
// we still want to sort passes, but we do not want to merge them for debugging
|
|
249
|
-
if (automaticEffectsOrdering)
|
|
250
|
-
this.orderEffects();
|
|
251
362
|
|
|
252
|
-
|
|
363
|
+
const effectsToMerge: Array<Effect> = [];
|
|
364
|
+
let hasConvolutionEffectInArray = false;
|
|
365
|
+
|
|
366
|
+
for (const entry of this._effects) {
|
|
367
|
+
const ef = entry.effect;
|
|
368
|
+
|
|
369
|
+
if (ef instanceof MODULES.POSTPROCESSING.MODULE.SMAAEffect) {
|
|
370
|
+
this._hasSmaaEffect = true;
|
|
371
|
+
}
|
|
372
|
+
else if (ef instanceof MODULES.POSTPROCESSING.MODULE.NormalPass) {
|
|
373
|
+
this._anyPassHasNormal = true;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
// There can be only one tonemapping effect in the scene, so we can skip all others
|
|
378
|
+
if (ef instanceof MODULES.POSTPROCESSING.MODULE.ToneMappingEffect && activeTonemappingEffect !== ef) {
|
|
379
|
+
// If we already have a tonemapping effect, we can skip this one
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// We can also not merge multiple effects of the same type in one pass
|
|
384
|
+
// So we first need to create a new pass with whatever effects we have so far
|
|
385
|
+
// TODO: this seems to work fine for some effects (like ColorAdjustments) and only caused issues with multiple Tonemapping effects so far which is handled above
|
|
386
|
+
// const constructor = ef.constructor as Constructor<Effect | Pass>;
|
|
387
|
+
// if(effectsToMerge.find(e => e.constructor === constructor)) {
|
|
388
|
+
// // this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
|
|
389
|
+
// }
|
|
390
|
+
|
|
253
391
|
if (ef instanceof MODULES.POSTPROCESSING.MODULE.Effect) {
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
392
|
+
const attributes = ef.getAttributes();
|
|
393
|
+
const convolution = MODULES.POSTPROCESSING.MODULE.EffectAttribute.CONVOLUTION;
|
|
394
|
+
if (attributes & convolution) {
|
|
395
|
+
if (debug) console.log("[PostProcessing] Convolution effect: " + ef.name);
|
|
396
|
+
if (hasConvolutionEffectInArray) {
|
|
397
|
+
if (debug) console.log("[PostProcessing] Merging effects with convolution", effectsToMerge.map(e => e.name).join(", "));
|
|
398
|
+
this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
|
|
399
|
+
}
|
|
400
|
+
hasConvolutionEffectInArray = true;
|
|
401
|
+
}
|
|
402
|
+
// Otherwise we can merge it
|
|
403
|
+
effectsToMerge.push(ef as Effect);
|
|
257
404
|
}
|
|
258
|
-
else if (ef instanceof MODULES.POSTPROCESSING.MODULE.Pass)
|
|
405
|
+
else if (ef instanceof MODULES.POSTPROCESSING.MODULE.Pass) {
|
|
406
|
+
hasConvolutionEffectInArray = false;
|
|
407
|
+
this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
|
|
408
|
+
ef.renderToScreen = false;
|
|
259
409
|
composer.addPass(ef as Pass);
|
|
260
|
-
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
261
412
|
// seems some effects are not correctly typed, but three can deal with them,
|
|
262
|
-
// so we just pass them through
|
|
413
|
+
// so we might need to just pass them through
|
|
414
|
+
hasConvolutionEffectInArray = false;
|
|
415
|
+
this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
|
|
263
416
|
composer.addPass(ef);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
|
|
421
|
+
}
|
|
422
|
+
catch (e) {
|
|
423
|
+
console.error("Error while applying postprocessing effects", e);
|
|
424
|
+
composer.removeAllPasses();
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// The last pass is the one that renders to the screen, so we need to set the gamma correction for it (and enable it for all others)
|
|
428
|
+
for (let i = 0; i < composer.passes.length; i++) {
|
|
429
|
+
const pass = composer.passes[i];
|
|
430
|
+
const isLast = i === composer.passes.length - 1;
|
|
431
|
+
if ((pass as any)?.configuration !== undefined) {
|
|
432
|
+
(pass as any).configuration.gammaCorrection = isLast;
|
|
264
433
|
}
|
|
434
|
+
else if ("autosetGamma" in pass) {
|
|
435
|
+
// Some effects have a autosetGamma property that we can use to set the gamma correction
|
|
436
|
+
pass.autosetGamma = isLast;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
this._anyPassHasDepth ||= pass.needsDepthTexture;
|
|
265
440
|
}
|
|
266
441
|
|
|
267
|
-
|
|
442
|
+
// DEBUG LAND BELOW
|
|
443
|
+
if (debug) console.log("[PostProcessing] Passes →", [...composer.passes], "\n---------------------------------\n• " + composer.passes.map(i => i.name).join("\n• ") + "\n");
|
|
444
|
+
if (debug) this._onCreateEffectsDebug(this._composer!, cam);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
|
|
268
448
|
|
|
269
|
-
|
|
449
|
+
/** Should be called before `composer.addPass()` to create an effect pass with all previously collected effects that can be merged up to that point */
|
|
450
|
+
private createPassForMergeableEffects(effects: Array<Effect>, composer: EffectComposer, camera: Camera3, scene: Scene) {
|
|
451
|
+
if (effects.length > 0) {
|
|
452
|
+
const pass = new MODULES.POSTPROCESSING.MODULE.EffectPass(camera, ...effects);
|
|
453
|
+
pass.name = effects.map(e => e.name).join(", ");
|
|
454
|
+
pass.mainScene = scene;
|
|
455
|
+
pass.enabled = true;
|
|
456
|
+
pass.renderToScreen = false;
|
|
457
|
+
composer.addPass(pass);
|
|
458
|
+
effects.length = 0; // Clear effects after adding them to the pass
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
private _menuEntry: HTMLSelectElement | null = null;
|
|
465
|
+
private _passIndices: number[] | null = null;
|
|
270
466
|
|
|
467
|
+
private _onCreateEffectsDebug(composer: EffectComposer, cam: Camera3) {
|
|
468
|
+
if (debug === "passes") {
|
|
271
469
|
// DepthEffect for debugging purposes, disabled by default, can be selected in the debug pass select
|
|
272
470
|
const depthEffect = new MODULES.POSTPROCESSING.MODULE.DepthEffect({
|
|
273
471
|
blendFunction: MODULES.POSTPROCESSING.MODULE.BlendFunction.NORMAL,
|
|
@@ -303,7 +501,7 @@ export class PostProcessingHandler {
|
|
|
303
501
|
if (menu && this._passIndices === null) {
|
|
304
502
|
if (this._menuEntry)
|
|
305
503
|
this._menuEntry.remove();
|
|
306
|
-
|
|
504
|
+
|
|
307
505
|
const select = document.createElement("select");
|
|
308
506
|
select.multiple = true;
|
|
309
507
|
const defaultOpt = document.createElement("option");
|
|
@@ -327,73 +525,11 @@ export class PostProcessingHandler {
|
|
|
327
525
|
else {
|
|
328
526
|
this._passIndices = indices;
|
|
329
527
|
}
|
|
330
|
-
|
|
331
|
-
this.applyEffects(context);
|
|
528
|
+
this.applyEffects(this.context);
|
|
332
529
|
});
|
|
333
530
|
}
|
|
334
531
|
}
|
|
335
532
|
}
|
|
336
533
|
|
|
337
|
-
private _menuEntry: HTMLSelectElement | null = null;
|
|
338
|
-
private _passIndices: number[] | null = null;
|
|
339
|
-
|
|
340
|
-
private orderEffects() {
|
|
341
|
-
if (debug) console.log("Before ordering effects", [...this._effects]);
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
// Order of effects for correct results.
|
|
346
|
-
// Aligned with https://github.com/pmndrs/postprocessing/wiki/Effect-Merging#effect-execution-order
|
|
347
|
-
// We can not put this into global scope because then the module might not yet be initialized
|
|
348
|
-
effectsOrder ??= [
|
|
349
|
-
MODULES.POSTPROCESSING.MODULE.NormalPass,
|
|
350
|
-
MODULES.POSTPROCESSING.MODULE.DepthDownsamplingPass,
|
|
351
|
-
MODULES.POSTPROCESSING.MODULE.SMAAEffect,
|
|
352
|
-
MODULES.POSTPROCESSING.MODULE.SSAOEffect,
|
|
353
|
-
MODULES.POSTPROCESSING_AO.MODULE.N8AOPostPass,
|
|
354
|
-
MODULES.POSTPROCESSING.MODULE.TiltShiftEffect,
|
|
355
|
-
MODULES.POSTPROCESSING.MODULE.DepthOfFieldEffect,
|
|
356
|
-
MODULES.POSTPROCESSING.MODULE.ChromaticAberrationEffect,
|
|
357
|
-
MODULES.POSTPROCESSING.MODULE.BloomEffect,
|
|
358
|
-
MODULES.POSTPROCESSING.MODULE.SelectiveBloomEffect,
|
|
359
|
-
MODULES.POSTPROCESSING.MODULE.VignetteEffect,
|
|
360
|
-
MODULES.POSTPROCESSING.MODULE.PixelationEffect,
|
|
361
|
-
MODULES.POSTPROCESSING.MODULE.ToneMappingEffect,
|
|
362
|
-
MODULES.POSTPROCESSING.MODULE.HueSaturationEffect,
|
|
363
|
-
MODULES.POSTPROCESSING.MODULE.BrightnessContrastEffect,
|
|
364
|
-
// __SHARPENING_MODULE._SharpeningEffect,
|
|
365
|
-
];
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
// TODO: enforce correct order of effects (e.g. DOF before Bloom)
|
|
369
|
-
const effects = this._effects;
|
|
370
|
-
effects.sort((a, b) => {
|
|
371
|
-
// we use find index here because sometimes constructor names are prefixed with `_`
|
|
372
|
-
// TODO: find a more robust solution that isnt name based (not sure if that exists tho... maybe we must give effect TYPES some priority/index)
|
|
373
|
-
const aidx = effectsOrder!.findIndex(e => a.constructor.name.endsWith(e.name));
|
|
374
|
-
const bidx = effectsOrder!.findIndex(e => b.constructor.name.endsWith(e.name));
|
|
375
|
-
// Unknown effects should be rendered first
|
|
376
|
-
if (aidx < 0) {
|
|
377
|
-
if (debug) console.warn("Unknown effect found: ", a.constructor.name);
|
|
378
|
-
return -1;
|
|
379
|
-
}
|
|
380
|
-
else if (bidx < 0) {
|
|
381
|
-
if (debug) console.warn("Unknown effect found: ", b.constructor.name);
|
|
382
|
-
return 1;
|
|
383
|
-
}
|
|
384
|
-
if (aidx < 0) return 1;
|
|
385
|
-
if (bidx < 0) return -1;
|
|
386
|
-
return aidx - bidx;
|
|
387
|
-
});
|
|
388
|
-
if (debug) console.log("After ordering effects", [...this._effects]);
|
|
389
|
-
for (let i = 0; i < effects.length; i++) {
|
|
390
|
-
const effect = effects[i] as any;
|
|
391
|
-
if (effect?.configuration?.gammaCorrection !== undefined) {
|
|
392
|
-
const isLast = i === effects.length - 1;
|
|
393
|
-
effect.configuration.gammaCorrection = isLast;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
534
|
}
|
|
398
535
|
|
|
399
|
-
let effectsOrder: Array<Constructor<Effect | Pass>> | null = null;
|