@@ -17,4 +17,4 @@
|
|
17
17
|
import "./AnimationUtils.js"
|
18
18
|
|
19
19
|
export { ParticleSystemBaseBehaviour, type QParticle, type QParticleBehaviour } from "./ParticleSystem.js"
|
20
|
-
|
20
|
+
export { ParticleSystemShapeType } from "./ParticleSystemModules.js"
|
@@ -327,7 +327,7 @@
|
|
327
327
|
}
|
328
328
|
}
|
329
329
|
|
330
|
-
private onNewClip(clip?: string | MediaStream) {
|
330
|
+
private async onNewClip(clip?: string | MediaStream) {
|
331
331
|
if (clip) this.clip = clip;
|
332
332
|
if (typeof clip === "string") {
|
333
333
|
if (debug)
|
@@ -343,7 +343,10 @@
|
|
343
343
|
this._lastClipStartedLoading = clip;
|
344
344
|
if (debug)
|
345
345
|
console.log("load audio", clip);
|
346
|
-
this.audioLoader.
|
346
|
+
const buffer = await this.audioLoader.loadAsync(clip).catch(console.error);
|
347
|
+
this._lastClipStartedLoading = null;
|
348
|
+
if (buffer)
|
349
|
+
this.createAudio(buffer);
|
347
350
|
}
|
348
351
|
else console.warn("Unsupported audio clip type", clip)
|
349
352
|
}
|
@@ -1,10 +1,13 @@
|
|
1
1
|
import { isLocalNetwork } from "../engine_networking_utils.js";
|
2
|
+
import { getParam } from "../engine_utils.js";
|
2
3
|
import { showDebugConsole } from "./debug_console.js";
|
3
4
|
import { addLog, LogType, setAllowOverlayMessages } from "./debug_overlay.js";
|
4
5
|
|
5
6
|
export { showDebugConsole }
|
6
7
|
export { LogType, setAllowOverlayMessages };
|
7
8
|
|
9
|
+
const noDevLogs = getParam("nodevlogs");
|
10
|
+
|
8
11
|
/** Displays a debug message on screen for a certain amount of time */
|
9
12
|
export function showBalloonMessage(text: string, logType: LogType = LogType.Log): void {
|
10
13
|
addLog(logType, text);
|
@@ -22,6 +25,7 @@
|
|
22
25
|
|
23
26
|
/** True when the application runs on a local url */
|
24
27
|
export function isDevEnvironment(): boolean {
|
28
|
+
if (noDevLogs) return false;
|
25
29
|
if (_manuallySetDevEnvironment !== undefined) return _manuallySetDevEnvironment;
|
26
30
|
return isLocalNetwork();
|
27
31
|
}
|
@@ -228,6 +228,18 @@
|
|
228
228
|
}
|
229
229
|
}
|
230
230
|
|
231
|
+
const container = document.createElement("div");
|
232
|
+
container.style.cssText = `
|
233
|
+
display: flex;
|
234
|
+
flex-direction: column;
|
235
|
+
align-items: center;
|
236
|
+
justify-content: center;
|
237
|
+
width: 100%;
|
238
|
+
opacity: 0;
|
239
|
+
transition: opacity 1.2s ease-in-out .2s;
|
240
|
+
`;
|
241
|
+
setTimeout(() => { container.style.opacity = "1"; }, 1);
|
242
|
+
this._loadingElement.appendChild(container);
|
231
243
|
|
232
244
|
const loadingBarContainer = document.createElement("div");
|
233
245
|
const maxWidth = 30;
|
@@ -270,8 +282,8 @@
|
|
270
282
|
logo.style.pointerEvents = "all";
|
271
283
|
logo.addEventListener("click", () => window.open("https://needle.tools", "_blank"));
|
272
284
|
}
|
273
|
-
|
274
|
-
|
285
|
+
container.appendChild(logo);
|
286
|
+
container.appendChild(loadingBarContainer);
|
275
287
|
|
276
288
|
|
277
289
|
this._loadingBar = document.createElement("div");
|
@@ -302,7 +314,7 @@
|
|
302
314
|
this._loadingTextContainer.style.display = "flex";
|
303
315
|
this._loadingTextContainer.style.justifyContent = "center";
|
304
316
|
this._loadingTextContainer.style.marginTop = "1.2em";
|
305
|
-
|
317
|
+
container.appendChild(this._loadingTextContainer);
|
306
318
|
|
307
319
|
const messageContainer = document.createElement("div");
|
308
320
|
this._messageContainer = messageContainer;
|
@@ -312,7 +324,7 @@
|
|
312
324
|
messageContainer.style.fontWeight = "200";
|
313
325
|
// messageContainer.style.border = "1px solid rgba(255,255,255,.1)";
|
314
326
|
messageContainer.style.justifyContent = "center";
|
315
|
-
|
327
|
+
container.appendChild(messageContainer);
|
316
328
|
|
317
329
|
if (hasLicense && this._element) {
|
318
330
|
const loadingTextColor = this._element.getAttribute("loading-text-color");
|
@@ -321,7 +333,7 @@
|
|
321
333
|
}
|
322
334
|
}
|
323
335
|
|
324
|
-
this.handleRuntimeLicense(
|
336
|
+
this.handleRuntimeLicense(container);
|
325
337
|
|
326
338
|
return this._loadingElement;
|
327
339
|
}
|
@@ -674,6 +674,5 @@
|
|
674
674
|
correctLevel: QRCODE.CorrectLevel.M,
|
675
675
|
...args,
|
676
676
|
});
|
677
|
-
console.log("QRCode generated for " + args.text);
|
678
677
|
return target;
|
679
678
|
}
|
@@ -157,17 +157,32 @@
|
|
157
157
|
}
|
158
158
|
private readonly _gripWorldQuaternion: Quaternion = new Quaternion();
|
159
159
|
|
160
|
-
/** Controller ray position in worldspace */
|
160
|
+
/** Controller ray position in worldspace (this value is calculated once per frame by default - call `updateRayWorldPosition` to force an update) */
|
161
161
|
get rayWorldPosition() {
|
162
162
|
return getTempVector(this._rayWorldPosition);
|
163
163
|
}
|
164
164
|
private readonly _rayWorldPosition: Vector3 = new Vector3();
|
165
|
+
/** Recalculates the ray world position */
|
166
|
+
updateRayWorldPosition() {
|
167
|
+
const parent = this.xr.context.mainCamera?.parent;
|
168
|
+
this._rayWorldPosition.copy(this._rayPosition);
|
169
|
+
if (parent) this._rayWorldPosition.applyMatrix4(parent.matrixWorld);
|
170
|
+
}
|
165
171
|
|
166
|
-
/** Controller ray rotation in wordspace */
|
172
|
+
/** Controller ray rotation in wordspace (this value is calculated once per frame by default - call `updateRayWorldQuaternion` to force an update) */
|
167
173
|
get rayWorldQuaternion() {
|
168
174
|
return getTempQuaternion(this._rayWorldQuaternion);
|
169
175
|
}
|
170
176
|
private readonly _rayWorldQuaternion: Quaternion = new Quaternion();
|
177
|
+
/** Recalculates the ray world quaternion */
|
178
|
+
updateRayWorldQuaternion() {
|
179
|
+
const parent = this.xr.context.mainCamera?.parent;
|
180
|
+
const parentWorldQuaternion = parent ? getWorldQuaternion(parent) : undefined;
|
181
|
+
this._rayWorldQuaternion.copy(this._rayQuaternion)
|
182
|
+
// flip forward because we want +Z to be forward
|
183
|
+
.multiply(flipForwardQuaternion);
|
184
|
+
if (parentWorldQuaternion) this._rayWorldQuaternion.premultiply(parentWorldQuaternion)
|
185
|
+
}
|
171
186
|
|
172
187
|
/** The controller ray in worldspace */
|
173
188
|
get ray(): Ray {
|
@@ -324,12 +339,8 @@
|
|
324
339
|
if (parentWorldQuaternion) this._gripWorldQuaternion.premultiply(parentWorldQuaternion)
|
325
340
|
|
326
341
|
// RAY
|
327
|
-
this.
|
328
|
-
|
329
|
-
this._rayWorldQuaternion.copy(this._rayQuaternion)
|
330
|
-
// flip forward because we want +Z to be forward
|
331
|
-
.multiply(flipForwardQuaternion);
|
332
|
-
if (parentWorldQuaternion) this._rayWorldQuaternion.premultiply(parentWorldQuaternion)
|
342
|
+
this.updateRayWorldPosition();
|
343
|
+
this.updateRayWorldQuaternion();
|
333
344
|
}
|
334
345
|
|
335
346
|
/** Called when the input source disconnects */
|
@@ -429,7 +429,7 @@
|
|
429
429
|
const simulationSpeed = this.system.main.simulationSpeed;
|
430
430
|
|
431
431
|
particle.startSpeed = this.system.main.startSpeed.evaluate(Math.random(), Math.random());
|
432
|
-
particle.velocity.copy(this.system.shape.getDirection(particle.position)).multiplyScalar(particle.startSpeed);
|
432
|
+
particle.velocity.copy(this.system.shape.getDirection(particle, particle.position)).multiplyScalar(particle.startSpeed);
|
433
433
|
if (this.system.inheritVelocity?.enabled) {
|
434
434
|
this.system.inheritVelocity.applyInitial(particle.velocity);
|
435
435
|
}
|
@@ -1,15 +1,18 @@
|
|
1
1
|
import { createNoise4D, type NoiseFunction4D } from 'simplex-noise';
|
2
|
-
import { Euler, Matrix4, Object3D, Quaternion, Vector2, Vector3, Vector4 } from "three";
|
2
|
+
import { BufferGeometry, Euler, Matrix4, Mesh, Object3D, Quaternion, Triangle, Vector2, Vector3, Vector4 } from "three";
|
3
3
|
import type { EmitterShape, Particle, ShapeJSON } from "three.quarks";
|
4
4
|
|
5
|
+
import { isDevEnvironment } from '../engine/debug/index.js';
|
5
6
|
import { Gizmos } from "../engine/engine_gizmos.js";
|
6
7
|
import { Mathf } from "../engine/engine_math.js";
|
7
8
|
import { serializable } from "../engine/engine_serialization.js";
|
8
9
|
import { Context } from "../engine/engine_setup.js";
|
10
|
+
import { getTempVector, getWorldQuaternion } from '../engine/engine_three_utils.js';
|
9
11
|
import type { Vec2, Vec3 } from "../engine/engine_types.js";
|
10
12
|
import { getParam } from "../engine/engine_utils.js";
|
11
13
|
import { AnimationCurve } from "./AnimationCurve.js";
|
12
14
|
import { RGBAColor } from "./js-extensions/RGBAColor.js";
|
15
|
+
import { MeshRenderer } from './Renderer.js';
|
13
16
|
|
14
17
|
const debug = getParam("debugparticles");
|
15
18
|
|
@@ -500,6 +503,13 @@
|
|
500
503
|
}
|
501
504
|
}
|
502
505
|
|
506
|
+
|
507
|
+
export enum ParticleSystemMeshShapeType {
|
508
|
+
Vertex = 0,
|
509
|
+
Edge = 1,
|
510
|
+
Triangle = 2,
|
511
|
+
}
|
512
|
+
|
503
513
|
export class ShapeModule implements EmitterShape {
|
504
514
|
|
505
515
|
// Emittershape start
|
@@ -507,7 +517,7 @@
|
|
507
517
|
return ParticleSystemShapeType[this.shapeType];
|
508
518
|
}
|
509
519
|
initialize(particle: Particle): void {
|
510
|
-
this.
|
520
|
+
this.onInitialize(particle);
|
511
521
|
particle.position.copy(this._vector);
|
512
522
|
}
|
513
523
|
toJSON(): ShapeJSON {
|
@@ -557,6 +567,30 @@
|
|
557
567
|
@serializable()
|
558
568
|
randomPositionAmount!: number;
|
559
569
|
|
570
|
+
/** Controls if particles should spawn off vertices, faces or edges. `shapeType` must be set to `MeshRenderer` */
|
571
|
+
@serializable()
|
572
|
+
meshShapeType?: ParticleSystemMeshShapeType;
|
573
|
+
/** When assigned and `shapeType` is set to `MeshRenderer` particles will spawn using a mesh in the scene.
|
574
|
+
* Use the `meshShapeType` to choose if particles should be spawned from vertices, faces or edges
|
575
|
+
* To re-assign use the `setMesh` function to cache the mesh and geometry
|
576
|
+
* */
|
577
|
+
@serializable(MeshRenderer)
|
578
|
+
meshRenderer?: MeshRenderer;
|
579
|
+
|
580
|
+
private _meshObj?: Mesh;
|
581
|
+
private _meshGeometry?: BufferGeometry;
|
582
|
+
setMesh(mesh: MeshRenderer) {
|
583
|
+
this.meshRenderer = mesh;
|
584
|
+
if (mesh) {
|
585
|
+
this._meshObj = mesh.sharedMeshes[Math.floor(Math.random() * mesh.sharedMeshes.length)];
|
586
|
+
this._meshGeometry = this._meshObj.geometry;
|
587
|
+
}
|
588
|
+
else {
|
589
|
+
this._meshObj = undefined;
|
590
|
+
this._meshGeometry = undefined;
|
591
|
+
}
|
592
|
+
}
|
593
|
+
|
560
594
|
private system!: IParticleSystem;
|
561
595
|
private _space?: ParticleSystemSimulationSpace;
|
562
596
|
private readonly _worldSpaceMatrix: Matrix4 = new Matrix4();
|
@@ -607,12 +641,13 @@
|
|
607
641
|
/** initializer implementation */
|
608
642
|
private _vector: Vector3 = new Vector3(0, 0, 0);
|
609
643
|
private _temp: Vector3 = new Vector3(0, 0, 0);
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
}
|
614
|
-
getPosition(): void {
|
644
|
+
private _triangle: Triangle = new Triangle();
|
645
|
+
|
646
|
+
onInitialize(particle: Particle): void {
|
615
647
|
this._vector.set(0, 0, 0);
|
648
|
+
// remove mesh from particle in case it got destroyed (we dont want to keep a reference to a destroyed mesh in the particle system)
|
649
|
+
particle["mesh"] = undefined;
|
650
|
+
particle["mesh_geometry"] = undefined;
|
616
651
|
|
617
652
|
const pos = this._temp.copy(this.position);
|
618
653
|
const isWorldSpace = this._space === ParticleSystemSimulationSpace.World;
|
@@ -639,8 +674,64 @@
|
|
639
674
|
case ParticleSystemShapeType.Circle:
|
640
675
|
this.randomCirclePoint(this.position, radius, this.radiusThickness, this.arc, this._vector);
|
641
676
|
break;
|
677
|
+
case ParticleSystemShapeType.MeshRenderer:
|
678
|
+
const renderer = this.meshRenderer;
|
679
|
+
if (renderer?.destroyed == false) this.setMesh(renderer);
|
680
|
+
const mesh = particle["mesh"] = this._meshObj;
|
681
|
+
const geometry = particle["mesh_geometry"] = this._meshGeometry;
|
682
|
+
if (mesh && geometry) {
|
683
|
+
switch (this.meshShapeType) {
|
684
|
+
case ParticleSystemMeshShapeType.Vertex:
|
685
|
+
{
|
686
|
+
const vertices = geometry.getAttribute("position");
|
687
|
+
const index = Math.floor(Math.random() * vertices.count);
|
688
|
+
this._vector.fromBufferAttribute(vertices, index);
|
689
|
+
this._vector.applyMatrix4(mesh.matrixWorld);
|
690
|
+
particle["mesh_normal"] = index;
|
691
|
+
}
|
692
|
+
break;
|
693
|
+
case ParticleSystemMeshShapeType.Edge:
|
694
|
+
break;
|
695
|
+
case ParticleSystemMeshShapeType.Triangle:
|
696
|
+
{
|
697
|
+
const faces = geometry.index;
|
698
|
+
if (faces) {
|
699
|
+
let u = Math.random();
|
700
|
+
let v = Math.random();
|
701
|
+
if (u + v > 1) {
|
702
|
+
u = 1 - u;
|
703
|
+
v = 1 - v;
|
704
|
+
}
|
705
|
+
const faceIndex = Math.floor(Math.random() * (faces.count / 3));
|
706
|
+
let i0 = faceIndex * 3;
|
707
|
+
let i1 = faceIndex * 3 + 1;
|
708
|
+
let i2 = faceIndex * 3 + 2;
|
709
|
+
i0 = faces.getX(i0);
|
710
|
+
i1 = faces.getX(i1);
|
711
|
+
i2 = faces.getX(i2);
|
712
|
+
const positionAttribute = geometry.getAttribute("position");
|
713
|
+
this._triangle.a.fromBufferAttribute(positionAttribute, i0);
|
714
|
+
this._triangle.b.fromBufferAttribute(positionAttribute, i1);
|
715
|
+
this._triangle.c.fromBufferAttribute(positionAttribute, i2);
|
716
|
+
this._vector
|
717
|
+
.set(0, 0, 0)
|
718
|
+
.addScaledVector(this._triangle.a, u)
|
719
|
+
.addScaledVector(this._triangle.b, v)
|
720
|
+
.addScaledVector(this._triangle.c, 1 - (u + v));
|
721
|
+
this._vector.applyMatrix4(mesh.matrixWorld);
|
722
|
+
particle["mesh_normal"] = faceIndex;
|
723
|
+
}
|
724
|
+
}
|
725
|
+
break;
|
726
|
+
}
|
727
|
+
}
|
728
|
+
break;
|
642
729
|
default:
|
643
730
|
this._vector.set(0, 0, 0);
|
731
|
+
if (isDevEnvironment() && !globalThis["__particlesystem_shapetype_unsupported"]) {
|
732
|
+
console.warn("ParticleSystem ShapeType is not supported:", ParticleSystemShapeType[this.shapeType]);
|
733
|
+
globalThis["__particlesystem_shapetype_unsupported"] = true;
|
734
|
+
}
|
644
735
|
break;
|
645
736
|
// case ParticleSystemShapeType.Hemisphere:
|
646
737
|
// randomSpherePoint(this.position.x, this.position.y, this.position.z, this.radius, this.radiusThickness, 180, this._vector);
|
@@ -666,7 +757,7 @@
|
|
666
757
|
|
667
758
|
private _dir: Vector3 = new Vector3();
|
668
759
|
|
669
|
-
getDirection(pos: Vec3): Vector3 {
|
760
|
+
getDirection(particle: Particle, pos: Vec3): Vector3 {
|
670
761
|
if (!this.enabled) {
|
671
762
|
this._dir.set(0, 0, 1);
|
672
763
|
return this._dir;
|
@@ -691,6 +782,47 @@
|
|
691
782
|
else
|
692
783
|
this._dir.sub(this.position)
|
693
784
|
break;
|
785
|
+
case ParticleSystemShapeType.MeshRenderer:
|
786
|
+
const mesh = particle["mesh"];
|
787
|
+
const geometry = particle["mesh_geometry"];
|
788
|
+
if (mesh && geometry) {
|
789
|
+
switch (this.meshShapeType) {
|
790
|
+
case ParticleSystemMeshShapeType.Vertex:
|
791
|
+
{
|
792
|
+
const normal = geometry.getAttribute("normal");
|
793
|
+
const index = particle["mesh_normal"];
|
794
|
+
this._dir.fromBufferAttribute(normal, index);
|
795
|
+
}
|
796
|
+
break;
|
797
|
+
case ParticleSystemMeshShapeType.Edge:
|
798
|
+
break;
|
799
|
+
case ParticleSystemMeshShapeType.Triangle:
|
800
|
+
{
|
801
|
+
const faces = geometry.index;
|
802
|
+
if (faces) {
|
803
|
+
const index = particle["mesh_normal"];
|
804
|
+
const i0 = faces.getX(index * 3);
|
805
|
+
const i1 = faces.getX(index * 3 + 1);
|
806
|
+
const i2 = faces.getX(index * 3 + 2);
|
807
|
+
const positionAttribute = geometry.getAttribute("position");
|
808
|
+
const a = getTempVector();
|
809
|
+
const b = getTempVector();
|
810
|
+
const c = getTempVector();
|
811
|
+
a.fromBufferAttribute(positionAttribute, i0);
|
812
|
+
b.fromBufferAttribute(positionAttribute, i1);
|
813
|
+
c.fromBufferAttribute(positionAttribute, i2);
|
814
|
+
a.sub(b);
|
815
|
+
c.sub(b);
|
816
|
+
a.cross(c);
|
817
|
+
this._dir.copy(a).multiplyScalar(-1);
|
818
|
+
const rot = getWorldQuaternion(mesh);
|
819
|
+
this._dir.applyQuaternion(rot)
|
820
|
+
}
|
821
|
+
}
|
822
|
+
break;
|
823
|
+
}
|
824
|
+
}
|
825
|
+
break;
|
694
826
|
default:
|
695
827
|
this._dir.set(0, 0, 1);
|
696
828
|
break;
|
@@ -241,7 +241,11 @@
|
|
241
241
|
// private _materialProperties: Array<MaterialProperties> | undefined = undefined;
|
242
242
|
private _lightmaps?: RendererLightmap[];
|
243
243
|
|
244
|
-
|
244
|
+
/** Get the mesh Object3D for this renderer
|
245
|
+
* Warn: if this is a multimaterial object it will return the first mesh only
|
246
|
+
* @returns the mesh object3D.
|
247
|
+
* */
|
248
|
+
get sharedMesh(): Mesh | SkinnedMesh | undefined {
|
245
249
|
if (this.gameObject.type === "Mesh") {
|
246
250
|
return this.gameObject as unknown as Mesh
|
247
251
|
}
|
@@ -254,6 +258,26 @@
|
|
254
258
|
return undefined;
|
255
259
|
}
|
256
260
|
|
261
|
+
private readonly _sharedMeshes: Mesh[] = [];
|
262
|
+
/** Get all the mesh Object3D for this renderer
|
263
|
+
* @returns an array of mesh object3D.
|
264
|
+
*/
|
265
|
+
get sharedMeshes(): Mesh[] {
|
266
|
+
if (this.destroyed || !this.gameObject) return this._sharedMeshes;
|
267
|
+
this._sharedMeshes.length = 0;
|
268
|
+
if (this.gameObject.type === "Group") {
|
269
|
+
for (const ch of this.gameObject.children) {
|
270
|
+
if (ch.type === "Mesh" || ch.type === "SkinnedMesh") {
|
271
|
+
this._sharedMeshes.push(ch as Mesh);
|
272
|
+
}
|
273
|
+
}
|
274
|
+
}
|
275
|
+
else if (this.gameObject.type === "Mesh" || this.gameObject.type === "SkinnedMesh") {
|
276
|
+
this._sharedMeshes.push(this.gameObject as unknown as Mesh);
|
277
|
+
}
|
278
|
+
return this._sharedMeshes;
|
279
|
+
}
|
280
|
+
|
257
281
|
get sharedMaterial(): Material {
|
258
282
|
return this.sharedMaterials[0];
|
259
283
|
}
|
@@ -518,6 +542,9 @@
|
|
518
542
|
}
|
519
543
|
|
520
544
|
onEnable() {
|
545
|
+
// ensure shared meshes are initialized
|
546
|
+
const _ = this.sharedMeshes;
|
547
|
+
|
521
548
|
this.setVisibility(true);
|
522
549
|
|
523
550
|
if (this._isInstancingEnabled) {
|
@@ -1009,7 +1036,7 @@
|
|
1009
1036
|
material.defines["USE_INSTANCING"] = true;
|
1010
1037
|
material.needsUpdate = true;
|
1011
1038
|
}
|
1012
|
-
|
1039
|
+
|
1013
1040
|
context.pre_render_callbacks.push(this.onBeforeRender);
|
1014
1041
|
context.post_render_callbacks.push(this.onAfterRender);
|
1015
1042
|
}
|
@@ -53,7 +53,11 @@
|
|
53
53
|
if (controller.hand) {
|
54
54
|
if (this.createHandModel) {
|
55
55
|
const res = await this.loadHandModel(controller);
|
56
|
-
if (!res || !controller.connected)
|
56
|
+
if (!res || !controller.connected) {
|
57
|
+
res?.handObject?.removeFromParent();
|
58
|
+
res?.handmesh?.controller?.removeFromParent();
|
59
|
+
return;
|
60
|
+
}
|
57
61
|
this._models[controller.index] = { controller: controller, model: res.handObject, handmesh: res.handmesh };
|
58
62
|
this.scene.add(res.handObject);
|
59
63
|
}
|
@@ -215,6 +219,9 @@
|
|
215
219
|
if (NeedleXRSession.active?.isPassThrough)
|
216
220
|
this.makeOccluder(child);
|
217
221
|
});
|
222
|
+
if (!controller.connected) {
|
223
|
+
object.removeFromParent();
|
224
|
+
}
|
218
225
|
});
|
219
226
|
|
220
227
|
if (debug) handObject.add(new AxesHelper(.5));
|
@@ -60,10 +60,6 @@
|
|
60
60
|
|
61
61
|
// in AR pass through mode we dont want to move the rig
|
62
62
|
if (args.xr.isPassThrough) {
|
63
|
-
if (this.showRays)
|
64
|
-
this.renderRays(args.xr);
|
65
|
-
if (this.showHits)
|
66
|
-
this.renderHits(args.xr);
|
67
63
|
return;
|
68
64
|
}
|
69
65
|
|
@@ -78,10 +74,6 @@
|
|
78
74
|
this.onHandleTeleport(teleportController, rig.gameObject);
|
79
75
|
}
|
80
76
|
|
81
|
-
if (this.showRays)
|
82
|
-
this.renderRays(args.xr);
|
83
|
-
if (this.showHits)
|
84
|
-
this.renderHits(args.xr);
|
85
77
|
}
|
86
78
|
onLeaveXR(_: NeedleXREventArgs): void {
|
87
79
|
for (const line of this._lines) {
|
@@ -92,6 +84,15 @@
|
|
92
84
|
}
|
93
85
|
}
|
94
86
|
|
87
|
+
onBeforeRender(): void {
|
88
|
+
if (this.context.xr?.running) {
|
89
|
+
if (this.showRays)
|
90
|
+
this.renderRays(this.context.xr);
|
91
|
+
if (this.showHits)
|
92
|
+
this.renderHits(this.context.xr);
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
95
96
|
protected onHandleMovement(controller: NeedleXRController, rig: IGameObject) {
|
96
97
|
const stick = controller.getStick("xr-standard-thumbstick");
|
97
98
|
const vec = new Vector3(stick.x, 0, stick.y);
|
@@ -185,6 +186,8 @@
|
|
185
186
|
this._lines[i] = line;
|
186
187
|
}
|
187
188
|
|
189
|
+
ctrl.updateRayWorldPosition();
|
190
|
+
ctrl.updateRayWorldQuaternion();
|
188
191
|
const pos = ctrl.rayWorldPosition;
|
189
192
|
const rot = ctrl.rayWorldQuaternion;
|
190
193
|
line.position.copy(pos);
|