@@ -23,6 +23,22 @@
|
|
23
23
|
@serializable(Keyframe)
|
24
24
|
keys!: Array<Keyframe>;
|
25
25
|
|
26
|
+
clone() {
|
27
|
+
const curve = new AnimationCurve();
|
28
|
+
curve.keys = this.keys?.map(k => {
|
29
|
+
const key = new Keyframe();
|
30
|
+
key.time = k.time;
|
31
|
+
key.value = k.value;
|
32
|
+
key.inTangent = k.inTangent;
|
33
|
+
key.inWeight = k.inWeight;
|
34
|
+
key.outTangent = k.outTangent;
|
35
|
+
key.outWeight = k.outWeight;
|
36
|
+
key.weightedMode = k.weightedMode;
|
37
|
+
return key;
|
38
|
+
}) || [];
|
39
|
+
return curve;
|
40
|
+
}
|
41
|
+
|
26
42
|
get duration(): number {
|
27
43
|
if (!this.keys || this.keys.length == 0) return 0;
|
28
44
|
return this.keys[this.keys.length - 1].time;
|
@@ -38,9 +54,9 @@
|
|
38
54
|
for (let i = 0; i < this.keys.length; i++) {
|
39
55
|
const kf = this.keys[i];
|
40
56
|
if (kf.time <= time) {
|
41
|
-
const hasNextKeyframe = i+1 < this.keys.length;
|
57
|
+
const hasNextKeyframe = i + 1 < this.keys.length;
|
42
58
|
if (hasNextKeyframe) {
|
43
|
-
const nextKf = this.keys[i+1];
|
59
|
+
const nextKf = this.keys[i + 1];
|
44
60
|
// if the next
|
45
61
|
if (nextKf.time < time) continue;
|
46
62
|
// tangents are set to Infinity if interpolation is set to constant - in that case we should always return the floored value
|
@@ -552,7 +552,11 @@
|
|
552
552
|
|
553
553
|
/** @internal */
|
554
554
|
constructor() {
|
555
|
-
this.
|
555
|
+
this.__didAwake = false;
|
556
|
+
this.__didStart = false;
|
557
|
+
this.__didEnable = false;
|
558
|
+
this.__isEnabled = undefined;
|
559
|
+
this.__destroyed = false;
|
556
560
|
}
|
557
561
|
|
558
562
|
|
@@ -18,7 +18,7 @@
|
|
18
18
|
import { getLoader } from './engine_gltf.js';
|
19
19
|
import { Input } from './engine_input.js';
|
20
20
|
import { invokeLifecycleFunctions } from './engine_lifecycle_functions_internal.js';
|
21
|
-
import { type ILightDataRegistry,LightDataRegistry } from './engine_lightdata.js';
|
21
|
+
import { type ILightDataRegistry, LightDataRegistry } from './engine_lightdata.js';
|
22
22
|
import * as looputils from './engine_mainloop_utils.js';
|
23
23
|
import { NetworkConnection } from './engine_networking.js';
|
24
24
|
import { isLocalNetwork } from './engine_networking_utils.js';
|
@@ -30,7 +30,7 @@
|
|
30
30
|
import { type CoroutineData, type GLTF, type ICamera, type IComponent, type IContext, type ILight, INeedleXRSession, type LoadedGLTF } from "./engine_types.js";
|
31
31
|
import * as utils from "./engine_utils.js";
|
32
32
|
import { delay, getParam } from './engine_utils.js';
|
33
|
-
import type { INeedleXRSessionEventReceiver } from './engine_xr.js';
|
33
|
+
import type { INeedleXRSessionEventReceiver, NeedleXRSession } from './engine_xr.js';
|
34
34
|
|
35
35
|
|
36
36
|
const debug = utils.getParam("debugcontext");
|
@@ -242,8 +242,10 @@
|
|
242
242
|
}
|
243
243
|
get isInXR() { return this.renderer?.xr?.isPresenting || false; }
|
244
244
|
/** shorthand for `NeedleXRSession.active`
|
245
|
-
* Automatically set by NeedleXRSession when a XR session is active
|
246
|
-
|
245
|
+
* Automatically set by NeedleXRSession when a XR session is active
|
246
|
+
* @returns the active XR session or null if no session is active
|
247
|
+
* */
|
248
|
+
xr: NeedleXRSession | null = null;
|
247
249
|
get xrSessionMode() { return this.xr?.mode; }
|
248
250
|
get isInVR() { return this.xrSessionMode === "immersive-vr"; }
|
249
251
|
get isInAR() { return this.xrSessionMode === "immersive-ar"; }
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import type { Camera, Color, Material, Mesh,Object3D, Quaternion, Ray, Scene, WebGLRenderer } from "three";
|
1
|
+
import type { Camera, Color, Material, Mesh, Object3D, Quaternion, Ray, Scene, WebGLRenderer } from "three";
|
2
2
|
import { Vector3 } from "three";
|
3
3
|
import { type GLTF as GLTF3 } from "three/examples/jsm/loaders/GLTFLoader.js";
|
4
4
|
|
@@ -6,7 +6,7 @@
|
|
6
6
|
import { CollisionDetectionMode, type PhysicsMaterial, RigidbodyConstraints } from "./engine_physics.types.js";
|
7
7
|
import { RenderTexture } from "./engine_texture.js";
|
8
8
|
import { CircularBuffer } from "./engine_utils.js";
|
9
|
-
import {
|
9
|
+
import type { INeedleXRSessionEventReceiver, NeedleXRSession } from "./engine_xr.js";
|
10
10
|
|
11
11
|
export type GLTF = GLTF3 & {
|
12
12
|
// asset: { generator: string, version: string }
|
@@ -98,15 +98,7 @@
|
|
98
98
|
stopAllCoroutinesFrom(script: IComponent);
|
99
99
|
}
|
100
100
|
|
101
|
-
export
|
102
|
-
get running(): boolean;
|
103
|
-
readonly mode: XRSessionMode;
|
104
|
-
readonly session: XRSession;
|
105
|
-
|
106
|
-
get isVR();
|
107
|
-
get isAR();
|
108
|
-
get isPassThrough();
|
109
|
-
}
|
101
|
+
export type INeedleXRSession = NeedleXRSession;
|
110
102
|
|
111
103
|
export declare interface INeedleEngineComponent extends HTMLElement {
|
112
104
|
getAROverlayContainer(): HTMLElement;
|
@@ -32,6 +32,7 @@
|
|
32
32
|
export type NeedleXRHitTestResult = { hit: XRHitTestResult, position: Vector3, quaternion: Quaternion };
|
33
33
|
|
34
34
|
const debug = getParam("debugwebxr");
|
35
|
+
const debugFPS = getParam("stats");
|
35
36
|
|
36
37
|
// TODO: move this into the IComponent interface!?
|
37
38
|
export interface INeedleXRSessionEventReceiver extends Pick<IComponent, "destroyed"> {
|
@@ -765,6 +766,7 @@
|
|
765
766
|
|
766
767
|
const newController = new NeedleXRController(this, newInputSource, index);
|
767
768
|
this.controllers.push(newController);
|
769
|
+
this.controllers.sort((a, b) => a.index - b.index);
|
768
770
|
this._newControllers.push(newController);
|
769
771
|
this.invokeControllerEvent(newController, this._controllerAdded, "added");
|
770
772
|
|
@@ -883,7 +885,7 @@
|
|
883
885
|
this.updateActiveXRRig();
|
884
886
|
}
|
885
887
|
|
886
|
-
if (debug && this.rig) {
|
888
|
+
if ((debug || debugFPS) && this.rig) {
|
887
889
|
const pos = this.rig.gameObject.worldPosition;
|
888
890
|
const forward = this.rig.gameObject.worldForward;
|
889
891
|
pos.add(forward.multiplyScalar(1.5));
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import * as THREE from "three";
|
2
|
-
import { AxesHelper, BufferGeometry, Color, Material, Matrix4, Mesh, MeshStandardMaterial, Object3D, OneMinusDstAlphaFactor, PlaneGeometry, Quaternion, Sprite, SpriteMaterial, Vector3, Vector4 } from "three";
|
3
|
-
import type { BatchedRenderer, Behavior, BehaviorPlugin, BillBoardSettings, BurstParameters, ColorGenerator, EmissionState, EmitSubParticleSystem, EmitterShape, FunctionColorGenerator, FunctionJSON, FunctionValueGenerator, IntervalValue, MeshSettings, Particle, ParticleEmitter, ParticleSystemParameters, PointEmitter, RecordState, RotationGenerator, SizeOverLife, TrailSettings, ValueGenerator,VFXBatchSettings } from "three.quarks";
|
4
|
-
import { BatchedParticleRenderer, ConstantColor, ConstantValue, ParticleSystem as _ParticleSystem, RenderMode,TrailBatch, TrailParticle } from "three.quarks";
|
2
|
+
import { AxesHelper, BackSide, BufferGeometry, Color, FrontSide, Material, Matrix4, Mesh, MeshBasicMaterial, MeshStandardMaterial, Object3D, OneMinusDstAlphaFactor, PlaneGeometry, Quaternion, Sprite, SpriteMaterial, Vector3, Vector4 } from "three";
|
3
|
+
import type { BatchedRenderer, Behavior, BehaviorPlugin, BillBoardSettings, BurstParameters, ColorGenerator, EmissionState, EmitSubParticleSystem, EmitterShape, FunctionColorGenerator, FunctionJSON, FunctionValueGenerator, IntervalValue, MeshSettings, Particle, ParticleEmitter, ParticleSystemParameters, PointEmitter, RecordState, RotationGenerator, SizeOverLife, TrailSettings, ValueGenerator, VFXBatchSettings } from "three.quarks";
|
4
|
+
import { BatchedParticleRenderer, ConstantColor, ConstantValue, ParticleSystem as _ParticleSystem, RenderMode, TrailBatch, TrailParticle } from "three.quarks";
|
5
5
|
|
6
6
|
import { isDevEnvironment, showBalloonWarning } from "../engine/debug/index.js";
|
7
7
|
import { Gizmos } from "../engine/engine_gizmos.js";
|
@@ -17,7 +17,7 @@
|
|
17
17
|
import { NEEDLE_progressive } from "../engine/extensions/NEEDLE_progressive.js";
|
18
18
|
import { Behaviour, GameObject } from "./Component.js";
|
19
19
|
import { RGBAColor } from "./js-extensions/RGBAColor.js";
|
20
|
-
import { ColorBySpeedModule, ColorOverLifetimeModule, EmissionModule, InheritVelocityModule, type IParticleSystem, LimitVelocityOverLifetimeModule, MainModule, MinMaxCurve, MinMaxGradient, NoiseModule, ParticleBurst, ParticleSystemRenderMode, ParticleSystemScalingMode,ParticleSystemShapeType, ParticleSystemSimulationSpace, RotationBySpeedModule, RotationOverLifetimeModule, ShapeModule, SizeBySpeedModule, SizeOverLifetimeModule, TextureSheetAnimationModule, TrailModule, VelocityOverLifetimeModule } from "./ParticleSystemModules.js"
|
20
|
+
import { ColorBySpeedModule, ColorOverLifetimeModule, EmissionModule, InheritVelocityModule, type IParticleSystem, LimitVelocityOverLifetimeModule, MainModule, MinMaxCurve, MinMaxGradient, NoiseModule, ParticleBurst, ParticleSystemRenderMode, ParticleSystemScalingMode, ParticleSystemShapeType, ParticleSystemSimulationSpace, RotationBySpeedModule, RotationOverLifetimeModule, ShapeModule, SizeBySpeedModule, SizeOverLifetimeModule, TextureSheetAnimationModule, TrailModule, VelocityOverLifetimeModule } from "./ParticleSystemModules.js"
|
21
21
|
import { ParticleSubEmitter } from "./ParticleSystemSubEmitter.js";
|
22
22
|
|
23
23
|
const debug = getParam("debugparticles");
|
@@ -25,7 +25,7 @@
|
|
25
25
|
const debugProgressiveLoading = getParam("debugprogressive");
|
26
26
|
|
27
27
|
|
28
|
-
export type { Particle as QParticle,Behavior as QParticleBehaviour } from "three.quarks"
|
28
|
+
export type { Particle as QParticle, Behavior as QParticleBehaviour } from "three.quarks"
|
29
29
|
|
30
30
|
|
31
31
|
|
@@ -80,23 +80,17 @@
|
|
80
80
|
return res;
|
81
81
|
}
|
82
82
|
|
83
|
-
private static _havePatchedQuarkShaders = false;
|
84
|
-
|
85
83
|
getMaterial(trailEnabled: boolean = false) {
|
84
|
+
const material = (trailEnabled === true && this.trailMaterial) ? this.trailMaterial : this.particleMaterial;
|
86
85
|
|
87
|
-
if (
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
TrailBatch.prototype.rebuildMaterial = function () {
|
93
|
-
_rebuild.call(this);
|
94
|
-
this.material.defines.MAP_UV = "uv";
|
86
|
+
if (material) {
|
87
|
+
if (trailEnabled) {
|
88
|
+
// the particle material for trails must be DoubleSide or BackSide (since otherwise the trail is invisible)
|
89
|
+
if (material.side === FrontSide)
|
90
|
+
material.side = BackSide;
|
95
91
|
}
|
96
92
|
}
|
97
93
|
|
98
|
-
const material = (trailEnabled === true && this.trailMaterial) ? this.trailMaterial : this.particleMaterial;
|
99
|
-
|
100
94
|
// progressive load on start
|
101
95
|
// TODO: figure out how to do this before particle system rendering so we only load textures for visible materials
|
102
96
|
if (material && !suppressProgressiveLoading && material["_didRequestTextureLOD"] === undefined) {
|
@@ -397,7 +391,7 @@
|
|
397
391
|
let size = particle.size;
|
398
392
|
if (size <= 0 && !this.system.trails.sizeAffectsWidth) {
|
399
393
|
// Not sure where we get to 100* from, tested in SOC trong com
|
400
|
-
size =
|
394
|
+
size = 20 * this.system.trails.widthOverTrail.evaluate(.5, trailParticle[$trailWidthRandom]);
|
401
395
|
}
|
402
396
|
state.size = this.system.trails.getWidth(size, age01, pos01, trailParticle[$trailWidthRandom]);
|
403
397
|
state.color.copy(particle.color);
|
@@ -429,8 +423,7 @@
|
|
429
423
|
initialize(particle: Particle): void {
|
430
424
|
const simulationSpeed = this.system.main.simulationSpeed;
|
431
425
|
|
432
|
-
|
433
|
-
particle.startSpeed = this.system.main.startSpeed.evaluate(Math.random(), Math.random()) * factor;
|
426
|
+
particle.startSpeed = this.system.main.startSpeed.evaluate(Math.random(), Math.random());
|
434
427
|
particle.velocity.copy(this.system.shape.getDirection(particle.position)).multiplyScalar(particle.startSpeed);
|
435
428
|
if (this.system.inheritVelocity?.enabled) {
|
436
429
|
this.system.inheritVelocity.applyInitial(particle.velocity);
|
@@ -615,8 +608,7 @@
|
|
615
608
|
if (mat && mat["map"]) {
|
616
609
|
const original = mat["map"]! as THREE.Texture;
|
617
610
|
// cache the last original one so we're not creating tons of clones
|
618
|
-
if (this.clonedTexture.original !== original || !this.clonedTexture.clone)
|
619
|
-
{
|
611
|
+
if (this.clonedTexture.original !== original || !this.clonedTexture.clone) {
|
620
612
|
const tex = original.clone();
|
621
613
|
tex.premultiplyAlpha = false;
|
622
614
|
tex.colorSpace = THREE.LinearSRGBColorSpace;
|
@@ -755,7 +747,7 @@
|
|
755
747
|
readonly limitVelocityOverLifetime!: LimitVelocityOverLifetimeModule;
|
756
748
|
|
757
749
|
@serializable(InheritVelocityModule)
|
758
|
-
|
750
|
+
inheritVelocity!: InheritVelocityModule;
|
759
751
|
|
760
752
|
@serializable(ColorBySpeedModule)
|
761
753
|
readonly colorBySpeed!: ColorBySpeedModule;
|
@@ -934,6 +926,8 @@
|
|
934
926
|
}
|
935
927
|
|
936
928
|
awake(): void {
|
929
|
+
this._worldPositionFrame = -1;
|
930
|
+
|
937
931
|
this._renderer = this.gameObject.getComponent(ParticleSystemRenderer) as ParticleSystemRenderer;
|
938
932
|
|
939
933
|
if (!this.main) {
|
@@ -967,9 +961,12 @@
|
|
967
961
|
const emitter = this._particleSystem.emitter;
|
968
962
|
this.context.scene.add(emitter);
|
969
963
|
|
970
|
-
this.inheritVelocity
|
971
|
-
|
964
|
+
if (this.inheritVelocity.system && this.inheritVelocity.system !== this) {
|
965
|
+
this.inheritVelocity = this.inheritVelocity.clone();
|
966
|
+
}
|
967
|
+
this.inheritVelocity.awake(this);
|
972
968
|
|
969
|
+
|
973
970
|
if (debug) {
|
974
971
|
console.log(this);
|
975
972
|
this.gameObject.add(new AxesHelper(1))
|
@@ -1113,7 +1110,6 @@
|
|
1113
1110
|
this.shape.update(this, this.context, this.main.simulationSpace, this.gameObject);
|
1114
1111
|
this.noise.update(this.context);
|
1115
1112
|
|
1116
|
-
this.inheritVelocity.system = this;
|
1117
1113
|
this.inheritVelocity?.update(this.context);
|
1118
1114
|
this.velocityOverLifetime.update(this);
|
1119
1115
|
}
|
@@ -180,6 +180,19 @@
|
|
180
180
|
@serializable()
|
181
181
|
curveMultiplier?: number;
|
182
182
|
|
183
|
+
clone() {
|
184
|
+
const clone = new MinMaxCurve();
|
185
|
+
clone.mode = this.mode;
|
186
|
+
clone.constant = this.constant;
|
187
|
+
clone.constantMin = this.constantMin;
|
188
|
+
clone.constantMax = this.constantMax;
|
189
|
+
clone.curve = this.curve?.clone();
|
190
|
+
clone.curveMin = this.curveMin?.clone();
|
191
|
+
clone.curveMax = this.curveMax?.clone();
|
192
|
+
clone.curveMultiplier = this.curveMultiplier;
|
193
|
+
return clone;
|
194
|
+
}
|
195
|
+
|
183
196
|
evaluate(t01: number, lerpFactor?: number): number {
|
184
197
|
const t = lerpFactor === undefined ? Math.random() : lerpFactor;
|
185
198
|
switch (this.mode) {
|
@@ -600,6 +613,7 @@
|
|
600
613
|
}
|
601
614
|
getPosition(): void {
|
602
615
|
this._vector.set(0, 0, 0);
|
616
|
+
|
603
617
|
const pos = this._temp.copy(this.position);
|
604
618
|
const isWorldSpace = this._space === ParticleSystemSimulationSpace.World;
|
605
619
|
if (isWorldSpace) {
|
@@ -742,7 +756,7 @@
|
|
742
756
|
vec.z = z;
|
743
757
|
}
|
744
758
|
|
745
|
-
private randomCirclePoint(pos:Vec3, radius:number, thickness:number, arg:number, vec:Vec3){
|
759
|
+
private randomCirclePoint(pos: Vec3, radius: number, thickness: number, arg: number, vec: Vec3) {
|
746
760
|
const u = Math.random();
|
747
761
|
const theta = 2 * Math.PI * u * (arg / 360);
|
748
762
|
const r = Mathf.lerp(1, 1 - (Math.pow(1 - Math.random(), Math.PI)), thickness) * (radius);
|
@@ -973,7 +987,7 @@
|
|
973
987
|
@serializable()
|
974
988
|
worldSpace: boolean = false;
|
975
989
|
|
976
|
-
getWidth(size: number, _life01: number, pos01: number, t
|
990
|
+
getWidth(size: number, _life01: number, pos01: number, t: number) {
|
977
991
|
const res = this.widthOverTrail.evaluate(pos01, t);
|
978
992
|
size *= res;
|
979
993
|
return size;
|
@@ -1385,29 +1399,54 @@
|
|
1385
1399
|
@serializable()
|
1386
1400
|
mode!: ParticleSystemInheritVelocityMode;
|
1387
1401
|
|
1402
|
+
clone() {
|
1403
|
+
const ni = new InheritVelocityModule();
|
1404
|
+
ni.enabled = this.enabled;
|
1405
|
+
ni.curve = this.curve?.clone();
|
1406
|
+
ni.curveMultiplier = this.curveMultiplier;
|
1407
|
+
ni.mode = this.mode;
|
1408
|
+
return ni;
|
1409
|
+
}
|
1410
|
+
|
1388
1411
|
system!: IParticleSystem;
|
1389
1412
|
|
1390
|
-
private _lastWorldPosition
|
1391
|
-
|
1392
|
-
|
1413
|
+
private get _lastWorldPosition() {
|
1414
|
+
if (!this.system['_iv_lastWorldPosition']) {
|
1415
|
+
this.system['_iv_lastWorldPosition'] = new Vector3();
|
1416
|
+
}
|
1417
|
+
return this.system['_iv_lastWorldPosition'];
|
1418
|
+
}
|
1419
|
+
private get _velocity() {
|
1420
|
+
if (!this.system['_iv_velocity']) {
|
1421
|
+
this.system['_iv_velocity'] = new Vector3();
|
1422
|
+
}
|
1423
|
+
return this.system['_iv_velocity'];
|
1424
|
+
}
|
1393
1425
|
|
1394
|
-
|
1395
|
-
|
1396
|
-
|
1397
|
-
|
1426
|
+
private readonly _temp: Vector3 = new Vector3();
|
1427
|
+
private _firstUpdate: boolean = true;
|
1428
|
+
|
1429
|
+
awake(system: IParticleSystem) {
|
1430
|
+
this.system = system;
|
1431
|
+
this.reset();
|
1398
1432
|
}
|
1399
1433
|
|
1400
|
-
|
1434
|
+
reset() {
|
1435
|
+
this._firstUpdate = true;
|
1436
|
+
}
|
1437
|
+
|
1438
|
+
update(_context: Context) {
|
1401
1439
|
if (!this.enabled) return;
|
1402
1440
|
if (this.system.worldspace === false) return;
|
1403
|
-
if (this.
|
1441
|
+
if (this._firstUpdate) {
|
1442
|
+
this._firstUpdate = false;
|
1443
|
+
this._velocity.set(0, 0, 0);
|
1444
|
+
this._lastWorldPosition.copy(this.system.worldPos);
|
1445
|
+
}
|
1446
|
+
else if (this._lastWorldPosition) {
|
1404
1447
|
this._velocity.copy(this.system.worldPos).sub(this._lastWorldPosition).multiplyScalar(1 / this.system.deltaTime);
|
1405
1448
|
this._lastWorldPosition.copy(this.system.worldPos);
|
1406
1449
|
}
|
1407
|
-
else {
|
1408
|
-
this._velocity.set(0, 0, 0);
|
1409
|
-
this._lastWorldPosition = this.system.worldPos.clone();
|
1410
|
-
}
|
1411
1450
|
}
|
1412
1451
|
|
1413
1452
|
// TODO: make work for subsystems
|
@@ -1421,8 +1460,10 @@
|
|
1421
1460
|
}
|
1422
1461
|
}
|
1423
1462
|
|
1463
|
+
private _frames = 0;
|
1424
1464
|
applyCurrent(vel: Vector3, t01: number, lerpFactor: number) {
|
1425
1465
|
if (!this.enabled) return;
|
1466
|
+
if (!this.system) return;
|
1426
1467
|
if (this.system.worldspace === false) return;
|
1427
1468
|
if (this.mode === ParticleSystemInheritVelocityMode.Current) {
|
1428
1469
|
const factor = this.curve.evaluate(t01, lerpFactor);
|
@@ -403,7 +403,7 @@
|
|
403
403
|
const scale = 1 / sessionRoot!.arScale;
|
404
404
|
if (debug) console.log("AR Session Root scale", scale, target);
|
405
405
|
target.matrix.makeScale(scale, scale, scale);
|
406
|
-
if (sessionRoot.invertForward) {
|
406
|
+
if (sessionRoot.invertForward == false) {
|
407
407
|
target.matrix.multiply(new Matrix4().makeRotationY(Math.PI));
|
408
408
|
}
|
409
409
|
}
|
@@ -36,7 +36,7 @@
|
|
36
36
|
}
|
37
37
|
private _arScale: number = 1;
|
38
38
|
|
39
|
-
/** When enabled the scene
|
39
|
+
/** When enabled the placed scene forward direction will towards the XRRig */
|
40
40
|
@serializable()
|
41
41
|
invertForward: boolean = false;
|
42
42
|
|
@@ -357,7 +357,7 @@
|
|
357
357
|
rigObject.updateMatrix();
|
358
358
|
// if invert forward is disabled we need to invert the forward rotation
|
359
359
|
// we want to look into positive Z direction (if invertForward is enabled we look into negative Z direction)
|
360
|
-
if (
|
360
|
+
if (this.invertForward == false)
|
361
361
|
rigObject.matrix.premultiply(invertForwardMatrix);
|
362
362
|
rigObject.matrix.premultiply(this._startOffset);
|
363
363
|
|
@@ -75,8 +75,8 @@
|
|
75
75
|
|
76
76
|
onEnable(): void {
|
77
77
|
if (this.useQuicklookExport) {
|
78
|
-
|
79
|
-
if (!
|
78
|
+
const existingUSDZExporter = GameObject.findObjectOfType(USDZExporter);
|
79
|
+
if (!existingUSDZExporter) {
|
80
80
|
// if no USDZ Exporter is found we add one and assign the scene to be exported
|
81
81
|
if (debug) console.log("WebXR: Adding USDZExporter");
|
82
82
|
this._usdzExporter = GameObject.addNewComponent(this.gameObject, USDZExporter);
|
@@ -106,6 +106,7 @@
|
|
106
106
|
onDisable(): void {
|
107
107
|
// remove the container automatically if it was added to the shadow root
|
108
108
|
this._container?.remove();
|
109
|
+
this._usdzExporter?.destroy();
|
109
110
|
}
|
110
111
|
|
111
112
|
private async handleOfferSession() {
|
@@ -29,6 +29,9 @@
|
|
29
29
|
*/
|
30
30
|
controlVisibility: boolean = true;
|
31
31
|
|
32
|
+
/** when true it will use the grip space, otherwise the ray space */
|
33
|
+
useGripSpace = false;
|
34
|
+
|
32
35
|
onUpdateXR(args: NeedleXREventArgs): void {
|
33
36
|
|
34
37
|
// try to get the controller
|
@@ -49,8 +52,14 @@
|
|
49
52
|
// we're following a controller (or hand)
|
50
53
|
if (this.controlVisibility)
|
51
54
|
this.gameObject.visible = true;
|
52
|
-
this.
|
53
|
-
|
55
|
+
if (this.useGripSpace) {
|
56
|
+
this.gameObject.worldPosition = ctrl.gripWorldPosition;
|
57
|
+
this.gameObject.worldQuaternion = ctrl.gripWorldQuaternion;
|
58
|
+
}
|
59
|
+
else {
|
60
|
+
this.gameObject.worldPosition = ctrl.rayWorldPosition;
|
61
|
+
this.gameObject.worldQuaternion = ctrl.rayWorldQuaternion;
|
62
|
+
}
|
54
63
|
}
|
55
64
|
|
56
65
|
}
|