@needle-tools/engine 5.0.2 → 5.1.0-canary.525aa82

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 (176) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +6 -7
  3. package/SKILL.md +39 -21
  4. package/components.needle.json +1 -1
  5. package/dist/needle-engine.bundle-DPag02s9.min.js +1732 -0
  6. package/dist/needle-engine.bundle-IPMzQpe1.umd.cjs +1732 -0
  7. package/dist/{needle-engine.bundle-BoTyA-Le.js → needle-engine.bundle-qa_NEunk.js} +8881 -8148
  8. package/dist/needle-engine.d.ts +633 -61
  9. package/dist/needle-engine.js +576 -565
  10. package/dist/needle-engine.min.js +1 -1
  11. package/dist/needle-engine.umd.cjs +1 -1
  12. package/dist/{vendor-vHLk8sXu.js → vendor-CAcsI0eU.js} +116 -115
  13. package/dist/{vendor-CntUvmJu.umd.cjs → vendor-CEM38hLE.umd.cjs} +2 -2
  14. package/dist/{vendor-DPbfJJ4d.min.js → vendor-HRlxIBga.min.js} +2 -2
  15. package/lib/engine/api.d.ts +2 -0
  16. package/lib/engine/api.js +2 -0
  17. package/lib/engine/api.js.map +1 -1
  18. package/lib/engine/engine_addressables.js +5 -1
  19. package/lib/engine/engine_addressables.js.map +1 -1
  20. package/lib/engine/engine_animation.d.ts +14 -7
  21. package/lib/engine/engine_animation.js +49 -9
  22. package/lib/engine/engine_animation.js.map +1 -1
  23. package/lib/engine/engine_components.js +33 -4
  24. package/lib/engine/engine_components.js.map +1 -1
  25. package/lib/engine/engine_context.d.ts +7 -2
  26. package/lib/engine/engine_context.js +10 -2
  27. package/lib/engine/engine_context.js.map +1 -1
  28. package/lib/engine/engine_gameobject.d.ts +4 -0
  29. package/lib/engine/engine_gameobject.js.map +1 -1
  30. package/lib/engine/engine_init.js +4 -0
  31. package/lib/engine/engine_init.js.map +1 -1
  32. package/lib/engine/engine_input.js +4 -1
  33. package/lib/engine/engine_input.js.map +1 -1
  34. package/lib/engine/engine_materialpropertyblock.js +1 -20
  35. package/lib/engine/engine_materialpropertyblock.js.map +1 -1
  36. package/lib/engine/engine_networking.d.ts +11 -8
  37. package/lib/engine/engine_networking.js +43 -26
  38. package/lib/engine/engine_networking.js.map +1 -1
  39. package/lib/engine/engine_networking_instantiate.d.ts +100 -5
  40. package/lib/engine/engine_networking_instantiate.js +150 -16
  41. package/lib/engine/engine_networking_instantiate.js.map +1 -1
  42. package/lib/engine/engine_networking_prefabs.d.ts +59 -0
  43. package/lib/engine/engine_networking_prefabs.js +67 -0
  44. package/lib/engine/engine_networking_prefabs.js.map +1 -0
  45. package/lib/engine/engine_physics_rapier.d.ts +3 -0
  46. package/lib/engine/engine_physics_rapier.js +13 -9
  47. package/lib/engine/engine_physics_rapier.js.map +1 -1
  48. package/lib/engine/postprocessing/api.d.ts +2 -0
  49. package/lib/engine/postprocessing/api.js +2 -0
  50. package/lib/engine/postprocessing/api.js.map +1 -0
  51. package/lib/engine/postprocessing/index.d.ts +2 -0
  52. package/lib/engine/postprocessing/index.js +2 -0
  53. package/lib/engine/postprocessing/index.js.map +1 -0
  54. package/lib/engine/postprocessing/postprocessing.d.ts +83 -0
  55. package/lib/engine/postprocessing/postprocessing.js +280 -0
  56. package/lib/engine/postprocessing/postprocessing.js.map +1 -0
  57. package/lib/engine/postprocessing/types.d.ts +39 -0
  58. package/lib/engine/postprocessing/types.js +2 -0
  59. package/lib/engine/postprocessing/types.js.map +1 -0
  60. package/lib/engine/webcomponents/WebXRButtons.js +17 -3
  61. package/lib/engine/webcomponents/WebXRButtons.js.map +1 -1
  62. package/lib/engine/webcomponents/icons.js +3 -1
  63. package/lib/engine/webcomponents/icons.js.map +1 -1
  64. package/lib/engine/xr/NeedleXRSession.d.ts +1 -0
  65. package/lib/engine/xr/NeedleXRSession.js +43 -10
  66. package/lib/engine/xr/NeedleXRSession.js.map +1 -1
  67. package/lib/engine/xr/init.d.ts +4 -0
  68. package/lib/engine/xr/init.js +49 -0
  69. package/lib/engine/xr/init.js.map +1 -0
  70. package/lib/engine-components/AnimationUtils.d.ts +4 -1
  71. package/lib/engine-components/AnimationUtils.js +7 -19
  72. package/lib/engine-components/AnimationUtils.js.map +1 -1
  73. package/lib/engine-components/AnimatorController.d.ts +135 -2
  74. package/lib/engine-components/AnimatorController.js +216 -13
  75. package/lib/engine-components/AnimatorController.js.map +1 -1
  76. package/lib/engine-components/GroundProjection.d.ts +1 -0
  77. package/lib/engine-components/GroundProjection.js +184 -48
  78. package/lib/engine-components/GroundProjection.js.map +1 -1
  79. package/lib/engine-components/OrbitControls.d.ts +4 -0
  80. package/lib/engine-components/OrbitControls.js +5 -1
  81. package/lib/engine-components/OrbitControls.js.map +1 -1
  82. package/lib/engine-components/SeeThrough.d.ts +0 -2
  83. package/lib/engine-components/SeeThrough.js +0 -89
  84. package/lib/engine-components/SeeThrough.js.map +1 -1
  85. package/lib/engine-components/SyncedRoom.d.ts +4 -0
  86. package/lib/engine-components/SyncedRoom.js +23 -8
  87. package/lib/engine-components/SyncedRoom.js.map +1 -1
  88. package/lib/engine-components/SyncedTransform.js +5 -5
  89. package/lib/engine-components/SyncedTransform.js.map +1 -1
  90. package/lib/engine-components/Voip.d.ts +46 -0
  91. package/lib/engine-components/Voip.js +126 -2
  92. package/lib/engine-components/Voip.js.map +1 -1
  93. package/lib/engine-components/api.d.ts +1 -0
  94. package/lib/engine-components/api.js +1 -0
  95. package/lib/engine-components/api.js.map +1 -1
  96. package/lib/engine-components/codegen/components.d.ts +1 -0
  97. package/lib/engine-components/codegen/components.js +1 -0
  98. package/lib/engine-components/codegen/components.js.map +1 -1
  99. package/lib/engine-components/postprocessing/Effects/Tonemapping.d.ts +5 -2
  100. package/lib/engine-components/postprocessing/Effects/Tonemapping.js +11 -18
  101. package/lib/engine-components/postprocessing/Effects/Tonemapping.js.map +1 -1
  102. package/lib/engine-components/postprocessing/PostProcessingEffect.d.ts +3 -4
  103. package/lib/engine-components/postprocessing/PostProcessingEffect.js +6 -15
  104. package/lib/engine-components/postprocessing/PostProcessingEffect.js.map +1 -1
  105. package/lib/engine-components/postprocessing/PostProcessingHandler.d.ts +2 -1
  106. package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
  107. package/lib/engine-components/postprocessing/Volume.d.ts +18 -11
  108. package/lib/engine-components/postprocessing/Volume.js +61 -140
  109. package/lib/engine-components/postprocessing/Volume.js.map +1 -1
  110. package/lib/engine-components/postprocessing/index.d.ts +1 -0
  111. package/lib/engine-components/postprocessing/index.js +1 -0
  112. package/lib/engine-components/postprocessing/index.js.map +1 -1
  113. package/lib/engine-components/postprocessing/utils.d.ts +2 -0
  114. package/lib/engine-components/postprocessing/utils.js +2 -0
  115. package/lib/engine-components/postprocessing/utils.js.map +1 -1
  116. package/lib/engine-components/ui/Canvas.js +2 -2
  117. package/lib/engine-components/ui/Canvas.js.map +1 -1
  118. package/lib/engine-components/ui/Graphic.d.ts +3 -3
  119. package/lib/engine-components/ui/Graphic.js +6 -2
  120. package/lib/engine-components/ui/Graphic.js.map +1 -1
  121. package/lib/engine-components/ui/Text.d.ts +64 -11
  122. package/lib/engine-components/ui/Text.js +154 -45
  123. package/lib/engine-components/ui/Text.js.map +1 -1
  124. package/lib/engine-components/ui/index.d.ts +1 -0
  125. package/lib/engine-components/ui/index.js +1 -0
  126. package/lib/engine-components/ui/index.js.map +1 -1
  127. package/lib/engine-components-experimental/networking/PlayerSync.d.ts +25 -3
  128. package/lib/engine-components-experimental/networking/PlayerSync.js +60 -11
  129. package/lib/engine-components-experimental/networking/PlayerSync.js.map +1 -1
  130. package/package.json +6 -5
  131. package/plugins/vite/ai.d.ts +11 -10
  132. package/plugins/vite/ai.js +305 -31
  133. package/src/engine/api.ts +3 -0
  134. package/src/engine/engine_addressables.ts +4 -1
  135. package/src/engine/engine_animation.ts +47 -9
  136. package/src/engine/engine_components.ts +36 -7
  137. package/src/engine/engine_context.ts +11 -2
  138. package/src/engine/engine_gameobject.ts +5 -0
  139. package/src/engine/engine_init.ts +4 -0
  140. package/src/engine/engine_input.ts +2 -1
  141. package/src/engine/engine_materialpropertyblock.ts +1 -20
  142. package/src/engine/engine_networking.ts +46 -23
  143. package/src/engine/engine_networking_instantiate.ts +160 -18
  144. package/src/engine/engine_networking_prefabs.ts +80 -0
  145. package/src/engine/engine_physics_rapier.ts +14 -9
  146. package/src/engine/postprocessing/api.ts +2 -0
  147. package/src/engine/postprocessing/index.ts +2 -0
  148. package/src/engine/postprocessing/postprocessing.ts +322 -0
  149. package/src/engine/postprocessing/types.ts +43 -0
  150. package/src/engine/webcomponents/WebXRButtons.ts +21 -4
  151. package/src/engine/webcomponents/icons.ts +5 -3
  152. package/src/engine/xr/NeedleXRSession.ts +50 -15
  153. package/src/engine/xr/init.ts +56 -0
  154. package/src/engine-components/AnimationUtils.ts +7 -17
  155. package/src/engine-components/AnimatorController.ts +288 -18
  156. package/src/engine-components/GroundProjection.ts +226 -52
  157. package/src/engine-components/OrbitControls.ts +5 -1
  158. package/src/engine-components/SeeThrough.ts +0 -116
  159. package/src/engine-components/SyncedRoom.ts +28 -9
  160. package/src/engine-components/SyncedTransform.ts +5 -5
  161. package/src/engine-components/Voip.ts +129 -2
  162. package/src/engine-components/api.ts +1 -0
  163. package/src/engine-components/codegen/components.ts +1 -0
  164. package/src/engine-components/postprocessing/Effects/Tonemapping.ts +16 -24
  165. package/src/engine-components/postprocessing/PostProcessingEffect.ts +9 -16
  166. package/src/engine-components/postprocessing/PostProcessingHandler.ts +2 -1
  167. package/src/engine-components/postprocessing/Volume.ts +72 -163
  168. package/src/engine-components/postprocessing/index.ts +1 -0
  169. package/src/engine-components/postprocessing/utils.ts +2 -0
  170. package/src/engine-components/ui/Canvas.ts +2 -2
  171. package/src/engine-components/ui/Graphic.ts +7 -3
  172. package/src/engine-components/ui/Text.ts +170 -52
  173. package/src/engine-components/ui/index.ts +2 -1
  174. package/src/engine-components-experimental/networking/PlayerSync.ts +64 -11
  175. package/dist/needle-engine.bundle-B3ywqx5o.min.js +0 -1654
  176. package/dist/needle-engine.bundle-CzOPcOui.umd.cjs +0 -1654
