@needle-tools/engine 2.67.4-pre → 2.67.6-pre

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 (32) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/needle-engine.js +5376 -5344
  3. package/dist/needle-engine.umd.cjs +227 -227
  4. package/lib/engine/engine_gizmos.js +7 -0
  5. package/lib/engine/engine_gizmos.js.map +1 -1
  6. package/lib/engine/engine_setup.js +5 -5
  7. package/lib/engine/engine_setup.js.map +1 -1
  8. package/lib/engine-components/postprocessing/Effects/DepthOfField.js +1 -0
  9. package/lib/engine-components/postprocessing/Effects/DepthOfField.js.map +1 -1
  10. package/lib/engine-components/postprocessing/Effects/Pixelation.js +0 -1
  11. package/lib/engine-components/postprocessing/Effects/Pixelation.js.map +1 -1
  12. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.js +3 -3
  13. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.js.map +1 -1
  14. package/lib/engine-components/postprocessing/PostProcessingEffect.js +3 -2
  15. package/lib/engine-components/postprocessing/PostProcessingEffect.js.map +1 -1
  16. package/lib/engine-components/postprocessing/PostProcessingHandler.d.ts +1 -0
  17. package/lib/engine-components/postprocessing/PostProcessingHandler.js +70 -22
  18. package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
  19. package/lib/engine-components/postprocessing/Volume.js +20 -10
  20. package/lib/engine-components/postprocessing/Volume.js.map +1 -1
  21. package/lib/engine-components/postprocessing/VolumeParameter.js +1 -1
  22. package/lib/engine-components/postprocessing/VolumeParameter.js.map +1 -1
  23. package/package.json +1 -1
  24. package/src/engine/engine_gizmos.ts +7 -0
  25. package/src/engine/engine_setup.ts +4 -5
  26. package/src/engine-components/postprocessing/Effects/DepthOfField.ts +1 -0
  27. package/src/engine-components/postprocessing/Effects/Pixelation.ts +0 -1
  28. package/src/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.ts +2 -2
  29. package/src/engine-components/postprocessing/PostProcessingEffect.ts +3 -2
  30. package/src/engine-components/postprocessing/PostProcessingHandler.ts +75 -29
  31. package/src/engine-components/postprocessing/Volume.ts +213 -201
  32. package/src/engine-components/postprocessing/VolumeParameter.ts +1 -1
