@needle-tools/engine 4.6.0-next.ffc175e → 4.6.1-next.1e3d612
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-BYdv-DmQ.min.js +1563 -0
- package/dist/{needle-engine.bundle-DUkg_M5A.umd.cjs → needle-engine.bundle-DsI9yYlp.umd.cjs} +152 -148
- package/dist/{needle-engine.bundle-B3vWYoFH.js → needle-engine.bundle-Dx31Hfkf.js} +8129 -8036
- package/dist/needle-engine.js +343 -342
- 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 +4 -2
- package/lib/engine/engine_context.js +17 -10
- package/lib/engine/engine_context.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-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 +1 -1
- package/lib/engine-components/postprocessing/Effects/BloomEffect.js +3 -0
- package/lib/engine-components/postprocessing/Effects/BloomEffect.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.js +10 -6
- package/lib/engine-components/postprocessing/Effects/Tonemapping.js.map +1 -1
- 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 +11 -3
- package/lib/engine-components/postprocessing/PostProcessingHandler.js +117 -117
- 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 +50 -27
- 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 +81 -0
- package/lib/engine-components/postprocessing/utils.js.map +1 -1
- package/package.json +1 -1
- package/plugins/vite/dependency-watcher.js +8 -2
- package/src/engine/engine_assetdatabase.ts +3 -1
- package/src/engine/engine_context.ts +22 -12
- package/src/engine/engine_utils_screenshot.ts +13 -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 +4 -2
- 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 +9 -7
- package/src/engine-components/postprocessing/PostProcessingEffect.ts +23 -3
- package/src/engine-components/postprocessing/PostProcessingHandler.ts +135 -123
- package/src/engine-components/postprocessing/Volume.ts +56 -33
- package/src/engine-components/postprocessing/index.ts +2 -1
- package/src/engine-components/postprocessing/utils.ts +101 -2
- package/dist/generateMeshBVH.worker-Cdfpaq5W.js +0 -25
- package/dist/needle-engine.bundle-CZu9qkBv.min.js +0 -1559
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Effect, EffectComposer, Pass, ToneMappingEffect as _TonemappingEffect } from "postprocessing";
|
|
2
|
-
import { HalfFloatType, NoToneMapping } from "three";
|
|
2
|
+
import { Camera as Camera3, HalfFloatType, NoToneMapping, Scene } from "three";
|
|
3
3
|
|
|
4
4
|
import { showBalloonWarning } from "../../engine/debug/index.js";
|
|
5
5
|
// import { internal_SetSharpeningEffectModule } from "./Effects/Sharpening.js";
|
|
@@ -9,13 +9,13 @@ import type { Constructor } from "../../engine/engine_types.js";
|
|
|
9
9
|
import { DeviceUtilities, getParam } from "../../engine/engine_utils.js";
|
|
10
10
|
import { Camera } from "../Camera.js";
|
|
11
11
|
import { PostProcessingEffect, PostProcessingEffectContext } from "./PostProcessingEffect.js";
|
|
12
|
+
import { orderEffects, PostprocessingEffectData } from "./utils.js";
|
|
12
13
|
|
|
13
14
|
declare const NEEDLE_USE_POSTPROCESSING: boolean;
|
|
14
15
|
globalThis["NEEDLE_USE_POSTPROCESSING"] = globalThis["NEEDLE_USE_POSTPROCESSING"] !== undefined ? globalThis["NEEDLE_USE_POSTPROCESSING"] : true;
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
const debug = getParam("debugpost");
|
|
18
|
-
const dontMergePasses = getParam("debugpostpasses");
|
|
19
19
|
|
|
20
20
|
const activeKey = Symbol("needle:postprocessing-handler");
|
|
21
21
|
const autoclearSetting = Symbol("needle:previous-autoclear-state");
|
|
@@ -27,7 +27,7 @@ export class PostProcessingHandler {
|
|
|
27
27
|
|
|
28
28
|
private _composer: EffectComposer | null = null;
|
|
29
29
|
private _lastVolumeComponents?: PostProcessingEffect[];
|
|
30
|
-
private _effects: Array<
|
|
30
|
+
private readonly _effects: Array<PostprocessingEffectData> = [];
|
|
31
31
|
|
|
32
32
|
get isActive() {
|
|
33
33
|
return this._isActive;
|
|
@@ -44,7 +44,7 @@ export class PostProcessingHandler {
|
|
|
44
44
|
this.context = context;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
apply(components: PostProcessingEffect[])
|
|
47
|
+
apply(components: PostProcessingEffect[]): Promise<void> {
|
|
48
48
|
if ("env" in import.meta && import.meta.env.VITE_NEEDLE_USE_POSTPROCESSING === "false") {
|
|
49
49
|
if (debug) console.warn("Postprocessing is disabled via vite env setting");
|
|
50
50
|
else console.debug("Postprocessing is disabled via vite env setting");
|
|
@@ -60,7 +60,7 @@ export class PostProcessingHandler {
|
|
|
60
60
|
return this.onApply(this.context, components);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
unapply() {
|
|
63
|
+
unapply(dispose: boolean = true) {
|
|
64
64
|
if (debug) console.log("Unapplying postprocessing effects");
|
|
65
65
|
this._isActive = false;
|
|
66
66
|
if (this._lastVolumeComponents) {
|
|
@@ -73,21 +73,26 @@ export class PostProcessingHandler {
|
|
|
73
73
|
const active = context[activeKey] as PostProcessingHandler | null;
|
|
74
74
|
if (active === this) {
|
|
75
75
|
delete context[activeKey];
|
|
76
|
+
|
|
77
|
+
// Restore the auto clear setting
|
|
78
|
+
if (typeof context.renderer[autoclearSetting] === "boolean") {
|
|
79
|
+
context.renderer.autoClear = context.renderer[autoclearSetting];
|
|
80
|
+
}
|
|
76
81
|
}
|
|
82
|
+
|
|
83
|
+
this._composer?.removeAllPasses();
|
|
84
|
+
if (dispose) this._composer?.dispose();
|
|
85
|
+
|
|
77
86
|
if (context.composer === this._composer) {
|
|
78
|
-
context.composer?.dispose();
|
|
79
87
|
context.composer = null;
|
|
80
88
|
}
|
|
81
|
-
if (typeof context.renderer[autoclearSetting] === "boolean") {
|
|
82
|
-
context.renderer.autoClear = context.renderer[autoclearSetting];
|
|
83
|
-
}
|
|
84
89
|
}
|
|
85
90
|
|
|
86
91
|
dispose() {
|
|
87
|
-
this.unapply();
|
|
92
|
+
this.unapply(true);
|
|
88
93
|
|
|
89
94
|
for (const effect of this._effects) {
|
|
90
|
-
effect.dispose();
|
|
95
|
+
effect.effect.dispose();
|
|
91
96
|
}
|
|
92
97
|
this._effects.length = 0;
|
|
93
98
|
this._composer = null;
|
|
@@ -105,6 +110,7 @@ export class PostProcessingHandler {
|
|
|
105
110
|
// import("./Effects/Sharpening.effect")
|
|
106
111
|
]);
|
|
107
112
|
|
|
113
|
+
|
|
108
114
|
// try {
|
|
109
115
|
// internal_SetSharpeningEffectModule(modules[2]);
|
|
110
116
|
// }
|
|
@@ -141,10 +147,22 @@ export class PostProcessingHandler {
|
|
|
141
147
|
// apply or collect effects
|
|
142
148
|
const res = component.apply(ctx);
|
|
143
149
|
if (!res) continue;
|
|
150
|
+
|
|
151
|
+
|
|
144
152
|
if (Array.isArray(res)) {
|
|
145
|
-
|
|
153
|
+
for (const effect of res) {
|
|
154
|
+
this._effects.push({
|
|
155
|
+
effect,
|
|
156
|
+
priority: component.priority
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
this._effects.push({
|
|
162
|
+
effect: res,
|
|
163
|
+
priority: component.priority
|
|
164
|
+
});
|
|
146
165
|
}
|
|
147
|
-
else this._effects.push(res);
|
|
148
166
|
}
|
|
149
167
|
}
|
|
150
168
|
else {
|
|
@@ -157,20 +175,33 @@ export class PostProcessingHandler {
|
|
|
157
175
|
if (this.context.renderer.toneMapping != NoToneMapping) {
|
|
158
176
|
if (!this._effects.find(e => e instanceof MODULES.POSTPROCESSING.MODULE.ToneMappingEffect)) {
|
|
159
177
|
const tonemapping = new MODULES.POSTPROCESSING.MODULE.ToneMappingEffect();
|
|
160
|
-
this._effects.push(tonemapping);
|
|
178
|
+
this._effects.push({ effect: tonemapping });
|
|
161
179
|
}
|
|
162
180
|
}
|
|
163
181
|
|
|
164
182
|
this.applyEffects(context);
|
|
165
183
|
}
|
|
166
184
|
|
|
185
|
+
private _anyPassHasDepth = false;
|
|
186
|
+
private _anyPassHasNormal = false;
|
|
187
|
+
private _hasSmaaEffect = false;
|
|
188
|
+
|
|
189
|
+
get anyPassHasDepth() { return this._anyPassHasDepth; }
|
|
190
|
+
get anyPassHasNormal() { return this._anyPassHasNormal; }
|
|
191
|
+
get hasSmaaEffect() { return this._hasSmaaEffect; }
|
|
192
|
+
|
|
167
193
|
|
|
168
194
|
/** Build composer passes */
|
|
169
195
|
private applyEffects(context: Context) {
|
|
196
|
+
// Reset state
|
|
197
|
+
this._anyPassHasDepth = false;
|
|
198
|
+
this._anyPassHasNormal = false;
|
|
199
|
+
this._hasSmaaEffect = false;
|
|
170
200
|
|
|
171
201
|
const effectsOrPasses = this._effects;
|
|
172
|
-
|
|
173
|
-
|
|
202
|
+
if (effectsOrPasses.length <= 0) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
174
205
|
|
|
175
206
|
const camera = context.mainCameraComponent as Camera;
|
|
176
207
|
const renderer = context.renderer;
|
|
@@ -180,6 +211,10 @@ export class PostProcessingHandler {
|
|
|
180
211
|
// Store the auto clear setting because the postprocessing composer just disables it
|
|
181
212
|
// and when we disable postprocessing we want to restore the original setting
|
|
182
213
|
// https://github.com/pmndrs/postprocessing/blob/271944b74b543a5b743a62803a167b60cc6bb4ee/src/core/EffectComposer.js#L230C12-L230C12
|
|
214
|
+
// First we need to get the previously set autoClear setting, if it exists
|
|
215
|
+
if (typeof renderer[autoclearSetting] === "boolean") {
|
|
216
|
+
renderer.autoClear = renderer[autoclearSetting];
|
|
217
|
+
}
|
|
183
218
|
renderer[autoclearSetting] = renderer.autoClear;
|
|
184
219
|
|
|
185
220
|
// create composer and set active on context
|
|
@@ -194,11 +229,14 @@ export class PostProcessingHandler {
|
|
|
194
229
|
if (context.composer && context.composer !== this._composer) {
|
|
195
230
|
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
231
|
}
|
|
232
|
+
|
|
197
233
|
context.composer = this._composer;
|
|
198
234
|
const composer = context.composer;
|
|
199
235
|
composer.setMainCamera(cam);
|
|
200
236
|
composer.setRenderer(renderer);
|
|
201
237
|
composer.setMainScene(scene);
|
|
238
|
+
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)
|
|
239
|
+
composer.multisampling = 0;
|
|
202
240
|
|
|
203
241
|
for (const prev of composer.passes)
|
|
204
242
|
prev.dispose();
|
|
@@ -210,64 +248,100 @@ export class PostProcessingHandler {
|
|
|
210
248
|
screenpass.mainScene = scene;
|
|
211
249
|
composer.addPass(screenpass);
|
|
212
250
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
try {
|
|
216
|
-
this.orderEffects();
|
|
251
|
+
try {
|
|
252
|
+
orderEffects(this._effects);
|
|
217
253
|
|
|
218
|
-
|
|
254
|
+
const effectsToMerge: Array<Effect> = [];
|
|
255
|
+
let hasConvolutionEffectInArray = false;
|
|
219
256
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
effects.push(ef as Effect);
|
|
223
|
-
else if (ef instanceof MODULES.POSTPROCESSING.MODULE.Pass) {
|
|
224
|
-
composer.addPass(ef as Pass);
|
|
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
|
-
}
|
|
257
|
+
for (const entry of effectsOrPasses) {
|
|
258
|
+
const ef = entry.effect;
|
|
232
259
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
pass.enabled = true;
|
|
239
|
-
composer.addPass(pass);
|
|
260
|
+
if (ef instanceof MODULES.POSTPROCESSING.MODULE.SMAAEffect) {
|
|
261
|
+
this._hasSmaaEffect = true;
|
|
262
|
+
}
|
|
263
|
+
else if (ef instanceof MODULES.POSTPROCESSING.MODULE.NormalPass) {
|
|
264
|
+
this._anyPassHasNormal = true;
|
|
240
265
|
}
|
|
241
|
-
}
|
|
242
|
-
catch (e) {
|
|
243
|
-
console.error("Error while applying postprocessing effects", e);
|
|
244
|
-
composer.removeAllPasses();
|
|
245
|
-
}
|
|
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
266
|
|
|
252
|
-
for (const ef of effectsOrPasses) {
|
|
253
267
|
if (ef instanceof MODULES.POSTPROCESSING.MODULE.Effect) {
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
268
|
+
const attributes = ef.getAttributes();
|
|
269
|
+
const convolution = MODULES.POSTPROCESSING.MODULE.EffectAttribute.CONVOLUTION;
|
|
270
|
+
if (attributes & convolution) {
|
|
271
|
+
if (debug) console.log("[PostProcessing] Convolution effect: " + ef.name);
|
|
272
|
+
if (hasConvolutionEffectInArray) {
|
|
273
|
+
if (debug) console.log("[PostProcessing] Merging effects with convolution", effectsToMerge.map(e => e.name).join(", "));
|
|
274
|
+
this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
|
|
275
|
+
}
|
|
276
|
+
hasConvolutionEffectInArray = true;
|
|
277
|
+
}
|
|
278
|
+
// Otherwise we can merge it
|
|
279
|
+
effectsToMerge.push(ef as Effect);
|
|
257
280
|
}
|
|
258
|
-
else if (ef instanceof MODULES.POSTPROCESSING.MODULE.Pass)
|
|
281
|
+
else if (ef instanceof MODULES.POSTPROCESSING.MODULE.Pass) {
|
|
282
|
+
hasConvolutionEffectInArray = false;
|
|
283
|
+
this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
|
|
284
|
+
ef.renderToScreen = false;
|
|
259
285
|
composer.addPass(ef as Pass);
|
|
260
|
-
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
261
288
|
// seems some effects are not correctly typed, but three can deal with them,
|
|
262
|
-
// so we just pass them through
|
|
289
|
+
// so we might need to just pass them through
|
|
290
|
+
hasConvolutionEffectInArray = false;
|
|
291
|
+
this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
|
|
263
292
|
composer.addPass(ef);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
|
|
297
|
+
}
|
|
298
|
+
catch (e) {
|
|
299
|
+
console.error("Error while applying postprocessing effects", e);
|
|
300
|
+
composer.removeAllPasses();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// 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)
|
|
304
|
+
for (let i = 0; i < composer.passes.length; i++) {
|
|
305
|
+
const pass = composer.passes[i];
|
|
306
|
+
const isLast = i === composer.passes.length - 1;
|
|
307
|
+
if ((pass as any)?.configuration !== undefined) {
|
|
308
|
+
(pass as any).configuration.gammaCorrection = isLast;
|
|
309
|
+
}
|
|
310
|
+
else if ("autosetGamma" in pass) {
|
|
311
|
+
// Some effects have a autosetGamma property that we can use to set the gamma correction
|
|
312
|
+
pass.autosetGamma = isLast;
|
|
264
313
|
}
|
|
314
|
+
|
|
315
|
+
this._anyPassHasDepth ||= pass.needsDepthTexture;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// DEBUG LAND BELOW
|
|
319
|
+
if (debug) console.log("[PostProcessing] Passes →", [...composer.passes], "\n---------------------------------\n• " + composer.passes.map(i => i.name).join("\n• ") + "\n");
|
|
320
|
+
if (debug) this._onCreateEffectsDebug(this._composer!, cam);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
/** Should be called before `composer.addPass()` to create an effect pass with all previously collected effects that can be merged up to that point */
|
|
326
|
+
private createPassForMergeableEffects(effects: Array<Effect>, composer: EffectComposer, camera: Camera3, scene: Scene) {
|
|
327
|
+
if (effects.length > 0) {
|
|
328
|
+
const pass = new MODULES.POSTPROCESSING.MODULE.EffectPass(camera, ...effects);
|
|
329
|
+
pass.name = effects.map(e => e.name).join(", ");
|
|
330
|
+
pass.mainScene = scene;
|
|
331
|
+
pass.enabled = true;
|
|
332
|
+
pass.renderToScreen = false;
|
|
333
|
+
composer.addPass(pass);
|
|
334
|
+
effects.length = 0; // Clear effects after adding them to the pass
|
|
265
335
|
}
|
|
336
|
+
}
|
|
337
|
+
|
|
266
338
|
|
|
267
|
-
if (debug) {
|
|
268
339
|
|
|
269
|
-
|
|
340
|
+
private _menuEntry: HTMLSelectElement | null = null;
|
|
341
|
+
private _passIndices: number[] | null = null;
|
|
270
342
|
|
|
343
|
+
private _onCreateEffectsDebug(composer: EffectComposer, cam: Camera3) {
|
|
344
|
+
if (debug === "passes") {
|
|
271
345
|
// DepthEffect for debugging purposes, disabled by default, can be selected in the debug pass select
|
|
272
346
|
const depthEffect = new MODULES.POSTPROCESSING.MODULE.DepthEffect({
|
|
273
347
|
blendFunction: MODULES.POSTPROCESSING.MODULE.BlendFunction.NORMAL,
|
|
@@ -303,7 +377,7 @@ export class PostProcessingHandler {
|
|
|
303
377
|
if (menu && this._passIndices === null) {
|
|
304
378
|
if (this._menuEntry)
|
|
305
379
|
this._menuEntry.remove();
|
|
306
|
-
|
|
380
|
+
|
|
307
381
|
const select = document.createElement("select");
|
|
308
382
|
select.multiple = true;
|
|
309
383
|
const defaultOpt = document.createElement("option");
|
|
@@ -327,73 +401,11 @@ export class PostProcessingHandler {
|
|
|
327
401
|
else {
|
|
328
402
|
this._passIndices = indices;
|
|
329
403
|
}
|
|
330
|
-
|
|
331
|
-
this.applyEffects(context);
|
|
404
|
+
this.applyEffects(this.context);
|
|
332
405
|
});
|
|
333
406
|
}
|
|
334
407
|
}
|
|
335
408
|
}
|
|
336
409
|
|
|
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
410
|
}
|
|
398
411
|
|
|
399
|
-
let effectsOrder: Array<Constructor<Effect | Pass>> | null = null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Effect } from "postprocessing";
|
|
1
|
+
import type { Effect, EffectComposer } from "postprocessing";
|
|
2
2
|
|
|
3
3
|
import { isDevEnvironment, showBalloonMessage } from "../../engine/debug/index.js";
|
|
4
4
|
import { Context } from "../../engine/engine_context.js";
|
|
@@ -56,6 +56,9 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
|
|
|
56
56
|
return this._activeEffects;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
get dirty() { return this._isDirty; }
|
|
60
|
+
set dirty(value: boolean) { this._isDirty = value; }
|
|
61
|
+
|
|
59
62
|
@serializeable(VolumeProfile)
|
|
60
63
|
sharedProfile?: VolumeProfile;
|
|
61
64
|
|
|
@@ -184,40 +187,64 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
|
|
|
184
187
|
|
|
185
188
|
this.context.composer.setMainScene(this.context.scene);
|
|
186
189
|
|
|
187
|
-
const composer = this.context.composer;
|
|
188
|
-
if (this.multisampling === "auto") {
|
|
189
|
-
|
|
190
|
-
const timeSinceLastChange = this.context.time.realtimeSinceStartup - this._multisampleAutoChangeTime;
|
|
190
|
+
const composer = this.context.composer as EffectComposer;
|
|
191
191
|
|
|
192
|
-
|
|
193
|
-
&& timeSinceLastChange > .5
|
|
194
|
-
) {
|
|
195
|
-
const prev = composer.multisampling;
|
|
192
|
+
if (this.multisampling === "auto") {
|
|
196
193
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
composer.multisampling
|
|
201
|
-
|
|
202
|
-
|
|
194
|
+
// If the postprocessing handler is using depth+normals (e.g. with SMAA) we ALWAYS disable multisampling to avoid ugly edges
|
|
195
|
+
if (this._postprocessing && (this._postprocessing.hasSmaaEffect)) {
|
|
196
|
+
if (composer.multisampling !== 0) {
|
|
197
|
+
composer.multisampling = 0;
|
|
198
|
+
if (debug || isDevEnvironment()) {
|
|
199
|
+
console.warn(`[PostProcessing] Disabling multisampling you're using SMAA and have set the 'multisampling: auto' on your PostprocessingManager/Volume component. If you need anti-aliasing, consider adding an Antialiasing component or SMAA effect to the PostprocessingManager.`);
|
|
200
|
+
}
|
|
203
201
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
const timeSinceLastChange = this.context.time.realtimeSinceStartup - this._multisampleAutoChangeTime;
|
|
205
|
+
|
|
206
|
+
if (this.context.time.realtimeSinceStartup - this._componentEnabledTime > 2
|
|
207
|
+
&& timeSinceLastChange > .5
|
|
209
208
|
) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
composer.multisampling
|
|
213
|
-
|
|
209
|
+
const prev = composer.multisampling;
|
|
210
|
+
|
|
211
|
+
if (composer.multisampling > 0 && this.context.time.smoothedFps <= 50) {
|
|
212
|
+
this._multisampleAutoChangeTime = this.context.time.realtimeSinceStartup;
|
|
213
|
+
this._multisampleAutoDecreaseTime = this.context.time.realtimeSinceStartup;
|
|
214
|
+
let newMultiSample = composer.multisampling * .5;
|
|
215
|
+
newMultiSample = Math.floor(newMultiSample);
|
|
216
|
+
if (newMultiSample != composer.multisampling) {
|
|
217
|
+
composer.multisampling = newMultiSample;
|
|
218
|
+
}
|
|
219
|
+
if (debug) console.debug(`[PostProcessing] Reduced multisampling from ${prev} to ${composer.multisampling}`);
|
|
220
|
+
}
|
|
221
|
+
// if performance is good for a while try increasing multisampling again
|
|
222
|
+
else if (timeSinceLastChange > 1
|
|
223
|
+
&& this.context.time.smoothedFps >= 59
|
|
224
|
+
&& composer.multisampling < this.context.renderer.capabilities.maxSamples
|
|
225
|
+
&& this.context.time.realtimeSinceStartup - this._multisampleAutoDecreaseTime > 10
|
|
226
|
+
) {
|
|
227
|
+
this._multisampleAutoChangeTime = this.context.time.realtimeSinceStartup;
|
|
228
|
+
let newMultiSample = composer.multisampling <= 0 ? 1 : composer.multisampling * 2;
|
|
229
|
+
newMultiSample = Math.floor(newMultiSample);
|
|
230
|
+
if (newMultiSample !== composer.multisampling) {
|
|
231
|
+
composer.multisampling = newMultiSample;
|
|
232
|
+
}
|
|
233
|
+
if (debug) console.debug(`[PostProcessing] Increased multisampling from ${prev} to ${composer.multisampling}`);
|
|
234
|
+
}
|
|
214
235
|
}
|
|
215
236
|
}
|
|
216
237
|
}
|
|
217
238
|
else {
|
|
218
|
-
|
|
239
|
+
const newMultiSample = Math.max(0, Math.min(this.multisampling, this.context.renderer.capabilities.maxSamples));
|
|
240
|
+
if (newMultiSample !== composer.multisampling)
|
|
241
|
+
composer.multisampling = newMultiSample;
|
|
219
242
|
}
|
|
220
243
|
|
|
244
|
+
// Fix multisampling for the composer, it ONLY needs to be done for the input buffer
|
|
245
|
+
// this is super important for performance a negative visual impact
|
|
246
|
+
composer.outputBuffer.samples = 0;
|
|
247
|
+
|
|
221
248
|
// only set the main camera if any pass has a different camera
|
|
222
249
|
// trying to avoid doing this regularly since it involves doing potentially unnecessary work
|
|
223
250
|
// https://github.com/pmndrs/postprocessing/blob/3d3df0576b6d49aec9e763262d5a1ff7429fd91a/src/core/EffectComposer.js#L406
|
|
@@ -244,7 +271,7 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
|
|
|
244
271
|
private _isDirty: boolean = false;
|
|
245
272
|
|
|
246
273
|
private apply() {
|
|
247
|
-
if (debug) console.log(`Apply PostProcessing "${this.name}"`);
|
|
274
|
+
if (debug) console.log(`Apply PostProcessing "${this.name || "unnamed"}"`);
|
|
248
275
|
|
|
249
276
|
if (isDevEnvironment()) {
|
|
250
277
|
if (this._lastApplyTime !== undefined && Date.now() - this._lastApplyTime < 100) {
|
|
@@ -256,7 +283,6 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
|
|
|
256
283
|
}
|
|
257
284
|
|
|
258
285
|
this._isDirty = false;
|
|
259
|
-
this.unapply();
|
|
260
286
|
|
|
261
287
|
this._activeEffects.length = 0;
|
|
262
288
|
// get from profile
|
|
@@ -299,16 +325,13 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
|
|
|
299
325
|
console.warn(`[PostProcessing] No composer found`);
|
|
300
326
|
}
|
|
301
327
|
})
|
|
302
|
-
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
this._postprocessing?.unapply(false);
|
|
303
331
|
}
|
|
304
332
|
|
|
305
333
|
}
|
|
306
334
|
|
|
307
|
-
private unapply() {
|
|
308
|
-
this._postprocessing?.unapply();
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
|
|
312
335
|
private _applyPostQueue() {
|
|
313
336
|
if (this._modificationQueue) {
|
|
314
337
|
for (const entry of this._modificationQueue.values()) this.onEditorModification(entry);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from "./PostProcessingEffect.js";
|
|
2
2
|
export * from "./PostProcessingHandler.js"
|
|
3
|
+
export { PostProcessingEffectPriority } from "./utils.js";
|
|
3
4
|
export { PostProcessingManager } from "./Volume.js"
|
|
4
5
|
export * from "./VolumeParameter.js"
|
|
5
|
-
export * from "./VolumeProfile.js";
|
|
6
|
+
export * from "./VolumeProfile.js";
|