@@ -1,14 +1,13 @@
1
- import type { Effect, EffectComposer } from "postprocessing";
1
+ import type { Effect } from "postprocessing";
2
2
 
3
- import { isDevEnvironment, showBalloonMessage } from "../../engine/debug/index.js";
4
- import { Context } from "../../engine/engine_context.js";
3
+ import { showBalloonMessage } from "../../engine/debug/index.js";
5
4
  import type { EditorModification, IEditorModification as IEditorModificationReceiver } from "../../engine/engine_editor-sync.js";
6
5
  import { serializeable } from "../../engine/engine_serialization_decorator.js";
7
- import { DeviceUtilities, getParam } from "../../engine/engine_utils.js";
6
+ import { getParam } from "../../engine/engine_utils.js";
7
+ import type { PostProcessing } from "../../engine/postprocessing/index.js";
8
8
  import { Behaviour } from "../Component.js";
9
9
  import { EffectWrapper } from "./Effects/EffectWrapper.js";
10
10
  import { PostProcessingEffect } from "./PostProcessingEffect.js";
11
- import { PostProcessingHandler } from "./PostProcessingHandler.js";
12
11
  import { IPostProcessingManager, setPostprocessingManagerType } from "./utils.js";
13
12
  import { VolumeParameter } from "./VolumeParameter.js";
