@needle-tools/engine 4.6.0 → 4.6.1-next.50abb78

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 (78) 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-DsrPZ9gj.js → needle-engine.bundle-BcXxWyWw.js} +8052 -7969
  7. package/dist/{needle-engine.bundle-CoJqbtmp.umd.cjs → needle-engine.bundle-DTkya1lV.umd.cjs} +152 -148
  8. package/dist/needle-engine.bundle-DxbvIKfK.min.js +1563 -0
  9. package/dist/needle-engine.js +343 -342
  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_assetdatabase.js +3 -1
  28. package/lib/engine/engine_assetdatabase.js.map +1 -1
  29. package/lib/engine/engine_context.d.ts +2 -2
  30. package/lib/engine/engine_context.js +15 -11
  31. package/lib/engine/engine_context.js.map +1 -1
  32. package/lib/engine/engine_utils_screenshot.d.ts +1 -1
  33. package/lib/engine/engine_utils_screenshot.js +11 -2
  34. package/lib/engine/engine_utils_screenshot.js.map +1 -1
  35. package/lib/engine-components/ReflectionProbe.d.ts +2 -1
  36. package/lib/engine-components/ReflectionProbe.js +4 -1
  37. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  38. package/lib/engine-components/Renderer.js +9 -5
  39. package/lib/engine-components/Renderer.js.map +1 -1
  40. package/lib/engine-components/postprocessing/Effects/Antialiasing.js +3 -1
  41. package/lib/engine-components/postprocessing/Effects/Antialiasing.js.map +1 -1
  42. package/lib/engine-components/postprocessing/Effects/BloomEffect.d.ts +1 -1
  43. package/lib/engine-components/postprocessing/Effects/BloomEffect.js +3 -0
  44. package/lib/engine-components/postprocessing/Effects/BloomEffect.js.map +1 -1
  45. package/lib/engine-components/postprocessing/Effects/Tonemapping.js +10 -6
  46. package/lib/engine-components/postprocessing/Effects/Tonemapping.js.map +1 -1
  47. package/lib/engine-components/postprocessing/PostProcessingEffect.d.ts +18 -0
  48. package/lib/engine-components/postprocessing/PostProcessingEffect.js +20 -1
  49. package/lib/engine-components/postprocessing/PostProcessingEffect.js.map +1 -1
  50. package/lib/engine-components/postprocessing/PostProcessingHandler.d.ts +11 -3
  51. package/lib/engine-components/postprocessing/PostProcessingHandler.js +118 -117
  52. package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
  53. package/lib/engine-components/postprocessing/Volume.d.ts +2 -1
  54. package/lib/engine-components/postprocessing/Volume.js +50 -27
  55. package/lib/engine-components/postprocessing/Volume.js.map +1 -1
  56. package/lib/engine-components/postprocessing/index.d.ts +1 -0
  57. package/lib/engine-components/postprocessing/index.js +1 -0
  58. package/lib/engine-components/postprocessing/index.js.map +1 -1
  59. package/lib/engine-components/postprocessing/utils.d.ts +38 -0
  60. package/lib/engine-components/postprocessing/utils.js +98 -0
  61. package/lib/engine-components/postprocessing/utils.js.map +1 -1
  62. package/package.json +2 -2
  63. package/plugins/vite/dependency-watcher.js +8 -2
  64. package/src/engine/engine_assetdatabase.ts +3 -1
  65. package/src/engine/engine_context.ts +17 -12
  66. package/src/engine/engine_utils_screenshot.ts +13 -3
  67. package/src/engine-components/ReflectionProbe.ts +5 -1
  68. package/src/engine-components/Renderer.ts +10 -7
  69. package/src/engine-components/postprocessing/Effects/Antialiasing.ts +3 -1
  70. package/src/engine-components/postprocessing/Effects/BloomEffect.ts +4 -2
  71. package/src/engine-components/postprocessing/Effects/Tonemapping.ts +9 -7
  72. package/src/engine-components/postprocessing/PostProcessingEffect.ts +21 -1
  73. package/src/engine-components/postprocessing/PostProcessingHandler.ts +137 -123
  74. package/src/engine-components/postprocessing/Volume.ts +56 -33
  75. package/src/engine-components/postprocessing/index.ts +1 -0
  76. package/src/engine-components/postprocessing/utils.ts +118 -2
  77. package/dist/generateMeshBVH.worker-Cdfpaq5W.js +0 -25
  78. package/dist/needle-engine.bundle-BDO_N7gN.min.js +0 -1559
@@ -1,6 +1,7 @@
1
1
  import { isDevEnvironment } from "../../engine/debug/index.js";
2
2
  import { addComponent } from "../../engine/engine_components.js";
