Needle Engine

Changes between version 3.11.2-beta and 3.11.3-beta
Files changed (8) hide show
  1. src/engine-components/Animator.ts +7 -0
  2. src/engine-components/AnimatorController.ts +9 -3
  3. src/engine-components/CharacterController.ts +47 -20
  4. src/engine/engine_element.ts +5 -2
  5. src/engine-components/ParticleSystem.ts +20 -6
  6. src/engine-components/export/usdz/utils/quicklook.ts +3 -3
  7. src/engine-components/SceneSwitcher.ts +5 -3
  8. src/engine-components/export/usdz/ThreeUSDZExporter.ts +4 -4
src/engine-components/Animator.ts CHANGED
@@ -113,6 +113,13 @@
113
113
  this.runtimeAnimatorController?.resetTrigger(name);
114
114
  }
115
115
 
116
+ /**@deprecated use getTrigger */
117
+ GetTrigger(name: string | number) { this.getTrigger(name); }
118
+ getTrigger(name: string | number) {
119
+ if (debug) console.log("GetTrigger", name);
120
+ this.runtimeAnimatorController?.getTrigger(name);
121
+ }
122
+
116
123
  /**@deprecated use isInTransition */
117
124
  IsInTransition() { return this.isInTransition(); }
118
125
  isInTransition(): boolean {
src/engine-components/AnimatorController.ts CHANGED
@@ -79,6 +79,11 @@
79
79
  return this.model?.parameters?.filter(p => p[key] === name).forEach(p => p.value = false);
80
80
  }
81
81
 
82
+ getTrigger(name: string | number): boolean {
83
+ const key = typeof name === "string" ? "name" : "hash";
84
+ return this.model?.parameters?.find(p => p[key] === name)?.value as boolean ?? false;
85
+ }
86
+
82
87
  isInTransition(): boolean {
83
88
  return this._activeStates.length > 1;
84
89
  }
@@ -88,13 +93,13 @@
88
93
  }
89
94
 
90
95
  /**@deprecated use findState */