14
13
  import { VolumeProfile } from "./VolumeProfile.js";
@@ -16,9 +15,12 @@ import { VolumeProfile } from "./VolumeProfile.js";
16
15
  const debug = getParam("debugpost");
17
16
 
18
17
 
19
- /** [Volume](https://engine.needle.tools/docs/api/Volume) The Volume/PostprocessingManager component is responsible for managing post processing effects.
20
- * Add this component to any object in your scene to enable post processing effects.
21
- *
18
+ /** [Volume](https://engine.needle.tools/docs/api/Volume) The Volume/PostprocessingManager component is responsible for managing post processing effects.
19
+ * Add this component to any object in your scene to enable post processing effects.
20
+ *
21
+ * Effects added to this Volume (via profile or code) are pushed to `context.postprocessing` when the Volume is enabled,
22
+ * and removed when it is disabled.
23
+ *
22
24
  * @example Add bloom
23
25
  * ```ts
24
26
  * const volume = new Volume();
@@ -28,22 +30,25 @@ const debug = getParam("debugpost");
28
30
  * }));
29
31
  * gameObject.addComponent(volume);
30
32
  * ```
31
- *
33
+ *
32
34
  * @example Remove bloom
33
35
  * ```ts
34
36
  * volume.removeEffect(bloom);
35
37
  * ```
36
- *
38
+ *
37
39
  * @example Add pixelation
38
40
  * ```ts
39
41
  * const pixelation = new PixelationEffect();
40
42
  * pixelation.granularity.value = 10;
41
43
  * volume.addEffect(pixelation);
42
44
  * ```
43
- *
45
+ *
44
46
  * @summary Manage Post-Processing Effects
45
47
  * @category Rendering
46
48
  * @category Effects
49
+ * @see {@link VolumeProfile} for profile-based effect management
50
+ * @see {@link PostProcessingEffect} for creating custom effects
51
+ * @see {@link PostProcessing} for core Needle Engine postprocessing control, also accessible via `context.postprocessing`
47
52
  * @group Components
48
53
  */