3
3
  import { foreachComponentEnumerator } from "../../engine/engine_gameobject.js";
4
+ import { MODULES } from "../../engine/engine_modules.js";
4
5
  import { getParam } from "../../engine/engine_utils.js";
5
6
  export const debug = getParam("debugpost");
6
7
  let PostprocessingManagerType = null;
@@ -35,4 +36,101 @@ export function getPostProcessingManager(effect) {
35
36
  }
36
37
  return manager;
37
38
  }
39
+ /**
40
+ * Default priority for post-processing effects. This can be used to sort effects by their rendering order when creating custom effects.
41
+ * E.g. in your custom effect, you can set `priority: PostProcessingEffectPriority.Bloom + 1;` to ensure it gets rendered after the bloom effect.
42
+ * OR `priority: PostProcessingEffectPriority.Bloom - 1;` to ensure it gets rendered before the bloom effect.
43
+ * @example
44
+ * ```typescript
45
+ * import { PostProcessingEffectPriority } from "@needle-tools/engine"
46
+ *
47
+ * export class MyCustomEffect extends PostProcessingEffect {
48
+ * priority: PostProcessingEffectPriority.Bloom + 1; // render after bloom
49
+ *
50
+ * // ... your effect code
51
+ * }
52
+ * ```
53
+ */
54
+ export const PostProcessingEffectPriority = {
55
+ NormalPass: 0,
56
+ DepthDownsamplingPass: 10,
57
+ SMAA: 20,
58
+ SSAO: 30,
59
+ TiltShift: 40,
60
+ DepthOfField: 50,
61
+ ChromaticAberration: 60,
62
+ Bloom: 70,
63
+ Vignette: 80,
64
+ Pixelation: 90,
65
+ ToneMapping: 100,
66
+ HueSaturation: 110,
67
+ BrightnessContrast: 120,
68
+ // Sharpening: 130,
69
+ };
70
+ // let effectsOrder: Array<Constructor<Effect | Pass>> | null = null;
71
+ let builtinOrder = null;
72
+ export function orderEffects(effects) {
73
+ if (debug === "verbose")
74
+ console.debug("Before ordering effects", [...effects]);
75
+ if (!builtinOrder) {
76
+ builtinOrder = new Map();
77
+ builtinOrder.set(MODULES.POSTPROCESSING.MODULE.NormalPass, PostProcessingEffectPriority.NormalPass);
78
+ builtinOrder.set(MODULES.POSTPROCESSING.MODULE.DepthDownsamplingPass, PostProcessingEffectPriority.DepthDownsamplingPass);
79
+ builtinOrder.set(MODULES.POSTPROCESSING.MODULE.SMAAEffect, PostProcessingEffectPriority.SMAA);
80
+ builtinOrder.set(MODULES.POSTPROCESSING.MODULE.SSAOEffect, PostProcessingEffectPriority.SSAO);
81
+ builtinOrder.set(MODULES.POSTPROCESSING.MODULE.TiltShiftEffect, PostProcessingEffectPriority.TiltShift);
82
+ builtinOrder.set(MODULES.POSTPROCESSING.MODULE.DepthOfFieldEffect, PostProcessingEffectPriority.DepthOfField);
83
+ builtinOrder.set(MODULES.POSTPROCESSING.MODULE.ChromaticAberrationEffect, PostProcessingEffectPriority.ChromaticAberration);
84
+ builtinOrder.set(MODULES.POSTPROCESSING.MODULE.BloomEffect, PostProcessingEffectPriority.Bloom);
85
+ builtinOrder.set(MODULES.POSTPROCESSING.MODULE.VignetteEffect, PostProcessingEffectPriority.Vignette);
86
+ builtinOrder.set(MODULES.POSTPROCESSING.MODULE.PixelationEffect, PostProcessingEffectPriority.Pixelation);
87
+ builtinOrder.set(MODULES.POSTPROCESSING.MODULE.ToneMappingEffect, PostProcessingEffectPriority.ToneMapping);
88
+ builtinOrder.set(MODULES.POSTPROCESSING.MODULE.HueSaturationEffect, PostProcessingEffectPriority.HueSaturation);
89
+ builtinOrder.set(MODULES.POSTPROCESSING.MODULE.BrightnessContrastEffect, PostProcessingEffectPriority.BrightnessContrast);
90
+ }
91
+ // enforce correct order of effects (e.g. DOF before Bloom)
92
+ effects.sort((a, b) => {
93
+ // we use find index here because sometimes constructor names are prefixed with `_`
94
+ // 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)
95
+ const aidx = typeof a.priority === "number" ? a.priority : builtinOrder.get(a.effect.constructor) || -1;
96
+ const bidx = typeof b.priority === "number" ? b.priority : builtinOrder.get(b.effect.constructor) || -1;
97
+ // Unknown effects should be rendered first
98
+ if (aidx < 0) {
99
+ if (debug)
100
+ console.warn("Unknown effect found: ", a.constructor.name);
101
+ return -1;
102
+ }
103
+ else if (bidx < 0) {
104
+ if (debug)
105
+ console.warn("Unknown effect found: ", b.constructor.name);
106
+ return 1;
107
+ }
108
+ // if (aidx < 0) return 1;
109
+ // if (bidx < 0) return -1;
110
+ return aidx - bidx;
111
+ });
112
+ // effects.sort((a, b) => {
113
+ // if (a.beforeEffect) {
114
+ // const beforeA = effectsOrder!.findIndex(e => a.beforeEffect!.constructor.name.endsWith(e.name));
115
+ // if (beforeA >= 0) {
116
+ // return -1; // before effect should be rendered first
117
+ // }
118
+ // else {
119
+ // return 1; // no before effect, so we can keep the order
120
+ // }
121
+ // }
122
+ // else if (b.beforeEffect) {
123
+ // const beforeB = effectsOrder!.findIndex(e => b.beforeEffect!.constructor.name.endsWith(e.name));
124
+ // if (beforeB >= 0) {
125
+ // return 1; // before effect should be rendered first
126
+ // }
127
+ // else if (a.beforeEffect) {
128
+ // return -1; // no before effect, so we can keep the order
129
+ // }
130
+ // }
131
+ // return 0; // no before effect, so we can keep the order
132
+ // });
133
+ if (debug === "verbose")
134
+ console.debug("After ordering effects", [...effects]);
135
+ }
38
136
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/engine-components/postprocessing/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;AAE/E,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAGxD,MAAM,CAAC,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;AAS3C,IAAI,yBAAyB,GAAuD,IAAI,CAAC;AAEzF,MAAM,UAAU,4BAA4B,CAAC,IAAiD;IAC1F,yBAAyB,GAAG,IAAI,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,MAA4B;IAClE,IAAI,GAAG,GAAG,MAAM,CAAC,UAA6B,CAAC;IAC/C,OAAO,GAAG,EAAE;QACR,KAAK,MAAM,IAAI,IAAI,0BAA0B,CAAC,GAAG,CAAC,EAAE;YAChD,IAAK,IAA0C,CAAC,uBAAuB,KAAK,IAAI,EAAE;gBAC9E,OAAO,IAAyC,CAAC;aACpD;SACJ;QACD,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC;KACpB;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,MAA4B;IACjE,IAAI,OAAO,GAAkC,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAC/E,IAAI,CAAC,OAAO,EAAE;QACV,IAAI,yBAAyB,EAAE;YAC3B,IAAI,KAAK;gBACL,OAAO,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;YAChE,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;YAC3B,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,yBAAyB,CAAC,CAAC;SAC5D;aACI;YACD,IAAI,gBAAgB,EAAE;gBAClB,OAAO,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;SACxD;KACJ;IACD,OAAO,OAAO,CAAC;AACnB,CAAC"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/engine-components/postprocessing/utils.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAEzD,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAGxD,MAAM,CAAC,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;AAW3C,IAAI,yBAAyB,GAAuD,IAAI,CAAC;AAEzF,MAAM,UAAU,4BAA4B,CAAC,IAAiD;IAC1F,yBAAyB,GAAG,IAAI,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,MAA4B;IAClE,IAAI,GAAG,GAAG,MAAM,CAAC,UAA6B,CAAC;IAC/C,OAAO,GAAG,EAAE;QACR,KAAK,MAAM,IAAI,IAAI,0BAA0B,CAAC,GAAG,CAAC,EAAE;YAChD,IAAK,IAA0C,CAAC,uBAAuB,KAAK,IAAI,EAAE;gBAC9E,OAAO,IAAyC,CAAC;aACpD;SACJ;QACD,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC;KACpB;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,MAA4B;IACjE,IAAI,OAAO,GAAkC,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAC/E,IAAI,CAAC,OAAO,EAAE;QACV,IAAI,yBAAyB,EAAE;YAC3B,IAAI,KAAK;gBACL,OAAO,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;YAChE,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;YAC3B,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,yBAAyB,CAAC,CAAC;SAC5D;aACI;YACD,IAAI,gBAAgB,EAAE;gBAClB,OAAO,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;SACxD;KACJ;IACD,OAAO,OAAO,CAAC;AACnB,CAAC;AASD;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG;IACxC,UAAU,EAAE,CAAC;IACb,qBAAqB,EAAE,EAAE;IACzB,IAAI,EAAE,EAAE;IACR,IAAI,EAAE,EAAE;IACR,SAAS,EAAE,EAAE;IACb,YAAY,EAAE,EAAE;IAChB,mBAAmB,EAAE,EAAE;IACvB,KAAK,EAAE,EAAE;IACT,QAAQ,EAAE,EAAE;IACZ,UAAU,EAAE,EAAE;IACd,WAAW,EAAE,GAAG;IAChB,aAAa,EAAE,GAAG;IAClB,kBAAkB,EAAE,GAAG;IACvB,mBAAmB;CACtB,CAAA;AACD,qEAAqE;AAErE,IAAI,YAAY,GAAmD,IAAI,CAAC;AAExE,MAAM,UAAU,YAAY,CAAC,OAAwC;IACjE,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAEhF,IAAI,CAAC,YAAY,EAAE;QACf,YAAY,GAAG,IAAI,GAAG,EAAsC,CAAC;QAC7D,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,UAAU,EAAE,4BAA4B,CAAC,UAAU,CAAC,CAAC;QACpG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,qBAAqB,EAAE,4BAA4B,CAAC,qBAAqB,CAAC,CAAC;QAC1H,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,UAAU,EAAE,4BAA4B,CAAC,IAAI,CAAC,CAAC;QAC9F,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,UAAU,EAAE,4BAA4B,CAAC,IAAI,CAAC,CAAC;QAC9F,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,eAAe,EAAE,4BAA4B,CAAC,SAAS,CAAC,CAAC;QACxG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,kBAAkB,EAAE,4BAA4B,CAAC,YAAY,CAAC,CAAC;QAC9G,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,yBAAyB,EAAE,4BAA4B,CAAC,mBAAmB,CAAC,CAAC;QAC5H,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,WAAW,EAAE,4BAA4B,CAAC,KAAK,CAAC,CAAC;QAChG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,cAAc,EAAE,4BAA4B,CAAC,QAAQ,CAAC,CAAC;QACtG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,gBAAgB,EAAE,4BAA4B,CAAC,UAAU,CAAC,CAAC;QAC1G,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,iBAAiB,EAAE,4BAA4B,CAAC,WAAW,CAAC,CAAC;QAC5G,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,mBAAmB,EAAE,4BAA4B,CAAC,aAAa,CAAC,CAAC;QAChH,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,wBAAwB,EAAE,4BAA4B,CAAC,kBAAkB,CAAC,CAAC;KAC7H;IAED,2DAA2D;IAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAClB,mFAAmF;QACnF,8IAA8I;QAC9I,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAa,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,WAAyC,CAAC,IAAI,CAAC,CAAC,CAAC;QACvI,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAa,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,WAAyC,CAAC,IAAI,CAAC,CAAC,CAAC;QAEvI,2CAA2C;QAC3C,IAAI,IAAI,GAAG,CAAC,EAAE;YACV,IAAI,KAAK;gBAAE,OAAO,CAAC,IAAI,CAAC,wBAAwB,EAAE,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YACtE,OAAO,CAAC,CAAC,CAAC;SACb;aACI,IAAI,IAAI,GAAG,CAAC,EAAE;YACf,IAAI,KAAK;gBAAE,OAAO,CAAC,IAAI,CAAC,wBAAwB,EAAE,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YACtE,OAAO,CAAC,CAAC;SACZ;QACD,0BAA0B;QAC1B,2BAA2B;QAC3B,OAAO,IAAI,GAAG,IAAI,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,2BAA2B;IAC3B,4BAA4B;IAC5B,2GAA2G;IAC3G,8BAA8B;IAC9B,mEAAmE;IACnE,YAAY;IACZ,iBAAiB;IACjB,sEAAsE;IACtE,YAAY;IACZ,QAAQ;IACR,iCAAiC;IACjC,2GAA2G;IAC3G,8BAA8B;IAC9B,kEAAkE;IAClE,YAAY;IACZ,qCAAqC;IACrC,uEAAuE;IACvE,YAAY;IAEZ,QAAQ;IACR,8DAA8D;IAC9D,MAAM;IAGN,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;AACnF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/engine",
3
- "version": "4.6.0",
3
+ "version": "4.6.1-next.50abb78",
4
4
  "description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.",
