@needle-tools/engine 2.42.0-pre → 2.44.0-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 (62) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/needle-engine.d.ts +224 -81
  3. package/dist/needle-engine.js +3836 -422
  4. package/dist/needle-engine.js.map +4 -4
  5. package/dist/needle-engine.min.js +40 -40
  6. package/dist/needle-engine.min.js.map +4 -4
  7. package/lib/engine/engine_element_loading.js +22 -6
  8. package/lib/engine/engine_element_loading.js.map +1 -1
  9. package/lib/engine/engine_input.js +17 -6
  10. package/lib/engine/engine_input.js.map +1 -1
  11. package/lib/engine/engine_serialization_builtin_serializer.js +60 -58
  12. package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
  13. package/lib/engine/engine_three_utils.d.ts +1 -0
  14. package/lib/engine/engine_three_utils.js +10 -0
  15. package/lib/engine/engine_three_utils.js.map +1 -1
  16. package/lib/engine/engine_time.js +2 -0
  17. package/lib/engine/engine_time.js.map +1 -1
  18. package/lib/engine/extensions/NEEDLE_techniques_webgl.js +42 -0
  19. package/lib/engine/extensions/NEEDLE_techniques_webgl.js.map +1 -1
  20. package/lib/engine-components/Animation.d.ts +3 -1
  21. package/lib/engine-components/Animation.js +25 -1
  22. package/lib/engine-components/Animation.js.map +1 -1
  23. package/lib/engine-components/AnimatorController.js +4 -1
  24. package/lib/engine-components/AnimatorController.js.map +1 -1
  25. package/lib/engine-components/Camera.d.ts +3 -0
  26. package/lib/engine-components/Camera.js +17 -9
  27. package/lib/engine-components/Camera.js.map +1 -1
  28. package/lib/engine-components/ParticleSystem.d.ts +33 -7
  29. package/lib/engine-components/ParticleSystem.js +464 -249
  30. package/lib/engine-components/ParticleSystem.js.map +1 -1
  31. package/lib/engine-components/ParticleSystemBehaviours.d.ts +0 -0
  32. package/lib/engine-components/ParticleSystemBehaviours.js +2 -0
  33. package/lib/engine-components/ParticleSystemBehaviours.js.map +1 -0
  34. package/lib/engine-components/ParticleSystemModules.d.ts +123 -20
  35. package/lib/engine-components/ParticleSystemModules.js +461 -63
  36. package/lib/engine-components/ParticleSystemModules.js.map +1 -1
  37. package/lib/engine-components/WebXRController.d.ts +1 -0
  38. package/lib/engine-components/WebXRController.js +2 -1
  39. package/lib/engine-components/WebXRController.js.map +1 -1
  40. package/lib/engine-components/codegen/components.d.ts +6 -0
  41. package/lib/engine-components/codegen/components.js +6 -0
  42. package/lib/engine-components/codegen/components.js.map +1 -1
  43. package/lib/engine-components/js-extensions/RGBAColor.d.ts +1 -0
  44. package/lib/engine-components/js-extensions/RGBAColor.js +7 -0
  45. package/lib/engine-components/js-extensions/RGBAColor.js.map +1 -1
  46. package/package.json +2 -1
  47. package/src/engine/codegen/register_types.js +24 -0
  48. package/src/engine/engine_element_loading.ts +22 -5
  49. package/src/engine/engine_input.ts +16 -7
  50. package/src/engine/engine_serialization_builtin_serializer.ts +59 -57
  51. package/src/engine/engine_three_utils.ts +11 -2
  52. package/src/engine/engine_time.ts +1 -0
  53. package/src/engine/extensions/NEEDLE_techniques_webgl.ts +43 -1
  54. package/src/engine-components/Animation.ts +18 -2
  55. package/src/engine-components/AnimatorController.ts +5 -1
  56. package/src/engine-components/Camera.ts +17 -10
  57. package/src/engine-components/ParticleSystem.ts +526 -303
  58. package/src/engine-components/ParticleSystemBehaviours.ts +0 -0
  59. package/src/engine-components/ParticleSystemModules.ts +408 -66
  60. package/src/engine-components/WebXRController.ts +2 -1
  61. package/src/engine-components/codegen/components.ts +6 -0
  62. package/src/engine-components/js-extensions/RGBAColor.ts +7 -0