@@ -1,201 +1,213 @@
1
- import { Behaviour, GameObject } from "../Component";
2
- import { serializeable } from "../../engine/engine_serialization_decorator";
3
- import { getParam } from "../../engine/engine_utils";
4
- import { VolumeProfile } from "./VolumeProfile";
5
- import { EditorModification, IEditorModification as IEditorModificationReceiver } from "../../engine/engine_editor-sync";
6
- import { PostProcessingHandler } from "./PostProcessingHandler";
7
- import { PostProcessingEffect } from "./PostProcessingEffect";
8
- import { VolumeParameter } from "./VolumeParameter";
9
- import { getEditorModificationCache } from "../../engine/engine_editor-sync";
10
- import { isDevEnvironment } from "../../engine/debug";
11
-
12
- const debug = getParam("debugpost");
13
-
14
- export class Volume extends Behaviour implements IEditorModificationReceiver {
15
-
16
- @serializeable(VolumeProfile)
17
- sharedProfile?: VolumeProfile;
18
-
19
- private _postprocessing?: PostProcessingHandler;
20
- private _effects: PostProcessingEffect[] = [];
21
-
22
- awake() {
23
- // ensure the profile is initialized
24
- this.sharedProfile?.init();
25
-
26
- if (debug) {
27
- console.log(this);
28
- console.log("Press P to toggle post processing");
29
- window.addEventListener("keydown", (e) => {
30
- if (e.key === "p") {
31
- console.log("Toggle volume: " + this.name, !this.enabled);
32
- this.enabled = !this.enabled;
33
- }
34
- });
35
- }
36
- }
37
-
38
- onDisable() {
39
- this._postprocessing?.unapply();
40
- }
41
-
42
- onBeforeRender(): void {
43
- // Wait for the first frame to be rendered before creating because then we know we have a camera (issue 135)
44
- if (this.context.mainCamera) {
45
- if (!this._postprocessing || !this._postprocessing.isActive)
46
- this.apply();
47
- }
48
-
49
- if (!this.context.isInXR && this.context.composer && this.context.mainCamera) {
50
- this.context.composer.setRenderer(this.context.renderer);
51
- this.context.composer.setMainScene(this.context.scene);
52
- this.context.composer.setMainCamera(this.context.mainCamera);
53
- }
54
- }
55
-
56
- onDestroy(): void {
57
- this._postprocessing?.dispose();
58
- }
59
-
60
- private _lastApplyTime?: number;
61
- private _rapidApplyCount = 0;
62
-
63
- private apply() {
64
- if (debug) console.log("Apply PostProcessing", this, this.context.mainCamera?.name);
65
-
66
- if (isDevEnvironment()) {
67
- if (this._lastApplyTime !== undefined && Date.now() - this._lastApplyTime < 100) {
68
- this._rapidApplyCount++;
69
- if (this._rapidApplyCount === 5)
70
- console.warn("Detected rapid post processing modifications - this might be a bug", this);
71
- }
72
- this._lastApplyTime = Date.now();
73
- }
74
-
75
-
76
- this.unapply();
77
-
78
- this._effects.length = 0;
79
- // get from profile
80
- if (this.sharedProfile?.components) {
81
- this._effects.push(...this.sharedProfile.components);
82
- }
83
- // get additional effects
84
- const additionalComponents = this.gameObject.getComponentsInChildren(PostProcessingEffect);
85
- if (debug && additionalComponents?.length)
86
- console.log("Additional", additionalComponents);
87
- if (additionalComponents) {
88
- for (const comp of additionalComponents) {
89
- if (comp.active) this._effects.push(comp);
90
- }
91
- }
92
-
93
- if (this._effects.length > 0) {
94
- if (!this._postprocessing)
95
- this._postprocessing = new PostProcessingHandler(this.context);
96
- this._postprocessing.apply(this._effects);
97
- }
98
-
99
- this._applyPostQueue();
100
- }
101
-
102
- private unapply() {
103
- this._postprocessing?.unapply();
104
- }
105
-
106
-
107
- private _applyPostQueue() {
108
- if (this._modificationQueue) {
109
- for (const entry of this._modificationQueue.values()) this.onEditorModification(entry);
110
- this._modificationQueue.clear();
111
- }
112
- }
113
-
114
- /** called from needle editor sync package if its active */
115
- onEditorModification(modification: EditorModification): void | boolean | undefined {
116
-
117
- if (modification.propertyName.startsWith("postprocessing.")) {
118
-
119
- if (!this._postprocessing) {
120
- if (!this._modificationQueue) this._modificationQueue = new Map<string, EditorModification>();
121
- this._modificationQueue.set(modification.propertyName, modification);
122
- return true;
123
- }
124
-
125
- if (!this._effects?.length) return;
126
- const path = modification.propertyName.split(".");
127
- if (path.length === 3 || path.length === 4) {
128
- const componentName = path[1];
129
- const propertyName = path[2];
130
- for (const comp of this._effects) {
131
- if (comp.typeName?.toLowerCase() === componentName.toLowerCase()) {
132
-
133
- if (propertyName === "active") {
134
- comp.active = modification.value;
135
- this.scheduleRecreate();
136
- return;
137
- }
138
-
139
- // cache the volume parameters
140
- if (!effectVolumeProperties.has(componentName)) {
141
- const volumeParameterKeys = new Array<string>();
142
- effectVolumeProperties.set(componentName, volumeParameterKeys);
143
- const keys = Object.keys(comp);
144
- for (const key of keys) {
145
- const prop = comp[key];
146
- if (prop instanceof VolumeParameter) {
147
- volumeParameterKeys.push(key);
148
- }
149
- }
150
- }
151
-
152
- if (effectVolumeProperties.has(componentName)) {
153
- const paramName = propertyName.toLowerCase();
154
- const volumeParameterKeys = effectVolumeProperties.get(componentName)!;
155
- for (const key of volumeParameterKeys) {
156
- if (key.toLowerCase() === paramName) {
157
- const prop = comp[key] as VolumeParameter;
158
- if (prop instanceof VolumeParameter) {
159
- const isActiveStateChange = path.length === 4 && path[3] === "active";
160
- if (isActiveStateChange) {
161
- prop.overrideState = modification.value;
162
- this.scheduleRecreate();
163
- }
164
- else if (prop && prop.value !== undefined) {
165
- prop.value = modification.value;
166
- }
167
- }
168
- return;
169
- }
170
- }
171
- }
172
-
173
- console.warn("Unknown modification", propertyName);
174
- return;
175
- }
176
- }
177
- }
178
- return true;
179
- }
180
-
181
- return false;
182
- }
183
-
184
- private _modificationQueue?: Map<string, EditorModification>;
185
-
186
- private _recreateId: number = -1;
187
- private scheduleRecreate() {
188
- // When the editor modifications come in with changed active effects we want/need to re-create the effects
189
- // We defer it slightly because multiple active changes could be made and we dont want to recreate the full effect stack multiple times
190
- const id = ++this._recreateId;
191
- setTimeout(() => {
192
- if (id !== this._recreateId) return;
193
- this.onDisable();
194
- this.onEnable();
195
- }, 200);
196
- }
197
-
198
- }
199
-
200
- /** cached VolumeParameter keys per object */
201
- const effectVolumeProperties: Map<string, string[]> = new Map<string, string[]>();
1
+ import { Behaviour, GameObject } from "../Component";
2
+ import { serializeable } from "../../engine/engine_serialization_decorator";
3
+ import { getParam } from "../../engine/engine_utils";
4
+ import { VolumeProfile } from "./VolumeProfile";
5
+ import { EditorModification, IEditorModification as IEditorModificationReceiver } from "../../engine/engine_editor-sync";
6
+ import { PostProcessingHandler } from "./PostProcessingHandler";
7
+ import { PostProcessingEffect } from "./PostProcessingEffect";
8
+ import { VolumeParameter } from "./VolumeParameter";
9
+ import { getEditorModificationCache } from "../../engine/engine_editor-sync";
10
+ import { isDevEnvironment } from "../../engine/debug";
11
+ import { EffectComposer } from "postprocessing";
12
+
13
+ const debug = getParam("debugpost");
14
+
15
+ export class Volume extends Behaviour implements IEditorModificationReceiver {
16
+
17
+ @serializeable(VolumeProfile)
18
+ sharedProfile?: VolumeProfile;
19
+
20
+ private _postprocessing?: PostProcessingHandler;
21
+ private _effects: PostProcessingEffect[] = [];
22
+
23
+ awake() {
24
+ // ensure the profile is initialized
25
+ this.sharedProfile?.init();
26
+
27
+ if (debug) {
28
+ console.log(this);
29
+ console.log("Press P to toggle post processing");
30
+ window.addEventListener("keydown", (e) => {
31
+ if (e.key === "p") {
32
+ console.log("Toggle volume: " + this.name, !this.enabled);
33
+ this.enabled = !this.enabled;
34
+ }
35
+ });
36
+ }
37
+ }
38
+
39
+ onDisable() {
40
+ this._postprocessing?.unapply();
41
+ }
42
+
43
+ onBeforeRender(): void {
44
+ if (!this.context.isInXR) {
45
+
46
+ if (this.context.composer && (this.context.composer instanceof EffectComposer) === false) {
47
+ return;
48
+ }
49
+
50
+ // Wait for the first frame to be rendered before creating because then we know we have a camera (issue 135)
51
+ if (this.context.mainCamera) {
52
+ if (!this._postprocessing || !this._postprocessing.isActive) {
53
+ this.apply();
54
+ // TODO: remove this workaround for postprocessing rendering not working correctly when applied for the first time
55
+ this.apply();
56
+ }
57
+ }
58
+
59
+ if (this.context.composer) {
60
+ this.context.composer.setRenderer(this.context.renderer);
61
+ this.context.composer.setMainScene(this.context.scene);
62
+ if (this.context.mainCamera)
63
+ this.context.composer.setMainCamera(this.context.mainCamera);
64
+ }
65
+ }
66
+ }
67
+
68
+ onDestroy(): void {
69
+ this._postprocessing?.dispose();
70
+ }
71
+
72
+ private _lastApplyTime?: number;
73
+ private _rapidApplyCount = 0;
74
+
75
+ private apply() {
76
+ if (debug) console.log("Apply PostProcessing", this, this.context.mainCamera?.name);
77
+
78
+ if (isDevEnvironment()) {
79
+ if (this._lastApplyTime !== undefined && Date.now() - this._lastApplyTime < 100) {
80
+ this._rapidApplyCount++;
81
+ if (this._rapidApplyCount === 5)
82
+ console.warn("Detected rapid post processing modifications - this might be a bug", this);
83
+ }
84
+ this._lastApplyTime = Date.now();
85
+ }
86
+
87
+
88
+ this.unapply();
89
+
90
+ this._effects.length = 0;
91
+ // get from profile
92
+ if (this.sharedProfile?.components) {
93
+ this._effects.push(...this.sharedProfile.components);
94
+ }
95
+ // get additional effects
96
+ const additionalComponents = this.gameObject.getComponentsInChildren(PostProcessingEffect);
97
+ if (debug && additionalComponents?.length)
98
+ console.log("Additional", additionalComponents);
99
+ if (additionalComponents) {
100
+ for (const comp of additionalComponents) {
101
+ if (comp.active) this._effects.push(comp);
102
+ }
103
+ }
104
+
105
+ if (this._effects.length > 0) {
106
+ if (!this._postprocessing)
107
+ this._postprocessing = new PostProcessingHandler(this.context);
108
+ this._postprocessing.apply(this._effects);
109
+ this._applyPostQueue();
110
+ }
111
+
112
+ }
113
+
114
+ private unapply() {
115
+ this._postprocessing?.unapply();
116
+ }
117
+
118
+
119
+ private _applyPostQueue() {
120
+ if (this._modificationQueue) {
121
+ for (const entry of this._modificationQueue.values()) this.onEditorModification(entry);
122
+ this._modificationQueue.clear();
123
+ }
124
+ }
125
+
126
+ /** called from needle editor sync package if its active */
127
+ onEditorModification(modification: EditorModification): void | boolean | undefined {
128
+
129
+ if (modification.propertyName.startsWith("postprocessing.")) {
130
+
131
+ if (!this._postprocessing) {
132
+ if (!this._modificationQueue) this._modificationQueue = new Map<string, EditorModification>();
133
+ this._modificationQueue.set(modification.propertyName, modification);
134
+ return true;
135
+ }
136
+
137
+ if (!this._effects?.length) return;
138
+ const path = modification.propertyName.split(".");
139
+ if (path.length === 3 || path.length === 4) {
140
+ const componentName = path[1];
141
+ const propertyName = path[2];
142
+ for (const comp of this._effects) {
143
+ if (comp.typeName?.toLowerCase() === componentName.toLowerCase()) {
144
+
145
+ if (propertyName === "active") {
146
+ comp.active = modification.value;
147
+ this.scheduleRecreate();
148
+ return;
149
+ }
150
+
151
+ // cache the volume parameters
152
+ if (!effectVolumeProperties.has(componentName)) {
153
+ const volumeParameterKeys = new Array<string>();
154
+ effectVolumeProperties.set(componentName, volumeParameterKeys);
155
+ const keys = Object.keys(comp);
156
+ for (const key of keys) {
157
+ const prop = comp[key];
158
+ if (prop instanceof VolumeParameter) {
159
+ volumeParameterKeys.push(key);
160
+ }
161
+ }
162
+ }
163
+
164
+ if (effectVolumeProperties.has(componentName)) {
165
+ const paramName = propertyName.toLowerCase();
166
+ const volumeParameterKeys = effectVolumeProperties.get(componentName)!;
167
+ for (const key of volumeParameterKeys) {
168
+ if (key.toLowerCase() === paramName) {
169
+ const prop = comp[key] as VolumeParameter;
170
+ if (prop instanceof VolumeParameter) {
171
+ const isActiveStateChange = path.length === 4 && path[3] === "active";
172
+ if (isActiveStateChange) {
173
+ prop.overrideState = modification.value;
174
+ this.scheduleRecreate();
175
+ }
176
+ else if (prop && prop.value !== undefined) {
177
+ prop.value = modification.value;
178
+ }
179
+ }
180
+ return;
181
+ }
182
+ }
183
+ }
184
+
185
+ console.warn("Unknown modification", propertyName);
186
+ return;
187
+ }
188
+ }
189
+ }
190
+ return true;
191
+ }
192
+
193
+ return false;
194
+ }
195
+
196
+ private _modificationQueue?: Map<string, EditorModification>;
197
+
198
+ private _recreateId: number = -1;
199
+ private scheduleRecreate() {
200
+ // When the editor modifications come in with changed active effects we want/need to re-create the effects
201
+ // We defer it slightly because multiple active changes could be made and we dont want to recreate the full effect stack multiple times
202
+ const id = ++this._recreateId;
203
+ setTimeout(() => {
204
+ if (id !== this._recreateId) return;
205
+ this.onDisable();
206
+ this.onEnable();
207
+ }, 200);
208
+ }
209
+
210
+ }
211
+
212
+ /** cached VolumeParameter keys per object */
213
+ const effectVolumeProperties: Map<string, string[]> = new Map<string, string[]>();
@@ -15,7 +15,7 @@ export class VolumeParameter {
15
15
  const value = val ? this._lastActiveSetValue : this._defaultValue;
16
16
  this.processValue(value, true);
17
17
  }
18
- private _active: boolean = false;
18
+ private _active: boolean = true;
19
19
 
20
20
 
21
21