49
54
  export class Volume extends Behaviour implements IEditorModificationReceiver, IPostProcessingManager {
@@ -52,7 +57,7 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
52
57
  return true;
53
58
  }
54
59
 
55
- /** Currently active postprocessing effects */
60
+ /** Currently active postprocessing effects managed by this Volume */
56
61
  get effects() {
57
62
  return this._activeEffects;
58
63
  }
@@ -64,8 +69,9 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
64
69
  sharedProfile?: VolumeProfile;
65
70
 
66
71
  /**
67
- * Set multisampling to "auto" to automatically adjust the multisampling level based on performance.
72
+ * Set multisampling to "auto" to automatically adjust the multisampling level based on performance.
68
73
  * Set to a number to manually set the multisampling level.
74
+ * Pushed to `context.postprocessing.multisampling` when this Volume is active.
69
75
  * @default "auto"
70
76
  * @min 0
71
77
  * @max renderer.capabilities.maxSamples
@@ -76,6 +82,7 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
76
82
  /** When enabled, the device pixel ratio will be gradually reduced when FPS is low
77
83
  * and restored when performance recovers. This helps maintain smooth frame rates
78
84
  * on devices where full retina resolution is too expensive for postprocessing.
85
+ * Pushed to `context.postprocessing.adaptiveResolution` when this Volume is active.
79
86
  * Disable this if you need a fixed resolution and prefer consistent quality over frame rate.
80
87
  * @default true
81
88
  */
