@needle-tools/engine 3.9.0-alpha → 3.9.1-alpha

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.
@@ -13,7 +13,7 @@ const DEFAULT_DRACO_DECODER_LOCATION ='https://www.gstatic.com/draco/versioned/d
13
13
  const DEFAULT_KTX2_TRANSCODER_LOCATION ='https://www.gstatic.com/basis-universal/versioned/2021-04-15-ba1c3e4/';
14
14
 
15
15
  let dracoLoader: DRACOLoader;
16
- let meshoptDecoder: MeshoptDecoder;
16
+ let meshoptDecoder: typeof MeshoptDecoder;
17
17
  let ktx2Loader: KTX2Loader;
18
18
 
19
19
  export function setDracoDecoderPath(path: string | undefined) {
@@ -40,7 +40,7 @@ export class Camera extends Behaviour implements ICamera {
40
40
  }
41
41
  @serializable()
42
42
  set fieldOfView(val: number | undefined) {
43
- const changed = this._fov != val;
43
+ const changed = this.fieldOfView != val;
44
44
  this._fov = val;
45
45
  if (changed && this._cam) {
46
46
  if (this._cam instanceof PerspectiveCamera) {
@@ -300,8 +300,11 @@ export class Camera extends Behaviour implements ICamera {
300
300
  if (debug) console.log("Camera does not exist (apply clear flags)")
301
301
  return;
302
302
  }
303
- if (debug)
304
- showBalloonMessage("apply Camera clear flags: " + this._clearFlags);
303
+
304
+ // restore previous fov (e.g. when user was in VR or AR and the camera's fov has changed)
305
+ this.fieldOfView = this._fov;
306
+
307
+ if (debug) showBalloonMessage("apply Camera clear flags: " + this._clearFlags);
305
308
  switch (this._clearFlags) {
306
309
  case ClearFlags.Skybox:
307
310
  if (Camera.backgroundShouldBeTransparent(this.context)) {
@@ -75,7 +75,7 @@ export class ParticleSystemRenderer extends Behaviour {
75
75
 
76
76
  if (!ParticleSystemRenderer._havePatchedQuarkShaders) {
77
77
  ParticleSystemRenderer._havePatchedQuarkShaders = true;
78
-
78
+
79
79
  // HACK patch three.quarks fo three152+, see https://github.com/Alchemist0823/three.quarks/issues/56#issuecomment-1560825038
80
80
  const _rebuild = TrailBatch.prototype.rebuildMaterial;
81
81
  TrailBatch.prototype.rebuildMaterial = function () {
@@ -130,13 +130,17 @@ export class ParticleSystemRenderer extends Behaviour {
130
130
  class MinMaxCurveFunction implements FunctionValueGenerator {
131
131
 
132
132
  private _curve: MinMaxCurve;
133
+ private _factor: number;
133
134
 
134
- constructor(curve: MinMaxCurve) { this._curve = curve; }
135
+ constructor(curve: MinMaxCurve, factor: number = 1) {
136
+ this._curve = curve;
137
+ this._factor = factor;
138
+ }
135
139
 
136
140
  type: "function" = "function";
137
141
 
138
142
  genValue(t: number): number {
139
- return this._curve.evaluate(t, Math.random());
143
+ return this._curve.evaluate(t, Math.random()) * this._factor;
140
144
  }
141
145
  toJSON(): FunctionJSON {
142
146
  throw new Error("Method not implemented.");
@@ -416,7 +420,7 @@ class VelocityBehaviour extends ParticleSystemBaseBehaviour {
416
420
  initialize(particle: Particle): void {
417
421
  const simulationSpeed = this.system.main.simulationSpeed;
418
422
 
419
- const factor = 1 * simulationSpeed;
423
+ const factor = 1;
420
424
  particle.startSpeed = this.system.main.startSpeed.evaluate(Math.random(), Math.random()) * factor;
421
425
  particle.velocity.copy(this.system.shape.getDirection(particle.position)).multiplyScalar(particle.startSpeed);
422
426
  if (this.system.inheritVelocity?.enabled) {
@@ -425,16 +429,16 @@ class VelocityBehaviour extends ParticleSystemBaseBehaviour {
425
429
  if (!particle[$startVelocity]) particle[$startVelocity] = particle.velocity.clone();
426
430
  else particle[$startVelocity].copy(particle.velocity);
427
431
 
428
- const gravityFactor = this.system.main.gravityModifier.evaluate(Math.random(), Math.random()) / (9.81 * 2);
432
+ const gravityFactor = this.system.main.gravityModifier.evaluate(Math.random(), Math.random());
429
433
  particle[$gravityFactor] = gravityFactor * simulationSpeed;
430
- particle[$gravitySpeed] = 1;
434
+ particle[$gravitySpeed] = gravityFactor * simulationSpeed * .5
431
435
 
432
436
  particle[$velocityLerpFactor] = Math.random();
433
437
  this.system.velocityOverLifetime?.init(particle);
434
438
 
435
439
  this._gravityDirection.set(0, -1, 0);
436
440
  if (this.system.main.simulationSpace === ParticleSystemSimulationSpace.Local)
437
- this._gravityDirection.applyQuaternion(this.system.worldQuaternionInverted);
441
+ this._gravityDirection.applyQuaternion(this.system.worldQuaternionInverted).normalize();
438
442
  }
439
443
 
440
444
  update(particle: Particle, delta: number): void {
@@ -444,10 +448,9 @@ class VelocityBehaviour extends ParticleSystemBaseBehaviour {
444
448
  const baseVelocity = particle[$startVelocity];
445
449
  let gravityFactor = particle[$gravityFactor];
446
450
  if (gravityFactor !== 0) {
447
- // gravityFactor *= -1;
448
- temp3.copy(this._gravityDirection).multiplyScalar(gravityFactor * particle[$gravitySpeed]);
449
- particle[$gravitySpeed] += delta;
450
- if (debug) Gizmos.DrawDirection(particle.position, temp3, 0x0000ff, 0, false, 10);
451
+ const factor = gravityFactor * particle[$gravitySpeed];
452
+ temp3.copy(this._gravityDirection).multiplyScalar(factor);
453
+ particle[$gravitySpeed] += delta * .05;
451
454
  baseVelocity.add(temp3);
452
455
  }
453
456
  particle.velocity.copy(baseVelocity);
@@ -931,10 +934,10 @@ export class ParticleSystem extends Behaviour implements IParticleSystem {
931
934
  const duration = this.main.duration;
932
935
  const lifetime = this.main.startLifetime.getMax();
933
936
  const maxDurationToPrewarm = 1000;
934
- const timeToSimulate = Math.min(duration, lifetime, maxDurationToPrewarm);
937
+ const timeToSimulate = Math.min(Math.max(duration, lifetime) / Math.max(.01, this.main.simulationSpeed), maxDurationToPrewarm);
935
938
  const framesToSimulate = Math.ceil(timeToSimulate / dt);
936
939
  const startTime = Date.now();
937
- if (debug)
940
+ if (debug || this.name === "Snow")
938
941
  console.log(`Particles ${this.name} - Prewarm for ${framesToSimulate} frames (${timeToSimulate} sec). Duration: ${duration}, Lifetime: ${lifetime}`);
939
942
  for (let i = 0; i < framesToSimulate; i++) {
940
943
  if (this.currentParticles >= this.maxParticles) break;
@@ -38,6 +38,13 @@ export class SceneSwitcher extends Behaviour {
38
38
  @serializable()
39
39
  queryParameterName: string = "scene";
40
40
 
41
+ /**
42
+ * when enabled the scene name will be used as the query parameter (otherwise the scene index will be used)
43
+ * Needs `queryParameterName` set
44
+ * */
45
+ @serializable()
46
+ useSceneName: boolean = true;
47
+
41
48
  @serializable()
42
49
  clamp: boolean = true;
43
50
 
@@ -281,9 +288,15 @@ export class SceneSwitcher extends Behaviour {
281
288
  if (this.useSceneLighting)
282
289
  this.context.sceneLighting.enable(scene)
283
290
  if (this.useHistory && index >= 0) {
291
+ // take the index as the query parameter value
292
+ let queryParameterValue = index.toString();
293
+ // unless the user defines that he wants to use the scene name
294
+ if (this.useSceneName) {
295
+ queryParameterValue = sceneUriToName(scene.uri);
296
+ }
284
297
  // save the loaded scene as an url parameter
285
298
  if (this.queryParameterName?.length)
286
- setParamWithoutReload(this.queryParameterName, index.toString(), this.useHistory);
299
+ setParamWithoutReload(this.queryParameterName, queryParameterValue, this.useHistory);
287
300
  // or set the history state without updating the url parameter
288
301
  else {
289
302
  const lastState = history.state;
@@ -328,9 +341,11 @@ export class SceneSwitcher extends Behaviour {
328
341
  }
329
342
  else {
330
343
  // Try to find a scene with a matching name
344
+ // we don't care about casing. e.g. Scene1 and scene1 should both match
345
+ const lowerCaseValue = value.toLowerCase();
331
346
  for (let i = 0; i < this.scenes.length; i++) {
332
347
  const scene = this.scenes[i];
333
- if (scene.uri.toLowerCase().includes(value)) {
348
+ if (sceneUriToName(scene.uri).toLowerCase().includes(lowerCaseValue)) {
334
349
  return this.select(i);;
335
350
  }
336
351
  }
@@ -349,6 +364,13 @@ export class SceneSwitcher extends Behaviour {
349
364
  }
350
365
 
351
366
 
367
+ function sceneUriToName(uri: string): string {
368
+ const name = uri.split("/").pop();
369
+ let value = name?.split(".").shift();
370
+ if (value?.length) return value;
371
+ return uri;
372
+ }
373
+
352
374
 
353
375
 
354
376
  class PreLoadScheduler {
@@ -21,7 +21,7 @@ import { showBalloonWarning } from '../../engine/debug';
21
21
  const debugWebXR = getParam("debugwebxr");
22
22
 
23
23
  export async function detectARSupport() {
24
- if(isMozillaXR()) return true;
24
+ if (isMozillaXR()) return true;
25
25
  if ("xr" in navigator) {
26
26
  //@ts-ignore
27
27
  return (await navigator["xr"].isSessionSupported('immersive-ar')) === true;
@@ -136,7 +136,7 @@ export class WebXR extends Behaviour {
136
136
  return arButton;
137
137
  }
138
138
 
139
- private static onModifyAROptions(options){
139
+ private static onModifyAROptions(options) {
140
140
  WebXR.dispatchEvent(WebXREvent.ModifyAROptions, options);
141
141
  }
142
142
 
@@ -255,11 +255,10 @@ export class WebXR extends Behaviour {
255
255
  this.context.appendHTMLElement(buttonsContainer);
256
256
 
257
257
  const forceButtons = debugWebXR;
258
- if(debugWebXR) console.log("ARSupported?", arSupported, "VRSupported?", vrSupported);
258
+ if (debugWebXR) console.log("ARSupported?", arSupported, "VRSupported?", vrSupported);
259
259
 
260
260
  // AR support
261
- if (forceButtons || (this.createARButton && this.enableAR && arSupported))
262
- {
261
+ if (forceButtons || (this.createARButton && this.enableAR && arSupported)) {
263
262
  arButton = WebXR.createARButton(this);
264
263
  this._arButton = arButton;
265
264
  buttonsContainer.appendChild(arButton);
@@ -271,7 +270,7 @@ export class WebXR extends Behaviour {
271
270
  this._vrButton = vrButton;
272
271
  buttonsContainer.appendChild(vrButton);
273
272
  }
274
-
273
+
275
274
  setTimeout(() => {
276
275
  WebXR.resetButtonStyles(vrButton);
277
276
  WebXR.resetButtonStyles(arButton);
@@ -289,11 +288,11 @@ export class WebXR extends Behaviour {
289
288
  // TODO: figure out why screen is black if we enable the code written here
290
289
  // const referenceSpace = renderer.xr.getReferenceSpace();
291
290
  const session = this.context.renderer.xr.getSession();
292
-
291
+
293
292
 
294
293
  if (session) {
295
294
  const pose = frame.getViewerPose(this.context.renderer.xr.getReferenceSpace());
296
- if(!pose) return;
295
+ if (!pose) return;
297
296
  this._currentHeadPose = pose;
298
297
  const transform: XRRigidTransform = pose?.transform;
299
298
  if (transform) {
@@ -356,7 +355,7 @@ export class WebXR extends Behaviour {
356
355
  this._originalCameraRotation.copy(getWorldQuaternion(this.context.mainCamera));
357
356
  this._originalCameraParent = this.context.mainCamera.parent;
358
357
  }
359
- if(this.Rig){
358
+ if (this.Rig) {
360
359
  this._originalXRRigParent = this.Rig.parent;
361
360
  this._originalXRRigPosition.copy(this.Rig.position);
362
361
  this._originalXRRigRotation.copy(this.Rig.quaternion);
@@ -415,9 +414,9 @@ export class WebXR extends Behaviour {
415
414
  const xr = this.context.renderer.xr;
416
415
  if (this.context.mainCamera) {
417
416
  const cam = xr.getCamera() as WebXRArrayCamera;
418
- if(debugWebXR) console.log("WebXRCamera", cam);
417
+ if (debugWebXR) console.log("WebXRCamera", cam);
419
418
  const cull = this.context.mainCameraComponent?.cullingMask;
420
- if(cam && cull !== undefined){
419
+ if (cam && cull !== undefined) {
421
420
  for (const c of cam.cameras) {
422
421
  c.layers.mask = cull;
423
422
  }
@@ -467,8 +466,14 @@ export class WebXR extends Behaviour {
467
466
 
468
467
  const wasInAR = this._isInAR;
469
468
 
470
- if (this._isInAR && session) {
471
- this.webAR?.onEnd(session);
469
+ if (session) {
470
+ if (this._isInAR) {
471
+ this.webAR?.onEnd(session);
472
+ }
473
+ else {
474
+ // if in VR we want to restore the FOV
475
+ this.context.mainCameraComponent?.applyClearFlagsIfIsActiveCamera();
476
+ }
472
477
  }
473
478
 
474
479
  this._isInAR = false;
@@ -491,7 +496,7 @@ export class WebXR extends Behaviour {
491
496
  this.context.mainCamera.scale.set(1, 1, 1);
492
497
  }
493
498
 
494
- if(wasInAR){
499
+ if (wasInAR) {
495
500
  this._originalXRRigParent?.add(this.rig);
496
501
  this.rig.position.copy(this._originalXRRigPosition);
497
502
  this.rig.quaternion.copy(this._originalXRRigRotation);