@needle-tools/engine 4.6.1 → 4.6.2

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.
Files changed (103) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/generateMeshBVH.worker-BaNp_Xtp.js +25 -0
  3. package/dist/{gltf-progressive-Bm9eEfgu.min.js → gltf-progressive-Bl4okF1b.min.js} +1 -1
  4. package/dist/{gltf-progressive-GjIqwSG3.js → gltf-progressive-DSpdn0QT.js} +2 -2
  5. package/dist/{gltf-progressive-Dn6o99rH.umd.cjs → gltf-progressive-P8b8a0qY.umd.cjs} +1 -1
  6. package/dist/needle-engine.bundle-D0XWaCQs.min.js +1575 -0
  7. package/dist/{needle-engine.bundle-BVg46UWZ.js → needle-engine.bundle-DGcStTA7.js} +9715 -9555
  8. package/dist/needle-engine.bundle-DmYMLdWP.umd.cjs +1575 -0
  9. package/dist/needle-engine.js +352 -351
  10. package/dist/needle-engine.min.js +1 -1
  11. package/dist/needle-engine.umd.cjs +1 -1
  12. package/dist/{postprocessing-CRQa6Qxn.umd.cjs → postprocessing-CjW23fio.umd.cjs} +18 -18
  13. package/dist/{postprocessing-D6W1EyZ-.js → postprocessing-DYLNOL3W.js} +4 -3
  14. package/dist/{postprocessing-DF8AlRgW.min.js → postprocessing-xYQWCHFu.min.js} +26 -26
  15. package/dist/{three-DMrv-4ar.umd.cjs → three-B_hneGZr.umd.cjs} +4 -4
  16. package/dist/{three-Bz6X1mrw.js → three-DrqIzZTH.js} +4198 -4198
  17. package/dist/{three-Boa-jOq-.min.js → three-DuDKwKB8.min.js} +33 -33
  18. package/dist/{three-examples-GggCDHv0.js → three-examples-B50TT3Iu.js} +5 -5
  19. package/dist/{three-examples-DuVhxqft.min.js → three-examples-DaDLBuy6.min.js} +14 -14
  20. package/dist/{three-examples-C7ryg8vN.umd.cjs → three-examples-X3OadjXB.umd.cjs} +3 -3
  21. package/dist/{three-mesh-ui-CY6Izc7C.min.js → three-mesh-ui-B3p3gyUz.min.js} +1 -1
  22. package/dist/{three-mesh-ui-CwlN0FUC.umd.cjs → three-mesh-ui-CQiIQIlA.umd.cjs} +1 -1
  23. package/dist/{three-mesh-ui-CLNOfsWn.js → three-mesh-ui-CxuWt7m-.js} +1 -1
  24. package/dist/{vendor-zxXa3Dmr.min.js → vendor-BlSxe9JJ.min.js} +3 -3
  25. package/dist/{vendor-BSD1RQIh.js → vendor-BmYIgaS1.js} +3 -3
  26. package/dist/{vendor-DHr4aqIZ.umd.cjs → vendor-Cavtu3CP.umd.cjs} +3 -3
  27. package/lib/engine/engine_context.d.ts +4 -1
  28. package/lib/engine/engine_context.js +9 -2
  29. package/lib/engine/engine_context.js.map +1 -1
  30. package/lib/engine/engine_three_utils.d.ts +17 -14
  31. package/lib/engine/engine_three_utils.js +106 -53
  32. package/lib/engine/engine_three_utils.js.map +1 -1
  33. package/lib/engine/engine_tonemapping.d.ts +4 -0
  34. package/lib/engine/engine_tonemapping.js +21 -18
  35. package/lib/engine/engine_tonemapping.js.map +1 -1
  36. package/lib/engine/engine_utils.js.map +1 -1
  37. package/lib/engine/engine_utils_screenshot.d.ts +1 -1
  38. package/lib/engine/engine_utils_screenshot.js +11 -2
  39. package/lib/engine/engine_utils_screenshot.js.map +1 -1
  40. package/lib/engine/webcomponents/needle-engine.d.ts +4 -1
  41. package/lib/engine/webcomponents/needle-engine.extras.js +3 -3
  42. package/lib/engine/webcomponents/needle-engine.extras.js.map +1 -1
  43. package/lib/engine/webcomponents/needle-engine.js +11 -21
  44. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  45. package/lib/engine-components/CameraUtils.js.map +1 -1
  46. package/lib/engine-components/postprocessing/Effects/Antialiasing.js +3 -1
  47. package/lib/engine-components/postprocessing/Effects/Antialiasing.js.map +1 -1
  48. package/lib/engine-components/postprocessing/Effects/BloomEffect.d.ts +2 -2
  49. package/lib/engine-components/postprocessing/Effects/BloomEffect.js +5 -2
  50. package/lib/engine-components/postprocessing/Effects/BloomEffect.js.map +1 -1
  51. package/lib/engine-components/postprocessing/Effects/ColorAdjustments.d.ts +8 -0
  52. package/lib/engine-components/postprocessing/Effects/ColorAdjustments.js +27 -8
  53. package/lib/engine-components/postprocessing/Effects/ColorAdjustments.js.map +1 -1
  54. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.js +1 -0
  55. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.js.map +1 -1
  56. package/lib/engine-components/postprocessing/Effects/Sharpening.d.ts +1 -0
  57. package/lib/engine-components/postprocessing/Effects/Sharpening.js +4 -0
  58. package/lib/engine-components/postprocessing/Effects/Sharpening.js.map +1 -1
  59. package/lib/engine-components/postprocessing/Effects/Tonemapping.d.ts +2 -9
  60. package/lib/engine-components/postprocessing/Effects/Tonemapping.js +23 -71
  61. package/lib/engine-components/postprocessing/Effects/Tonemapping.js.map +1 -1
  62. package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.d.ts +13 -0
  63. package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.js +52 -0
  64. package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.js.map +1 -0
  65. package/lib/engine-components/postprocessing/PostProcessingEffect.d.ts +18 -0
  66. package/lib/engine-components/postprocessing/PostProcessingEffect.js +22 -3
  67. package/lib/engine-components/postprocessing/PostProcessingEffect.js.map +1 -1
  68. package/lib/engine-components/postprocessing/PostProcessingHandler.d.ts +20 -4
  69. package/lib/engine-components/postprocessing/PostProcessingHandler.js +209 -112
  70. package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
  71. package/lib/engine-components/postprocessing/Volume.d.ts +2 -1
  72. package/lib/engine-components/postprocessing/Volume.js +51 -33
  73. package/lib/engine-components/postprocessing/Volume.js.map +1 -1
  74. package/lib/engine-components/postprocessing/index.d.ts +1 -0
  75. package/lib/engine-components/postprocessing/index.js +1 -0
  76. package/lib/engine-components/postprocessing/index.js.map +1 -1
  77. package/lib/engine-components/postprocessing/utils.d.ts +43 -0
  78. package/lib/engine-components/postprocessing/utils.js +82 -0
  79. package/lib/engine-components/postprocessing/utils.js.map +1 -1
  80. package/package.json +1 -1
  81. package/src/engine/engine_context.ts +13 -4
  82. package/src/engine/engine_three_utils.ts +134 -58
  83. package/src/engine/engine_tonemapping.ts +23 -24
  84. package/src/engine/engine_utils.ts +2 -2
  85. package/src/engine/engine_utils_screenshot.ts +13 -3
  86. package/src/engine/webcomponents/needle-engine.extras.ts +3 -3
  87. package/src/engine/webcomponents/needle-engine.ts +14 -25
  88. package/src/engine-components/CameraUtils.ts +3 -3
  89. package/src/engine-components/postprocessing/Effects/Antialiasing.ts +3 -1
  90. package/src/engine-components/postprocessing/Effects/BloomEffect.ts +6 -4
  91. package/src/engine-components/postprocessing/Effects/ColorAdjustments.ts +24 -13
  92. package/src/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.ts +1 -0
  93. package/src/engine-components/postprocessing/Effects/Sharpening.ts +5 -0
  94. package/src/engine-components/postprocessing/Effects/Tonemapping.ts +26 -80
  95. package/src/engine-components/postprocessing/Effects/Tonemapping.utils.ts +60 -0
  96. package/src/engine-components/postprocessing/PostProcessingEffect.ts +23 -3
  97. package/src/engine-components/postprocessing/PostProcessingHandler.ts +239 -119
  98. package/src/engine-components/postprocessing/Volume.ts +54 -38
  99. package/src/engine-components/postprocessing/index.ts +2 -1
  100. package/src/engine-components/postprocessing/utils.ts +102 -2
  101. package/dist/generateMeshBVH.worker-Cdfpaq5W.js +0 -25
  102. package/dist/needle-engine.bundle-AOXFIsYk.umd.cjs +0 -1563
  103. package/dist/needle-engine.bundle-Dt52m2jf.min.js +0 -1563