91
- FindState(name: string | undefined | null): State | null { return this.findState(name); }
92
- findState(name: string | undefined | null): State | null {
96
+ FindState(name: string | number | undefined | null): State | null { return this.findState(name); }
97
+ findState(name: string | number | undefined | null): State | null {
93
98
  if (!name) return null;
94
99
  if (Array.isArray(this.model.layers)) {
95
100
  for (const layer of this.model.layers) {
96
101
  for (const state of layer.stateMachine.states) {
97
- if (state.name === name) return state;
102
+ if (state.name === name || state.hash == name) return state;
98
103
  }
99
104
  }
100
105
  }
@@ -166,6 +171,7 @@
166
171
 
167
172
  private _mixer!: AnimationMixer;
168
173
  private _activeState?: State;
174
+ get activeState(): State | undefined { return this._activeState; }
169
175
 
170
176
  constructor(model: AnimatorControllerModel) {
171
177
  this.model = model;
src/engine-components/CharacterController.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Quaternion, Ray, Vector3 } from "three";
1
+ import { Quaternion, Ray, Vector2, Vector3 } from "three";
2
2
  import { Mathf } from "../engine/engine_math.js";
3
3
  import { serializable } from "../engine/engine_serialization.js";
4
4
  import { Collision } from "../engine/engine_types.js";
@@ -99,6 +99,48 @@
99
99
 
100
100
  lookForward: boolean = true;
101
101
 
102
+ awake(){
103
+ this._currentRotation = new Quaternion();
104
+ }
105
+
106
+ update(){
107
+ const input = this.context.input;
108
+ if(input.isKeyPressed("KeyW"))
109
+ this.moveInput.y += 1;
110
+ else if(input.isKeyPressed("KeyS"))
111
+ this.moveInput.y -= 1;
112
+ if(input.isKeyPressed("KeyD"))
113
+ this.lookInput.x += 1;
114
+ else if(input.isKeyPressed("KeyA"))
115
+ this.lookInput.x -= 1;
116
+
117
+ this.jumpInput ||= input.isKeyDown("Space");
118
+ }
119
+
120
+ move(move: Vector2) {
121
+ this.moveInput.add(move);
122
+ }
123
+
124
+ look(look: Vector2) {
125
+ this.lookInput.add(look);
126
+ }
127
+
128
+ jump() {
129
+ this.jumpInput = true;
130
+ }
131
+
132
+ private lookInput: Vector2 = new Vector2(0, 0);
133
+ private moveInput: Vector2 = new Vector2(0, 0);
134
+ private jumpInput: boolean = false;
135
+
136
+ onBeforeRender() {
137
+ this.handleInput(this.moveInput, this.lookInput, this.jumpInput);
138
+
139
+ this.lookInput.set(0, 0);
140
+ this.moveInput.set(0, 0);
141
+ this.jumpInput = false;
142
+ }
143
+
102
144
  private _currentSpeed: Vector3 = new Vector3(0, 0, 0);
103
145
  private _currentAngularSpeed: Vector3 = new Vector3(0, 0, 0);
104
146
 
@@ -106,30 +148,16 @@
106
148
  private _jumpCount: number = 0;
107
149
  private _currentRotation!: Quaternion;
108
150
 
109
- awake(){
110
- this._currentRotation = new Quaternion();
111
- }
151
+ handleInput (move: Vector2, look: Vector2, jump: boolean) {
112
152
 
113
- update() {
114
-
115
153
  if (this.controller?.isGrounded) {
116
154
  this._jumpCount = 0;
117
155
  if (this.doubleJumpForce > 0) this.animator?.setBool("doubleJump", false);
118
156
  }
119
157
 
120
- const forward = this.context.input.isKeyPressed("w");
121
- const backward = this.context.input.isKeyPressed("s");
122
- const rotateLeft = this.context.input.isKeyPressed("a");
123
- const rotateRight = this.context.input.isKeyPressed("d");
124
- const jump = this.context.input.isKeyDown(" ");
125
- // if (jumpDown) this._jumpDownTime = this.context.time.time;
126
- // const jumpUp = this.context.input.isKeyUp(" ");
158
+ this._currentSpeed.z += move.y * this.movementSpeed * this.context.time.deltaTime;
127
159
 
128
- const step = (forward ? 1 : 0) + (backward ? -1 : 0);
129
- this._currentSpeed.z += step * this.movementSpeed * this.context.time.deltaTime;
130
-
131
- // if (!this.controller || this.controller.isGrounded)
132
- this.animator?.setBool("running", step != 0);
160
+ this.animator?.setBool("running", move.length() > 0.01);
133
161
  this.animator?.setBool("jumping", this.controller?.isGrounded === true && jump);
134
162
 
135
163
  this._temp.copy(this._currentSpeed);
@@ -137,8 +165,7 @@
137
165
  if (this.controller) this.controller.move(this._temp);
138
166
  else this.gameObject.position.add(this._temp);
139
167
 
140
- const rotation = (rotateLeft ? 1 : 0) + (rotateRight ? -1 : 0);
141
- this._currentAngularSpeed.y += Mathf.toRadians(rotation * this.rotationSpeed) * this.context.time.deltaTime;
168
+ this._currentAngularSpeed.y += Mathf.toRadians(-look.x * this.rotationSpeed) * this.context.time.deltaTime;
142
169
  if (this.lookForward && Math.abs(this._currentAngularSpeed.y) < .01) {
143
170
  const forwardVector = this.context.mainCameraComponent!.forward;
144
171
  forwardVector.y = 0;
src/engine/engine_element.ts CHANGED
@@ -118,7 +118,9 @@
118
118
  touch-action: none;
119
119
  }
120
120
  :host .content {
121
- position: fixed;
121
+ position: relative;
122
+ width: 100%;
123
+ height: 100%;
122
124
  visibility: visible;
123
125
  z-index: 500; /* < must be less than the webxr buttons element */
124
126
  pointer-events: none;
@@ -384,7 +386,8 @@
384
386
  this.dispatchEvent(new CustomEvent("loadfinished", {
385
387
  detail: {
386
388
  context: this._context,
387
- src: alias
389
+ src: alias,
390
+ loadedFiles: loadedFiles,
388
391
  }
389
392
  }));
390
393
  }
src/engine-components/ParticleSystem.ts CHANGED
@@ -901,6 +901,7 @@
901
901
 
902
902
  start() {
903
903
  this.addSubParticleSystems();
904
+ this.updateLayers();
904
905
  }
905
906
 
906
907
  onDestroy(): void {
@@ -959,17 +960,19 @@
959
960
  }
960
961
  }
961
962
 
963
+ private _lastBatchesCount = -1;
962
964
  private onSimulate(dt: number) {
963
965
  if (this._batchSystem) {
966
+ let needsUpdate = this.context.time.frameCount % 60 === 0;
967
+ if(this._lastBatchesCount !== this._batchSystem.batches.length) {
968
+ this._lastBatchesCount = this._batchSystem.batches.length;
969
+ needsUpdate = true;
970
+ }
964
971
  // Updating layers on batches
965
972
  // TODO: figure out a better way to do this
966
973
  // Issue: https://github.com/Alchemist0823/three.quarks/issues/49
967
- if (this.context.time.frameCount % 60 === 0) {
968
- for (let i = 0; i < this._batchSystem.batches.length; i++) {
969
- const batch = this._batchSystem.batches[i];
970
- batch.layers.disableAll();
971
- batch.layers.set(2);
972
- }
974
+ if (needsUpdate) {
975
+ this.updateLayers();
973
976
  }
974
977
  this._batchSystem.update(dt);
975
978
  }
@@ -977,6 +980,17 @@
977
980
  if (this._time > this.duration) this._time = 0;
978
981
  }
979
982
 
983
+ private updateLayers() {
984
+ if (this._batchSystem) {
985
+ for (let i = 0; i < this._batchSystem.batches.length; i++) {
986
+ const batch = this._batchSystem.batches[i];
987
+ batch.layers.disableAll();
988
+ const layer = this.layer;
989
+ batch.layers.mask = 1 << layer;
990
+ }
991
+ }
992
+ }
993
+
980
994
  private lastMaterialVersion: number = -1;
981
995
  private onUpdate() {
982
996
  const mat = this.renderer.getMaterial(this.trails.enabled);
src/engine-components/export/usdz/utils/quicklook.ts CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
 
4
4
  export function ensureQuicklookLinkIsCreated(context: Context) : HTMLAnchorElement {
5
- const existingLink = context.domElement.querySelector("link[rel='ar']");
6
- if(existingLink) return existingLink as HTMLAnchorElement;
5
+ const existingLink = context.domElement.shadowRoot!.querySelector("link[rel='ar']");
6
+ if (existingLink) return existingLink as HTMLAnchorElement;
7
7
 
8
8
  /*
9
9
  generating this:
@@ -38,6 +38,6 @@
38
38
  // img.src = "files/arkit.png";
39
39
  link.appendChild(img);
40
40
 
41
- context.domElement.appendChild(div);
41
+ context.domElement.shadowRoot!.appendChild(div);
42
42
  return link as HTMLAnchorElement;
43
43
  }
src/engine-components/SceneSwitcher.ts CHANGED
@@ -246,7 +246,7 @@
246
246
  const reference = AssetReference.getOrCreate(this.sourceId ?? "", index, this.context);
247
247
  return this.switchScene(reference);
248
248
  }
249
- if (scene) index = this.scenes.indexOf(scene);
249
+ if (scene) index = this.scenes?.indexOf(scene);
250
250
  else return couldNotLoadScenePromise;
251
251
  }
252
252
 
@@ -437,8 +437,10 @@
437
437
  }
438
438
 
439
439
  allLoaded(): boolean {
440
- for (const scene of this._switcher.scenes) {
441
- if (scene?.isLoaded() === false) return false;
440
+ if (this._switcher.scenes) {
441
+ for (const scene of this._switcher.scenes) {
442
+ if (scene?.isLoaded() === false) return false;
443
+ }
442
444
  }
443
445
  return true;
444
446
  }
src/engine-components/export/usdz/ThreeUSDZExporter.ts CHANGED
@@ -1183,9 +1183,9 @@
1183
1183
 
1184
1184
  const needsTextureScale = mapType !== 'normal' && (color && (color.r !== 1 || color.g !== 1 || color.b !== 1 || opacity !== 1)) || false;
1185
1185
  const needsNormalScaleAndBias = mapType === 'normal';
1186
- const normalScaleValueString = material instanceof MeshStandardMaterial
1187
- ? (material.normalScale ? material.normalScale.x * 2 : 2).toFixed( PRECISION )
1188
- : "1";
1186
+ const normalScale = material instanceof MeshStandardMaterial ? (material.normalScale ? material.normalScale.x * 2 : 2) : 2;
1187
+ const normalScaleValueString = normalScale.toFixed( PRECISION );
1188
+ const normalBiasString = (-1 * (normalScale / 2)).toFixed( PRECISION );
1189
1189
 
1190
1190
  return `
1191
1191
  ${needsTextureTransform ? `def Shader "Transform2d_${mapType}" (
@@ -1213,7 +1213,7 @@
1213
1213
  ` : `` }
1214
1214
  ${needsNormalScaleAndBias ? `
1215
1215
  float4 inputs:scale = (${normalScaleValueString}, ${normalScaleValueString}, ${normalScaleValueString}, 1)
1216
- float4 inputs:bias = (-1, -1, -1, 0)
1216
+ float4 inputs:bias = (${normalBiasString}, ${normalBiasString}, ${normalBiasString}, 0)
1217
1217
  ` : `` }
1218
1218
  token inputs:wrapS = "${wrapS}"
1219
1219
  token inputs:wrapT = "${wrapT}"