@@ -194,71 +194,73 @@ class EventListSerializer extends TypeSerializer {
194
194
  if (debugExtension)
195
195
  console.log("DESERIALIZE EVENT", data);
196
196
  const fns = new Array<CallInfo>();
197
- for (const call of data.calls) {
198
- if (debugExtension)
199
- console.log(call);
200
- let target = componentSerializer.findObjectForGuid(call.target, context.root);
201
- // if the object is not found in the current glb try find it in the whole scene
202
- if (!target && context.context?.scene) {
203
- target = componentSerializer.findObjectForGuid(call.target, context.context?.scene);
204
- }
205
- const hasMethod = call.method?.length > 0;
206
- if (target && hasMethod) {
207
- const printWarningMethodNotFound = () => console.warn(`Could not find method ${call.method} on object ${target.name}`, target, typeof target[call.method]);
208
- if (typeof target[call.method] !== "function") {
209
- let foundMethod = false;
210
- // test if the target method is actually a property setter
211
- // in which case we want to remove the leading set prefix and see if the method or property exists
212
- if (call.method.startsWith("set_") && call.method.length > 4) {
213
- call.method = call.method.substring(4);
214
- if (target[call.method] !== undefined) foundMethod = true;
197
+ if (data.calls && Array.isArray(data.calls)) {
198
+ for (const call of data.calls) {
199
+ if (debugExtension)
200
+ console.log(call);
201
+ let target = componentSerializer.findObjectForGuid(call.target, context.root);
202
+ // if the object is not found in the current glb try find it in the whole scene
203
+ if (!target && context.context?.scene) {
204
+ target = componentSerializer.findObjectForGuid(call.target, context.context?.scene);
205
+ }
206
+ const hasMethod = call.method?.length > 0;
207
+ if (target && hasMethod) {
208
+ const printWarningMethodNotFound = () => console.warn(`Could not find method ${call.method} on object ${target.name}`, target, typeof target[call.method]);
209
+ if (typeof target[call.method] !== "function") {
210
+ let foundMethod = false;
211
+ // test if the target method is actually a property setter
212
+ // in which case we want to remove the leading set prefix and see if the method or property exists
213
+ if (call.method.startsWith("set_") && call.method.length > 4) {
214
+ call.method = call.method.substring(4);
215
+ if (target[call.method] !== undefined) foundMethod = true;
216
+ }
217
+ if (!foundMethod)
218
+ printWarningMethodNotFound();
215
219
  }
216
- if (!foundMethod)
217
- printWarningMethodNotFound();
218
220
  }
219
- }
220
- let fn: CallInfo | undefined;
221
- let args = call.argument;
222
- if (call.argument !== undefined) {
223
- if (typeof args === "object") {
224
- args = objectSerializer.onDeserialize(call.argument, context);
225
- if (!args) args = componentSerializer.onDeserialize(call.argument, context);
221
+ let fn: CallInfo | undefined;
222
+ let args = call.argument;
223
+ if (call.argument !== undefined) {
224
+ if (typeof args === "object") {
225
+ args = objectSerializer.onDeserialize(call.argument, context);
226
+ if (!args) args = componentSerializer.onDeserialize(call.argument, context);
227
+ }
228
+ fn = new CallInfo(hasMethod ? (...args) => invokeFunction(...args) : undefined, call.enabled);
226
229
  }
227
- fn = new CallInfo(hasMethod ? (...args) => invokeFunction(...args) : undefined, call.enabled);
228
- }
229
- else
230
- fn = new CallInfo(hasMethod ? (...args) => invokeFunction(...args) : undefined, call.enabled);
230
+ else
231
+ fn = new CallInfo(hasMethod ? (...args) => invokeFunction(...args) : undefined, call.enabled);
231
232
 
232
233
 
233
- // TODO: move this into the event list directly
234
- // this scope should not stay in the serializer.
235
- // the event list should be able to modify the args that were set in unity if necessary
236
- // and pass them on to the component
237
- const invokeFunction = (...forwardedArgs) => {
238
- const method = target[call.method];
234
+ // TODO: move this into the event list directly
235
+ // this scope should not stay in the serializer.
236
+ // the event list should be able to modify the args that were set in unity if necessary
237
+ // and pass them on to the component
238
+ const invokeFunction = (...forwardedArgs) => {
239
+ const method = target[call.method];
239
240
 
240
- if (typeof method === "function") {
241
- if (args !== undefined)
242
- method?.call(target, args);
243
- else // support invoking EventList with any number of arguments (if none were declared in unity)
244
- method?.call(target, ...forwardedArgs);
245
- }
246
- else // the target "method" can be a property too
247
- {
248
- target[call.method] = args;
249
- }
250
- };
241
+ if (typeof method === "function") {
242
+ if (args !== undefined)
243
+ method?.call(target, args);
244
+ else // support invoking EventList with any number of arguments (if none were declared in unity)
245
+ method?.call(target, ...forwardedArgs);
246
+ }
247
+ else // the target "method" can be a property too
248
+ {
249
+ target[call.method] = args;
250
+ }
251
+ };
251
252
 
252
- if (!fn.method)
253
- fn["__debuginfo"] = context.object?.name;
254
- if (!target || !fn.method) {
255
- const debugInfo = context.object ? "Current object: " + context.object.name + ", " + context.object["guid"] : null;
256
- if (!target)
257
- console.warn("EventList is missing target - will be ignored", call.target, debugInfo, data);
258
- else console.warn("EventList method not found: \"" + call.method + "\" on", target);
253
+ if (!fn.method)
254
+ fn["__debuginfo"] = context.object?.name;
255
+ if (!target || !fn.method) {
256
+ const debugInfo = context.object ? "Current object: " + context.object.name + ", " + context.object["guid"] : null;
257
+ if (!target)
258
+ console.warn("EventList is missing target - will be ignored", call.target, debugInfo, data);
259
+ else console.warn("EventList method not found: \"" + call.method + "\" on", target);
260
+ }
261
+ else
262
+ fns.push(fn);
259
263
  }
260
- else
261
- fns.push(fn);
262
264
  }
263
265
  const evt: EventList = new EventList(fns);
264
266
  if (debugExtension)
@@ -1,10 +1,9 @@
1
1
  import * as THREE from "three";
2
2
  import { Mathf } from "./engine_math"
3
- import { WebGLRenderTarget, WebGLRenderer, Vector3, Quaternion, Uniform, Texture, Material, ShaderMaterial, CanvasTexture } from "three";
3
+ import { WebGLRenderTarget, WebGLRenderer, Vector3, Quaternion, Uniform, Texture, Material, ShaderMaterial, CanvasTexture, AnimationAction } from "three";
4
4
  import { CircularBuffer } from "./engine_utils";
5
5
 
6
6
 
7
-
8
7
  const flipYQuat: Quaternion = new Quaternion().setFromAxisAngle(new Vector3(0, 1, 0), Math.PI);
9
8
  export function lookAtInverse(obj: THREE.Object3D, target: Vector3) {
10
9
 
@@ -177,6 +176,16 @@ export function logHierarchy(root: THREE.Object3D | null | undefined, collapsibl
177
176
  }
178
177
 
179
178
 
179
+ export function isAnimationAction(obj:object){
180
+ if(obj){
181
+ // this doesnt work :(
182
+ // return obj instanceof AnimationAction;
183
+ // instead we do this:
184
+ const act = obj as AnimationAction;
185
+ return act.blendMode !== undefined && act.clampWhenFinished !== undefined && act.enabled !== undefined && act.fadeIn !== undefined && act.getClip !== undefined;
186
+ }
187
+ return false;
188
+ }
180
189
 
181
190
 
182
191
 
@@ -27,6 +27,7 @@ export class Time {
27
27
  this.deltaTime = this.clock.getDelta();
28
28
  // clamp delta time because if tab is not active clock.getDelta can get pretty big
29
29
  this.deltaTime = Math.min(.1, this.deltaTime);
30
+ if(this.deltaTime <= 0) this.deltaTime = 0.000000000001;
30
31
  this.frame += 1;
31
32
  this.time += this.deltaTime;
32
33
 
@@ -57,6 +57,16 @@ enum CullMode {
57
57
  Front = 1,
58
58
  Back = 2,
59
59
  }
60
+ enum ZTestMode {
61
+ Never = 1,
62
+ Less = 2,
63
+ Equal = 3,
64
+ LEqual = 4,
65
+ Greater = 5,
66
+ NotEqual = 6,
67
+ GEqual = 7,
68
+ Always = 8,
69
+ }
60
70
 
61
71
  export class CustomShader extends RawShaderMaterial {
62
72
 
@@ -446,6 +456,7 @@ export class NEEDLE_techniques_webgl implements GLTFLoaderPlugin {
446
456
  // "USE_SHADOWMAP" : true
447
457
  // },
448
458
  });
459
+
449
460
  const culling = uniforms["_Cull"]?.value;
450
461
  switch (culling) {
451
462
  case CullMode.Off:
@@ -462,6 +473,38 @@ export class NEEDLE_techniques_webgl implements GLTFLoaderPlugin {
462
473
  break;
463
474
  }
464
475
 
476
+ const zTest = uniforms["_ZTest"]?.value as ZTestMode;
477
+ switch (zTest) {
478
+ case ZTestMode.Equal:
479
+ material.depthTest = true;
480
+ material.depthFunc = THREE.EqualDepth;
481
+ break;
482
+ case ZTestMode.NotEqual:
483
+ material.depthTest = true;
484
+ material.depthFunc = THREE.NotEqualDepth;
485
+ break;
486
+ case ZTestMode.Less:
487
+ material.depthTest = true;
488
+ material.depthFunc = THREE.LessDepth;
489
+ break;
490
+ case ZTestMode.LEqual:
491
+ material.depthTest = true;
492
+ material.depthFunc = THREE.LessEqualDepth;
493
+ break;
494
+ case ZTestMode.Greater:
495
+ material.depthTest = true;
496
+ material.depthFunc = THREE.GreaterDepth;
497
+ break;
498
+ case ZTestMode.GEqual:
499
+ material.depthTest = true;
500
+ material.depthFunc = THREE.GreaterEqualDepth;
501
+ break;
502
+ case ZTestMode.Always:
503
+ material.depthTest = false;
504
+ material.depthFunc = THREE.AlwaysDepth;
505
+ break;
506
+ }
507
+
465
508
  material.transparent = isTransparent;
466
509
  if (isTransparent)
467
510
  material.depthWrite = false;
@@ -490,7 +533,6 @@ export class NEEDLE_techniques_webgl implements GLTFLoaderPlugin {
490
533
  if (debug)
491
534
  console.log(material.uuid, uniforms);
492
535
 
493
-
494
536
  createUniformProperties(material);
495
537
 
496
538
  resolve(material);
@@ -6,6 +6,9 @@ import { serializeable } from "../engine/engine_serialization_decorator";
6
6
  import { InstancingUtil } from "../engine/engine_instancing";
7
7
  import { Mathf } from "../engine/engine_math";
8
8
  import { Vec2 } from "../engine/engine_types";
9
+ import { getParam } from "../engine/engine_utils";
10
+
11
+ const debug = getParam("debuganimation");
9
12
 
10
13
  export declare class PlayOptions {
11
14
  fadeDuration?: number;
@@ -28,21 +31,30 @@ export class Animation extends Behaviour {
28
31
  minMaxSpeed?: Vec2;
29
32
  minMaxOffsetNormalized?: Vec2;
30
33
 
34
+ @serializeable()
35
+ loop: boolean = true;
36
+
37
+ @serializeable()
38
+ clampWhenFinished: boolean = false;
39
+
31
40
  private _tempAnimationClipBeforeGameObjectExisted: AnimationClip | null = null;
32
41
  get clip(): AnimationClip | null {
33
42
  return this.animations?.length ? this.animations[0] : null;
34
43
  }
35
44
  set clip(val: AnimationClip | null) {
36
- if (!this.gameObject) {
45
+ if (!this.__didAwake) {
46
+ if (debug) console.log("Assign clip during serialization", val);
37
47
  this._tempAnimationClipBeforeGameObjectExisted = val;
38
48
  return;
39
49
  }
40
50
  if (!val) return;
51
+ if (debug) console.log("Assign clip", val, Boolean(this.gameObject));
41
52
  if (!this.gameObject.animations) this.gameObject.animations = [];
42
53
  this.gameObject.animations.push(val);
43
54
  }
44
55
 
45
56
  set animations(animations: THREE.AnimationClip[]) {
57
+ if (debug) console.log("assign animations", animations);
46
58
  this.gameObject.animations = animations;
47
59
  }
48
60
 
@@ -120,9 +132,10 @@ export class Animation extends Behaviour {
120
132
  return false;
121
133
  }
122
134
 
123
- play(clipOrNumber: AnimationClip | number | string, options?: PlayOptions): Promise<AnimationAction> | void {
135
+ play(clipOrNumber: AnimationClip | number | string | undefined, options?: PlayOptions): Promise<AnimationAction> | void {
124
136
  this.init();
125
137
  if (!this.mixer) return;
138
+ if (clipOrNumber === undefined) clipOrNumber = 0;
126
139
  let clip: AnimationClip | undefined = clipOrNumber as AnimationClip;
127
140
  if (typeof clipOrNumber === 'number') {
128
141
  if (clipOrNumber >= this.animations.length) return;
@@ -138,6 +151,8 @@ export class Animation extends Behaviour {
138
151
  if (!options) options = {};
139
152
  if (!options.minMaxOffsetNormalized) options.minMaxOffsetNormalized = this.minMaxOffsetNormalized;
140
153
  if (!options.minMaxSpeed) options.minMaxSpeed = this.minMaxSpeed;
154
+ if (!options.loop) options.loop = this.loop;
155
+ if (!options.clampWhenFinished) options.clampWhenFinished = this.clampWhenFinished;
141
156
  for (const act of this.actions) {
142
157
  if (act.getClip() === clip) {
143
158
  return this.internalOnPlay(act, options);
@@ -176,6 +191,7 @@ export class Animation extends Behaviour {
176
191
 
177
192
  if (options?.loop !== undefined)
178
193
  action.loop = options.loop ? THREE.LoopRepeat : THREE.LoopOnce;
194
+ else action.loop = THREE.LoopOnce;
179
195
  action.play();
180
196
  // console.log("PLAY", action.getClip().name, action)
181
197
 
@@ -7,6 +7,7 @@ import * as THREE from "three";
7
7
  import { TypeStore } from "../engine/engine_typestore";
8
8
  import { assign } from "../engine/engine_serialization_core";
9
9
  import { Mathf } from "../engine/engine_math";
10
+ import { isAnimationAction } from "../engine/engine_three_utils";
10
11
 
11
12
  const debug = getParam("debuganimatorcontroller");
12
13
  const debugRootMotion = getParam("debugrootmotion");
@@ -122,7 +123,10 @@ export class AnimatorController {
122
123
  // dont clone three Objects
123
124
  if (_value.type === "Object3D" || _value.isObject3D === true) return false;
124
125
  // dont clone AnimationAction
125
- if (_value?.constructor?.name === "AnimationAction") return false;
126
+ if (isAnimationAction(_value)) { //.constructor.name === "AnimationAction") {
127
+ console.log(_value);
128
+ return false;
129
+ }
126
130
  // dont clone AnimationClip
127
131
  if (_value["tracks"] !== undefined) return false;
128
132
  return true;
@@ -80,6 +80,19 @@ export class Camera extends Behaviour implements ICamera {
80
80
  @serializeable()
81
81
  public ARBackgroundAlpha: number = 0;
82
82
 
83
+ @serializeable()
84
+ public set cullingMask(val: number) {
85
+ this._cullingMask = val;
86
+ if (this._cam) {
87
+ this._cam.layers.mask = val;
88
+ }
89
+ }
90
+ public get cullingMask(): number {
91
+ if (this._cam) return this._cam.layers.mask;
92
+ return this._cullingMask;
93
+ }
94
+ private _cullingMask: number = 0xffffffff;
95
+
83
96
  private _nearClipPlane: number = 0.1;
84
97
  private _farClipPlane: number = 1000;
85
98
 
@@ -95,7 +108,7 @@ export class Camera extends Behaviour implements ICamera {
95
108
  }
96
109
  else this._backgroundColor.copy(val);
97
110
  // set background color to solid if provided color doesnt have any alpha channel
98
- if(val.alpha === undefined) this._backgroundColor.alpha = 1;
111
+ if (val.alpha === undefined) this._backgroundColor.alpha = 1;
99
112
  this.applyClearFlagsIfIsActiveCamera();
100
113
  }
101
114
 
@@ -113,10 +126,6 @@ export class Camera extends Behaviour implements ICamera {
113
126
  }
114
127
 
115
128
 
116
- // constructor(){
117
- // super();
118
- // console.log(this);
119
- // }
120
129
 
121
130
  awake() {
122
131
  if (!this.sourceId) {
@@ -146,6 +155,7 @@ export class Camera extends Behaviour implements ICamera {
146
155
  let cam: THREE.PerspectiveCamera | THREE.OrthographicCamera | null = null;
147
156
  if (cameraAlreadyCreated) {
148
157
  cam = this.gameObject as any;
158
+ cam?.layers.enableAll();
149
159
  }
150
160
  else
151
161
  cam = this.gameObject.children[0] as THREE.PerspectiveCamera | THREE.OrthographicCamera | null;
@@ -167,11 +177,8 @@ export class Camera extends Behaviour implements ICamera {
167
177
  }
168
178
  this._cam = cam;
169
179
 
170
- // workaround for layers in three affecting visibility by default
171
- // we should probably export this info from unity as well
172
- if (this.layer === 0) {
173
- this._cam.layers.enableAll();
174
- }
180
+ this._cam.layers.mask = this._cullingMask;
181
+
175
182
  if (this.tag == "MainCamera") {
176
183
  this.context.setCurrentCamera(this);
177
184
  }