@@ -83,7 +90,7 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
83
90
  adaptiveResolution: boolean = true;
84
91
 
85
92
  /**
86
- * Add a post processing effect to the stack and schedules the effect stack to be re-created.
93
+ * Add a post processing effect to this Volume and push it to the core postprocessing stack.
87
94
  */
88
95
  addEffect<T extends PostProcessingEffect | Effect>(effect: T & { order?: number }): T {
89
96
  let entry = effect as PostProcessingEffect;
@@ -94,24 +101,34 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
94
101
  if (entry.gameObject === undefined) this.gameObject.addComponent(entry);
95
102
  if (this._effects.includes(entry)) return effect;
96
103
  this._effects.push(entry);
104
+ // Track as active so removeEffectsFromCore cleans it up on disable
105
+ if (!this._activeEffects.includes(entry))
106
+ this._activeEffects.push(entry);
107
+ // Push to core stack
108
+ this.context.postprocessing.addEffect(entry);
97
109
  this._isDirty = true;
98
110
  return effect;
99
111
  }
112
+
100
113
  /**
101
- * Remove a post processing effect from the stack and schedules the effect stack to be re-created.
114
+ * Remove a post processing effect from this Volume and the core postprocessing stack.
102
115
  */
103
116
  removeEffect<T extends PostProcessingEffect | Effect>(effect: T): T {
104
117
 
105
118
  let index = -1;
119
+ let entry: PostProcessingEffect | undefined;
106
120
  if (!(effect instanceof PostProcessingEffect)) {
107
121
  index = this._effects.findIndex(e => e instanceof EffectWrapper && e.effect === effect);
122
+ if (index !== -1) entry = this._effects[index];
108
123
  }
109
124
  else {
110
125
  index = this._effects.indexOf(effect);
126
+ if (index !== -1) entry = this._effects[index];
111
127
  }
112
128
 
113
- if (index !== -1) {
129
+ if (index !== -1 && entry) {
114
130
  this._effects.splice(index, 1);
131
+ this.context.postprocessing.removeEffect(entry);
115
132
  this._isDirty = true;
116
133
  return effect;
117
134
  }
@@ -119,15 +136,15 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
119
136
  // if the effect is part of the shared profile remove it from there
120
137
  const si = this.sharedProfile?.components?.indexOf(effect);
121
138
  if (si !== undefined && si !== -1) {
122
- this._isDirty = true;
123
139
  this.sharedProfile?.components?.splice(si, 1);
140
+ this.context.postprocessing.removeEffect(effect);
141
+ this._isDirty = true;
124
142
  }
125
143
  }
126
144
 
127
145
  return effect;
128
146
  }
129
147
 
130
- private _postprocessing?: PostProcessingHandler;
131
148
  private readonly _activeEffects: PostProcessingEffect[] = [];
132
149
  private readonly _effects: PostProcessingEffect[] = [];
133
150
 
@@ -156,144 +173,46 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
156
173
  this.sharedProfile?.__init(this);
157
174
  }
158
175
 
159
- private _componentEnabledTime: number = -1;
160
- private _multisampleAutoChangeTime: number = 0;
161
- private _multisampleAutoDecreaseTime: number = 0;
176
+ private _isDirty: boolean = false;
162
177
 
163
178
  /** @internal */
164
179
  onEnable(): void {
165
- this._componentEnabledTime = this.context.time.realtimeSinceStartup;
166
180
  this._isDirty = true;
181
+ this.pushEffectsToCore();
182
+ this.syncConfigToCore();
167
183
  }
168
184
 
169
185
  /** @internal */
170
186
  onDisable() {
171
- this._postprocessing?.unapply();
187
+ this.removeEffectsFromCore();
172
188
  this._isDirty = false;
173
189
  }
174
190
 
175
191
  /** @internal */
