@needle-tools/engine 4.2.0 → 4.2.3
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.
- package/CHANGELOG.md +11 -0
- package/dist/gltf-progressive.js +258 -257
- package/dist/gltf-progressive.light.js +258 -257
- package/dist/gltf-progressive.light.min.js +7 -7
- package/dist/gltf-progressive.light.umd.cjs +7 -7
- package/dist/gltf-progressive.min.js +7 -7
- package/dist/gltf-progressive.umd.cjs +7 -7
- package/dist/needle-engine.bundle.js +6660 -6588
- package/dist/needle-engine.bundle.light.js +6651 -6579
- package/dist/needle-engine.bundle.light.min.js +124 -120
- package/dist/needle-engine.bundle.light.umd.cjs +122 -118
- package/dist/needle-engine.bundle.min.js +124 -120
- package/dist/needle-engine.bundle.umd.cjs +122 -118
- package/dist/needle-engine.light.d.ts +9 -9
- package/lib/engine/engine_context.d.ts +1 -0
- package/lib/engine/engine_context.js +7 -3
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_input.d.ts +14 -2
- package/lib/engine/engine_input.js +41 -6
- package/lib/engine/engine_input.js.map +1 -1
- package/lib/engine/engine_loaders.js +6 -12
- package/lib/engine/engine_loaders.js.map +1 -1
- package/lib/engine/engine_physics_rapier.js +1 -1
- package/lib/engine/engine_physics_rapier.js.map +1 -1
- package/lib/engine/engine_serialization_core.js +16 -3
- package/lib/engine/engine_serialization_core.js.map +1 -1
- package/lib/engine/engine_types.d.ts +5 -0
- package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js +2 -2
- package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js.map +1 -1
- package/lib/engine-components/Duplicatable.js +2 -2
- package/lib/engine-components/Duplicatable.js.map +1 -1
- package/lib/engine-components/EventTrigger.d.ts +2 -0
- package/lib/engine-components/EventTrigger.js +12 -0
- package/lib/engine-components/EventTrigger.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +9 -2
- package/lib/engine-components/OrbitControls.js +62 -19
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/Renderer.js +5 -0
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/ScreenCapture.js +2 -2
- package/lib/engine-components/ScreenCapture.js.map +1 -1
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +0 -1
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.js.map +1 -1
- package/lib/engine-components/export/usdz/USDZExporter.js +2 -2
- package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
- package/lib/engine-components/export/usdz/extensions/behavior/Behaviour.js +19 -11
- package/lib/engine-components/export/usdz/extensions/behavior/Behaviour.js.map +1 -1
- package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.d.ts +7 -2
- package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js +33 -11
- package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js.map +1 -1
- package/lib/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.d.ts +1 -0
- package/lib/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.js +5 -2
- package/lib/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.js.map +1 -1
- package/lib/engine-components/ui/Button.js +3 -3
- package/lib/engine-components/ui/Button.js.map +1 -1
- package/lib/engine-components/ui/EventSystem.d.ts +6 -10
- package/lib/engine-components/ui/EventSystem.js +35 -52
- package/lib/engine-components/ui/EventSystem.js.map +1 -1
- package/lib/engine-components/ui/InputField.d.ts +4 -1
- package/lib/engine-components/ui/InputField.js +19 -0
- package/lib/engine-components/ui/InputField.js.map +1 -1
- package/lib/engine-components/utils/OpenURL.js +2 -2
- package/lib/engine-components/utils/OpenURL.js.map +1 -1
- package/lib/engine-components/webxr/WebXRImageTracking.js +5 -1
- package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
- package/package.json +2 -2
- package/plugins/types/userconfig.d.ts +2 -2
- package/plugins/vite/pwa.js +33 -22
- package/src/engine/codegen/register_types.ts +2 -2
- package/src/engine/engine_context.ts +7 -3
- package/src/engine/engine_input.ts +47 -9
- package/src/engine/engine_loaders.ts +6 -10
- package/src/engine/engine_physics_rapier.ts +1 -1
- package/src/engine/engine_serialization_core.ts +13 -4
- package/src/engine/engine_types.ts +5 -0
- package/src/engine/webcomponents/needle menu/needle-menu-spatial.ts +2 -2
- package/src/engine-components/Duplicatable.ts +2 -2
- package/src/engine-components/EventTrigger.ts +14 -0
- package/src/engine-components/OrbitControls.ts +71 -21
- package/src/engine-components/Renderer.ts +5 -0
- package/src/engine-components/ScreenCapture.ts +2 -2
- package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +0 -1
- package/src/engine-components/export/usdz/USDZExporter.ts +2 -2
- package/src/engine-components/export/usdz/extensions/behavior/Behaviour.ts +17 -11
- package/src/engine-components/export/usdz/extensions/behavior/BehaviourComponents.ts +41 -23
- package/src/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.ts +5 -2
- package/src/engine-components/ui/Button.ts +3 -3
- package/src/engine-components/ui/EventSystem.ts +45 -62
- package/src/engine-components/ui/InputField.ts +18 -1
- package/src/engine-components/utils/OpenURL.ts +2 -2
- package/src/engine-components/webxr/WebXRImageTracking.ts +5 -1
|
@@ -3,7 +3,7 @@ import { Intersection, Matrix4, Object3D, Ray, Vector2, Vector3 } from 'three';
|
|
|
3
3
|
import { showBalloonMessage, showBalloonWarning } from './debug/debug.js';
|
|
4
4
|
import { Context } from './engine_setup.js';
|
|
5
5
|
import { getTempVector, getWorldQuaternion } from './engine_three_utils.js';
|
|
6
|
-
import type { ButtonName, IGameObject, IInput, MouseButtonName, Vec2 } from './engine_types.js';
|
|
6
|
+
import type { ButtonName, CursorTypeName, IGameObject, IInput, MouseButtonName, Vec2 } from './engine_types.js';
|
|
7
7
|
import { DeviceUtilities, type EnumToPrimitiveUnion, getParam } from './engine_utils.js';
|
|
8
8
|
|
|
9
9
|
const debug = getParam("debuginput");
|
|
@@ -394,21 +394,46 @@ export class Input implements IInput {
|
|
|
394
394
|
get mouseWheelChanged(): boolean { return this.getMouseWheelChanged(0); }
|
|
395
395
|
|
|
396
396
|
/** Is the primary pointer double clicked (usually the left button). This is equivalent to `input.mouseDoubleClick` */
|
|
397
|
-
get click()
|
|
397
|
+
get click(): boolean { return this._pointerClick[0]; }
|
|
398
398
|
/** Was a double click detected for the primary pointer? */
|
|
399
|
-
get doubleClick()
|
|
399
|
+
get doubleClick(): boolean { return this._pointerDoubleClick[0]; }
|
|
400
400
|
|
|
401
|
-
private
|
|
401
|
+
private readonly _setCursorTypes: CursorTypeName[] = [];
|
|
402
402
|
|
|
403
|
+
/** @deprecated use setCursor("pointer") */
|
|
403
404
|
setCursorPointer() {
|
|
404
|
-
this.
|
|
405
|
-
this.context.domElement.style.cursor = "pointer";
|
|
405
|
+
this.setCursor("pointer");
|
|
406
406
|
}
|
|
407
|
+
/** @deprecated use unsetCursor() */
|
|
407
408
|
setCursorNormal() {
|
|
408
|
-
this.
|
|
409
|
-
|
|
410
|
-
|
|
409
|
+
this.unsetCursor("pointer");
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Set a custom cursor. This will set the cursor type until unsetCursor is called
|
|
413
|
+
*/
|
|
414
|
+
setCursor(type: CursorTypeName) {
|
|
415
|
+
this._setCursorTypes.push(type);
|
|
416
|
+
if (this._setCursorTypes.length > 10) {
|
|
417
|
+
this._setCursorTypes.shift();
|
|
418
|
+
}
|
|
419
|
+
this.updateCursor();
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Unset a custom cursor. This will set the cursor type to the previous type or default
|
|
423
|
+
*/
|
|
424
|
+
unsetCursor(type: CursorTypeName) {
|
|
425
|
+
for (let i = this._setCursorTypes.length - 1; i >= 0; i--) {
|
|
426
|
+
if (this._setCursorTypes[i] === type) {
|
|
427
|
+
this._setCursorTypes.splice(i, 1);
|
|
428
|
+
this.updateCursor();
|
|
429
|
+
break;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
private updateCursor() {
|
|
434
|
+
if (this._setCursorTypes?.length == 0)
|
|
411
435
|
this.context.domElement.style.cursor = "default";
|
|
436
|
+
else this.context.domElement.style.cursor = this._setCursorTypes[this._setCursorTypes.length - 1];
|
|
412
437
|
}
|
|
413
438
|
|
|
414
439
|
/**
|
|
@@ -756,6 +781,10 @@ export class Input implements IInput {
|
|
|
756
781
|
window.removeEventListener('pointerup', this.onPointerUp);
|
|
757
782
|
window.removeEventListener('pointercancel', this.onPointerCancel);
|
|
758
783
|
|
|
784
|
+
window.removeEventListener("touchstart", this.onTouchStart);
|
|
785
|
+
window.removeEventListener("touchmove", this.onTouchMove);
|
|
786
|
+
window.removeEventListener("touchend", this.onTouchEnd);
|
|
787
|
+
|
|
759
788
|
this._htmlEventSource?.removeEventListener('wheel', this.onMouseWheel, false);
|
|
760
789
|
window.removeEventListener("wheel", this.onWheelWindow, false);
|
|
761
790
|
|
|
@@ -778,7 +807,10 @@ export class Input implements IInput {
|
|
|
778
807
|
}
|
|
779
808
|
}
|
|
780
809
|
|
|
810
|
+
private readonly _receivedPointerMoveEventsThisFrame = new Array<number>;
|
|
811
|
+
|
|
781
812
|
private onEndOfFrame = () => {
|
|
813
|
+
this._receivedPointerMoveEventsThisFrame.length = 0;
|
|
782
814
|
for (let i = 0; i < this._pointerUp.length; i++)
|
|
783
815
|
this._pointerUp[i] = false;
|
|
784
816
|
for (let i = 0; i < this._pointerDown.length; i++)
|
|
@@ -901,8 +933,14 @@ export class Input implements IInput {
|
|
|
901
933
|
}
|
|
902
934
|
private onPointerMove = (evt: PointerEvent) => {
|
|
903
935
|
if (this.context.isInAR) return;
|
|
936
|
+
|
|
937
|
+
// Prevent multiple pointerMove events per frame
|
|
938
|
+
if (this._receivedPointerMoveEventsThisFrame.includes(evt.pointerId)) return;
|
|
939
|
+
this._receivedPointerMoveEventsThisFrame.push(evt.pointerId);
|
|
940
|
+
|
|
904
941
|
// We want to keep receiving move events until pointerUp and not stop handling events just because we're hovering over *some* HTML element
|
|
905
942
|
// if (this.canReceiveInput(evt) === false) return;
|
|
943
|
+
|
|
906
944
|
let button = evt.button;
|
|
907
945
|
if (evt.pointerType === "mouse") {
|
|
908
946
|
const pressedButton = this.getFirstPressedButtonForPointer(0);
|
|
@@ -23,26 +23,22 @@ function ensureLoaders() {
|
|
|
23
23
|
export function setDracoDecoderPath(path: string | undefined) {
|
|
24
24
|
if (path !== undefined && typeof path === "string") {
|
|
25
25
|
setDracoDecoderLocation(path);
|
|
26
|
-
const loaders = ensureLoaders();
|
|
27
|
-
if (debug) console.log("Setting draco decoder path to", path);
|
|
28
|
-
loaders.dracoLoader.setDecoderPath(path);
|
|
29
26
|
}
|
|
30
27
|
}
|
|
31
28
|
|
|
32
29
|
export function setDracoDecoderType(type: string | undefined) {
|
|
33
30
|
if (type !== undefined && typeof type === "string") {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
if (type !== "js") {
|
|
32
|
+
const loaders = ensureLoaders();
|
|
33
|
+
if (debug) console.log("Setting draco decoder type to", type);
|
|
34
|
+
loaders.dracoLoader.setDecoderConfig({ type: type });
|
|
35
|
+
}
|
|
37
36
|
}
|
|
38
37
|
}
|
|
39
38
|
|
|
40
39
|
export function setKtx2TranscoderPath(path: string) {
|
|
41
40
|
if (path !== undefined && typeof path === "string") {
|
|
42
41
|
setKTX2TranscoderLocation(path);
|
|
43
|
-
const loaders = ensureLoaders();
|
|
44
|
-
if (debug) console.log("Setting ktx2 transcoder path to", path);
|
|
45
|
-
loaders.ktx2Loader.setTranscoderPath(path);
|
|
46
42
|
}
|
|
47
43
|
}
|
|
48
44
|
|
|
@@ -78,7 +74,7 @@ export function addDracoAndKTX2Loaders(loader: GLTFLoader, context: Pick<Context
|
|
|
78
74
|
if (!(loader as any).meshoptDecoder)
|
|
79
75
|
loader.setMeshoptDecoder(loaders.meshoptDecoder);
|
|
80
76
|
|
|
81
|
-
configureLoader(loader, {
|
|
77
|
+
configureLoader(loader, {
|
|
82
78
|
progressive: true,
|
|
83
79
|
});
|
|
84
80
|
|
|
@@ -710,7 +710,7 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
710
710
|
positions = this._meshCache.get(key)!;
|
|
711
711
|
}
|
|
712
712
|
else {
|
|
713
|
-
if (debugPhysics || isDevEnvironment()) console.
|
|
713
|
+
if (debugPhysics || isDevEnvironment()) console.debug(`[Performance] Your MeshCollider \"${collider.name}\" is scaled: consider applying the scale to the collider mesh instead (${scale.x}, ${scale.y}, ${scale.z})`);
|
|
714
714
|
const scaledPositions = new Float32Array(positions.length);
|
|
715
715
|
for (let i = 0; i < positions.length; i += 3) {
|
|
716
716
|
scaledPositions[i] = positions[i] * scale.x;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { AnimationClip, Material, Mesh, Object3D, Texture } from "three";
|
|
1
|
+
import { AnimationClip, BufferGeometry, InstancedBufferGeometry, Material, Mesh, Object3D, Texture, WireframeGeometry } from "three";
|
|
2
2
|
import { type GLTF } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
3
3
|
|
|
4
4
|
import { debugExtension } from "../engine/engine_default_parameters.js";
|
|
5
|
-
import { addLog,LogType } from "./debug/debug_overlay.js";
|
|
5
|
+
import { addLog, LogType } from "./debug/debug_overlay.js";
|
|
6
6
|
import { isLocalNetwork } from "./engine_networking_utils.js";
|
|
7
7
|
import { Context } from "./engine_setup.js";
|
|
8
8
|
import type { Constructor, ConstructorConcrete, SourceIdentifier } from "./engine_types.js";
|
|
@@ -515,8 +515,17 @@ function deserializeObjectWithType(data: any, typeOrConstructor: ConstructorConc
|
|
|
515
515
|
|
|
516
516
|
// e.g. when @serializable(Texture) and the texture is already resolved via json pointer from gltf
|
|
517
517
|
// then we dont need to do anything else
|
|
518
|
-
if (!typeIsFunction && currentValue
|
|
519
|
-
|
|
518
|
+
if (!typeIsFunction && currentValue) {
|
|
519
|
+
if (currentValue instanceof Material) return currentValue;
|
|
520
|
+
if (currentValue instanceof Texture) return currentValue;
|
|
521
|
+
if (currentValue instanceof Mesh) return currentValue;
|
|
522
|
+
if (currentValue instanceof BufferGeometry) return currentValue;
|
|
523
|
+
if (currentValue instanceof AnimationClip) return currentValue;
|
|
524
|
+
}
|
|
525
|
+
// Removed this line because it prevents assigning serialized values to existing instances for e.g. EventList
|
|
526
|
+
// https://linear.app/needle/issue/NE-5350
|
|
527
|
+
// if (!typeIsFunction && currentValue instanceof type) return currentValue;
|
|
528
|
+
|
|
520
529
|
// try to resolve the serializer for a type only once
|
|
521
530
|
if (!typeContext) {
|
|
522
531
|
typeContext = {
|
|
@@ -528,6 +528,11 @@ export interface IPhysicsEngine {
|
|
|
528
528
|
debugRenderRaycasts: boolean;
|
|
529
529
|
}
|
|
530
530
|
|
|
531
|
+
/**
|
|
532
|
+
* Available cursor types
|
|
533
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/CSS/cursor
|
|
534
|
+
*/
|
|
535
|
+
export type CursorTypeName = "auto" | "default" | "none" | "context-menu" | "help" | "pointer" | "progress" | "wait" | "cell" | "crosshair" | "text" | "vertical-text" | "alias" | "copy" | "move" | "no-drop" | "not-allowed" | "grab" | "grabbing" | "all-scroll" | "col-resize" | "row-resize" | "n-resize" | "e-resize" | "s-resize" | "w-resize" | "nw-resize" | "se-resize" | "sw-resize" | "ew-resize" | "ns-resize" | "nesw-resize" | "nwse-resize" | "zoom-in" | "zoom-out";
|
|
531
536
|
|
|
532
537
|
/** Typical mouse button names for most devices */
|
|
533
538
|
export type MouseButtonName = "left" | "right" | "middle";
|
|
@@ -548,14 +548,14 @@ class OnClick implements Pick<IComponent, "__internalAwake"> {
|
|
|
548
548
|
}
|
|
549
549
|
|
|
550
550
|
onPointerEnter() {
|
|
551
|
-
this.context.input.
|
|
551
|
+
this.context.input.setCursor("pointer");
|
|
552
552
|
if (this.allowModifyUI) {
|
|
553
553
|
this.element.set({ backgroundOpacity: 1 });
|
|
554
554
|
ThreeMeshUI.update();
|
|
555
555
|
}
|
|
556
556
|
}
|
|
557
557
|
onPointerExit() {
|
|
558
|
-
this.context.input.
|
|
558
|
+
this.context.input.unsetCursor("pointer");
|
|
559
559
|
if (this.allowModifyUI) {
|
|
560
560
|
this.element.set({ backgroundOpacity: 0 });
|
|
561
561
|
ThreeMeshUI.update();
|
|
@@ -105,14 +105,14 @@ export class Duplicatable extends Behaviour implements IPointerEventHandler {
|
|
|
105
105
|
if (!this.object) return;
|
|
106
106
|
if (!this.context.connection.allowEditing) return;
|
|
107
107
|
if (args.button !== 0) return;
|
|
108
|
-
this.context.input.
|
|
108
|
+
this.context.input.setCursor("pointer");
|
|
109
109
|
}
|
|
110
110
|
onPointerExit(args: PointerEventData) {
|
|
111
111
|
if (args.used) return;
|
|
112
112
|
if (!this.object) return;
|
|
113
113
|
if (!this.context.connection.allowEditing) return;
|
|
114
114
|
if (args.button !== 0) return;
|
|
115
|
-
this.context.input.
|
|
115
|
+
this.context.input.unsetCursor("pointer");
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
/** @internal */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { serializable } from "../engine/engine_serialization.js";
|
|
2
|
+
import { EventSystem } from "./api.js";
|
|
2
3
|
import { Behaviour } from "./Component.js"
|
|
3
4
|
import { EventList } from "./EventList.js";
|
|
4
5
|
import { EventType } from "./EventType.js"
|
|
@@ -33,6 +34,13 @@ export class EventTrigger extends Behaviour implements IPointerEventHandler {
|
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
private hasTrigger(type: EventType) {
|
|
38
|
+
return this.triggers?.some(t => t.eventID === type) ?? false;
|
|
39
|
+
}
|
|
40
|
+
private shouldChangeCursor() {
|
|
41
|
+
return this.hasTrigger(EventType.PointerClick) || this.hasTrigger(EventType.PointerDown) || this.hasTrigger(EventType.PointerUp);
|
|
42
|
+
}
|
|
43
|
+
|
|
36
44
|
/** @internal */
|
|
37
45
|
onPointerClick(_: PointerEventData) {
|
|
38
46
|
this.invoke(EventType.PointerClick);
|
|
@@ -40,11 +48,17 @@ export class EventTrigger extends Behaviour implements IPointerEventHandler {
|
|
|
40
48
|
|
|
41
49
|
/** @internal */
|
|
42
50
|
onPointerEnter(_: PointerEventData) {
|
|
51
|
+
if (this.shouldChangeCursor()) {
|
|
52
|
+
this.context.input.setCursor("pointer");
|
|
53
|
+
}
|
|
43
54
|
this.invoke(EventType.PointerEnter);
|
|
44
55
|
}
|
|
45
56
|
|
|
46
57
|
/** @internal */
|
|
47
58
|
onPointerExit(_: PointerEventData) {
|
|
59
|
+
if (this.shouldChangeCursor()) {
|
|
60
|
+
this.context.input.unsetCursor("pointer");
|
|
61
|
+
}
|
|
48
62
|
this.invoke(EventType.PointerExit);
|
|
49
63
|
}
|
|
50
64
|
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { Box3Helper, Object3D, PerspectiveCamera, Ray, Vector2, Vector3, Vector3Like } from "three";
|
|
1
|
+
import { Box3Helper, Euler, Object3D, PerspectiveCamera, Quaternion, Ray, Vector2, Vector3, Vector3Like } from "three";
|
|
2
2
|
import { OrbitControls as ThreeOrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
|
3
3
|
|
|
4
|
+
import { isDevEnvironment } from "../engine/debug/index.js";
|
|
4
5
|
import { setCameraController } from "../engine/engine_camera.js";
|
|
5
6
|
import { Gizmos } from "../engine/engine_gizmos.js";
|
|
6
7
|
import { InputEventQueue, NEPointerEvent } from "../engine/engine_input.js";
|
|
7
8
|
import { Mathf } from "../engine/engine_math.js";
|
|
8
9
|
import { RaycastOptions } from "../engine/engine_physics.js";
|
|
9
10
|
import { serializable } from "../engine/engine_serialization_decorator.js";
|
|
10
|
-
import { getBoundingBox, getWorldDirection, getWorldPosition, getWorldRotation, setWorldRotation } from "../engine/engine_three_utils.js";
|
|
11
|
+
import { getBoundingBox, getTempVector, getWorldDirection, getWorldPosition, getWorldRotation, setWorldRotation } from "../engine/engine_three_utils.js";
|
|
11
12
|
import type { ICameraController } from "../engine/engine_types.js";
|
|
12
13
|
import { DeviceUtilities, getParam } from "../engine/engine_utils.js";
|
|
13
14
|
import { Camera } from "./Camera.js";
|
|
@@ -616,14 +617,38 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
616
617
|
|
|
617
618
|
|
|
618
619
|
/**
|
|
619
|
-
* Sets camera target position and look direction
|
|
620
|
+
* Sets camera target position and look direction using a raycast in forward direction of the object.
|
|
621
|
+
*
|
|
622
|
+
* @param source The object to raycast from. If a camera is passed in the camera position will be used as the source.
|
|
623
|
+
* @param immediateOrDuration If true the camera target will move immediately to the new position, otherwise it will lerp. If a number is passed in it will be used as the duration of the lerp.
|
|
624
|
+
*
|
|
625
|
+
* This is useful for example if you want to align your camera with an object in your scene (or another camera). Simply pass in this other camera object
|
|
626
|
+
* @returns true if the target was set successfully
|
|
620
627
|
*/
|
|
621
|
-
public setCameraAndLookTarget(
|
|
622
|
-
if (!
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
628
|
+
public setCameraAndLookTarget(source: Object3D | Camera, immediateOrDuration: number | boolean = false): boolean {
|
|
629
|
+
if (!source) {
|
|
630
|
+
if (isDevEnvironment()) console.warn("[OrbitControls] setCameraAndLookTarget target is null");
|
|
631
|
+
return false;
|
|
632
|
+
}
|
|
633
|
+
if (!(source instanceof Object3D) && !(source instanceof Camera)) {
|
|
634
|
+
if (isDevEnvironment()) console.warn("[OrbitControls] setCameraAndLookTarget target is not an Object3D or Camera");
|
|
635
|
+
return false;
|
|
636
|
+
}
|
|
637
|
+
if (source instanceof Camera) {
|
|
638
|
+
source = source.gameObject;
|
|
639
|
+
}
|
|
640
|
+
const worldPosition = source.worldPosition;
|
|
641
|
+
const forward = source.worldForward;
|
|
642
|
+
const ray = new Ray(worldPosition, forward.multiplyScalar(-1));
|
|
643
|
+
|
|
644
|
+
if (debug) Gizmos.DrawRay(ray.origin, ray.direction, 0xff0000, 10);
|
|
645
|
+
|
|
646
|
+
if (!this.setTargetFromRaycast(ray, immediateOrDuration)) {
|
|
647
|
+
this.setLookTargetPosition(ray.at(2, getTempVector()), immediateOrDuration);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
this.setCameraTargetPosition(worldPosition, immediateOrDuration);
|
|
651
|
+
return true;
|
|
627
652
|
}
|
|
628
653
|
|
|
629
654
|
/** Moves the camera to position smoothly.
|
|
@@ -653,6 +678,38 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
653
678
|
else this._cameraLerpDuration = this.targetLerpDuration;
|
|
654
679
|
}
|
|
655
680
|
}
|
|
681
|
+
// public setCameraTargetRotation(rotation: Vector3 | Euler | Quaternion, immediateOrDuration: boolean | number = false): void {
|
|
682
|
+
// if (!this._cameraObject) return;
|
|
683
|
+
|
|
684
|
+
// if (typeof immediateOrDuration === "boolean") immediateOrDuration = immediateOrDuration ? 0 : this.targetLerpDuration;
|
|
685
|
+
|
|
686
|
+
// const ray = new Ray(this._cameraObject.worldPosition, getTempVector(0, 0, 1));
|
|
687
|
+
|
|
688
|
+
// // if the camera is in the middle of lerping we use the end position for the raycast
|
|
689
|
+
// if (immediateOrDuration > 0 && this._cameraEndPosition && this._cameraLerpActive) {
|
|
690
|
+
// ray.origin = getTempVector(this._cameraEndPosition)
|
|
691
|
+
// }
|
|
692
|
+
|
|
693
|
+
// if (rotation instanceof Vector3) {
|
|
694
|
+
// rotation = new Euler().setFromVector3(rotation);
|
|
695
|
+
// }
|
|
696
|
+
// if (rotation instanceof Euler) {
|
|
697
|
+
// rotation = new Quaternion().setFromEuler(rotation);
|
|
698
|
+
// }
|
|
699
|
+
|
|
700
|
+
// ray.direction.applyQuaternion(rotation);
|
|
701
|
+
// ray.direction.multiplyScalar(-1);
|
|
702
|
+
|
|
703
|
+
// const hits = this.context.physics.raycastFromRay(ray);
|
|
704
|
+
|
|
705
|
+
// if (hits.length > 0) {
|
|
706
|
+
// this.setCameraTargetPosition(hits[0].point, immediateOrDuration);
|
|
707
|
+
// }
|
|
708
|
+
// else {
|
|
709
|
+
// this.setLookTargetPosition(ray.at(2, getTempVector()));
|
|
710
|
+
// }
|
|
711
|
+
// }
|
|
712
|
+
|
|
656
713
|
/** True while the camera position is being lerped */
|
|
657
714
|
get cameraLerpActive() { return this._cameraLerpActive; }
|
|
658
715
|
/** Call to stop camera position lerping */
|
|
@@ -747,8 +804,8 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
747
804
|
else this._controls.target.lerp(position, delta);
|
|
748
805
|
}
|
|
749
806
|
|
|
750
|
-
private setTargetFromRaycast(ray?: Ray) {
|
|
751
|
-
if (!this.controls) return;
|
|
807
|
+
private setTargetFromRaycast(ray?: Ray, immediateOrDuration: number | boolean = false): boolean {
|
|
808
|
+
if (!this.controls) return false;
|
|
752
809
|
const rc = ray ? this.context.physics.raycastFromRay(ray) : this.context.physics.raycast();
|
|
753
810
|
for (const hit of rc) {
|
|
754
811
|
if (hit.distance > 0 && GameObject.isActiveInHierarchy(hit.object)) {
|
|
@@ -760,18 +817,11 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
760
817
|
break;
|
|
761
818
|
}
|
|
762
819
|
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
// if (this.context.mainCamera) {
|
|
767
|
-
// const pos = getWorldPosition(this.context.mainCamera);
|
|
768
|
-
// const cameraTarget = pos.clone().sub(this.controls.target).add(this._lookTargetEndPosition);
|
|
769
|
-
// this._cameraObject?.parent?.worldToLocal(cameraTarget);
|
|
770
|
-
// this.setCameraTargetPosition(cameraTarget);
|
|
771
|
-
// }
|
|
772
|
-
break;
|
|
820
|
+
this.setLookTargetPosition(hit.point, immediateOrDuration);
|
|
821
|
+
return true;
|
|
773
822
|
}
|
|
774
823
|
}
|
|
824
|
+
return false;
|
|
775
825
|
}
|
|
776
826
|
|
|
777
827
|
// Adapted from https://discourse.threejs.org/t/camera-zoom-to-fit-object/936/24
|
|
@@ -716,6 +716,11 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
716
716
|
const factor = this.hasLightmap ? Math.PI : 1;
|
|
717
717
|
const environmentIntensity = this.context.mainCameraComponent?.environmentIntensity ?? 1;
|
|
718
718
|
material.envMapIntensity = Math.max(0, environmentIntensity * this.context.sceneLighting.environmentIntensity / factor);
|
|
719
|
+
|
|
720
|
+
// since three 163 we need to set the envMap to the scene envMap if it is not set
|
|
721
|
+
// otherwise the envmapIntensity has no effect: https://github.com/mrdoob/three.js/pull/27903
|
|
722
|
+
// internal issue: https://linear.app/needle/issue/NE-6363
|
|
723
|
+
if (!material.envMap) material.envMap = this.context.scene.environment;
|
|
719
724
|
}
|
|
720
725
|
|
|
721
726
|
if (this._lightmaps) {
|
|
@@ -88,13 +88,13 @@ export class ScreenCapture extends Behaviour implements IPointerClickHandler {
|
|
|
88
88
|
onPointerEnter() {
|
|
89
89
|
if (this.context.connection.allowEditing == false) return;
|
|
90
90
|
if (!this.allowStartOnClick) return;
|
|
91
|
-
this.context.input.
|
|
91
|
+
this.context.input.setCursor("pointer");
|
|
92
92
|
}
|
|
93
93
|
/** @internal */
|
|
94
94
|
onPointerExit() {
|
|
95
95
|
if (this.context.connection.allowEditing == false) return;
|
|
96
96
|
if (!this.allowStartOnClick) return;
|
|
97
|
-
this.context.input.
|
|
97
|
+
this.context.input.unsetCursor("pointer");
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/** @internal */
|
|
@@ -1966,7 +1966,6 @@ function buildMaterial( material: MeshBasicMaterial, textures: TextureMap, quick
|
|
|
1966
1966
|
|
|
1967
1967
|
const materialName = getMaterialName(material);
|
|
1968
1968
|
|
|
1969
|
-
console.log(material);
|
|
1970
1969
|
// Special case: occluder material
|
|
1971
1970
|
// Supported on iOS 18+ and visionOS 1+
|
|
1972
1971
|
const isShadowCatcherMaterial =
|
|
@@ -403,7 +403,7 @@ export class USDZExporter extends Behaviour {
|
|
|
403
403
|
if (this.autoExportAnimations) {
|
|
404
404
|
implicitBehaviors.push(...registerAnimatorsImplictly(objectToExport, animExt));
|
|
405
405
|
}
|
|
406
|
-
const audioExt =
|
|
406
|
+
const audioExt = extensions.find(ext => ext.extensionName === "Audio");
|
|
407
407
|
if (audioExt && this.autoExportAudioSources)
|
|
408
408
|
implicitBehaviors.push(...registerAudioSourcesImplictly(objectToExport, audioExt as AudioExtension));
|
|
409
409
|
|
|
@@ -454,7 +454,7 @@ export class USDZExporter extends Behaviour {
|
|
|
454
454
|
});
|
|
455
455
|
}
|
|
456
456
|
|
|
457
|
-
const behaviorExt =
|
|
457
|
+
const behaviorExt = extensions.find(ext => ext.extensionName === "Behaviour") as BehaviorExtension | undefined;
|
|
458
458
|
if (this.interactive && behaviorExt && objectsToDisableAtSceneStart.length > 0) {
|
|
459
459
|
behaviorExt.addBehavior(disableObjectsAtStart(objectsToDisableAtSceneStart));
|
|
460
460
|
}
|
|
@@ -120,19 +120,21 @@ export class BehaviorExtension implements IUSDExporterExtension {
|
|
|
120
120
|
if (actionModel.tokenId === "StartAnimation") {
|
|
121
121
|
playAnimationActions.add(actionModel);
|
|
122
122
|
}
|
|
123
|
+
let actionType = actionModel.tokenId;
|
|
124
|
+
if (actionModel.type !== undefined) actionType += ":" + actionModel.type;
|
|
123
125
|
const affected = actionModel.affectedObjects;
|
|
124
126
|
if (affected) {
|
|
125
127
|
if (Array.isArray(affected)) {
|
|
126
128
|
for (const a of affected) {
|
|
127
129
|
actionTargets.add(a as Target);
|
|
128
130
|
//@ts-ignore
|
|
129
|
-
if (createMermaidGraphForDebugging) mermaidGraphTopLevel += `${actionModel.id}[${actionModel.id}] -- ${
|
|
131
|
+
if (createMermaidGraphForDebugging) mermaidGraphTopLevel += `${actionModel.id}[${actionModel.id}\n${actionType}] -- ${actionType} --> ${a.uuid}(("${a.displayName || a.name || a.uuid}"))\n`;
|
|
130
132
|
}
|
|
131
133
|
}
|
|
132
134
|
else if (typeof affected === "object") {
|
|
133
135
|
actionTargets.add(affected as Target);
|
|
134
136
|
//@ts-ignore
|
|
135
|
-
if (createMermaidGraphForDebugging) mermaidGraphTopLevel += `${actionModel.id}[${actionModel.id}] -- ${
|
|
137
|
+
if (createMermaidGraphForDebugging) mermaidGraphTopLevel += `${actionModel.id}[${actionModel.id}\n${actionType}] -- ${actionType} --> ${affected.uuid}(("${affected.displayName || affected.name || affected.uuid}"))\n`;
|
|
136
138
|
}
|
|
137
139
|
else if (typeof affected === "string") {
|
|
138
140
|
actionTargets.add({uuid: affected} as any as Target);
|
|
@@ -144,7 +146,7 @@ export class BehaviorExtension implements IUSDExporterExtension {
|
|
|
144
146
|
if (typeof xform === "object") {
|
|
145
147
|
actionTargets.add(xform as Target);
|
|
146
148
|
//@ts-ignore
|
|
147
|
-
if (createMermaidGraphForDebugging) mermaidGraphTopLevel += `${actionModel.id}[${actionModel.id}] -- ${
|
|
149
|
+
if (createMermaidGraphForDebugging) mermaidGraphTopLevel += `${actionModel.id}[${actionModel.id}\n${actionType}] -- ${actionType} --> ${xform.uuid}(("${xform.displayName || xform.name || xform.uuid}"))\n`;
|
|
148
150
|
}
|
|
149
151
|
else if (typeof xform === "string") {
|
|
150
152
|
actionTargets.add({uuid: xform} as any as Target);
|
|
@@ -159,19 +161,21 @@ export class BehaviorExtension implements IUSDExporterExtension {
|
|
|
159
161
|
collectTrigger(t, action);
|
|
160
162
|
}
|
|
161
163
|
else if (trigger instanceof TriggerModel) {
|
|
164
|
+
let triggerType = trigger.tokenId;
|
|
165
|
+
if (trigger.type !== undefined) triggerType += ":" + trigger.type;
|
|
162
166
|
if (typeof trigger.targetId === "object") {
|
|
163
167
|
triggerSources.add(trigger.targetId as Target);
|
|
164
168
|
//@ts-ignore
|
|
165
|
-
if (createMermaidGraphForDebugging) mermaidGraphTopLevel += `${trigger.targetId.uuid}(("${trigger.targetId.displayName}")) --> ${trigger.id}[${trigger.id}]\n`;
|
|
169
|
+
if (createMermaidGraphForDebugging) mermaidGraphTopLevel += `${trigger.targetId.uuid}(("${trigger.targetId.displayName}")) --> ${trigger.id}[${trigger.id}\n${triggerType}]\n`;
|
|
166
170
|
}
|
|
167
171
|
//@ts-ignore
|
|
168
|
-
if (createMermaidGraphForDebugging) mermaidGraph += `${trigger.id}((${trigger.id})) -- ${
|
|
172
|
+
if (createMermaidGraphForDebugging) mermaidGraph += `${trigger.id}((${trigger.id})) -- ${triggerType} --> ${action.id}[${action.tokenId || action.id}]\n`;
|
|
169
173
|
}
|
|
170
174
|
}
|
|
171
175
|
|
|
172
176
|
// collect all targets of all triggers and actions
|
|
173
177
|
for (const beh of this.behaviours) {
|
|
174
|
-
if (createMermaidGraphForDebugging) mermaidGraph += `subgraph
|
|
178
|
+
if (createMermaidGraphForDebugging) mermaidGraph += `subgraph ${beh.id}\n`;
|
|
175
179
|
collectAction(beh.action);
|
|
176
180
|
collectTrigger(beh.trigger, beh.action);
|
|
177
181
|
if (createMermaidGraphForDebugging) mermaidGraph += `end\n`;
|
|
@@ -180,10 +184,12 @@ export class BehaviorExtension implements IUSDExporterExtension {
|
|
|
180
184
|
|
|
181
185
|
if (createMermaidGraphForDebugging) {
|
|
182
186
|
console.log("All USDZ behaviours", this.behaviours);
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
+
if (this.behaviours.length) {
|
|
188
|
+
console.warn("The Mermaid graph can be pasted into https://massive-mermaid.glitch.me/ or https://mermaid.live/edit. It should be in your clipboard already!");
|
|
189
|
+
console.log(mermaidGraph);
|
|
190
|
+
// copy to clipboard, can be pasted into https://massive-mermaid.glitch.me/ or https://mermaid.live/edit
|
|
191
|
+
navigator.clipboard.writeText(mermaidGraph);
|
|
192
|
+
}
|
|
187
193
|
}
|
|
188
194
|
|
|
189
195
|
{
|
|
@@ -212,7 +218,7 @@ export class BehaviorExtension implements IUSDExporterExtension {
|
|
|
212
218
|
}
|
|
213
219
|
}
|
|
214
220
|
|
|
215
|
-
if (createMermaidGraphForDebugging) {
|
|
221
|
+
if (createMermaidGraphForDebugging && playAnimationActions.size) {
|
|
216
222
|
console.log(animationsGraph);
|
|
217
223
|
}
|
|
218
224
|
|