@needle-tools/engine 4.6.1-next.1e3d612 → 4.6.1-next.2b1af6a
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/dist/{needle-engine.bundle-Dx31Hfkf.js → needle-engine.bundle-BBxAzv6J.js} +6556 -6485
- package/dist/{needle-engine.bundle-BYdv-DmQ.min.js → needle-engine.bundle-BwVJc8bG.min.js} +170 -158
- package/dist/{needle-engine.bundle-DsI9yYlp.umd.cjs → needle-engine.bundle-cvRBTPLl.umd.cjs} +173 -161
- package/dist/needle-engine.js +48 -48
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/lib/engine/engine_context.d.ts +2 -1
- package/lib/engine/engine_context.js +3 -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/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/BloomEffect.d.ts +1 -1
- 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/Sharpening.d.ts +1 -1
- package/lib/engine-components/postprocessing/Effects/Sharpening.js +2 -2
- 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 +22 -57
- 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 +7 -7
- package/lib/engine-components/postprocessing/PostProcessingEffect.js +7 -7
- package/lib/engine-components/postprocessing/PostProcessingEffect.js.map +1 -1
- package/lib/engine-components/postprocessing/PostProcessingHandler.d.ts +6 -1
- package/lib/engine-components/postprocessing/PostProcessingHandler.js +107 -16
- package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
- package/lib/engine-components/postprocessing/Volume.js +19 -24
- package/lib/engine-components/postprocessing/Volume.js.map +1 -1
- package/lib/engine-components/postprocessing/index.d.ts +1 -1
- package/lib/engine-components/postprocessing/index.js +1 -1
- package/lib/engine-components/postprocessing/index.js.map +1 -1
- package/lib/engine-components/postprocessing/utils.d.ts +6 -6
- package/lib/engine-components/postprocessing/utils.js +26 -25
- package/lib/engine-components/postprocessing/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/engine/engine_context.ts +5 -3
- 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/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/BloomEffect.ts +2 -2
- package/src/engine-components/postprocessing/Effects/ColorAdjustments.ts +24 -13
- package/src/engine-components/postprocessing/Effects/Sharpening.ts +2 -2
- package/src/engine-components/postprocessing/Effects/Tonemapping.ts +24 -66
- package/src/engine-components/postprocessing/Effects/Tonemapping.utils.ts +60 -0
- package/src/engine-components/postprocessing/PostProcessingEffect.ts +7 -7
- package/src/engine-components/postprocessing/PostProcessingHandler.ts +122 -20
- package/src/engine-components/postprocessing/Volume.ts +19 -26
- package/src/engine-components/postprocessing/index.ts +1 -1
- package/src/engine-components/postprocessing/utils.ts +27 -26
|
@@ -1,70 +1,18 @@
|
|
|
1
1
|
import type { ToneMappingEffect as _TonemappingEffect, ToneMappingMode } from "postprocessing";
|
|
2
|
-
import { ACESFilmicToneMapping, AgXToneMapping, LinearToneMapping, NeutralToneMapping, NoToneMapping, ReinhardToneMapping, WebGLRenderer } from "three";
|
|
3
2
|
|
|
4
3
|
import { MODULES } from "../../../engine/engine_modules.js";
|
|
5
4
|
import { serializable } from "../../../engine/engine_serialization.js";
|
|
5
|
+
import { nameToThreeTonemapping } from "../../../engine/engine_tonemapping.js";
|
|
6
6
|
import { getParam } from "../../../engine/engine_utils.js";
|
|
7
7
|
import { EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect.js";
|
|
8
8
|
import { findPostProcessingManager } from "../utils.js";
|
|
9
9
|
import { VolumeParameter } from "../VolumeParameter.js";
|
|
10
10
|
import { registerCustomEffectType } from "../VolumeProfile.js";
|
|
11
|
+
import { NEToneMappingMode, NEToneMappingModeNames, threeToNeedleToneMapping, threeToneMappingToEffectMode, toThreeToneMapping } from "./Tonemapping.utils.js";
|
|
11
12
|
|
|
12
13
|
const debug = getParam("debugpost");
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
enum NEToneMappingMode {
|
|
16
|
-
None = 0,
|
|
17
|
-
Neutral = 1, // Neutral tonemapper, close to Reinhard
|
|
18
|
-
ACES = 2, // ACES Filmic reference tonemapper (custom approximation)
|
|
19
|
-
AgX = 3, // AgX Filmic tonemapper
|
|
20
|
-
KhronosNeutral = 4, // PBR Neural tonemapper
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
type NEToneMappingModeNames = keyof typeof NEToneMappingMode;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
function toThreeToneMapping(mode: NEToneMappingMode | undefined) {
|
|
27
|
-
switch (mode) {
|
|
28
|
-
case NEToneMappingMode.None:
|
|
29
|
-
return LinearToneMapping;
|
|
30
|
-
case NEToneMappingMode.Neutral:
|
|
31
|
-
return ReinhardToneMapping;
|
|
32
|
-
case NEToneMappingMode.ACES:
|
|
33
|
-
return ACESFilmicToneMapping;
|
|
34
|
-
case NEToneMappingMode.AgX:
|
|
35
|
-
return AgXToneMapping;
|
|
36
|
-
case NEToneMappingMode.KhronosNeutral:
|
|
37
|
-
return NeutralToneMapping;
|
|
38
|
-
default:
|
|
39
|
-
if(debug) console.warn("[Postprocessing] Unknown tone mapping mode", mode);
|
|
40
|
-
return NeutralToneMapping;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function threeToNeToneMapping(mode: number | undefined): NEToneMappingMode {
|
|
45
|
-
switch (mode) {
|
|
46
|
-
case LinearToneMapping: return NEToneMappingMode.None;
|
|
47
|
-
case ACESFilmicToneMapping: return NEToneMappingMode.ACES;
|
|
48
|
-
case AgXToneMapping: return NEToneMappingMode.AgX;
|
|
49
|
-
case NeutralToneMapping: return NEToneMappingMode.Neutral;
|
|
50
|
-
case ReinhardToneMapping: return NEToneMappingMode.Neutral;
|
|
51
|
-
default: return NEToneMappingMode.None;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
function threeToneMappingToEffectMode(mode: number | undefined): ToneMappingMode {
|
|
58
|
-
switch (mode) {
|
|
59
|
-
case LinearToneMapping: return MODULES.POSTPROCESSING.MODULE.ToneMappingMode.LINEAR;
|
|
60
|
-
case ACESFilmicToneMapping: return MODULES.POSTPROCESSING.MODULE.ToneMappingMode.ACES_FILMIC;
|
|
61
|
-
case AgXToneMapping: return MODULES.POSTPROCESSING.MODULE.ToneMappingMode.AGX;
|
|
62
|
-
case NeutralToneMapping: return MODULES.POSTPROCESSING.MODULE.ToneMappingMode.NEUTRAL;
|
|
63
|
-
case ReinhardToneMapping: return MODULES.POSTPROCESSING.MODULE.ToneMappingMode.REINHARD;
|
|
64
|
-
default: return MODULES.POSTPROCESSING.MODULE.ToneMappingMode.LINEAR;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
16
|
/**
|
|
69
17
|
* @category Effects
|
|
70
18
|
* @group Components
|
|
@@ -102,6 +50,7 @@ export class ToneMappingEffect extends PostProcessingEffect {
|
|
|
102
50
|
super.onEffectEnabled(ppmanager);
|
|
103
51
|
}
|
|
104
52
|
|
|
53
|
+
private _didCreateEffect = false;
|
|
105
54
|
onCreateEffect(): EffectProviderResult | undefined {
|
|
106
55
|
|
|
107
56
|
// TODO: this should be done in the PostProcessingHandler
|
|
@@ -118,10 +67,12 @@ export class ToneMappingEffect extends PostProcessingEffect {
|
|
|
118
67
|
}
|
|
119
68
|
|
|
120
69
|
|
|
70
|
+
this._didCreateEffect = true;
|
|
71
|
+
|
|
121
72
|
// ensure the effect tonemapping value is initialized
|
|
122
73
|
if (this.mode.isInitialized == false) {
|
|
123
|
-
const mode =
|
|
124
|
-
if(debug) console.log("[PostProcessing] Initializing ToneMapping mode to renderer.toneMapping", this.context.renderer.toneMapping + " → " + mode);
|
|
74
|
+
const mode = threeToNeedleToneMapping(this.context.renderer.toneMapping);
|
|
75
|
+
if (debug) console.log("[PostProcessing] Initializing ToneMapping mode to renderer.toneMapping", this.context.renderer.toneMapping + " → " + mode);
|
|
125
76
|
this.mode.initialize(mode);
|
|
126
77
|
}
|
|
127
78
|
|
|
@@ -130,26 +81,33 @@ export class ToneMappingEffect extends PostProcessingEffect {
|
|
|
130
81
|
mode: threeToneMappingToEffectMode(threeMode),
|
|
131
82
|
});
|
|
132
83
|
this.mode.onValueChanged = (newValue) => {
|
|
133
|
-
|
|
134
|
-
|
|
84
|
+
if (typeof newValue === "string") {
|
|
85
|
+
newValue = nameToThreeTonemapping(newValue);
|
|
86
|
+
tonemapping.mode = threeToneMappingToEffectMode(newValue);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
const threeMode = toThreeToneMapping(newValue);
|
|
90
|
+
tonemapping.mode = threeToneMappingToEffectMode(threeMode);
|
|
91
|
+
}
|
|
92
|
+
tonemapping.name = "ToneMapping (" + NEToneMappingMode[newValue] + ")";
|
|
135
93
|
if (debug) console.log("[PostProcessing] ToneMapping mode changed to", NEToneMappingMode[newValue], threeMode, tonemapping.mode);
|
|
136
94
|
};
|
|
137
95
|
if (debug) console.log("[PostProcessing] Use ToneMapping", NEToneMappingMode[this.mode.value], threeMode, tonemapping.mode, "renderer.tonemapping: " + this.context.renderer.toneMapping);
|
|
138
96
|
|
|
139
97
|
|
|
140
|
-
this.exposure.onValueChanged = (newValue) => {
|
|
141
|
-
this.context.renderer.toneMappingExposure = newValue;
|
|
142
|
-
};
|
|
143
|
-
|
|
144
98
|
return tonemapping;
|
|
145
99
|
}
|
|
146
100
|
|
|
147
101
|
|
|
148
102
|
onBeforeRender(): void {
|
|
149
|
-
if (this.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
this.
|
|
103
|
+
if (this._didCreateEffect) {
|
|
104
|
+
if (this.mode.overrideState)
|
|
105
|
+
this.context.renderer.toneMapping = toThreeToneMapping(this.mode.value);
|
|
106
|
+
if (this.exposure.overrideState && this.exposure.value !== undefined) {
|
|
107
|
+
const newValue = Math.max(0.01, this.exposure.value);
|
|
108
|
+
this.context.renderer.toneMappingExposure = newValue;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
153
111
|
}
|
|
154
112
|
|
|
155
113
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { ToneMappingMode } from "postprocessing";
|
|
2
|
+
import { ACESFilmicToneMapping, AgXToneMapping, LinearToneMapping, NeutralToneMapping, ReinhardToneMapping, ToneMapping } from "three";
|
|
3
|
+
|
|
4
|
+
import { MODULES } from "../../../engine/engine_modules.js";
|
|
5
|
+
|
|
6
|
+
export enum NEToneMappingMode {
|
|
7
|
+
None = 0,
|
|
8
|
+
Neutral = 1, // Neutral tonemapper, close to Reinhard
|
|
9
|
+
ACES = 2, // ACES Filmic reference tonemapper (custom approximation)
|
|
10
|
+
AgX = 3, // AgX Filmic tonemapper
|
|
11
|
+
KhronosNeutral = 4, // PBR Neural tonemapper
|
|
12
|
+
}
|
|
13
|
+
export type NEToneMappingModeNames = keyof typeof NEToneMappingMode;
|
|
14
|
+
|
|
15
|
+
const unknownTonemappingWarning = new Map<any, boolean>();
|
|
16
|
+
|
|
17
|
+
export function toThreeToneMapping(mode: NEToneMappingMode | undefined) {
|
|
18
|
+
switch (mode) {
|
|
19
|
+
case NEToneMappingMode.None:
|
|
20
|
+
return LinearToneMapping;
|
|
21
|
+
case NEToneMappingMode.Neutral:
|
|
22
|
+
return ReinhardToneMapping;
|
|
23
|
+
case NEToneMappingMode.ACES:
|
|
24
|
+
return ACESFilmicToneMapping;
|
|
25
|
+
case NEToneMappingMode.AgX:
|
|
26
|
+
return AgXToneMapping;
|
|
27
|
+
case NEToneMappingMode.KhronosNeutral:
|
|
28
|
+
return NeutralToneMapping;
|
|
29
|
+
default:
|
|
30
|
+
if(!unknownTonemappingWarning.has(mode)) {
|
|
31
|
+
unknownTonemappingWarning.set(mode, true);
|
|
32
|
+
console.warn("[Postprocessing] Unknown tone mapping mode", mode);
|
|
33
|
+
}
|
|
34
|
+
return NeutralToneMapping;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function threeToNeedleToneMapping(mode: ToneMapping | number | undefined): NEToneMappingMode {
|
|
39
|
+
switch (mode) {
|
|
40
|
+
case LinearToneMapping: return NEToneMappingMode.None;
|
|
41
|
+
case ACESFilmicToneMapping: return NEToneMappingMode.ACES;
|
|
42
|
+
case AgXToneMapping: return NEToneMappingMode.AgX;
|
|
43
|
+
case NeutralToneMapping: return NEToneMappingMode.Neutral;
|
|
44
|
+
case ReinhardToneMapping: return NEToneMappingMode.Neutral;
|
|
45
|
+
default: return NEToneMappingMode.None;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
export function threeToneMappingToEffectMode(mode: number | undefined): ToneMappingMode {
|
|
52
|
+
switch (mode) {
|
|
53
|
+
case LinearToneMapping: return MODULES.POSTPROCESSING.MODULE.ToneMappingMode.LINEAR;
|
|
54
|
+
case ACESFilmicToneMapping: return MODULES.POSTPROCESSING.MODULE.ToneMappingMode.ACES_FILMIC;
|
|
55
|
+
case AgXToneMapping: return MODULES.POSTPROCESSING.MODULE.ToneMappingMode.AGX;
|
|
56
|
+
case NeutralToneMapping: return MODULES.POSTPROCESSING.MODULE.ToneMappingMode.NEUTRAL;
|
|
57
|
+
case ReinhardToneMapping: return MODULES.POSTPROCESSING.MODULE.ToneMappingMode.REINHARD;
|
|
58
|
+
default: return MODULES.POSTPROCESSING.MODULE.ToneMappingMode.LINEAR;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -56,23 +56,23 @@ export abstract class PostProcessingEffect extends Component implements IEffectP
|
|
|
56
56
|
get isPostProcessingEffect() { return true; }
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
|
-
* The
|
|
59
|
+
* The order of this effect. The higher the order the later the effect will be applied in the post processing stack.
|
|
60
60
|
* This can be used to control the order of effects when multiple effects are applied.
|
|
61
|
-
* It is recommended to use the
|
|
62
|
-
* @default `undefined` (no specific
|
|
61
|
+
* It is recommended to use the PostProcessingEffectOrder constant to order your custom effects before or after built-in effects.
|
|
62
|
+
* @default `undefined` (no specific order set, will be applied in the order of registration)
|
|
63
63
|
*
|
|
64
64
|
* @example
|
|
65
65
|
* ```typescript
|
|
66
|
-
* import {
|
|
66
|
+
* import { PostProcessingEffectOrder } from "@needle-tools/engine"
|
|
67
67
|
*
|
|
68
68
|
* export class MyCustomEffect extends PostProcessingEffect {
|
|
69
|
-
*
|
|
70
|
-
*
|
|
69
|
+
* order: PostProcessingEffectOrder.Bloom + 1; // render after bloom
|
|
70
|
+
* // This will ensure that the effect is applied after the bloom effect in the post processing stack.
|
|
71
71
|
* // ... the rest of your effect code
|
|
72
72
|
* }
|
|
73
73
|
* ```
|
|
74
74
|
*/
|
|
75
|
-
|
|
75
|
+
order: number | undefined = undefined;
|
|
76
76
|
|
|
77
77
|
constructor(params: any = undefined) {
|
|
78
78
|
super();
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Camera as Camera3, HalfFloatType, NoToneMapping, Scene } from "three";
|
|
1
|
+
import { Effect, EffectComposer, Pass, ToneMappingEffect as _TonemappingEffect } from "postprocessing";
|
|
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";
|
|
12
|
-
import { orderEffects, PostprocessingEffectData } from "./utils.js";
|
|
13
|
+
import { orderEffects, PostprocessingEffectData, PostProcessingEffectOrder } from "./utils.js";
|
|
13
14
|
|
|
14
15
|
declare const NEEDLE_USE_POSTPROCESSING: boolean;
|
|
15
16
|
globalThis["NEEDLE_USE_POSTPROCESSING"] = globalThis["NEEDLE_USE_POSTPROCESSING"] !== undefined ? globalThis["NEEDLE_USE_POSTPROCESSING"] : true;
|
|
@@ -19,6 +20,7 @@ const debug = getParam("debugpost");
|
|
|
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
|
|
@@ -78,6 +80,9 @@ export class PostProcessingHandler {
|
|
|
78
80
|
if (typeof context.renderer[autoclearSetting] === "boolean") {
|
|
79
81
|
context.renderer.autoClear = context.renderer[autoclearSetting];
|
|
80
82
|
}
|
|
83
|
+
if (typeof context.renderer[previousToneMapping] === "number") {
|
|
84
|
+
context.renderer.toneMapping = context.renderer[previousToneMapping] as ToneMapping;
|
|
85
|
+
}
|
|
81
86
|
}
|
|
82
87
|
|
|
83
88
|
this._composer?.removeAllPasses();
|
|
@@ -153,14 +158,14 @@ export class PostProcessingHandler {
|
|
|
153
158
|
for (const effect of res) {
|
|
154
159
|
this._effects.push({
|
|
155
160
|
effect,
|
|
156
|
-
priority: component.
|
|
161
|
+
priority: component.order
|
|
157
162
|
});
|
|
158
163
|
}
|
|
159
164
|
}
|
|
160
165
|
else {
|
|
161
166
|
this._effects.push({
|
|
162
167
|
effect: res,
|
|
163
|
-
priority: component.
|
|
168
|
+
priority: component.order
|
|
164
169
|
});
|
|
165
170
|
}
|
|
166
171
|
}
|
|
@@ -171,14 +176,6 @@ export class PostProcessingHandler {
|
|
|
171
176
|
}
|
|
172
177
|
}
|
|
173
178
|
|
|
174
|
-
// Ensure that we have a tonemapping effect if the renderer is set to use a tone mapping
|
|
175
|
-
if (this.context.renderer.toneMapping != NoToneMapping) {
|
|
176
|
-
if (!this._effects.find(e => e instanceof MODULES.POSTPROCESSING.MODULE.ToneMappingEffect)) {
|
|
177
|
-
const tonemapping = new MODULES.POSTPROCESSING.MODULE.ToneMappingEffect();
|
|
178
|
-
this._effects.push({ effect: tonemapping });
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
179
|
this.applyEffects(context);
|
|
183
180
|
}
|
|
184
181
|
|
|
@@ -191,6 +188,18 @@ export class PostProcessingHandler {
|
|
|
191
188
|
get hasSmaaEffect() { return this._hasSmaaEffect; }
|
|
192
189
|
|
|
193
190
|
|
|
191
|
+
|
|
192
|
+
private _customInputBuffer: WebGLRenderTarget<Texture> | null = null;
|
|
193
|
+
private _customInputBufferId = 0;
|
|
194
|
+
private _multisampling: number = 0;
|
|
195
|
+
set multisampling(value: number) {
|
|
196
|
+
this._multisampling = value;
|
|
197
|
+
}
|
|
198
|
+
get multisampling() {
|
|
199
|
+
return this._multisampling;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
|
|
194
203
|
/** Build composer passes */
|
|
195
204
|
private applyEffects(context: Context) {
|
|
196
205
|
// Reset state
|
|
@@ -198,8 +207,7 @@ export class PostProcessingHandler {
|
|
|
198
207
|
this._anyPassHasNormal = false;
|
|
199
208
|
this._hasSmaaEffect = false;
|
|
200
209
|
|
|
201
|
-
|
|
202
|
-
if (effectsOrPasses.length <= 0) {
|
|
210
|
+
if (this._effects.length <= 0) {
|
|
203
211
|
return;
|
|
204
212
|
}
|
|
205
213
|
|
|
@@ -217,6 +225,21 @@ export class PostProcessingHandler {
|
|
|
217
225
|
}
|
|
218
226
|
renderer[autoclearSetting] = renderer.autoClear;
|
|
219
227
|
|
|
228
|
+
if (typeof renderer[previousToneMapping] === "number") {
|
|
229
|
+
renderer.toneMapping = renderer[previousToneMapping] as ToneMapping;
|
|
230
|
+
}
|
|
231
|
+
renderer[previousToneMapping] = renderer.toneMapping;
|
|
232
|
+
|
|
233
|
+
// Ensure that we have a tonemapping effect if the renderer is set to use a tone mapping
|
|
234
|
+
if (renderer.toneMapping != NoToneMapping) {
|
|
235
|
+
if (!this._effects.find(e => e instanceof MODULES.POSTPROCESSING.MODULE.ToneMappingEffect)) {
|
|
236
|
+
const tonemapping = new MODULES.POSTPROCESSING.MODULE.ToneMappingEffect();
|
|
237
|
+
tonemapping.name = `ToneMapping (${renderer.toneMapping})`;
|
|
238
|
+
tonemapping.mode = threeToneMappingToEffectMode(renderer.toneMapping);
|
|
239
|
+
this._effects.push({ effect: tonemapping, priority: PostProcessingEffectOrder.ToneMapping });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
220
243
|
// create composer and set active on context
|
|
221
244
|
if (!this._composer) {
|
|
222
245
|
// const hdrRenderTarget = new WebGLRenderTarget(window.innerWidth, window.innerHeight, { type: HalfFloatType });
|
|
@@ -236,7 +259,7 @@ export class PostProcessingHandler {
|
|
|
236
259
|
composer.setRenderer(renderer);
|
|
237
260
|
composer.setMainScene(scene);
|
|
238
261
|
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;
|
|
262
|
+
composer.multisampling = 0; // Disable multisampling by default
|
|
240
263
|
|
|
241
264
|
for (const prev of composer.passes)
|
|
242
265
|
prev.dispose();
|
|
@@ -244,17 +267,80 @@ export class PostProcessingHandler {
|
|
|
244
267
|
|
|
245
268
|
// Render to screen pass
|
|
246
269
|
const screenpass = new MODULES.POSTPROCESSING.MODULE.RenderPass(scene, cam);
|
|
247
|
-
screenpass.name = "
|
|
270
|
+
screenpass.name = "RenderPass";
|
|
248
271
|
screenpass.mainScene = scene;
|
|
249
272
|
composer.addPass(screenpass);
|
|
250
273
|
|
|
274
|
+
const screenPassRender = screenpass.render;
|
|
275
|
+
this._customInputBuffer?.dispose();
|
|
276
|
+
this._customInputBuffer = null;
|
|
277
|
+
screenpass.render = (renderer, inputBuffer, outputBuffer, deltaTime, stencilTest) => {
|
|
278
|
+
if (!inputBuffer) return;
|
|
279
|
+
|
|
280
|
+
// screenPassRender.call(screenpass, renderer, inputBuffer, outputBuffer, deltaTime, stencilTest);
|
|
281
|
+
// return;
|
|
282
|
+
|
|
283
|
+
// 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
|
|
284
|
+
inputBuffer.samples = 0;
|
|
285
|
+
if (outputBuffer) {
|
|
286
|
+
outputBuffer.samples = 0;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Make sure the input buffer is a WebGLRenderTarget with the correct settings
|
|
290
|
+
if (!this._customInputBuffer
|
|
291
|
+
|| this._customInputBuffer.width !== inputBuffer.width
|
|
292
|
+
|| this._customInputBuffer.height !== inputBuffer.height
|
|
293
|
+
|| this._customInputBuffer.samples !== this._multisampling
|
|
294
|
+
|| this._customInputBuffer.texture.format !== inputBuffer.texture.format
|
|
295
|
+
|| this._customInputBuffer.texture.type !== HalfFloatType
|
|
296
|
+
) {
|
|
297
|
+
this._customInputBuffer?.dispose();
|
|
298
|
+
|
|
299
|
+
this._customInputBuffer = new WebGLRenderTarget(inputBuffer.width, inputBuffer.height, {
|
|
300
|
+
format: inputBuffer.texture.format,
|
|
301
|
+
type: HalfFloatType,
|
|
302
|
+
depthBuffer: inputBuffer.depthBuffer,
|
|
303
|
+
depthTexture: inputBuffer.depthTexture
|
|
304
|
+
? new DepthTexture(inputBuffer.width, inputBuffer.height)
|
|
305
|
+
: undefined,
|
|
306
|
+
stencilBuffer: inputBuffer.stencilBuffer,
|
|
307
|
+
samples: Math.max(0, this._multisampling),
|
|
308
|
+
minFilter: inputBuffer.texture.minFilter ?? LinearFilter,
|
|
309
|
+
magFilter: inputBuffer.texture.magFilter ?? LinearFilter,
|
|
310
|
+
generateMipmaps: inputBuffer.texture.generateMipmaps,
|
|
311
|
+
});
|
|
312
|
+
this._customInputBufferId++;
|
|
313
|
+
this._customInputBuffer.texture.name = `CustomInputBuffer-${this._customInputBufferId}`;
|
|
314
|
+
if (this._customInputBuffer.depthTexture && inputBuffer.depthTexture) {
|
|
315
|
+
this._customInputBuffer.depthTexture.format = inputBuffer.depthTexture.format;
|
|
316
|
+
this._customInputBuffer.depthTexture.type = inputBuffer.depthTexture.type;
|
|
317
|
+
}
|
|
318
|
+
// https://github.com/pmndrs/postprocessing/blob/ad338df710ef41fee4e5d10ad2c2c299030d46ef/src/core/EffectComposer.js#L366
|
|
319
|
+
if (this._customInputBuffer.samples > 0)
|
|
320
|
+
(this._customInputBuffer as any).ignoreDepthForMultisampleCopy = false;
|
|
321
|
+
|
|
322
|
+
if (debug) console.warn(`[PostProcessing] Input buffer created with size ${this._customInputBuffer.width}x${this._customInputBuffer.height} and samples ${this._customInputBuffer.samples}`);
|
|
323
|
+
}
|
|
324
|
+
// Calling the original render function with the input buffer
|
|
325
|
+
screenPassRender.call(screenpass, renderer, this._customInputBuffer, outputBuffer, deltaTime, stencilTest);
|
|
326
|
+
// Blit the resulting buffer to the input buffer passed in by the composer so it's used for subsequent effects
|
|
327
|
+
Graphics.blit(this._customInputBuffer.texture, inputBuffer, {
|
|
328
|
+
renderer,
|
|
329
|
+
depthTexture: this._customInputBuffer.depthTexture,
|
|
330
|
+
depthWrite: true,
|
|
331
|
+
depthTest: true,
|
|
332
|
+
});
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
let foundTonemappingEffect = false;
|
|
251
337
|
try {
|
|
252
338
|
orderEffects(this._effects);
|
|
253
339
|
|
|
254
340
|
const effectsToMerge: Array<Effect> = [];
|
|
255
341
|
let hasConvolutionEffectInArray = false;
|
|
256
342
|
|
|
257
|
-
for (const entry of
|
|
343
|
+
for (const entry of this._effects) {
|
|
258
344
|
const ef = entry.effect;
|
|
259
345
|
|
|
260
346
|
if (ef instanceof MODULES.POSTPROCESSING.MODULE.SMAAEffect) {
|
|
@@ -264,6 +350,22 @@ export class PostProcessingHandler {
|
|
|
264
350
|
this._anyPassHasNormal = true;
|
|
265
351
|
}
|
|
266
352
|
|
|
353
|
+
|
|
354
|
+
// There can be only one tonemapping effect in the scene, so we can skip all others
|
|
355
|
+
if (ef instanceof MODULES.POSTPROCESSING.MODULE.ToneMappingEffect) {
|
|
356
|
+
// If we already have a tonemapping effect, we can skip this one
|
|
357
|
+
if (foundTonemappingEffect) continue;
|
|
358
|
+
foundTonemappingEffect = true;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// We can also not merge multiple effects of the same type in one pass
|
|
362
|
+
// So we first need to create a new pass with whatever effects we have so far
|
|
363
|
+
// 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
|
|
364
|
+
// const constructor = ef.constructor as Constructor<Effect | Pass>;
|
|
365
|
+
// if(effectsToMerge.find(e => e.constructor === constructor)) {
|
|
366
|
+
// // this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
|
|
367
|
+
// }
|
|
368
|
+
|
|
267
369
|
if (ef instanceof MODULES.POSTPROCESSING.MODULE.Effect) {
|
|
268
370
|
const attributes = ef.getAttributes();
|
|
269
371
|
const convolution = MODULES.POSTPROCESSING.MODULE.EffectAttribute.CONVOLUTION;
|
|
@@ -187,14 +187,12 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
|
|
|
187
187
|
|
|
188
188
|
this.context.composer.setMainScene(this.context.scene);
|
|
189
189
|
|
|
190
|
-
const composer = this.context.composer as EffectComposer;
|
|
191
|
-
|
|
192
190
|
if (this.multisampling === "auto") {
|
|
193
191
|
|
|
194
192
|
// If the postprocessing handler is using depth+normals (e.g. with SMAA) we ALWAYS disable multisampling to avoid ugly edges
|
|
195
193
|
if (this._postprocessing && (this._postprocessing.hasSmaaEffect)) {
|
|
196
|
-
if (
|
|
197
|
-
|
|
194
|
+
if (this._postprocessing.multisampling !== 0) {
|
|
195
|
+
this._postprocessing.multisampling = 0;
|
|
198
196
|
if (debug || isDevEnvironment()) {
|
|
199
197
|
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
198
|
}
|
|
@@ -206,45 +204,41 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
|
|
|
206
204
|
if (this.context.time.realtimeSinceStartup - this._componentEnabledTime > 2
|
|
207
205
|
&& timeSinceLastChange > .5
|
|
208
206
|
) {
|
|
209
|
-
const prev =
|
|
207
|
+
const prev = this._postprocessing.multisampling;
|
|
210
208
|
|
|
211
|
-
if (
|
|
209
|
+
if (this._postprocessing.multisampling > 0 && this.context.time.smoothedFps <= 50) {
|
|
212
210
|
this._multisampleAutoChangeTime = this.context.time.realtimeSinceStartup;
|
|
213
211
|
this._multisampleAutoDecreaseTime = this.context.time.realtimeSinceStartup;
|
|
214
|
-
let newMultiSample =
|
|
212
|
+
let newMultiSample = this._postprocessing.multisampling * .5;
|
|
215
213
|
newMultiSample = Math.floor(newMultiSample);
|
|
216
|
-
if (newMultiSample !=
|
|
217
|
-
|
|
214
|
+
if (newMultiSample != this._postprocessing.multisampling) {
|
|
215
|
+
this._postprocessing.multisampling = newMultiSample;
|
|
218
216
|
}
|
|
219
|
-
if (debug) console.debug(`[PostProcessing] Reduced multisampling from ${prev} to ${
|
|
217
|
+
if (debug) console.debug(`[PostProcessing] Reduced multisampling from ${prev} to ${this._postprocessing.multisampling}`);
|
|
220
218
|
}
|
|
221
219
|
// if performance is good for a while try increasing multisampling again
|
|
222
220
|
else if (timeSinceLastChange > 1
|
|
223
221
|
&& this.context.time.smoothedFps >= 59
|
|
224
|
-
&&
|
|
222
|
+
&& this._postprocessing.multisampling < this.context.renderer.capabilities.maxSamples
|
|
225
223
|
&& this.context.time.realtimeSinceStartup - this._multisampleAutoDecreaseTime > 10
|
|
226
224
|
) {
|
|
227
225
|
this._multisampleAutoChangeTime = this.context.time.realtimeSinceStartup;
|
|
228
|
-
let newMultiSample =
|
|
226
|
+
let newMultiSample = this._postprocessing.multisampling <= 0 ? 1 : this._postprocessing.multisampling * 2;
|
|
229
227
|
newMultiSample = Math.floor(newMultiSample);
|
|
230
|
-
if (newMultiSample !==
|
|
231
|
-
|
|
228
|
+
if (newMultiSample !== this._postprocessing.multisampling) {
|
|
229
|
+
this._postprocessing.multisampling = newMultiSample;
|
|
232
230
|
}
|
|
233
|
-
if (debug) console.debug(`[PostProcessing] Increased multisampling from ${prev} to ${
|
|
231
|
+
if (debug) console.debug(`[PostProcessing] Increased multisampling from ${prev} to ${this._postprocessing.multisampling}`);
|
|
234
232
|
}
|
|
235
233
|
}
|
|
236
234
|
}
|
|
237
235
|
}
|
|
238
236
|
else {
|
|
239
237
|
const newMultiSample = Math.max(0, Math.min(this.multisampling, this.context.renderer.capabilities.maxSamples));
|
|
240
|
-
if (newMultiSample !==
|
|
241
|
-
|
|
238
|
+
if (newMultiSample !== this._postprocessing.multisampling)
|
|
239
|
+
this._postprocessing.multisampling = newMultiSample;
|
|
242
240
|
}
|
|
243
241
|
|
|
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
|
-
|
|
248
242
|
// only set the main camera if any pass has a different camera
|
|
249
243
|
// trying to avoid doing this regularly since it involves doing potentially unnecessary work
|
|
250
244
|
// https://github.com/pmndrs/postprocessing/blob/3d3df0576b6d49aec9e763262d5a1ff7429fd91a/src/core/EffectComposer.js#L406
|
|
@@ -309,17 +303,16 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
|
|
|
309
303
|
|
|
310
304
|
this._applyPostQueue();
|
|
311
305
|
|
|
312
|
-
|
|
313
|
-
if (composer) {
|
|
306
|
+
if (this._postprocessing) {
|
|
314
307
|
if (this.multisampling === "auto") {
|
|
315
|
-
|
|
308
|
+
this._postprocessing.multisampling = DeviceUtilities.isMobileDevice()
|
|
316
309
|
? 2
|
|
317
310
|
: 4;
|
|
318
311
|
}
|
|
319
312
|
else {
|
|
320
|
-
|
|
313
|
+
this._postprocessing.multisampling = Math.max(0, Math.min(this.multisampling, this.context.renderer.capabilities.maxSamples));
|
|
321
314
|
}
|
|
322
|
-
if (debug) console.debug(`[PostProcessing] Set multisampling to ${
|
|
315
|
+
if (debug) console.debug(`[PostProcessing] Set multisampling to ${this._postprocessing.multisampling} (Is Mobile: ${DeviceUtilities.isMobileDevice()})`);
|
|
323
316
|
}
|
|
324
317
|
else if (debug) {
|
|
325
318
|
console.warn(`[PostProcessing] No composer found`);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from "./PostProcessingEffect.js";
|
|
2
2
|
export * from "./PostProcessingHandler.js"
|
|
3
|
-
export {
|
|
3
|
+
export { PostProcessingEffectOrder } from "./utils.js";
|
|
4
4
|
export { PostProcessingManager } from "./Volume.js"
|
|
5
5
|
export * from "./VolumeParameter.js"
|
|
6
6
|
export * from "./VolumeProfile.js";
|