176
192
  onBeforeRender(): void {
177
- if (!this.context.isInXR) {
178
-
179
- // TODO: not sure when this was/could be the case? Maybe when using the default three composer?
180
- // if (this.context.composer && (this.context.composer instanceof EffectComposer) === false) {
181
- // if (debug) console.warn("PostProcessing: The current composer is not an EffectComposer - this is not supported");
182
- // return;
183
- // }
184
-
185
- // Wait for the first frame to be rendered before creating because then we know we have a camera (issue 135)
186
- if (this.context.mainCamera) {
187
- if (this._isDirty) {
188
- this.apply();
189
- }
190
- }
191
-
192
- if (this.context.composer && this._postprocessing && this._postprocessing.composer === this.context.composer) {
193
- if (this.context.renderer.getContext().isContextLost()) {
194
- this.context.renderer.forceContextRestore();
195
- }
196
- if (this.context.composer.getRenderer() !== this.context.renderer)
197
- this.context.composer.setRenderer(this.context.renderer);
198
-
199
- this.context.composer.setMainScene(this.context.scene);
200
-
201
- if (this.multisampling === "auto") {
202
-
203
- // If the postprocessing handler is using depth+normals (e.g. with SMAA) we ALWAYS disable multisampling to avoid ugly edges
204
- if (this._postprocessing && (this._postprocessing.hasSmaaEffect)) {
205
- if (this._postprocessing.multisampling !== 0) {
206
- this._postprocessing.multisampling = 0;
207
- if (debug || isDevEnvironment()) {
208
- console.log(`[PostProcessing] multisampling is disabled because it's set to 'auto' on your PostprocessingManager/Volume component that also has an SMAA effect.\n\nIf you need multisampling consider changing 'auto' to a fixed value (e.g. 4).`);
209
- }
210
- }
211
- }
212
- else {
213
- const timeSinceLastChange = this.context.time.realtimeSinceStartup - this._multisampleAutoChangeTime;
214
-
215
- if (this.context.time.realtimeSinceStartup - this._componentEnabledTime > 2
216
- && timeSinceLastChange > .5
217
- ) {
218
- const prev = this._postprocessing.multisampling;
219
-
220
- if (this._postprocessing.multisampling > 0 && this.context.time.smoothedFps <= 50) {
221
- this._multisampleAutoChangeTime = this.context.time.realtimeSinceStartup;
222
- this._multisampleAutoDecreaseTime = this.context.time.realtimeSinceStartup;
223
- let newMultiSample = this._postprocessing.multisampling * .5;
224
- newMultiSample = Math.floor(newMultiSample);
225
- if (newMultiSample != this._postprocessing.multisampling) {
226
- this._postprocessing.multisampling = newMultiSample;
227
- }
228
- if (debug) console.debug(`[PostProcessing] Reduced multisampling from ${prev} to ${this._postprocessing.multisampling}`);
229
- }
230
- // if performance is good for a while try increasing multisampling again
231
- else if (timeSinceLastChange > 1
232
- && this.context.time.smoothedFps >= 59
233
- && this._postprocessing.multisampling < this.context.renderer.capabilities.maxSamples
234
- && this.context.time.realtimeSinceStartup - this._multisampleAutoDecreaseTime > 10
235
- ) {
236
- this._multisampleAutoChangeTime = this.context.time.realtimeSinceStartup;
237
- let newMultiSample = this._postprocessing.multisampling <= 0 ? 1 : this._postprocessing.multisampling * 2;
238
- newMultiSample = Math.floor(newMultiSample);
239
- if (newMultiSample !== this._postprocessing.multisampling) {
240
- this._postprocessing.multisampling = newMultiSample;
241
- }
242
- if (debug) console.debug(`[PostProcessing] Increased multisampling from ${prev} to ${this._postprocessing.multisampling}`);
243
- }
244
- }
245
- }
246
- }
247
- else {
248
- const newMultiSample = Math.max(0, Math.min(this.multisampling, this.context.renderer.capabilities.maxSamples));
249
- if (newMultiSample !== this._postprocessing.multisampling)
250
- this._postprocessing.multisampling = newMultiSample;
251
- }
193
+ if (this._isDirty) {
194
+ this.removeEffectsFromCore();
195
+ this.pushEffectsToCore();
196
+ this._isDirty = false;
197
+ }
198
+ // Push config changes (user may change multisampling/adaptiveResolution at runtime)
199
+ this.syncConfigToCore();
252
200
 
253
- // Adaptively reduce pixel ratio when FPS is low
254
- this._postprocessing.adaptivePixelRatio = this.adaptiveResolution;
255
- this._postprocessing.updateAdaptivePixelRatio();
256
-
257
- // only set the main camera if any pass has a different camera
258
- // trying to avoid doing this regularly since it involves doing potentially unnecessary work
259
- // https://github.com/pmndrs/postprocessing/blob/3d3df0576b6d49aec9e763262d5a1ff7429fd91a/src/core/EffectComposer.js#L406
260
- if (this.context.mainCamera) {
261
- const passes = this.context.composer.passes;
262
- for (const pass of passes) {
263
- if (pass.mainCamera && pass.mainCamera !== this.context.mainCamera) {
264
- this.context.composer.setMainCamera(this.context.mainCamera);
265
- break;
266
- }
267
- }
268
- }
269
- }
201
+ // Process queued editor modifications after the handler is ready
202
+ if (this.context.postprocessing.handler) {
203
+ this._applyPostQueue();
270
204
  }
271
205
  }
272
206
 
273
207
  /** @internal */
274
208
  onDestroy(): void {
275
- this._postprocessing?.dispose();
209
+ this.removeEffectsFromCore();
276
210
  }
277
211
 
278
- private _lastApplyTime?: number;
279
- private _rapidApplyCount = 0;
280
- private _isDirty: boolean = false;
281
-
282
- private apply() {
283
- if (debug) console.log(`Apply PostProcessing "${this.name || "unnamed"}"`);
284
-
285
- if (isDevEnvironment()) {
286
- if (this._lastApplyTime !== undefined && Date.now() - this._lastApplyTime < 100) {
287
- this._rapidApplyCount++;
288
- if (this._rapidApplyCount === 5)
289
- console.warn("Detected rapid post processing modifications - this might be a bug", this);
290
- }
291
- this._lastApplyTime = Date.now();
292
- }
293
-
294
- this._isDirty = false;
295
-
212
+ /** Collect active effects from profile + code and push them to context.postprocessing */
213
+ private pushEffectsToCore() {
296
214
  this._activeEffects.length = 0;
215
+
297
216
  // get from profile
298
217
  if (this.sharedProfile?.components) {
299
218
  const comps = this.sharedProfile.components;
@@ -308,36 +227,26 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
308
227
  this._activeEffects.push(effect);
309
228
  }
310
229
 
311
- if (this._activeEffects.length > 0) {
312
- if (!this._postprocessing)
313
- this._postprocessing = new PostProcessingHandler(this.context);
314
-
315
- this._postprocessing.apply(this._activeEffects)
316
- ?.then(() => {
317
- if (!this.activeAndEnabled) return;
318
-
319
- this._applyPostQueue();
320
-
321
- if (this._postprocessing) {
322
- if (this.multisampling === "auto") {
323
- this._postprocessing.multisampling = DeviceUtilities.isMobileDevice()
324
- ? 2
325
- : 4;
326
- }
327
- else {
328
- this._postprocessing.multisampling = Math.max(0, Math.min(this.multisampling, this.context.renderer.capabilities.maxSamples));
329
- }
330
- if (debug) console.debug(`[PostProcessing] Set multisampling to ${this._postprocessing.multisampling} (Is Mobile: ${DeviceUtilities.isMobileDevice()})`);
331
- }
332
- else if (debug) {
333
- console.warn(`[PostProcessing] No composer found`);
334
- }
335
- })
230
+ const pp = this.context.postprocessing;
231
+ for (const effect of this._activeEffects) {
232
+ pp.addEffect(effect);
336
233
  }
337
- else {
338
- this._postprocessing?.unapply(false);
234
+ }
235
+
236
+ /** Remove all effects this Volume contributed from the core stack */
237
+ private removeEffectsFromCore() {
238
+ const pp = this.context.postprocessing;
239
+ for (const effect of this._activeEffects) {
240
+ pp.removeEffect(effect);
339
241
  }
242
+ this._activeEffects.length = 0;
243
+ }
340
244
 
245
+ /** Push multisampling and adaptiveResolution config to the core stack */
246
+ private syncConfigToCore() {
247
+ const pp = this.context.postprocessing;
248
+ pp.multisampling = this.multisampling;
249
+ pp.adaptiveResolution = this.adaptiveResolution;
341
250
  }
342
251
 
343
252
  private _applyPostQueue() {
@@ -352,7 +261,7 @@ export class Volume extends Behaviour implements IEditorModificationReceiver, IP
352
261
 
353
262
  if (modification.propertyName.startsWith("postprocessing.")) {
354
263
 
355
- if (!this._postprocessing) {
264
+ if (!this.context.postprocessing.handler) {
356
265
  if (!this._modificationQueue) this._modificationQueue = new Map<string, EditorModification>();
357
266
  this._modificationQueue.set(modification.propertyName, modification);
358
267
  return true;
@@ -439,4 +348,4 @@ const effectVolumeProperties: Map<string, string[]> = new Map<string, string[]>(
439
348
 
440
349
  setPostprocessingManagerType(Volume);
441
350
 
442
- export { Volume as PostProcessingManager };
351
+ export { Volume as PostProcessingManager };
@@ -2,5 +2,6 @@ export * from "./PostProcessingEffect.js";
2
2
  export * from "./PostProcessingHandler.js"
3
3
  export { PostProcessingEffectOrder } from "./utils.js";
4
4
  export { PostProcessingManager } from "./Volume.js"
5
+ export { Volume } from "./Volume.js"
5
6
  export * from "./VolumeParameter.js"
6
7
  export * from "./VolumeProfile.js";
@@ -26,6 +26,7 @@ export function setPostprocessingManagerType(type: ConstructorConcrete<IPostProc
26
26
  PostprocessingManagerType = type;
27
27
  }
28
28
 
29
+ /** @deprecated Use `context.postprocessing` instead. Effects now register directly with the core postprocessing stack. */
29
30
  export function findPostProcessingManager(effect: PostProcessingEffect): IPostProcessingManager | null {
30
31
  let obj = effect.gameObject as Object3D | null;
31
32
  while (obj) {
@@ -39,6 +40,7 @@ export function findPostProcessingManager(effect: PostProcessingEffect): IPostPr
39
40
  return null;
40
41
  }
41
42
 
43
+ /** @deprecated Use `context.postprocessing` instead. Effects now register directly with the core postprocessing stack. */
42
44
  export function getPostProcessingManager(effect: PostProcessingEffect): IPostProcessingManager | null {
43
45
  let manager: IPostProcessingManager | null = findPostProcessingManager(effect);
44
46
  if (!manager) {
@@ -132,7 +132,7 @@ export class Canvas extends UIRootComponent implements ICanvas {
132
132
  this._renderMode = val;
133
133
  this.onRenderSettingsChanged();
134
134
  }
135
- private _renderMode: RenderMode = RenderMode.Undefined;
135
+ private _renderMode: RenderMode = RenderMode.WorldSpace;
136
136
 
137
137
  private _rootCanvas!: Canvas;
138
138
 
@@ -159,7 +159,7 @@ export class Canvas extends UIRootComponent implements ICanvas {
159
159
  worldCamera?: Camera;
160
160
 
161
161
  @serializable()
162
- planeDistance: number = -1;
162
+ planeDistance: number = 100;
163
163
 
164
164
  awake() {
165
165
  //@ts-ignore
@@ -35,8 +35,12 @@ export class Graphic extends BaseUIComponent implements IGraphic, IRectTransform
35
35
  if (!this._color) this._color = new RGBAColor(1, 1, 1, 1);
36
36
  return this._color;
37
37
  }
38
- set color(col: RGBAColor) {
39
- const changed = !this._color || this._color.r !== col.r || this._color.g !== col.g || this._color.b !== col.b || this._color.alpha !== col.alpha;
38
+ set color(col: RGBAColor | Color) {
39
+ const changed = !this._color
40
+ || this._color.r !== col.r
41
+ || this._color.g !== col.g
42
+ || this._color.b !== col.b
43
+ || ("alpha" in col ? this._color.alpha !== col.alpha : this._color.alpha !== 1);
40
44
  if (!changed) return;
41
45
  if (!this._color) {
42
46
  this._color = new RGBAColor(1, 1, 1, 1);
@@ -44,6 +48,7 @@ export class Graphic extends BaseUIComponent implements IGraphic, IRectTransform
44
48
  this._color.copy(col);
45
49
  this.onColorChanged();
46
50
  }
51
+ private _color: RGBAColor = null!;
47
52
 
48
53
  private _alphaFactor: number = 1;
49
54
  setAlphaFactor(factor: number) {
@@ -88,7 +93,6 @@ export class Graphic extends BaseUIComponent implements IGraphic, IRectTransform
88
93
  raycastTarget: boolean = true;
89
94
 
90
95
  protected uiObject: ThreeMeshUI.Block | null = null;
91
- private _color: RGBAColor = null!;
92
96
 
93
97
  private _rect: RectTransform | null = null;
94
98