@@ -0,0 +1,13 @@
1
+ import type { ToneMappingMode } from "postprocessing";
2
+ import { ToneMapping } from "three";
3
+ export declare enum NEToneMappingMode {
4
+ None = 0,
5
+ Neutral = 1,
6
+ ACES = 2,
7
+ AgX = 3,
8
+ KhronosNeutral = 4
9
+ }
10
+ export type NEToneMappingModeNames = keyof typeof NEToneMappingMode;
11
+ export declare function toThreeToneMapping(mode: NEToneMappingMode | undefined): 1 | 2 | 4 | 6 | 7;
12
+ export declare function threeToNeedleToneMapping(mode: ToneMapping | number | undefined): NEToneMappingMode;
13
+ export declare function threeToneMappingToEffectMode(mode: number | undefined): ToneMappingMode;
@@ -0,0 +1,52 @@
1
+ import { ACESFilmicToneMapping, AgXToneMapping, LinearToneMapping, NeutralToneMapping, ReinhardToneMapping } from "three";
2
+ import { MODULES } from "../../../engine/engine_modules.js";
3
+ export var NEToneMappingMode;
4
+ (function (NEToneMappingMode) {
5
+ NEToneMappingMode[NEToneMappingMode["None"] = 0] = "None";
6
+ NEToneMappingMode[NEToneMappingMode["Neutral"] = 1] = "Neutral";
7
+ NEToneMappingMode[NEToneMappingMode["ACES"] = 2] = "ACES";
8
+ NEToneMappingMode[NEToneMappingMode["AgX"] = 3] = "AgX";
9
+ NEToneMappingMode[NEToneMappingMode["KhronosNeutral"] = 4] = "KhronosNeutral";
10
+ })(NEToneMappingMode || (NEToneMappingMode = {}));
11
+ const unknownTonemappingWarning = new Map();
12
+ export function toThreeToneMapping(mode) {
13
+ switch (mode) {
14
+ case NEToneMappingMode.None:
15
+ return LinearToneMapping;
16
+ case NEToneMappingMode.Neutral:
17
+ return ReinhardToneMapping;
18
+ case NEToneMappingMode.ACES:
19
+ return ACESFilmicToneMapping;
20
+ case NEToneMappingMode.AgX:
21
+ return AgXToneMapping;
22
+ case NEToneMappingMode.KhronosNeutral:
23
+ return NeutralToneMapping;
24
+ default:
25
+ if (!unknownTonemappingWarning.has(mode)) {
26
+ unknownTonemappingWarning.set(mode, true);
27
+ console.warn("[Postprocessing] Unknown tone mapping mode", mode);
28
+ }
29
+ return NeutralToneMapping;
30
+ }
31
+ }
32
+ export function threeToNeedleToneMapping(mode) {
33
+ switch (mode) {
34
+ case LinearToneMapping: return NEToneMappingMode.None;
35
+ case ACESFilmicToneMapping: return NEToneMappingMode.ACES;
36
+ case AgXToneMapping: return NEToneMappingMode.AgX;
37
+ case NeutralToneMapping: return NEToneMappingMode.Neutral;
38
+ case ReinhardToneMapping: return NEToneMappingMode.Neutral;
39
+ default: return NEToneMappingMode.None;
40
+ }
41
+ }
42
+ export function threeToneMappingToEffectMode(mode) {
43
+ switch (mode) {
44
+ case LinearToneMapping: return MODULES.POSTPROCESSING.MODULE.ToneMappingMode.LINEAR;
45
+ case ACESFilmicToneMapping: return MODULES.POSTPROCESSING.MODULE.ToneMappingMode.ACES_FILMIC;
46
+ case AgXToneMapping: return MODULES.POSTPROCESSING.MODULE.ToneMappingMode.AGX;
47
+ case NeutralToneMapping: return MODULES.POSTPROCESSING.MODULE.ToneMappingMode.NEUTRAL;
48
+ case ReinhardToneMapping: return MODULES.POSTPROCESSING.MODULE.ToneMappingMode.REINHARD;
49
+ default: return MODULES.POSTPROCESSING.MODULE.ToneMappingMode.LINEAR;
50
+ }
51
+ }
52
+ //# sourceMappingURL=Tonemapping.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tonemapping.utils.js","sourceRoot":"","sources":["../../../../src/engine-components/postprocessing/Effects/Tonemapping.utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,mBAAmB,EAAe,MAAM,OAAO,CAAC;AAEvI,OAAO,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAC;AAE5D,MAAM,CAAN,IAAY,iBAMX;AAND,WAAY,iBAAiB;IACzB,yDAAQ,CAAA;IACR,+DAAW,CAAA;IACX,yDAAQ,CAAA;IACR,uDAAO,CAAA;IACP,6EAAkB,CAAA;AACtB,CAAC,EANW,iBAAiB,KAAjB,iBAAiB,QAM5B;AAGD,MAAM,yBAAyB,GAAG,IAAI,GAAG,EAAgB,CAAC;AAE1D,MAAM,UAAU,kBAAkB,CAAC,IAAmC;IAClE,QAAQ,IAAI,EAAE;QACV,KAAK,iBAAiB,CAAC,IAAI;YACvB,OAAO,iBAAiB,CAAC;QAC7B,KAAK,iBAAiB,CAAC,OAAO;YAC1B,OAAO,mBAAmB,CAAC;QAC/B,KAAK,iBAAiB,CAAC,IAAI;YACvB,OAAO,qBAAqB,CAAC;QACjC,KAAK,iBAAiB,CAAC,GAAG;YACtB,OAAO,cAAc,CAAC;QAC1B,KAAK,iBAAiB,CAAC,cAAc;YACjC,OAAO,kBAAkB,CAAC;QAC9B;YACI,IAAG,CAAC,yBAAyB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;gBACrC,yBAAyB,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAC1C,OAAO,CAAC,IAAI,CAAC,4CAA4C,EAAE,IAAI,CAAC,CAAC;aACpE;YACD,OAAO,kBAAkB,CAAC;KACjC;AACL,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,IAAsC;IAC3E,QAAQ,IAAI,EAAE;QACV,KAAK,iBAAiB,CAAC,CAAC,OAAO,iBAAiB,CAAC,IAAI,CAAC;QACtD,KAAK,qBAAqB,CAAC,CAAC,OAAO,iBAAiB,CAAC,IAAI,CAAC;QAC1D,KAAK,cAAc,CAAC,CAAC,OAAO,iBAAiB,CAAC,GAAG,CAAC;QAClD,KAAK,kBAAkB,CAAC,CAAC,OAAO,iBAAiB,CAAC,OAAO,CAAC;QAC1D,KAAK,mBAAmB,CAAC,CAAC,OAAO,iBAAiB,CAAC,OAAO,CAAC;QAC3D,OAAO,CAAC,CAAC,OAAO,iBAAiB,CAAC,IAAI,CAAC;KAC1C;AAEL,CAAC;AAGD,MAAM,UAAU,4BAA4B,CAAC,IAAwB;IACjE,QAAQ,IAAI,EAAE;QACV,KAAK,iBAAiB,CAAC,CAAC,OAAO,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC;QACpF,KAAK,qBAAqB,CAAC,CAAC,OAAO,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,eAAe,CAAC,WAAW,CAAC;QAC7F,KAAK,cAAc,CAAC,CAAC,OAAO,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC;QAC9E,KAAK,kBAAkB,CAAC,CAAC,OAAO,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC;QACtF,KAAK,mBAAmB,CAAC,CAAC,OAAO,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC;QACxF,OAAO,CAAC,CAAC,OAAO,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC;KACxE;AACL,CAAC"}
@@ -43,6 +43,24 @@ export interface IEffectProvider {
43
43
  */
44
44
  export declare abstract class PostProcessingEffect extends Component implements IEffectProvider, IEditorModification {
45
45
  get isPostProcessingEffect(): boolean;
46
+ /**
47
+ * The order of this effect. The higher the order the later the effect will be applied in the post processing stack.
48
+ * This can be used to control the order of effects when multiple effects are applied.
49
+ * It is recommended to use the PostProcessingEffectOrder constant to order your custom effects before or after built-in effects.
50
+ * @default `undefined` (no specific order set, will be applied in the order of registration)
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * import { PostProcessingEffectOrder } from "@needle-tools/engine"
55
+ *
56
+ * export class MyCustomEffect extends PostProcessingEffect {
57
+ * order: PostProcessingEffectOrder.Bloom + 1; // render after bloom
58
+ * // This will ensure that the effect is applied after the bloom effect in the post processing stack.
59
+ * // ... the rest of your effect code
60
+ * }
61
+ * ```
62
+ */
63
+ order: number | undefined;
46
64
  constructor(params?: any);
47
65
  abstract get typeName(): string;
48
66
  /**
@@ -41,6 +41,24 @@ const debug = getParam("debugpost");
41
41
  */
42
42
  export class PostProcessingEffect extends Component {
43
43
  get isPostProcessingEffect() { return true; }
44
+ /**
45
+ * The order of this effect. The higher the order the later the effect will be applied in the post processing stack.
46
+ * This can be used to control the order of effects when multiple effects are applied.
47
+ * It is recommended to use the PostProcessingEffectOrder constant to order your custom effects before or after built-in effects.
48
+ * @default `undefined` (no specific order set, will be applied in the order of registration)
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * import { PostProcessingEffectOrder } from "@needle-tools/engine"
53
+ *
54
+ * export class MyCustomEffect extends PostProcessingEffect {
55
+ * order: PostProcessingEffectOrder.Bloom + 1; // render after bloom
56
+ * // This will ensure that the effect is applied after the bloom effect in the post processing stack.
57
+ * // ... the rest of your effect code
58
+ * }
59
+ * ```
60
+ */
61
+ order = undefined;
44
62
  constructor(params = undefined) {
45
63
  super();
46
64
  if (params) {
@@ -67,7 +85,7 @@ export class PostProcessingEffect extends Component {
67
85
  onEnable() {
68
86
  super.onEnable();
69
87
  if (debug)
70
- console.warn("onEnable effect", this, this.__internalDidAwakeAndStart);
88
+ console.warn("Enable", this.constructor.name + (!this.__internalDidAwakeAndStart ? " (awake)" : ""));
71
89
  // Dont override the serialized value by enabling (we could also just disable this component / map enabled to active)
72
90
  if (this.__internalDidAwakeAndStart)
73
91
  this.active = true;
@@ -76,7 +94,7 @@ export class PostProcessingEffect extends Component {
76
94
  onDisable() {
77
95
  super.onDisable();
78
96
  if (debug)
79
- console.warn("onDisable effect", this);
97
+ console.warn("Disable", this.constructor.name);
80
98
  this._manager?.removeEffect(this);
81
99
  this.active = false;
82
100
  }
@@ -85,7 +103,8 @@ export class PostProcessingEffect extends Component {
85
103
  this._manager = manager;
86
104
  else if (!this._manager)
87
105
  this._manager = getPostProcessingManager(this);
88
- this._manager?.addEffect(this);
106
+ this._manager.addEffect(this);
107
+ this._manager.dirty = true;
89
108
  }
90
109
  /** override to initialize bindings on parameters */
91
110
  init() { }
@@ -1 +1 @@
1
- {"version":3,"file":"PostProcessingEffect.js","sourceRoot":"","sources":["../../../src/engine-components/postprocessing/PostProcessingEffect.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PostProcessingEffect.js","sourceRoot":"","sources":["../../../src/engine-components/postprocessing/PostProcessingEffect.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { EffectComposer } from "postprocessing";
1
+ import type { Effect, EffectComposer } from "postprocessing";
2
2
  import { Context } from "../../engine/engine_setup.js";
3
3
  import { PostProcessingEffect } from "./PostProcessingEffect.js";
4
4
  /**
@@ -7,19 +7,35 @@ import { PostProcessingEffect } from "./PostProcessingEffect.js";
7
7
  export declare class PostProcessingHandler {
8
8
  private _composer;
9
9
  private _lastVolumeComponents?;
10
- private _effects;
10
+ private readonly _effects;
11
+ /**
12
+ * Returns true if a specific effect is currently active in the post processing stack.
13
+ */
14
+ getEffectIsActive(effect: Effect): boolean;
11
15
  get isActive(): boolean;
12
16
  get composer(): EffectComposer | null;
13
17
  private _isActive;
14
18
  private readonly context;
15
19
  constructor(context: Context);
16
20
  apply(components: PostProcessingEffect[]): Promise<void>;
17
- unapply(): void;
21
+ unapply(dispose?: boolean): void;
18
22
  dispose(): void;
19
23
  private onApply;
24
+ private _anyPassHasDepth;
25
+ private _anyPassHasNormal;
26
+ private _hasSmaaEffect;
27
+ get anyPassHasDepth(): boolean;
28
+ get anyPassHasNormal(): boolean;
29
+ get hasSmaaEffect(): boolean;
30
+ private _customInputBuffer;
31
+ private _customInputBufferId;
32
+ private _multisampling;
33
+ set multisampling(value: number);
34
+ get multisampling(): number;
20
35
  /** Build composer passes */
21
36
  private applyEffects;
22
- private orderEffects;
37
+ /** Should be called before `composer.addPass()` to create an effect pass with all previously collected effects that can be merged up to that point */
38
+ private createPassForMergeableEffects;
23
39
  private _menuEntry;
24
40
  private _passIndices;
25
41
  private _onCreateEffectsDebug;
@@ -1,13 +1,16 @@
1
- import { HalfFloatType, NoToneMapping } from "three";
1
+ import { DepthTexture, HalfFloatType, LinearFilter, NoToneMapping, WebGLRenderTarget } from "three";
2
2
  import { showBalloonWarning } from "../../engine/debug/index.js";
3
3
  // import { internal_SetSharpeningEffectModule } from "./Effects/Sharpening.js";
4
4
  import { MODULES } from "../../engine/engine_modules.js";
5
+ import { Graphics } from "../../engine/engine_three_utils.js";
5
6
  import { getParam } from "../../engine/engine_utils.js";
7
+ import { threeToneMappingToEffectMode } from "./Effects/Tonemapping.utils.js";
8
+ import { orderEffects, PostProcessingEffectOrder } from "./utils.js";
6
9
  globalThis["NEEDLE_USE_POSTPROCESSING"] = globalThis["NEEDLE_USE_POSTPROCESSING"] !== undefined ? globalThis["NEEDLE_USE_POSTPROCESSING"] : true;
7
10
  const debug = getParam("debugpost");
8
- const dontMergePasses = getParam("debugpostpasses");
9
11
  const activeKey = Symbol("needle:postprocessing-handler");
10
12
  const autoclearSetting = Symbol("needle:previous-autoclear-state");
13
+ const previousToneMapping = Symbol("needle:previous-tone-mapping");
11
14
  /**
12
15
  * PostProcessingHandler is responsible for applying post processing effects to the scene. It is internally used by the {@link Volume} component
13
16
  */
@@ -15,6 +18,14 @@ export class PostProcessingHandler {
15
18
  _composer = null;
16
19
  _lastVolumeComponents;
17
20
  _effects = [];
21
+ /**
22
+ * Returns true if a specific effect is currently active in the post processing stack.
23
+ */
24
+ getEffectIsActive(effect) {
25
+ if (!effect)
26
+ return false;
27
+ return this._isActive && this._effects.some(e => e.effect === effect);
28
+ }
18
29
  get isActive() {
19
30
  return this._isActive;
20
31
  }
@@ -44,7 +55,7 @@ export class PostProcessingHandler {
44
55
  this._isActive = true;
45
56
  return this.onApply(this.context, components);
46
57
  }
47
- unapply() {
58
+ unapply(dispose = true) {
48
59
  if (debug)
49
60
  console.log("Unapplying postprocessing effects");
50
61
  this._isActive = false;
@@ -58,19 +69,25 @@ export class PostProcessingHandler {
58
69
  const active = context[activeKey];
59
70
  if (active === this) {
60
71
  delete context[activeKey];
72
+ // Restore the auto clear setting
73
+ if (typeof context.renderer[autoclearSetting] === "boolean") {
74
+ context.renderer.autoClear = context.renderer[autoclearSetting];
75
+ }
76
+ if (typeof context.renderer[previousToneMapping] === "number") {
77
+ context.renderer.toneMapping = context.renderer[previousToneMapping];
78
+ }
61
79
  }
80
+ this._composer?.removeAllPasses();
81
+ if (dispose)
82
+ this._composer?.dispose();
62
83
  if (context.composer === this._composer) {
63
- context.composer?.dispose();
64
84
  context.composer = null;
65
85
  }
66
- if (typeof context.renderer[autoclearSetting] === "boolean") {
67
- context.renderer.autoClear = context.renderer[autoclearSetting];
68
- }
69
86
  }
70
87
  dispose() {
71
- this.unapply();
88
+ this.unapply(true);
72
89
  for (const effect of this._effects) {
73
- effect.dispose();
90
+ effect.effect.dispose();
74
91
  }
75
92
  this._effects.length = 0;
76
93
  this._composer = null;
@@ -118,10 +135,19 @@ export class PostProcessingHandler {
118
135
  if (!res)
119
136
  continue;
120
137
  if (Array.isArray(res)) {
121
- this._effects.push(...res);
138
+ for (const effect of res) {
139
+ this._effects.push({
140
+ effect,
141
+ priority: component.order
142
+ });
143
+ }
144
+ }
145
+ else {
146
+ this._effects.push({
147
+ effect: res,
148
+ priority: component.order
149
+ });
122
150
  }
123
- else
124
- this._effects.push(res);
125
151
  }
126
152
  }
127
153
  else {
@@ -129,20 +155,32 @@ export class PostProcessingHandler {
129
155
  showBalloonWarning("Volume component is not a VolumeComponent: " + component["__type"]);
130
156
  }
131
157
  }
132
- // Ensure that we have a tonemapping effect if the renderer is set to use a tone mapping
133
- if (this.context.renderer.toneMapping != NoToneMapping) {
134
- if (!this._effects.find(e => e instanceof MODULES.POSTPROCESSING.MODULE.ToneMappingEffect)) {
135
- const tonemapping = new MODULES.POSTPROCESSING.MODULE.ToneMappingEffect();
136
- this._effects.push(tonemapping);
137
- }
138
- }
139
158
  this.applyEffects(context);
140
159
  }
160
+ _anyPassHasDepth = false;
161
+ _anyPassHasNormal = false;
162
+ _hasSmaaEffect = false;
163
+ get anyPassHasDepth() { return this._anyPassHasDepth; }
164
+ get anyPassHasNormal() { return this._anyPassHasNormal; }
165
+ get hasSmaaEffect() { return this._hasSmaaEffect; }
166
+ _customInputBuffer = null;
167
+ _customInputBufferId = 0;
168
+ _multisampling = 0;
169
+ set multisampling(value) {
170
+ this._multisampling = value;
171
+ }
172
+ get multisampling() {
173
+ return this._multisampling;
174
+ }
141
175
  /** Build composer passes */
142
176
  applyEffects(context) {
143
- const effectsOrPasses = this._effects;
144
- if (effectsOrPasses.length <= 0)
177
+ // Reset state
178
+ this._anyPassHasDepth = false;
179
+ this._anyPassHasNormal = false;
180
+ this._hasSmaaEffect = false;
181
+ if (this._effects.length <= 0) {
145
182
  return;
183
+ }
146
184
  const camera = context.mainCameraComponent;
147
185
  const renderer = context.renderer;
148
186
  const scene = context.scene;
@@ -150,7 +188,24 @@ export class PostProcessingHandler {
150
188
  // Store the auto clear setting because the postprocessing composer just disables it
151
189
  // and when we disable postprocessing we want to restore the original setting
152
190
  // https://github.com/pmndrs/postprocessing/blob/271944b74b543a5b743a62803a167b60cc6bb4ee/src/core/EffectComposer.js#L230C12-L230C12
191
+ // First we need to get the previously set autoClear setting, if it exists
192
+ if (typeof renderer[autoclearSetting] === "boolean") {
193
+ renderer.autoClear = renderer[autoclearSetting];
194
+ }
153
195
  renderer[autoclearSetting] = renderer.autoClear;
196
+ if (typeof renderer[previousToneMapping] === "number") {
197
+ renderer.toneMapping = renderer[previousToneMapping];
198
+ }
199
+ renderer[previousToneMapping] = renderer.toneMapping;
200
+ // Ensure that we have a tonemapping effect if the renderer is set to use a tone mapping
201
+ if (renderer.toneMapping != NoToneMapping) {
202
+ if (!this._effects.find(e => e instanceof MODULES.POSTPROCESSING.MODULE.ToneMappingEffect)) {
203
+ const tonemapping = new MODULES.POSTPROCESSING.MODULE.ToneMappingEffect();
204
+ tonemapping.name = `ToneMapping (${renderer.toneMapping})`;
205
+ tonemapping.mode = threeToneMappingToEffectMode(renderer.toneMapping);
206
+ this._effects.push({ effect: tonemapping, priority: PostProcessingEffectOrder.ToneMapping });
207
+ }
208
+ }
154
209
  // create composer and set active on context
155
210
  if (!this._composer) {
156
211
  // const hdrRenderTarget = new WebGLRenderTarget(window.innerWidth, window.innerHeight, { type: HalfFloatType });
@@ -168,67 +223,146 @@ export class PostProcessingHandler {
168
223
  composer.setRenderer(renderer);
169
224
  composer.setMainScene(scene);
170
225
  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)
226
+ composer.multisampling = 0; // Disable multisampling by default
171
227
  for (const prev of composer.passes)
172
228
  prev.dispose();
173
229
  composer.removeAllPasses();
174
230
  // Render to screen pass
175
231
  const screenpass = new MODULES.POSTPROCESSING.MODULE.RenderPass(scene, cam);
176
- screenpass.name = "Render To Screen";
232
+ screenpass.name = "RenderPass";
177
233
  screenpass.mainScene = scene;
178
234
  composer.addPass(screenpass);
179
- const automaticEffectsOrdering = true;
180
- if (automaticEffectsOrdering && !dontMergePasses) {
181
- try {
182
- this.orderEffects();
183
- const effects = [];
184
- for (const ef of effectsOrPasses) {
185
- if (ef instanceof MODULES.POSTPROCESSING.MODULE.Effect) {
186
- effects.push(ef);
187
- }
188
- else if (ef instanceof MODULES.POSTPROCESSING.MODULE.Pass) {
189
- ef.renderToScreen = false;
190
- composer.addPass(ef);
191
- }
192
- else {
193
- // seems some effects are not correctly typed, but three can deal with them,
194
- // so we might need to just pass them through
195
- composer.addPass(ef);
196
- }
197
- }
198
- // create and apply uber pass
199
- if (effects.length > 0) {
200
- const pass = new MODULES.POSTPROCESSING.MODULE.EffectPass(cam, ...effects);
201
- pass.name = effects.map(e => e.name).join(", ");
202
- pass.mainScene = scene;
203
- pass.enabled = true;
204
- pass.renderToScreen = false;
205
- composer.addPass(pass);
235
+ const screenPassRender = screenpass.render;
236
+ this._customInputBuffer?.dispose();
237
+ this._customInputBuffer = null;
238
+ screenpass.render = (renderer, inputBuffer, outputBuffer, deltaTime, stencilTest) => {
239
+ if (!inputBuffer)
240
+ return;
241
+ // screenPassRender.call(screenpass, renderer, inputBuffer, outputBuffer, deltaTime, stencilTest);
242
+ // return;
243
+ // 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
244
+ inputBuffer.samples = 0;
245
+ if (outputBuffer) {
246
+ outputBuffer.samples = 0;
247
+ }
248
+ // Make sure the input buffer is a WebGLRenderTarget with the correct settings
249
+ if (!this._customInputBuffer
250
+ || this._customInputBuffer.width !== inputBuffer.width
251
+ || this._customInputBuffer.height !== inputBuffer.height
252
+ || this._customInputBuffer.samples !== this._multisampling
253
+ || this._customInputBuffer.texture.format !== inputBuffer.texture.format
254
+ || this._customInputBuffer.texture.type !== HalfFloatType) {
255
+ this._customInputBuffer?.dispose();
256
+ this._customInputBuffer = new WebGLRenderTarget(inputBuffer.width, inputBuffer.height, {
257
+ format: inputBuffer.texture.format,
258
+ type: HalfFloatType,
259
+ depthBuffer: inputBuffer.depthBuffer,
260
+ depthTexture: inputBuffer.depthTexture
261
+ ? new DepthTexture(inputBuffer.width, inputBuffer.height)
262
+ : undefined,
263
+ stencilBuffer: inputBuffer.stencilBuffer,
264
+ samples: Math.max(0, this._multisampling),
265
+ minFilter: inputBuffer.texture.minFilter ?? LinearFilter,
266
+ magFilter: inputBuffer.texture.magFilter ?? LinearFilter,
267
+ generateMipmaps: inputBuffer.texture.generateMipmaps,
268
+ });
269
+ this._customInputBufferId++;
270
+ this._customInputBuffer.texture.name = `CustomInputBuffer-${this._customInputBufferId}`;
271
+ if (this._customInputBuffer.depthTexture && inputBuffer.depthTexture) {
272
+ this._customInputBuffer.depthTexture.format = inputBuffer.depthTexture.format;
273
+ this._customInputBuffer.depthTexture.type = inputBuffer.depthTexture.type;
206
274
  }
275
+ // https://github.com/pmndrs/postprocessing/blob/ad338df710ef41fee4e5d10ad2c2c299030d46ef/src/core/EffectComposer.js#L366
276
+ if (this._customInputBuffer.samples > 0)
277
+ this._customInputBuffer.ignoreDepthForMultisampleCopy = false;
278
+ if (debug)
279
+ console.warn(`[PostProcessing] Input buffer created with size ${this._customInputBuffer.width}x${this._customInputBuffer.height} and samples ${this._customInputBuffer.samples}`);
207
280
  }
208
- catch (e) {
209
- console.error("Error while applying postprocessing effects", e);
210
- composer.removeAllPasses();
281
+ // Calling the original render function with the input buffer
282
+ screenPassRender.call(screenpass, renderer, this._customInputBuffer, outputBuffer, deltaTime, stencilTest);
283
+ // Blit the resulting buffer to the input buffer passed in by the composer so it's used for subsequent effects
284
+ Graphics.blit(this._customInputBuffer.texture, inputBuffer, {
285
+ renderer,
286
+ depthTexture: this._customInputBuffer.depthTexture,
287
+ depthWrite: true,
288
+ depthTest: true,
289
+ });
290
+ };
291
+ try {
292
+ orderEffects(this._effects);
293
+ let foundTonemappingEffect = false;
294
+ let activeTonemappingEffect = null;
295
+ for (let i = this._effects.length - 1; i >= 0; i--) {
296
+ const ef = this._effects[i].effect;
297
+ if (ef instanceof MODULES.POSTPROCESSING.MODULE.ToneMappingEffect) {
298
+ // If we already have a tonemapping effect, we can skip this one
299
+ if (foundTonemappingEffect) {
300
+ if (debug)
301
+ console.warn(`[PostProcessing] Found multiple tonemapping effects in the scene: ${ef.name} and ${activeTonemappingEffect?.name}. Only the last one added will be used.`);
302
+ this._effects.splice(i, 1);
303
+ continue;
304
+ }
305
+ activeTonemappingEffect = ef;
306
+ foundTonemappingEffect = true;
307
+ }
211
308
  }
212
- }
213
- else {
214
- // we still want to sort passes, but we do not want to merge them for debugging
215
- if (automaticEffectsOrdering)
216
- this.orderEffects();
217
- for (const ef of effectsOrPasses) {
309
+ const effectsToMerge = [];
310
+ let hasConvolutionEffectInArray = false;
311
+ for (const entry of this._effects) {
312
+ const ef = entry.effect;
313
+ if (ef instanceof MODULES.POSTPROCESSING.MODULE.SMAAEffect) {
314
+ this._hasSmaaEffect = true;
315
+ }
316
+ else if (ef instanceof MODULES.POSTPROCESSING.MODULE.NormalPass) {
317
+ this._anyPassHasNormal = true;
318
+ }
319
+ // There can be only one tonemapping effect in the scene, so we can skip all others
320
+ if (ef instanceof MODULES.POSTPROCESSING.MODULE.ToneMappingEffect && activeTonemappingEffect !== ef) {
321
+ // If we already have a tonemapping effect, we can skip this one
322
+ continue;
323
+ }
324
+ // We can also not merge multiple effects of the same type in one pass
325
+ // So we first need to create a new pass with whatever effects we have so far
326
+ // 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
327
+ // const constructor = ef.constructor as Constructor<Effect | Pass>;
328
+ // if(effectsToMerge.find(e => e.constructor === constructor)) {
329
+ // // this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
330
+ // }
218
331
  if (ef instanceof MODULES.POSTPROCESSING.MODULE.Effect) {
219
- const pass = new MODULES.POSTPROCESSING.MODULE.EffectPass(cam, ef);
220
- pass.name = ef.name;
221
- composer.addPass(pass);
332
+ const attributes = ef.getAttributes();
333
+ const convolution = MODULES.POSTPROCESSING.MODULE.EffectAttribute.CONVOLUTION;
334
+ if (attributes & convolution) {
335
+ if (debug)
336
+ console.log("[PostProcessing] Convolution effect: " + ef.name);
337
+ if (hasConvolutionEffectInArray) {
338
+ if (debug)
339
+ console.log("[PostProcessing] Merging effects with convolution", effectsToMerge.map(e => e.name).join(", "));
340
+ this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
341
+ }
342
+ hasConvolutionEffectInArray = true;
343
+ }
344
+ // Otherwise we can merge it
345
+ effectsToMerge.push(ef);
222
346
  }
223
347
  else if (ef instanceof MODULES.POSTPROCESSING.MODULE.Pass) {
348
+ hasConvolutionEffectInArray = false;
349
+ this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
224
350
  ef.renderToScreen = false;
225
351
  composer.addPass(ef);
226
352
  }
227
- else
353
+ else {
228
354
  // seems some effects are not correctly typed, but three can deal with them,
229
- // so we just pass them through
355
+ // so we might need to just pass them through
356
+ hasConvolutionEffectInArray = false;
357
+ this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
230
358
  composer.addPass(ef);
359
+ }
231
360
  }
361
+ this.createPassForMergeableEffects(effectsToMerge, composer, cam, scene);
362
+ }
363
+ catch (e) {
364
+ console.error("Error while applying postprocessing effects", e);
365
+ composer.removeAllPasses();
232
366
  }
233
367
  // 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)
234
368
  for (let i = 0; i < composer.passes.length; i++) {
@@ -241,6 +375,7 @@ export class PostProcessingHandler {
241
375
  // Some effects have a autosetGamma property that we can use to set the gamma correction
242
376
  pass.autosetGamma = isLast;
243
377
  }
378
+ this._anyPassHasDepth ||= pass.needsDepthTexture;
244
379
  }
245
380
  // DEBUG LAND BELOW
246
381
  if (debug)
@@ -248,54 +383,17 @@ export class PostProcessingHandler {
248
383
  if (debug)
249
384
  this._onCreateEffectsDebug(this._composer, cam);
250
385
  }
251
- orderEffects() {
252
- if (debug === "verbose")
253
- console.debug("Before ordering effects", [...this._effects]);
254
- // Order of effects for correct results.
255
- // Aligned with https://github.com/pmndrs/postprocessing/wiki/Effect-Merging#effect-execution-order
256
- // We can not put this into global scope because then the module might not yet be initialized
257
- effectsOrder ??= [
258
- MODULES.POSTPROCESSING.MODULE.NormalPass,
259
- MODULES.POSTPROCESSING.MODULE.DepthDownsamplingPass,
260
- MODULES.POSTPROCESSING.MODULE.SMAAEffect,
261
- MODULES.POSTPROCESSING.MODULE.SSAOEffect,
262
- MODULES.POSTPROCESSING_AO.MODULE.N8AOPostPass,
263
- MODULES.POSTPROCESSING.MODULE.TiltShiftEffect,
264
- MODULES.POSTPROCESSING.MODULE.DepthOfFieldEffect,
265
- MODULES.POSTPROCESSING.MODULE.ChromaticAberrationEffect,
266
- MODULES.POSTPROCESSING.MODULE.BloomEffect,
267
- MODULES.POSTPROCESSING.MODULE.SelectiveBloomEffect,
268
- MODULES.POSTPROCESSING.MODULE.VignetteEffect,
269
- MODULES.POSTPROCESSING.MODULE.PixelationEffect,
270
- MODULES.POSTPROCESSING.MODULE.ToneMappingEffect,
271
- MODULES.POSTPROCESSING.MODULE.HueSaturationEffect,
272
- MODULES.POSTPROCESSING.MODULE.BrightnessContrastEffect,
273
- // __SHARPENING_MODULE._SharpeningEffect,
274
- ];
275
- // TODO: enforce correct order of effects (e.g. DOF before Bloom)
276
- const effects = this._effects;
277
- effects.sort((a, b) => {
278
- // we use find index here because sometimes constructor names are prefixed with `_`
279
- // 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)
280
- const aidx = effectsOrder.findIndex(e => a.constructor.name.endsWith(e.name));
281
- const bidx = effectsOrder.findIndex(e => b.constructor.name.endsWith(e.name));
282
- // Unknown effects should be rendered first
283
- if (aidx < 0) {
284
- if (debug)
285
- console.warn("Unknown effect found: ", a.constructor.name);
286
- return -1;
287
- }
288
- else if (bidx < 0) {
289
- if (debug)
290
- console.warn("Unknown effect found: ", b.constructor.name);
291
- return 1;
292
- }
293
- // if (aidx < 0) return 1;
294
- // if (bidx < 0) return -1;
295
- return aidx - bidx;
296
- });
297
- if (debug === "verbose")
298
- console.debug("After ordering effects", [...this._effects]);
386
+ /** Should be called before `composer.addPass()` to create an effect pass with all previously collected effects that can be merged up to that point */
387
+ createPassForMergeableEffects(effects, composer, camera, scene) {
388
+ if (effects.length > 0) {
389
+ const pass = new MODULES.POSTPROCESSING.MODULE.EffectPass(camera, ...effects);
390
+ pass.name = effects.map(e => e.name).join(", ");
391
+ pass.mainScene = scene;
392
+ pass.enabled = true;
393
+ pass.renderToScreen = false;
394
+ composer.addPass(pass);
395
+ effects.length = 0; // Clear effects after adding them to the pass
396
+ }
299
397
  }
300
398
  _menuEntry = null;
301
399
  _passIndices = null;
@@ -362,5 +460,4 @@ export class PostProcessingHandler {
362
460
  }
363
461
  }
364
462
  }
365
- let effectsOrder = null;
366
463
  //# sourceMappingURL=PostProcessingHandler.js.map