5
5
  "main": "dist/needle-engine.min.js",
6
6
  "exports": {
@@ -167,4 +167,4 @@
167
167
  "module": "lib/needle-engine.js",
168
168
  "typings": "lib/needle-engine.d.ts",
169
169
  "types": "lib/needle-engine.d.ts"
170
- }
170
+ }
@@ -162,8 +162,14 @@ function testIfInstallIsRequired(projectDir, packageJson) {
162
162
  }
163
163
  if (expectedVersion?.length > 0) {
164
164
  const isRange = expectedVersion.includes("x") || expectedVersion.includes("^") || expectedVersion.includes(">") || expectedVersion.includes("<") || expectedVersion.includes("~");
165
- const isLatest = expectedVersion === "latest";
166
- if (!isRange && !isLatest) {
165
+ const isTagName = expectedVersion === "stable" ||
166
+ expectedVersion === "latest" ||
167
+ expectedVersion === "next" ||
168
+ expectedVersion === "beta" ||
169
+ expectedVersion === "alpha" ||
170
+ expectedVersion === "canary" ||
171
+ expectedVersion === "experimental";
172
+ if (!isRange && !isTagName) {
167
173
  const packageJsonPath = path.join(depPath, "package.json");
168
174
  /** @type {String} */
169
175
  const installedVersion = JSON.parse(readFileSync(packageJsonPath, "utf8")).version;
@@ -61,7 +61,9 @@ export function disposeObjectResources(obj: object | null | undefined) {
61
61
  return;
62
62
  }
63
63
 
64
- obj[$disposed] = true;
64
+ if(typeof obj === "object") {
65
+ obj[$disposed] = true;
66
+ }
65
67
 
66
68
  if (obj instanceof Scene) {
67
69
  disposeObjectResources(obj.environment);
@@ -33,7 +33,7 @@ import { NetworkConnection } from './engine_networking.js';
33
33
  import { Physics } from './engine_physics.js';
34
34
  import { PlayerViewManager } from './engine_playerview.js';
35
35
  import { RendererData as SceneLighting } from './engine_scenelighting.js';
36
- import { logHierarchy } from './engine_three_utils.js';
36
+ import { getTempColor, logHierarchy } from './engine_three_utils.js';
37
37
  import { Time } from './engine_time.js';
38
38
  import { patchTonemapping } from './engine_tonemapping.js';
39
39
  import type { CoroutineData, ICamera, IComponent, IContext, ILight, LoadedModel, Model, Vec2 } from "./engine_types.js";
@@ -758,6 +758,9 @@ export class Context implements IContext {
758
758
  this.physics?.engine?.clearCaches();
759
759
  this.lodsManager.disable();
760
760
 
761
+ this._onBeforeRenderListeners.clear();
762
+ this._onAfterRenderListeners.clear();
763
+
761
764
  if (!this.isManagedExternally) {
762
765
  if (this.renderer) {
763
766
  this.renderer.renderLists.dispose();
@@ -889,16 +892,17 @@ export class Context implements IContext {
889
892
  }
890
893
  }
891
894
 
892
- private _onBeforeRenderListeners = new Map<string, OnRenderCallback[]>();
893
- private _onAfterRenderListeners = new Map<string, OnRenderCallback[]>();
895
+ private readonly _onBeforeRenderListeners = new Map<string, OnRenderCallback[]>();
896
+ private readonly _onAfterRenderListeners = new Map<string, OnRenderCallback[]>();
894
897
 
895
898
  /** Use to subscribe to onBeforeRender events on threejs objects.
896
899
  * @link https://threejs.org/docs/#api/en/core/Object3D.onBeforeRender
897
900
  */
898
901
  addBeforeRenderListener(target: Object3D, callback: OnRenderCallback) {
899
902
  if (!this._onBeforeRenderListeners.has(target.uuid)) {
900
- this._onBeforeRenderListeners.set(target.uuid, []);
901
- target.onBeforeRender = this._createRenderCallbackWrapper(target, this._onBeforeRenderListeners);
903
+ const arr: OnRenderCallback[] = [];
904
+ this._onBeforeRenderListeners.set(target.uuid, arr);
905
+ target.onBeforeRender = this._createRenderCallbackWrapper(arr);
902
906
  }
903
907
  this._onBeforeRenderListeners.get(target.uuid)!.push(callback);
904
908
  }
@@ -919,8 +923,9 @@ export class Context implements IContext {
919
923
  */
920
924
  addAfterRenderListener(target: Object3D, callback: OnRenderCallback) {
921
925
  if (!this._onAfterRenderListeners.has(target.uuid)) {
922
- this._onAfterRenderListeners.set(target.uuid, []);
923
- target.onAfterRender = this._createRenderCallbackWrapper(target, this._onAfterRenderListeners);
926
+ const arr = [];
927
+ this._onAfterRenderListeners.set(target.uuid, arr);
928
+ target.onAfterRender = this._createRenderCallbackWrapper(arr);
924
929
  }
925
930
  this._onAfterRenderListeners.get(target.uuid)?.push(callback);
926
931
  }
@@ -937,12 +942,10 @@ export class Context implements IContext {
937
942
  }
938
943
 
939
944
 
940
- private _createRenderCallbackWrapper(target: Object3D, array: Map<string, OnRenderCallback[]>): OnRenderCallback {
945
+ private _createRenderCallbackWrapper(array: OnRenderCallback[]): OnRenderCallback {
941
946
  return (renderer, scene, camera, geometry, material, group) => {
942
- const arr = array.get(target.uuid);
943
- if (!arr) return;
944
- for (let i = 0; i < arr.length; i++) {
945
- const fn = arr[i];
947
+ for (let i = 0; i < array.length; i++) {
948
+ const fn = array[i];
946
949
  fn(renderer, scene, camera, geometry, material, group);
947
950
  }
948
951
  }
@@ -1609,6 +1612,8 @@ export class Context implements IContext {
1609
1612
  if (currentPassesCamera != camera)
1610
1613
  this.composer.setMainCamera(camera);
1611
1614
  }
1615
+ const backgroundColor = this.renderer.getClearColor(getTempColor());
1616
+ if(backgroundColor) this.renderer.setClearColor(backgroundColor.convertSRGBToLinear());
1612
1617
  this.composer.render(this.time.deltaTime);
1613
1618
  }
1614
1619
  else if (camera) {
@@ -45,7 +45,7 @@ export declare type ScreenshotOptions = {
45
45
  /**
46
46
  * The context to take the screenshot from. If not provided, the current context will be used.
47
47
  */
48
- context?: Pick<Context, "scene" | "renderer" | "mainCamera" | "renderNow" | "updateAspect" | "updateSize" | "currentFrameEvent">,
48
+ context?: Pick<Context, "scene" | "renderer" | "mainCamera" | "renderNow" | "updateAspect" | "updateSize" | "currentFrameEvent" | "devicePixelRatio">,
49
49
  /**
50
50
  * The width of the screenshot - if not provided, the width of the current renderer will be used.
51
51
  */
@@ -205,11 +205,21 @@ export function screenshot2(opts: ScreenshotOptionsDataUrl | ScreenshotOptionsTe
205
205
  const renderWidth = width;
206
206
  const renderHeight = height;
207
207
 
208
- // apply page zoom
209
- const zoomLevel = window.devicePixelRatio || 1;
208
+ // Apply page zoom
209
+ let zoomLevel = (window.devicePixelRatio || 1);
210
+ let contextZoomLevel = 1;
211
+ // Apply context zoom level
212
+ if (context.devicePixelRatio === 'auto' || context.devicePixelRatio === 'manual')
213
+ contextZoomLevel = 1;
214
+ else
215
+ contextZoomLevel = context.devicePixelRatio / window.devicePixelRatio;
216
+ zoomLevel *= contextZoomLevel;
210
217
  width /= zoomLevel;
211
218
  height /= zoomLevel;
212
219
 
220
+ width = Math.floor(width);
221
+ height = Math.floor(height);
222
+
213
223
  // save XR state and reset it for screenshot
214
224
  const xrframe = renderer.xr.isPresenting && renderer.xr.getFrame();
215
225
  const previousXRState = renderer.xr.enabled;
@@ -22,6 +22,10 @@ export class ReflectionProbe extends Behaviour {
22
22
 
23
23
  private static _probes: Map<Context, ReflectionProbe[]> = new Map();
24
24
 
25
+ static isUsingReflectionProbe(material: Material) {
26
+ return !!(material[$reflectionProbeKey] || material[$originalMaterial]?.[$reflectionProbeKey]);
27
+ }
28
+
25
29
  public static get(object: Object3D | null | undefined, context: Context, isAnchor: boolean, anchor?: Object3D): ReflectionProbe | null {
26
30
  if (!object || object.isObject3D !== true) return null;
27
31
  if (disable) return null;
@@ -29,7 +33,7 @@ export class ReflectionProbe extends Behaviour {
29
33
  if (probes) {
30
34
  for (const probe of probes) {
31
35
  if (!probe.__didAwake) probe.__internalAwake();
32
- if (probe.enabled) {
36
+ if (probe.activeAndEnabled) {
33
37
  if (anchor) {
34
38
  // test if anchor is reflection probe object
35
39
  if (probe.gameObject === anchor) {
@@ -708,7 +708,15 @@ export class Renderer extends Behaviour implements IRenderer {
708
708
  if (this.reflectionProbeUsage !== ReflectionProbeUsage.Off && this._reflectionProbe) {
709
709
  this._reflectionProbe.onSet(this);
710
710
  }
711
-
711
+ // since three 163 we need to set the envMap to the scene envMap if it is not set
712
+ // otherwise the envmapIntensity has no effect: https://github.com/mrdoob/three.js/pull/27903
713
+ // internal issue: https://linear.app/needle/issue/NE-6363
714
+ for (const mat of this._sharedMaterials) {
715
+ // If the material has a envMap and is NOT using a reflection probe we set the envMap to the scene environment
716
+ if (mat && "envMap" in mat && "envMapIntensity" in mat && !ReflectionProbe.isUsingReflectionProbe(mat)) {
717
+ mat.envMap = this.context.scene.environment;
718
+ }
719
+ }
712
720
  }
713
721
 
714
722
  private onBeforeRenderThree = (_renderer, _scene, _camera, _geometry, material, _group) => {
@@ -716,11 +724,6 @@ export class Renderer extends Behaviour implements IRenderer {
716
724
  const factor = this.hasLightmap ? Math.PI : 1;
717
725
  const environmentIntensity = this.context.mainCameraComponent?.environmentIntensity ?? 1;
718
726
  material.envMapIntensity = Math.max(0, environmentIntensity * this.context.sceneLighting.environmentIntensity / factor);
719
-
720
- // since three 163 we need to set the envMap to the scene envMap if it is not set
721
- // otherwise the envmapIntensity has no effect: https://github.com/mrdoob/three.js/pull/27903
722
- // internal issue: https://linear.app/needle/issue/NE-6363
723
- if (!material.envMap) material.envMap = this.context.scene.environment;
724
727
  }
725
728
 
726
729
  if (this._lightmaps) {
@@ -856,7 +859,7 @@ export class SkinnedMeshRenderer extends MeshRenderer {
856
859
  mesh.computeBoundingSphere();
857
860
  mesh.geometry = geometry;
858
861
  }
859
- catch(err) {
862
+ catch (err) {
860
863
  console.error(`Error updating bounding sphere for ${mesh.name}`, err);
861
864
  }
862
865
  }
@@ -33,7 +33,9 @@ export class Antialiasing extends PostProcessingEffect {
33
33
  onCreateEffect(): EffectProviderResult {
34
34
  const effect = new MODULES.POSTPROCESSING.MODULE.SMAAEffect({
35
35
  preset: MODULES.POSTPROCESSING.MODULE.SMAAPreset.HIGH,
36
- edgeDetectionMode: MODULES.POSTPROCESSING.MODULE.EdgeDetectionMode.DEPTH
36
+ edgeDetectionMode: MODULES.POSTPROCESSING.MODULE.EdgeDetectionMode.LUMA,
37
+ // Keep predication mode disabled (default) since it looks better
38
+ // predicationMode: MODULES.POSTPROCESSING.MODULE.PredicationMode.DEPTH,
37
39
  });
38
40
 
39
41
  this.preset.onValueChanged = (newValue) => {
@@ -1,4 +1,4 @@
1
- import type { BloomEffect as _BloomEffect } from "postprocessing";
1
+ import { BloomEffect as _BloomEffect, EffectAttribute } from "postprocessing";
2
2
  import { MathUtils } from "three";
3
3
 
4
4
  import { MODULES } from "../../../engine/engine_modules.js";
@@ -91,8 +91,10 @@ export class BloomEffect extends PostProcessingEffect {
91
91
  luminanceThreshold: this.threshold.value,
92
92
  luminanceSmoothing: this.scatter.value,
93
93
  radius: 0.85, // default value
94
- intensity: this.intensity.value,
94
+ intensity: this.intensity.value,
95
95
  });
96
+ // @ts-ignore Well... it's protected but bloom needs this :(
97
+ bloom.setAttributes(EffectAttribute.CONVOLUTION);
96
98
  }
97
99
 
98
100
  this.intensity.onValueChanged = newValue => {
@@ -1,5 +1,5 @@
1
1
  import type { ToneMappingEffect as _TonemappingEffect, ToneMappingMode } from "postprocessing";
2
- import { ACESFilmicToneMapping, AgXToneMapping, LinearToneMapping, NeutralToneMapping, NoToneMapping, ReinhardToneMapping } from "three";
2
+ import { ACESFilmicToneMapping, AgXToneMapping, LinearToneMapping, NeutralToneMapping, NoToneMapping, ReinhardToneMapping, WebGLRenderer } from "three";
3
3
 
4
4
  import { MODULES } from "../../../engine/engine_modules.js";
5
5
  import { serializable } from "../../../engine/engine_serialization.js";
@@ -36,6 +36,7 @@ function toThreeToneMapping(mode: NEToneMappingMode | undefined) {
36
36
  case NEToneMappingMode.KhronosNeutral:
37
37
  return NeutralToneMapping;
38
38
  default:
39
+ if(debug) console.warn("[Postprocessing] Unknown tone mapping mode", mode);
39
40
  return NeutralToneMapping;
40
41
  }
41
42
  }
@@ -84,7 +85,7 @@ export class ToneMappingEffect extends PostProcessingEffect {
84
85
  setMode(mode: NEToneMappingModeNames) {
85
86
  const enumValue = NEToneMappingMode[mode as NEToneMappingModeNames];
86
87
  if (enumValue === undefined) {
87
- console.error("Invalid ToneMapping mode", mode);
88
+ console.error("[PostProcessing] Invalid ToneMapping mode", mode);
88
89
  return this;
89
90
  }
90
91
  this.mode.value = enumValue;
@@ -110,7 +111,7 @@ export class ToneMappingEffect extends PostProcessingEffect {
110
111
  if (other === this) break;
111
112
  // If another tonemapping effect is found, warn the user
112
113
  if (other != this && other instanceof ToneMappingEffect) {
113
- console.warn("Multiple tonemapping effects found in the same postprocessing stack: Please check your scene setup.", { activeEffect: other, ignoredEffect: this });
114
+ console.warn("[PostProcessing] Multiple tonemapping effects found in the same postprocessing stack: Please check your scene setup.", { activeEffect: other, ignoredEffect: this });
114
115
  return undefined;
115
116
  }
116
117
  }
@@ -119,8 +120,9 @@ export class ToneMappingEffect extends PostProcessingEffect {
119
120
 
120
121
  // ensure the effect tonemapping value is initialized
121
122
  if (this.mode.isInitialized == false) {
122
- const init = threeToNeToneMapping(this.context.renderer.toneMapping);
123
- this.mode.initialize(init);
123
+ const mode = threeToNeToneMapping(this.context.renderer.toneMapping);
124
+ if(debug) console.log("[PostProcessing] Initializing ToneMapping mode to renderer.toneMapping", this.context.renderer.toneMapping + " → " + mode);
125
+ this.mode.initialize(mode);
124
126
  }
125
127
 
126
128
  const threeMode = toThreeToneMapping(this.mode.value);
@@ -130,9 +132,9 @@ export class ToneMappingEffect extends PostProcessingEffect {
130
132
  this.mode.onValueChanged = (newValue) => {
131
133
  const threeMode = toThreeToneMapping(newValue);
132
134
  tonemapping.mode = threeToneMappingToEffectMode(threeMode);
133
- if (debug) console.log("ToneMapping mode changed to", NEToneMappingMode[newValue], threeMode, tonemapping.mode);
135
+ if (debug) console.log("[PostProcessing] ToneMapping mode changed to", NEToneMappingMode[newValue], threeMode, tonemapping.mode);
134
136
  };
135
- if (debug) console.log("Use ToneMapping", NEToneMappingMode[this.mode.value], threeMode, tonemapping.mode, "renderer.tonemapping: " + this.context.renderer.toneMapping);
137
+ if (debug) console.log("[PostProcessing] Use ToneMapping", NEToneMappingMode[this.mode.value], threeMode, tonemapping.mode, "renderer.tonemapping: " + this.context.renderer.toneMapping);
136
138
 
137
139
 
138
140
  this.exposure.onValueChanged = (newValue) => {
@@ -55,6 +55,25 @@ export abstract class PostProcessingEffect extends Component implements IEffectP
55
55
 
56
56
  get isPostProcessingEffect() { return true; }
57
57
 
58
+ /**
59
+ * The priority of this effect. The higher the priority the later the effect will be applied in the post processing stack.
60
+ * This can be used to control the order of effects when multiple effects are applied.
61
+ * It is recommended to use the PostProcessingEffectPriority constant to order your custom effects before or after built-in effects.
62
+ * @default `undefined` (no specific priority set, will be applied in the order of registration)
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * import { PostProcessingEffectPriority } from "@needle-tools/engine"
67
+ *
68
+ * export class MyCustomEffect extends PostProcessingEffect {
69
+ * priority: PostProcessingEffectPriority.Bloom + 1; // render after bloom
70
+ *
71
+ * // ... the rest of your effect code
72
+ * }
73
+ * ```
74
+ */
75
+ priority: number | undefined = undefined;
76
+
58
77
  constructor(params: any = undefined) {
59
78
  super();
60
79
  if (params) {
@@ -103,7 +122,8 @@ export abstract class PostProcessingEffect extends Component implements IEffectP
103
122
  protected onEffectEnabled(manager?: IPostProcessingManager) {
104
123
  if (manager && manager.isPostProcessingManager === true) this._manager = manager;
105
124
  else if (!this._manager) this._manager = getPostProcessingManager(this);
106
- this._manager?.addEffect(this);
125
+ this._manager!.addEffect(this);
126
+ this._manager!.dirty = true;
107
127
  }
108
128
 
109
129
  /** override to initialize bindings on parameters */