@needle-tools/engine 4.6.1 → 4.6.2-next.fb486b2
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-CJ4jhuta.min.js +1575 -0
- package/dist/{needle-engine.bundle-BVg46UWZ.js → needle-engine.bundle-CQzZighj.js} +9722 -9554
- package/dist/needle-engine.bundle-CdAK5p8o.umd.cjs +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_context.d.ts +4 -1
- package/lib/engine/engine_context.js +9 -2
- 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/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 +2 -2
- 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 +23 -71
- 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 +20 -4
- package/lib/engine-components/postprocessing/PostProcessingHandler.js +231 -116
- 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 +44 -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/src/engine/engine_context.ts +13 -4
- 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/postprocessing/Effects/Antialiasing.ts +3 -1
- package/src/engine-components/postprocessing/Effects/BloomEffect.ts +4 -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 +26 -80
- 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 +267 -122
- 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 +103 -2
- package/dist/generateMeshBVH.worker-Cdfpaq5W.js +0 -25
- package/dist/needle-engine.bundle-AOXFIsYk.umd.cjs +0 -1563
- package/dist/needle-engine.bundle-Dt52m2jf.min.js +0 -1563
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
import type { Effect, EffectComposer, Pass, ToneMappingEffect as _TonemappingEffect } from "postprocessing";
|
|
2
|
-
import { HalfFloatType, NoToneMapping,
|
|
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 { Constructor } from "../../engine/engine_types.js";
|
|
10
|
+
import { getParam } from "../../engine/engine_utils.js";
|
|
10
11
|
import { Camera } from "../Camera.js";
|
|
12
|
+
import { threeToneMappingToEffectMode } from "./Effects/Tonemapping.utils.js";
|
|
11
13
|
import { PostProcessingEffect, PostProcessingEffectContext } from "./PostProcessingEffect.js";
|
|
14
|
+
import { orderEffects, PostprocessingEffectData, PostProcessingEffectOrder } from "./utils.js";
|
|
12
15
|
|
|
13
16
|
declare const NEEDLE_USE_POSTPROCESSING: boolean;
|
|
14
17
|
globalThis["NEEDLE_USE_POSTPROCESSING"] = globalThis["NEEDLE_USE_POSTPROCESSING"] !== undefined ? globalThis["NEEDLE_USE_POSTPROCESSING"] : true;
|
|
15
18
|
|
|
16
19
|
|
|
17
20
|
const debug = getParam("debugpost");
|
|
18
|
-
const dontMergePasses = getParam("debugpostpasses");
|
|
19
21
|
|
|
20
22
|
const activeKey = Symbol("needle:postprocessing-handler");
|
|
21
23
|
const autoclearSetting = Symbol("needle:previous-autoclear-state");
|
|
24
|
+
const previousToneMapping = Symbol("needle:previous-tone-mapping");
|
|
22
25
|
|
|
23
26
|
/**
|
|
24
27
|
* PostProcessingHandler is responsible for applying post processing effects to the scene. It is internally used by the {@link Volume} component
|
|
@@ -27,7 +30,15 @@ export class PostProcessingHandler {
|
|
|
27
30
|
|
|
28
31
|
private _composer: EffectComposer | null = null;
|
|
29
32
|
private _lastVolumeComponents?: PostProcessingEffect[];
|
|
30
|
-
private _effects: Array<
|
|
33
|
+
private readonly _effects: Array<PostprocessingEffectData> = [];
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Returns true if a specific effect is currently active in the post processing stack.
|
|
37
|
+
*/
|
|
38
|
+
getEffectIsActive(effect: Effect): boolean {
|
|
39
|
+
if (!effect) return false;
|
|
40
|
+
return this._isActive && this._effects.some(e => e.effect === effect);
|
|
41
|
+
}
|
|
31
42
|
|
|
32
43
|
get isActive() {
|
|
33
44
|
return this._isActive;
|
|
@@ -60,7 +71,7 @@ export class PostProcessingHandler {
|
|
|
60
71
|
return this.onApply(this.context, components);
|
|
61
72
|
}
|
|
62
73
|
|
|
63
|
-
unapply() {
|
|
74
|
+
unapply(dispose: boolean = true) {
|
|
64
75
|
if (debug) console.log("Unapplying postprocessing effects");
|
|
65
76
|
this._isActive = false;
|
|
66
77
|
if (this._lastVolumeComponents) {
|
|
@@ -73,21 +84,29 @@ export class PostProcessingHandler {
|
|
|
73
84
|
const active = context[activeKey] as PostProcessingHandler | null;
|
|
74
85
|
if (active === this) {
|
|
75
86
|
delete context[activeKey];
|
|
87
|
+
|
|
88
|
+
// Restore the auto clear setting
|
|
89
|
+
if (typeof context.renderer[autoclearSetting] === "boolean") {
|
|
90
|
+
context.renderer.autoClear = context.renderer[autoclearSetting];
|
|
91
|
+
}
|
|
92
|
+
if (typeof context.renderer[previousToneMapping] === "number") {
|
|
93
|
+
context.renderer.toneMapping = context.renderer[previousToneMapping] as ToneMapping;
|
|
94
|
+
}
|
|
76
95
|
}
|
|
96
|
+
|
|
97
|
+
this._composer?.removeAllPasses();
|
|
98
|
+
if (dispose) this._composer?.dispose();
|
|
99
|
+
|
|
77
100
|
if (context.composer === this._composer) {
|
|
78
|
-
context.composer?.dispose();
|
|
79
101
|
context.composer = null;
|
|
80
102
|
}
|
|
81
|
-
if (typeof context.renderer[autoclearSetting] === "boolean") {
|
|
82
|
-
context.renderer.autoClear = context.renderer[autoclearSetting];
|
|
83
|
-
}
|
|
84
103
|
}
|
|
85
104
|
|
|
86
105
|
dispose() {
|
|
87
|
-
this.unapply();
|
|
106
|
+
this.unapply(true);
|
|
88
107
|
|
|
89
108
|
for (const effect of this._effects) {
|
|
90
|
-
effect.dispose();
|
|
109
|
+
effect.effect.dispose();
|
|
91
110
|
}
|
|
92
111
|
this._effects.length = 0;
|
|
93
112
|
this._composer = null;
|
|
@@ -105,6 +124,7 @@ export class PostProcessingHandler {
|
|
|
105
124
|
// import("./Effects/Sharpening.effect")
|
|
106
125
|
]);
|
|
107
126
|
|
|
127
|
+
|
|
108
128
|
// try {
|
|
109
129
|
// internal_SetSharpeningEffectModule(modules[2]);
|
|
110
130
|
// }
|
|
@@ -141,10 +161,24 @@ export class PostProcessingHandler {
|
|
|
141
161
|
// apply or collect effects
|
|
142
162
|
const res = component.apply(ctx);
|
|
143
163
|
if (!res) continue;
|
|
164
|
+
|
|
165
|
+
|
|
144
166
|
if (Array.isArray(res)) {
|
|
145
|
-
|
|
167
|
+
for (const effect of res) {
|
|
168
|
+
this._effects.push({
|
|
169
|
+
effect,
|
|
170
|
+
typeName: component.typeName,
|
|
171
|
+
priority: component.order
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
this._effects.push({
|
|
177
|
+
effect: res,
|
|
178
|
+
typeName: component.typeName,
|
|
179
|
+
priority: component.order
|
|
180
|
+
});
|
|
146
181
|
}
|
|
147
|
-
else this._effects.push(res);
|
|
148
182
|
}
|
|
149
183
|
}
|
|
150
184
|
else {
|
|
@@ -153,23 +187,41 @@ export class PostProcessingHandler {
|
|
|
153
187
|
}
|
|
154
188
|
}
|
|
155
189
|
|
|
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
190
|
this.applyEffects(context);
|
|
165
191
|
}
|
|
166
192
|
|
|
193
|
+
private _anyPassHasDepth = false;
|
|
194
|
+
private _anyPassHasNormal = false;
|
|
195
|
+
private _hasSmaaEffect = false;
|
|
196
|
+
|
|
197
|
+
get anyPassHasDepth() { return this._anyPassHasDepth; }
|
|
198
|
+
get anyPassHasNormal() { return this._anyPassHasNormal; }
|
|
199
|
+
get hasSmaaEffect() { return this._hasSmaaEffect; }
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
private _customInputBuffer: WebGLRenderTarget<Texture> | null = null;
|
|
204
|
+
private _customInputBufferId = 0;
|
|
205
|
+
private _multisampling: number = 0;
|
|
206
|
+
set multisampling(value: number) {
|
|
207
|
+
this._multisampling = value;
|
|
208
|
+
}
|
|
209
|
+
get multisampling() {
|
|
210
|
+
return this._multisampling;
|
|
211
|
+
}
|
|
212
|
+
|
|
167
213
|
|
|
168
214
|
/** Build composer passes */
|
|
169
215
|
private applyEffects(context: Context) {
|
|
216
|
+
// Reset state
|
|
217
|
+
this._anyPassHasDepth = false;
|
|
218
|
+
this._anyPassHasNormal = false;
|
|
219
|
+
this._hasSmaaEffect = false;
|
|
220
|
+
|
|
221
|
+
if (this._effects.length <= 0) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
170
224
|
|
|
171
|
-
const effectsOrPasses = this._effects;
|
|
172
|
-
if (effectsOrPasses.length <= 0) return;
|
|
173
225
|
const camera = context.mainCameraComponent as Camera;
|
|
174
226
|
const renderer = context.renderer;
|
|
175
227
|
const scene = context.scene;
|
|
@@ -178,8 +230,31 @@ export class PostProcessingHandler {
|
|
|
178
230
|
// Store the auto clear setting because the postprocessing composer just disables it
|
|
179
231
|
// and when we disable postprocessing we want to restore the original setting
|
|
180
232
|
// https://github.com/pmndrs/postprocessing/blob/271944b74b543a5b743a62803a167b60cc6bb4ee/src/core/EffectComposer.js#L230C12-L230C12
|
|
233
|
+
// First we need to get the previously set autoClear setting, if it exists
|
|
234
|
+
if (typeof renderer[autoclearSetting] === "boolean") {
|
|
235
|
+
renderer.autoClear = renderer[autoclearSetting];
|
|
236
|
+
}
|
|
181
237
|
renderer[autoclearSetting] = renderer.autoClear;
|
|
182
238
|
|
|
239
|
+
if (typeof renderer[previousToneMapping] === "number") {
|
|
240
|
+
renderer.toneMapping = renderer[previousToneMapping] as ToneMapping;
|
|
241
|
+
}
|
|
242
|
+
renderer[previousToneMapping] = renderer.toneMapping;
|
|
243
|
+
|
|
244
|
+
// Ensure that we have a tonemapping effect if the renderer is set to use a tone mapping
|
|
245
|
+
if (renderer.toneMapping != NoToneMapping) {
|
|
246
|
+
if (!this._effects.find(e => e instanceof MODULES.POSTPROCESSING.MODULE.ToneMappingEffect)) {
|
|
247
|
+
const tonemapping = new MODULES.POSTPROCESSING.MODULE.ToneMappingEffect();
|
|
248
|
+
tonemapping.name = `ToneMapping (${renderer.toneMapping})`;
|
|
249
|
+
tonemapping.mode = threeToneMappingToEffectMode(renderer.toneMapping);
|
|
250
|
+
this._effects.push({
|
|
251
|
+
typeName: "ToneMapping",
|
|
252
|
+
effect: tonemapping,
|
|
253
|
+
priority: PostProcessingEffectOrder.ToneMapping
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
183
258
|
// create composer and set active on context
|
|
184
259
|
if (!this._composer) {
|
|
185
260
|
// const hdrRenderTarget = new WebGLRenderTarget(window.innerWidth, window.innerHeight, { type: HalfFloatType });
|
|
@@ -192,12 +267,14 @@ export class PostProcessingHandler {
|
|
|
192
267
|
if (context.composer && context.composer !== this._composer) {
|
|
193
268
|
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.");
|
|
194
269
|
}
|
|
270
|
+
|
|
195
271
|
context.composer = this._composer;
|
|
196
272
|
const composer = context.composer;
|
|
197
273
|
composer.setMainCamera(cam);
|
|
198
274
|
composer.setRenderer(renderer);
|
|
199
275
|
composer.setMainScene(scene);
|
|
200
276
|
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)
|
|
277
|
+
composer.multisampling = 0; // Disable multisampling by default
|
|
201
278
|
|
|
202
279
|
for (const prev of composer.passes)
|
|
203
280
|
prev.dispose();
|
|
@@ -205,81 +282,186 @@ export class PostProcessingHandler {
|
|
|
205
282
|
|
|
206
283
|
// Render to screen pass
|
|
207
284
|
const screenpass = new MODULES.POSTPROCESSING.MODULE.RenderPass(scene, cam);
|
|
208
|
-
screenpass.name = "
|
|
285
|
+
screenpass.name = "RenderPass";
|
|
209
286
|
screenpass.mainScene = scene;
|
|
210
287
|
composer.addPass(screenpass);
|
|
211
288
|
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
289
|
+
const screenPassRender = screenpass.render;
|
|
290
|
+
this._customInputBuffer?.dispose();
|
|
291
|
+
this._customInputBuffer = null;
|
|
292
|
+
screenpass.render = (renderer, inputBuffer, outputBuffer, deltaTime, stencilTest) => {
|
|
293
|
+
if (!inputBuffer) return;
|
|
216
294
|
|
|
217
|
-
|
|
295
|
+
// screenPassRender.call(screenpass, renderer, inputBuffer, outputBuffer, deltaTime, stencilTest);
|
|
296
|
+
// return;
|
|
218
297
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
ef.renderToScreen = false;
|
|
225
|
-
composer.addPass(ef as Pass);
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
// seems some effects are not correctly typed, but three can deal with them,
|
|
229
|
-
// so we might need to just pass them through
|
|
230
|
-
composer.addPass(ef);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
298
|
+
// 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
|
|
299
|
+
inputBuffer.samples = 0;
|
|
300
|
+
if (outputBuffer) {
|
|
301
|
+
outputBuffer.samples = 0;
|
|
302
|
+
}
|
|
233
303
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
304
|
+
// Make sure the input buffer is a WebGLRenderTarget with the correct settings
|
|
305
|
+
if (!this._customInputBuffer
|
|
306
|
+
|| this._customInputBuffer.width !== inputBuffer.width
|
|
307
|
+
|| this._customInputBuffer.height !== inputBuffer.height
|
|
308
|
+
|| this._customInputBuffer.samples !== this._multisampling
|
|
309
|
+
|| this._customInputBuffer.texture.format !== inputBuffer.texture.format
|
|
310
|
+
|| this._customInputBuffer.texture.type !== HalfFloatType
|
|
311
|
+
) {
|
|
312
|
+
this._customInputBuffer?.dispose();
|
|
313
|
+
|
|
314
|
+
this._customInputBuffer = new WebGLRenderTarget(inputBuffer.width, inputBuffer.height, {
|
|
315
|
+
format: inputBuffer.texture.format,
|
|
316
|
+
type: HalfFloatType,
|
|
317
|
+
depthBuffer: inputBuffer.depthBuffer,
|
|
318
|
+
depthTexture: inputBuffer.depthTexture
|
|
319
|
+
? new DepthTexture(inputBuffer.width, inputBuffer.height)
|
|
320
|
+
: undefined,
|
|
321
|
+
stencilBuffer: inputBuffer.stencilBuffer,
|
|
322
|
+
samples: Math.max(0, this._multisampling),
|
|
323
|
+
minFilter: inputBuffer.texture.minFilter ?? LinearFilter,
|
|
324
|
+
magFilter: inputBuffer.texture.magFilter ?? LinearFilter,
|
|
325
|
+
generateMipmaps: inputBuffer.texture.generateMipmaps,
|
|
326
|
+
});
|
|
327
|
+
this._customInputBufferId++;
|
|
328
|
+
this._customInputBuffer.texture.name = `CustomInputBuffer-${this._customInputBufferId}`;
|
|
329
|
+
if (this._customInputBuffer.depthTexture && inputBuffer.depthTexture) {
|
|
330
|
+
this._customInputBuffer.depthTexture.format = inputBuffer.depthTexture.format;
|
|
331
|
+
this._customInputBuffer.depthTexture.type = inputBuffer.depthTexture.type;
|
|
242
332
|
}
|
|
333
|
+
// https://github.com/pmndrs/postprocessing/blob/ad338df710ef41fee4e5d10ad2c2c299030d46ef/src/core/EffectComposer.js#L366
|
|
334
|
+
if (this._customInputBuffer.samples > 0)
|
|
335
|
+
(this._customInputBuffer as any).ignoreDepthForMultisampleCopy = false;
|
|
336
|
+
|
|
337
|
+
if (debug) console.warn(`[PostProcessing] Input buffer created with size ${this._customInputBuffer.width}x${this._customInputBuffer.height} and samples ${this._customInputBuffer.samples}`);
|
|
243
338
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
339
|
+
// Calling the original render function with the input buffer
|
|
340
|
+
screenPassRender.call(screenpass, renderer, this._customInputBuffer, outputBuffer, deltaTime, stencilTest);
|
|
341
|
+
// Blit the resulting buffer to the input buffer passed in by the composer so it's used for subsequent effects
|
|
342
|
+
Graphics.blit(this._customInputBuffer.texture, inputBuffer, {
|
|
343
|
+
renderer,
|
|
344
|
+
depthTexture: this._customInputBuffer.depthTexture,
|
|
345
|
+
depthWrite: true,
|
|
346
|
+
depthTest: true,
|
|
347
|
+
});
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
try {
|
|
352
|
+
orderEffects(this._effects);
|
|
353
|
+
|
|
354
|
+
let foundTonemappingEffect = false;
|
|
355
|
+
let activeTonemappingEffect: _TonemappingEffect | null = null;
|
|
356
|
+
for (let i = this._effects.length - 1; i >= 0; i--) {
|
|
357
|
+
const ef = this._effects[i].effect;
|
|
358
|
+
if (ef instanceof MODULES.POSTPROCESSING.MODULE.ToneMappingEffect) {
|
|
359
|
+
// If we already have a tonemapping effect, we can skip this one
|
|
360
|
+
if (foundTonemappingEffect) {
|
|
361
|
+
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.`);
|
|
362
|
+
this._effects.splice(i, 1);
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
activeTonemappingEffect = ef;
|
|
366
|
+
foundTonemappingEffect = true;
|
|
367
|
+
}
|
|
247
368
|
}
|
|
248
|
-
}
|
|
249
|
-
else {
|
|
250
|
-
// we still want to sort passes, but we do not want to merge them for debugging
|
|
251
|
-
if (automaticEffectsOrdering)
|
|
252
|
-
this.orderEffects();
|
|
253
369
|
|
|
254
|
-
|
|
370
|
+
const effectsToMerge: Array<Effect> = [];
|
|
371
|
+
let hasConvolutionEffectInArray = false;
|
|
372
|
+
|
|
373
|
+
for (let i = 0; i < this._effects.length; i++) {
|
|
374
|
+
const entry = this._effects[i];
|
|
375
|
+
const ef = entry.effect;
|
|
376
|
+
|
|
377
|
+
if (ef instanceof MODULES.POSTPROCESSING.MODULE.SMAAEffect) {
|
|
378
|
+
this._hasSmaaEffect = true;
|
|
379
|
+
}
|
|
380
|
+
else if (ef instanceof MODULES.POSTPROCESSING.MODULE.NormalPass) {
|
|
381
|
+
this._anyPassHasNormal = true;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// There can be only one tonemapping effect in the scene, so we skip all others
|
|
385
|
+
if (ef instanceof MODULES.POSTPROCESSING.MODULE.ToneMappingEffect && activeTonemappingEffect !== ef) {
|
|
386
|
+
// If we already have a tonemapping effect, we can skip this one
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// We can also not merge multiple effects of the same type in one pass
|
|
391
|
+
// So we first need to create a new pass with whatever effects we have so far
|
|
392
|
+
// 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
|
|
393
|
+
// const constructor = ef.constructor;
|
|
394
|
+
// if (effectsToMerge.find(e => e.constructor === constructor)) {
|
|
395
|
+
// this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
|
|
396
|
+
// }
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
|
|
255
400
|
if (ef instanceof MODULES.POSTPROCESSING.MODULE.Effect) {
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
401
|
+
const attributes = ef.getAttributes();
|
|
402
|
+
const convolution = MODULES.POSTPROCESSING.MODULE.EffectAttribute.CONVOLUTION;
|
|
403
|
+
if (attributes & convolution) {
|
|
404
|
+
if (debug) console.log("[PostProcessing] Convolution effect: " + ef.name);
|
|
405
|
+
if (hasConvolutionEffectInArray) {
|
|
406
|
+
if (debug) console.log("[PostProcessing] Merging effects with convolution", effectsToMerge.map(e => e.name).join(", "));
|
|
407
|
+
this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
|
|
408
|
+
}
|
|
409
|
+
hasConvolutionEffectInArray = true;
|
|
410
|
+
}
|
|
411
|
+
// Otherwise we can merge it
|
|
412
|
+
effectsToMerge.push(ef as Effect);
|
|
259
413
|
}
|
|
260
414
|
else if (ef instanceof MODULES.POSTPROCESSING.MODULE.Pass) {
|
|
415
|
+
hasConvolutionEffectInArray = false;
|
|
416
|
+
this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
|
|
261
417
|
ef.renderToScreen = false;
|
|
262
418
|
composer.addPass(ef as Pass);
|
|
263
419
|
}
|
|
264
|
-
else
|
|
420
|
+
else {
|
|
265
421
|
// seems some effects are not correctly typed, but three can deal with them,
|
|
266
|
-
// so we just pass them through
|
|
422
|
+
// so we might need to just pass them through
|
|
423
|
+
hasConvolutionEffectInArray = false;
|
|
424
|
+
this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
|
|
267
425
|
composer.addPass(ef);
|
|
426
|
+
}
|
|
427
|
+
|
|
268
428
|
}
|
|
269
|
-
}
|
|
270
429
|
|
|
430
|
+
this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
|
|
431
|
+
}
|
|
432
|
+
catch (e) {
|
|
433
|
+
console.error("Error while applying postprocessing effects", e);
|
|
434
|
+
composer.passes.forEach(p => p.dispose());
|
|
435
|
+
composer.removeAllPasses();
|
|
436
|
+
}
|
|
271
437
|
|
|
272
438
|
// 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)
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
439
|
+
let foundEnabled = false;
|
|
440
|
+
for (let i = composer.passes.length - 1; i >= 0; i--) {
|
|
441
|
+
const pass = composer.passes[i];
|
|
442
|
+
let gammaCorrect = false;
|
|
443
|
+
let renderToScreen = false;
|
|
444
|
+
if (pass.enabled) {
|
|
445
|
+
if (!foundEnabled) {
|
|
446
|
+
gammaCorrect = true;
|
|
447
|
+
renderToScreen = true;
|
|
448
|
+
}
|
|
449
|
+
foundEnabled = true;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
pass.renderToScreen = renderToScreen;
|
|
453
|
+
|
|
454
|
+
if ((pass as any)?.configuration !== undefined) {
|
|
455
|
+
(pass as any).configuration.gammaCorrection = gammaCorrect;
|
|
278
456
|
}
|
|
279
457
|
else if ("autosetGamma" in pass) {
|
|
280
458
|
// Some effects have a autosetGamma property that we can use to set the gamma correction
|
|
281
|
-
pass.autosetGamma =
|
|
459
|
+
pass.autosetGamma = gammaCorrect;
|
|
282
460
|
}
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
this._anyPassHasDepth ||= pass.needsDepthTexture;
|
|
464
|
+
|
|
283
465
|
}
|
|
284
466
|
|
|
285
467
|
// DEBUG LAND BELOW
|
|
@@ -287,56 +469,20 @@ export class PostProcessingHandler {
|
|
|
287
469
|
if (debug) this._onCreateEffectsDebug(this._composer!, cam);
|
|
288
470
|
}
|
|
289
471
|
|
|
290
|
-
private orderEffects() {
|
|
291
|
-
if (debug === "verbose") console.debug("Before ordering effects", [...this._effects]);
|
|
292
|
-
|
|
293
|
-
// Order of effects for correct results.
|
|
294
|
-
// Aligned with https://github.com/pmndrs/postprocessing/wiki/Effect-Merging#effect-execution-order
|
|
295
|
-
// We can not put this into global scope because then the module might not yet be initialized
|
|
296
|
-
effectsOrder ??= [
|
|
297
|
-
MODULES.POSTPROCESSING.MODULE.NormalPass,
|
|
298
|
-
MODULES.POSTPROCESSING.MODULE.DepthDownsamplingPass,
|
|
299
|
-
MODULES.POSTPROCESSING.MODULE.SMAAEffect,
|
|
300
|
-
MODULES.POSTPROCESSING.MODULE.SSAOEffect,
|
|
301
|
-
MODULES.POSTPROCESSING_AO.MODULE.N8AOPostPass,
|
|
302
|
-
MODULES.POSTPROCESSING.MODULE.TiltShiftEffect,
|
|
303
|
-
MODULES.POSTPROCESSING.MODULE.DepthOfFieldEffect,
|
|
304
|
-
MODULES.POSTPROCESSING.MODULE.ChromaticAberrationEffect,
|
|
305
|
-
MODULES.POSTPROCESSING.MODULE.BloomEffect,
|
|
306
|
-
MODULES.POSTPROCESSING.MODULE.SelectiveBloomEffect,
|
|
307
|
-
MODULES.POSTPROCESSING.MODULE.VignetteEffect,
|
|
308
|
-
MODULES.POSTPROCESSING.MODULE.PixelationEffect,
|
|
309
|
-
MODULES.POSTPROCESSING.MODULE.ToneMappingEffect,
|
|
310
|
-
MODULES.POSTPROCESSING.MODULE.HueSaturationEffect,
|
|
311
|
-
MODULES.POSTPROCESSING.MODULE.BrightnessContrastEffect,
|
|
312
|
-
// __SHARPENING_MODULE._SharpeningEffect,
|
|
313
|
-
];
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
// TODO: enforce correct order of effects (e.g. DOF before Bloom)
|
|
317
|
-
const effects = this._effects;
|
|
318
|
-
effects.sort((a, b) => {
|
|
319
|
-
// we use find index here because sometimes constructor names are prefixed with `_`
|
|
320
|
-
// 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)
|
|
321
|
-
const aidx = effectsOrder!.findIndex(e => a.constructor.name.endsWith(e.name));
|
|
322
|
-
const bidx = effectsOrder!.findIndex(e => b.constructor.name.endsWith(e.name));
|
|
323
|
-
// Unknown effects should be rendered first
|
|
324
|
-
if (aidx < 0) {
|
|
325
|
-
if (debug) console.warn("Unknown effect found: ", a.constructor.name);
|
|
326
|
-
return -1;
|
|
327
|
-
}
|
|
328
|
-
else if (bidx < 0) {
|
|
329
|
-
if (debug) console.warn("Unknown effect found: ", b.constructor.name);
|
|
330
|
-
return 1;
|
|
331
|
-
}
|
|
332
|
-
// if (aidx < 0) return 1;
|
|
333
|
-
// if (bidx < 0) return -1;
|
|
334
|
-
return aidx - bidx;
|
|
335
|
-
});
|
|
336
472
|
|
|
337
|
-
if (debug === "verbose") console.debug("After ordering effects", [...this._effects]);
|
|
338
|
-
}
|
|
339
473
|
|
|
474
|
+
/** Should be called before `composer.addPass()` to create an effect pass with all previously collected effects that can be merged up to that point */
|
|
475
|
+
private createPassForMergeableEffects(effects: Array<Effect>, composer: EffectComposer, camera: Camera3, scene: Scene) {
|
|
476
|
+
if (effects.length > 0) {
|
|
477
|
+
const pass = new MODULES.POSTPROCESSING.MODULE.EffectPass(camera, ...effects);
|
|
478
|
+
pass.name = effects.map(e => e.name).join(", ");
|
|
479
|
+
pass.mainScene = scene;
|
|
480
|
+
pass.enabled = true;
|
|
481
|
+
pass.renderToScreen = false;
|
|
482
|
+
composer.addPass(pass);
|
|
483
|
+
effects.length = 0; // Clear effects after adding them to the pass
|
|
484
|
+
}
|
|
485
|
+
}
|
|
340
486
|
|
|
341
487
|
|
|
342
488
|
|
|
@@ -412,4 +558,3 @@ export class PostProcessingHandler {
|
|
|
412
558
|
|
|
413
559
|
}
|
|
414
560
|
|
|
415
|
-
let effectsOrder: Array<Constructor<Effect | Pass>> | null = null;
|