@needle-tools/engine 4.10.0-next.55c0bf9 → 4.10.0-next.f5ce0ae
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/components.needle.json +1 -1
- package/dist/{needle-engine.bundle-CUo74dPe.js → needle-engine.bundle-DSzlnhCs.js} +7419 -7146
- package/dist/{needle-engine.bundle-Cf5H9Zy9.umd.cjs → needle-engine.bundle-VqrrECGF.umd.cjs} +154 -141
- package/dist/needle-engine.bundle-pI8o_eru.min.js +1652 -0
- package/dist/needle-engine.js +259 -257
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/vendor-CPuBPspY.umd.cjs +1121 -0
- package/dist/vendor-DPCU8cUF.min.js +1121 -0
- package/dist/vendor-MBoqSyFm.js +16240 -0
- package/lib/engine/codegen/register_types.js +2 -0
- package/lib/engine/codegen/register_types.js.map +1 -1
- package/lib/engine/engine_camera.d.ts +7 -1
- package/lib/engine/engine_camera.fit.d.ts +1 -1
- package/lib/engine/engine_camera.fit.js +3 -30
- package/lib/engine/engine_camera.fit.js.map +1 -1
- package/lib/engine/engine_camera.js +46 -6
- package/lib/engine/engine_camera.js.map +1 -1
- package/lib/engine/engine_context.d.ts +6 -0
- package/lib/engine/engine_context.js +48 -9
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_gizmos.d.ts +11 -10
- package/lib/engine/engine_gizmos.js +24 -10
- package/lib/engine/engine_gizmos.js.map +1 -1
- package/lib/engine/engine_license.js +1 -1
- package/lib/engine/engine_license.js.map +1 -1
- package/lib/engine/engine_lightdata.d.ts +3 -3
- package/lib/engine/engine_lightdata.js +10 -10
- package/lib/engine/engine_lightdata.js.map +1 -1
- package/lib/engine/engine_physics_rapier.js +4 -0
- package/lib/engine/engine_physics_rapier.js.map +1 -1
- package/lib/engine/engine_scenelighting.d.ts +1 -1
- package/lib/engine/engine_scenelighting.js +4 -5
- package/lib/engine/engine_scenelighting.js.map +1 -1
- package/lib/engine/engine_utils.d.ts +3 -1
- package/lib/engine/engine_utils.js +11 -0
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_lightmaps.js +1 -1
- package/lib/engine/extensions/NEEDLE_lightmaps.js.map +1 -1
- package/lib/engine/extensions/extension_utils.js +1 -1
- package/lib/engine/extensions/extension_utils.js.map +1 -1
- package/lib/engine/webcomponents/logo-element.d.ts +1 -1
- package/lib/engine/webcomponents/logo-element.js +29 -5
- package/lib/engine/webcomponents/logo-element.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.js +4 -3
- package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.js +22 -0
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.loading.d.ts +0 -1
- package/lib/engine/webcomponents/needle-engine.loading.js +3 -36
- package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
- package/lib/engine/xr/NeedleXRController.d.ts +3 -3
- package/lib/engine/xr/NeedleXRController.js +28 -0
- package/lib/engine/xr/NeedleXRController.js.map +1 -1
- package/lib/engine-components/CameraUtils.js +2 -1
- package/lib/engine-components/CameraUtils.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +4 -1
- package/lib/engine-components/OrbitControls.js +30 -6
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/Renderer.js +6 -1
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/Skybox.js +22 -4
- package/lib/engine-components/Skybox.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +1 -0
- package/lib/engine-components/codegen/components.js +1 -0
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/debug/LogStats.d.ts +1 -0
- package/lib/engine-components/debug/LogStats.js +1 -0
- package/lib/engine-components/debug/LogStats.js.map +1 -1
- package/lib/engine-components/timeline/PlayableDirector.d.ts +7 -0
- package/lib/engine-components/timeline/PlayableDirector.js +8 -1
- package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
- package/lib/engine-components/timeline/TimelineModels.d.ts +9 -1
- package/lib/engine-components/timeline/TimelineTracks.d.ts +2 -1
- package/lib/engine-components/timeline/TimelineTracks.js +30 -25
- package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
- package/lib/engine-components/utils/LookAt.js +5 -1
- package/lib/engine-components/utils/LookAt.js.map +1 -1
- package/lib/engine-components/web/Clickthrough.js +10 -2
- package/lib/engine-components/web/Clickthrough.js.map +1 -1
- package/lib/engine-components/web/ScrollFollow.d.ts +23 -0
- package/lib/engine-components/web/ScrollFollow.js +166 -41
- package/lib/engine-components/web/ScrollFollow.js.map +1 -1
- package/lib/engine-components/web/ViewBox.d.ts +27 -0
- package/lib/engine-components/web/ViewBox.js +242 -0
- package/lib/engine-components/web/ViewBox.js.map +1 -0
- package/lib/engine-components/web/index.d.ts +1 -0
- package/lib/engine-components/web/index.js +1 -0
- package/lib/engine-components/web/index.js.map +1 -1
- package/lib/engine-components-experimental/Presentation.d.ts +1 -0
- package/lib/engine-components-experimental/Presentation.js +1 -0
- package/lib/engine-components-experimental/Presentation.js.map +1 -1
- package/package.json +2 -1
- package/src/engine/codegen/register_types.ts +2 -0
- package/src/engine/engine_camera.fit.ts +2 -32
- package/src/engine/engine_camera.ts +61 -9
- package/src/engine/engine_context.ts +50 -10
- package/src/engine/engine_gizmos.ts +37 -23
- package/src/engine/engine_license.ts +1 -1
- package/src/engine/engine_lightdata.ts +11 -11
- package/src/engine/engine_physics_rapier.ts +3 -0
- package/src/engine/engine_scenelighting.ts +5 -6
- package/src/engine/engine_utils.ts +12 -0
- package/src/engine/extensions/NEEDLE_lightmaps.ts +1 -1
- package/src/engine/extensions/extension_utils.ts +1 -1
- package/src/engine/webcomponents/logo-element.ts +29 -4
- package/src/engine/webcomponents/needle menu/needle-menu.ts +4 -3
- package/src/engine/webcomponents/needle-engine.loading.ts +32 -32
- package/src/engine/webcomponents/needle-engine.ts +33 -6
- package/src/engine/xr/NeedleXRController.ts +36 -4
- package/src/engine-components/CameraUtils.ts +1 -1
- package/src/engine-components/OrbitControls.ts +40 -1
- package/src/engine-components/Renderer.ts +6 -1
- package/src/engine-components/Skybox.ts +26 -7
- package/src/engine-components/codegen/components.ts +1 -0
- package/src/engine-components/debug/LogStats.ts +1 -0
- package/src/engine-components/timeline/PlayableDirector.ts +10 -1
- package/src/engine-components/timeline/TimelineModels.ts +9 -1
- package/src/engine-components/timeline/TimelineTracks.ts +30 -25
- package/src/engine-components/utils/LookAt.ts +5 -1
- package/src/engine-components/web/Clickthrough.ts +11 -2
- package/src/engine-components/web/ScrollFollow.ts +199 -48
- package/src/engine-components/web/ViewBox.ts +262 -0
- package/src/engine-components/web/index.ts +2 -1
- package/src/engine-components-experimental/Presentation.ts +1 -0
- package/dist/needle-engine.bundle-DlAVTipB.min.js +0 -1639
- package/dist/vendor-D0Yvltn9.umd.cjs +0 -1121
- package/dist/vendor-DU8tJyl_.js +0 -14366
- package/dist/vendor-JyrX4DVM.min.js +0 -1121
|
@@ -38,14 +38,18 @@ const observedAttributes = [
|
|
|
38
38
|
"loadstart",
|
|
39
39
|
"progress",
|
|
40
40
|
"loadfinished",
|
|
41
|
+
|
|
41
42
|
"dracoDecoderPath",
|
|
42
43
|
"dracoDecoderType",
|
|
43
44
|
"ktx2DecoderPath",
|
|
45
|
+
|
|
44
46
|
"tone-mapping",
|
|
45
47
|
"tone-mapping-exposure",
|
|
46
48
|
"background-blurriness",
|
|
47
49
|
"background-color",
|
|
48
50
|
"environment-intensity",
|
|
51
|
+
|
|
52
|
+
"focus-rect",
|
|
49
53
|
]
|
|
50
54
|
|
|
51
55
|
// https://developers.google.com/web/fundamentals/web-components/customelements
|
|
@@ -95,7 +99,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
95
99
|
if (value === null) this.removeAttribute("camera-controls");
|
|
96
100
|
else this.setAttribute("camera-controls", value ? "true" : "false");
|
|
97
101
|
}
|
|
98
|
-
|
|
102
|
+
|
|
99
103
|
|
|
100
104
|
/**
|
|
101
105
|
* Get the current context for this web component instance. The context is created when the src attribute is set and the loading has finished.
|
|
@@ -331,17 +335,17 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
331
335
|
if (debug) console.log("ktx2DecoderPath", newValue);
|
|
332
336
|
setKtx2TranscoderPath(newValue);
|
|
333
337
|
break;
|
|
334
|
-
|
|
338
|
+
|
|
335
339
|
case "tonemapping":
|
|
336
340
|
case "tone-mapping":
|
|
337
341
|
case "tone-mapping-exposure":
|
|
338
342
|
case "background-blurriness":
|
|
339
343
|
case "background-color":
|
|
340
344
|
case "environment-intensity":
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
+
{
|
|
346
|
+
this.applyAttributes();
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
345
349
|
case "public-key": {
|
|
346
350
|
if (newValue != PUBLIC_KEY)
|
|
347
351
|
this.setPublicKey();
|
|
@@ -352,6 +356,25 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
352
356
|
this.setVersion();
|
|
353
357
|
break;
|
|
354
358
|
}
|
|
359
|
+
|
|
360
|
+
case "focus-rect":
|
|
361
|
+
{
|
|
362
|
+
const focus_rect = this.getAttribute("focus-rect") as HTMLElement | string | null;
|
|
363
|
+
if (focus_rect && this._context) {
|
|
364
|
+
if (focus_rect === null) {
|
|
365
|
+
this._context.setCameraFocusRect(null);
|
|
366
|
+
}
|
|
367
|
+
else if (typeof focus_rect === "string" && focus_rect.length > 0) {
|
|
368
|
+
const element = document.querySelector(focus_rect);
|
|
369
|
+
this._context.setCameraFocusRect(element instanceof HTMLElement ? element : null);
|
|
370
|
+
}
|
|
371
|
+
else if (focus_rect instanceof HTMLElement) {
|
|
372
|
+
this._context.setCameraFocusRect(focus_rect);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
break;
|
|
355
378
|
}
|
|
356
379
|
}
|
|
357
380
|
|
|
@@ -570,6 +593,10 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
570
593
|
this._context.renderer.setClearColor(rgbaColor, rgbaColor.alpha);
|
|
571
594
|
this.context.scene.background = null;
|
|
572
595
|
}
|
|
596
|
+
// HACK: if we set background-color to a color and then back to null we want the background-image attribute to re-apply
|
|
597
|
+
else if (this.getAttribute("background-image")) {
|
|
598
|
+
this.setAttribute("background-image", this.getAttribute("background-image")!);
|
|
599
|
+
}
|
|
573
600
|
}
|
|
574
601
|
}
|
|
575
602
|
|
|
@@ -23,10 +23,10 @@ const debugCustomGesture = getParam("debugcustomgesture");
|
|
|
23
23
|
// let _didReceiveSelectStartEvent = false;
|
|
24
24
|
|
|
25
25
|
// https://github.com/immersive-web/webxr-input-profiles/blob/4484a05e30bcd43fe86bb4e06b7a707861a26796/packages/registry/profiles/meta/meta-quest-touch-plus.json
|
|
26
|
-
declare type ControllerAxes = "xr-standard-thumbstick";
|
|
27
|
-
declare type StickName = "xr-standard-thumbstick";
|
|
26
|
+
declare type ControllerAxes = "xr-standard-thumbstick" | "xr-standard-touchpad";
|
|
27
|
+
declare type StickName = "xr-standard-thumbstick" | "xr-standard-touchpad";
|
|
28
28
|
declare type Mapping = "xr-standard";
|
|
29
|
-
declare type ComponentType = "button" | "thumbstick" | "squeeze";
|
|
29
|
+
declare type ComponentType = "button" | "thumbstick" | "squeeze" | "touchpad";
|
|
30
30
|
declare type GamepadKey = "button" | "xAxis" | "yAxis";
|
|
31
31
|
|
|
32
32
|
declare type NeedleXRControllerButtonName = ButtonName | "primary-button" | "primary";
|
|
@@ -407,6 +407,16 @@ C:${this.connected ? "x" : "-"} T:${this.isTracking ? "x" : "-"} Hand:${this.inp
|
|
|
407
407
|
gamepadStr += "\n[axes " + gp.axes.length + "]: " + gp.axes.map(a => a.toPrecision(1)).join(",");
|
|
408
408
|
debugStr += "\n" + gamepadStr;
|
|
409
409
|
}
|
|
410
|
+
if (this._layout) {
|
|
411
|
+
debugStr += "\nLayout: ";
|
|
412
|
+
for (const component of Object.keys(this._layout.components || {})) {
|
|
413
|
+
const val = this.getStick(component as StickName);
|
|
414
|
+
const indices = this._layout.components[component]?.gamepadIndices;
|
|
415
|
+
const indicesAsString = indices ? Object.entries(indices).map(e => e[0][0].toUpperCase() + e[0].slice(1) + "=" + e[1]).join(",") : "";
|
|
416
|
+
debugStr += `\n ${component}: ${this._layout.components[component]?.type} [${indicesAsString}] (${val.x.toPrecision(2)},${val.y.toPrecision(2)})`;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
410
420
|
Gizmos.DrawLabel(debugLabelPosition, debugStr, .006);
|
|
411
421
|
}
|
|
412
422
|
|
|
@@ -730,6 +740,7 @@ C:${this.connected ? "x" : "-"} T:${this.isTracking ? "x" : "-"} Hand:${this.inp
|
|
|
730
740
|
if (componentModel?.gamepadIndices) {
|
|
731
741
|
switch (componentModel.type) {
|
|
732
742
|
case "thumbstick":
|
|
743
|
+
case "touchpad":
|
|
733
744
|
if (this.inputSource.gamepad) {
|
|
734
745
|
const xIndex = componentModel.gamepadIndices!.xAxis!;
|
|
735
746
|
const yIndex = componentModel.gamepadIndices!.yAxis!;
|
|
@@ -760,7 +771,11 @@ C:${this.connected ? "x" : "-"} T:${this.isTracking ? "x" : "-"} Hand:${this.inp
|
|
|
760
771
|
this._isMetaQuestTouchController = this.profiles.includes("meta-quest-touch-plus") || this.profiles.includes("oculus-touch-v3");
|
|
761
772
|
|
|
762
773
|
// Proper profile starting with v69 and browser 35.1
|
|
763
|
-
this._isMxInk = this.profiles.includes("logitech-mx-ink")
|
|
774
|
+
this._isMxInk = this.profiles.includes("logitech-mx-ink");
|
|
775
|
+
|
|
776
|
+
// For debugging to see ALL available profiles
|
|
777
|
+
/** @ts-ignore */
|
|
778
|
+
// fetchProfilesList(DEFAULT_PROFILES_PATH).then(list => console.log("Available controller profiles", list));
|
|
764
779
|
|
|
765
780
|
if (!this._layout) {
|
|
766
781
|
// Ignore transient-pointer since we likely don't want to spawn a controller visual just for a temporary pointer.
|
|
@@ -780,6 +795,8 @@ C:${this.connected ? "x" : "-"} T:${this.isTracking ? "x" : "-"} Hand:${this.inp
|
|
|
780
795
|
res.assetPath || ""
|
|
781
796
|
);
|
|
782
797
|
|
|
798
|
+
// const overrideProfile = await fetch(DEFAULT_PROFILES_PATH + "/htc-vive-focus-3/profile.json").then(r => r.json());
|
|
799
|
+
|
|
783
800
|
const profile = res.profile as InputDeviceProfile;
|
|
784
801
|
const layout = profile.layouts[this.inputSource.handedness];
|
|
785
802
|
this._layout = layout;
|
|
@@ -791,6 +808,21 @@ C:${this.connected ? "x" : "-"} T:${this.isTracking ? "x" : "-"} Hand:${this.inp
|
|
|
791
808
|
this._layout.gamepad[component.gamepadIndices!.button!] = key as XRControllerButtonName;
|
|
792
809
|
}
|
|
793
810
|
}
|
|
811
|
+
|
|
812
|
+
// If we have 4 axes and no thumbstick defined, we define thumbstick for axis 3+4
|
|
813
|
+
// This is a workaround for HTC Vive Focus 3 controllers, which have the profile for Vive Focus Plus...
|
|
814
|
+
// This workaround fixes it for HTC Vive Focus 3 but does not change anything for Vive Focus Plus controllers
|
|
815
|
+
if (this.profiles.length >= 1 && this.profiles[0] === "htc-vive-focus-plus") {
|
|
816
|
+
if (this.inputSource.gamepad && this.inputSource.gamepad.axes.length === 4 && !this._layout.components["xr-standard-thumbstick"]) {
|
|
817
|
+
this._layout.components["xr-standard-thumbstick"] = {
|
|
818
|
+
type: "thumbstick",
|
|
819
|
+
gamepadIndices: {
|
|
820
|
+
xAxis: 2,
|
|
821
|
+
yAxis: 3,
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
794
826
|
}
|
|
795
827
|
// if (debug) console.log(this._layout, this.inputSource);
|
|
796
828
|
// debugger;
|
|
@@ -122,7 +122,7 @@ function createDefaultCameraControls(context: IContext, cam?: ICamera) {
|
|
|
122
122
|
orbit.autoRotate = autoRotate != "0" && autoRotate?.toLowerCase() != "false";
|
|
123
123
|
const autoRotateSpeed = Number.parseFloat(autoRotate || ".5");
|
|
124
124
|
orbit.autoRotateSpeed = !isNaN(autoRotateSpeed) ? autoRotateSpeed : .5;
|
|
125
|
-
console.log("Auto-rotate", orbit.autoRotate, "speed:", orbit.autoRotateSpeed);
|
|
125
|
+
if(debug) console.log("Auto-rotate", orbit.autoRotate, "speed:", orbit.autoRotateSpeed);
|
|
126
126
|
const autoFit = context.domElement.getAttribute("auto-fit");
|
|
127
127
|
orbit.autoFit = autoFit !== "0" && autoFit?.toLowerCase() != "false";
|
|
128
128
|
orbit.autoTarget = true;
|
|
@@ -993,11 +993,50 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
993
993
|
|
|
994
994
|
// Adapted from https://discourse.threejs.org/t/camera-zoom-to-fit-object/936/24
|
|
995
995
|
// Slower but better implementation that takes bones and exact vertex positions into account: https://github.com/google/model-viewer/blob/04e900c5027de8c5306fe1fe9627707f42811b05/packages/model-viewer/src/three-components/ModelScene.ts#L321
|
|
996
|
+
|
|
996
997
|
/**
|
|
997
998
|
* Fits the camera to show the objects provided (defaults to the scene if no objects are passed in)
|
|
999
|
+
* @param options The options for fitting the camera. Use to provide objects to fit to, fit direction and size and other settings.
|
|
998
1000
|
*/
|
|
999
|
-
fitCamera(options?: OrbitFitCameraOptions)
|
|
1001
|
+
fitCamera(options?: OrbitFitCameraOptions);
|
|
1002
|
+
/** @deprecated Use fitCamera(options) */
|
|
1003
|
+
fitCamera(objects?: Object3D | Array<Object3D>, options?: Omit<OrbitFitCameraOptions, "objects">);
|
|
1004
|
+
fitCamera(objectsOrOptions?: Object3D | Array<Object3D> | OrbitFitCameraOptions, options?: OrbitFitCameraOptions): void {
|
|
1005
|
+
|
|
1006
|
+
|
|
1007
|
+
let objects: Object3D | Array<Object3D> | undefined = undefined;
|
|
1008
|
+
// If the user passed in an array as first argument
|
|
1009
|
+
if (Array.isArray(objectsOrOptions)) {
|
|
1010
|
+
objects = objectsOrOptions;
|
|
1011
|
+
}
|
|
1012
|
+
// If the user passed in an object as first argument
|
|
1013
|
+
else if (objectsOrOptions && "type" in objectsOrOptions) {
|
|
1014
|
+
objects = objectsOrOptions;
|
|
1015
|
+
}
|
|
1016
|
+
// If the user passed in an object as first argument and options as second argument
|
|
1017
|
+
else if (objectsOrOptions && typeof objectsOrOptions === "object") {
|
|
1018
|
+
if (!(objectsOrOptions instanceof Object3D) && !Array.isArray(objectsOrOptions)) {
|
|
1019
|
+
options = objectsOrOptions;
|
|
1020
|
+
objects = options.objects;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
// Ensure objects are setup correctly
|
|
1024
|
+
if (objects && !Array.isArray(objects)) {
|
|
1025
|
+
objects = [objects];
|
|
1026
|
+
}
|
|
1027
|
+
if (!Array.isArray(objects) || objects && objects.length <= 0) {
|
|
1028
|
+
objects = this.context.scene.children;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
// Make sure there's anything to fit to
|
|
1032
|
+
if (!Array.isArray(objects) || objects.length <= 0) {
|
|
1033
|
+
console.warn("No objects to fit camera to...");
|
|
1034
|
+
return;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
|
|
1000
1038
|
const res = fitCamera({
|
|
1039
|
+
objects: [...objects],
|
|
1001
1040
|
...options,
|
|
1002
1041
|
autoApply: false,
|
|
1003
1042
|
context: this.context,
|
|
@@ -358,8 +358,11 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
358
358
|
//@ts-ignore
|
|
359
359
|
get sharedMaterials(): SharedMaterialArray {
|
|
360
360
|
|
|
361
|
+
// @ts-ignore (original materials will be set during deserialization)
|
|
362
|
+
if(this._originalMaterials === undefined) return null;
|
|
363
|
+
|
|
361
364
|
// @ts-ignore during deserialization code might access this property *before* the setter and then create an empty array
|
|
362
|
-
if (
|
|
365
|
+
if (this.__isDeserializing === true) return null;
|
|
363
366
|
|
|
364
367
|
if (!this._sharedMaterials || !this._sharedMaterials.is(this)) {
|
|
365
368
|
if (!this._originalMaterials) this._originalMaterials = [];
|
|
@@ -725,6 +728,8 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
725
728
|
// If the material has a envMap and is NOT using a reflection probe we set the envMap to the scene environment
|
|
726
729
|
if (mat && "envMap" in mat && "envMapIntensity" in mat && !ReflectionProbe.isUsingReflectionProbe(mat)) {
|
|
727
730
|
mat.envMap = this.context.scene.environment;
|
|
731
|
+
mat.envMapIntensity = this.context.scene.environmentIntensity;
|
|
732
|
+
mat.envMapRotation = this.context.scene.environmentRotation;
|
|
728
733
|
}
|
|
729
734
|
}
|
|
730
735
|
}
|
|
@@ -8,7 +8,7 @@ import { syncField } from "../engine/engine_networking_auto.js";
|
|
|
8
8
|
import { loadPMREM } from "../engine/engine_pmrem.js";
|
|
9
9
|
import { serializable } from "../engine/engine_serialization_decorator.js";
|
|
10
10
|
import { type IContext } from "../engine/engine_types.js";
|
|
11
|
-
import { addAttributeChangeCallback, getParam, PromiseAllWithErrors, removeAttributeChangeCallback } from "../engine/engine_utils.js";
|
|
11
|
+
import { addAttributeChangeCallback, getParam, PromiseAllWithErrors, removeAttributeChangeCallback, toSourceId } from "../engine/engine_utils.js";
|
|
12
12
|
import { registerObservableAttribute } from "../engine/webcomponents/needle-engine.extras.js";
|
|
13
13
|
import { Camera, ClearFlags } from "./Camera.js";
|
|
14
14
|
import { Behaviour, GameObject } from "./Component.js";
|
|
@@ -27,15 +27,34 @@ function createRemoteSkyboxComponent(context: IContext, url: string, skybox: boo
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
const remote = new RemoteSkybox();
|
|
30
|
+
remote.sourceId = toSourceId(url);
|
|
30
31
|
remote.allowDrop = false;
|
|
31
32
|
remote.allowNetworking = false;
|
|
32
33
|
remote.background = skybox;
|
|
33
34
|
remote.environment = environment;
|
|
34
35
|
GameObject.addComponent(context.scene, remote);
|
|
35
36
|
const urlChanged = newValue => {
|
|
36
|
-
if (
|
|
37
|
-
if (
|
|
38
|
-
|
|
37
|
+
if (debug) console.log(attribute, "CHANGED TO", newValue);
|
|
38
|
+
if (newValue) {
|
|
39
|
+
if (typeof newValue !== "string") {
|
|
40
|
+
console.warn("Invalid attribute value for " + attribute);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
remote.setSkybox(newValue);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
if (remote.sourceId) {
|
|
47
|
+
if (environment) {
|
|
48
|
+
if (!context.sceneLighting.internalEnableReflection(remote.sourceId)) {
|
|
49
|
+
context.scene.environment = null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (skybox) {
|
|
53
|
+
const skybox = context.lightmaps.tryGetSkybox(remote.sourceId);
|
|
54
|
+
context.scene.background = skybox;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
39
58
|
};
|
|
40
59
|
addAttributeChangeCallback(context.domElement, attribute, urlChanged);
|
|
41
60
|
remote.addEventListener("destroy", () => {
|
|
@@ -50,7 +69,7 @@ ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, (args) => {
|
|
|
50
69
|
const context = args.context;
|
|
51
70
|
const backgroundImage = context.domElement.getAttribute("background-image");
|
|
52
71
|
const environmentImage = context.domElement.getAttribute("environment-image");
|
|
53
|
-
|
|
72
|
+
|
|
54
73
|
if (backgroundImage) {
|
|
55
74
|
if (debug) console.log("Creating RemoteSkybox to load background " + backgroundImage);
|
|
56
75
|
// if the user is loading a GLB without a camera then the CameraUtils (which creates the default camera)
|
|
@@ -246,8 +265,8 @@ export class RemoteSkybox extends Behaviour {
|
|
|
246
265
|
envMap.needsUpdate = true;
|
|
247
266
|
}
|
|
248
267
|
|
|
249
|
-
if(this.destroyed) return;
|
|
250
|
-
if(!this.context) {
|
|
268
|
+
if (this.destroyed) return;
|
|
269
|
+
if (!this.context) {
|
|
251
270
|
console.warn("RemoteSkybox: Context is not available - can not apply skybox.");
|
|
252
271
|
return;
|
|
253
272
|
}
|
|
@@ -208,6 +208,7 @@ export { ClickThrough } from "../web/Clickthrough.js";
|
|
|
208
208
|
export { CursorFollow } from "../web/CursorFollow.js";
|
|
209
209
|
export { HoverAnimation } from "../web/HoverAnimation.js";
|
|
210
210
|
export { ScrollFollow } from "../web/ScrollFollow.js";
|
|
211
|
+
export { ViewBox } from "../web/ViewBox.js";
|
|
211
212
|
export { Avatar } from "../webxr/Avatar.js";
|
|
212
213
|
export { XRControllerFollow } from "../webxr/controllers/XRControllerFollow.js";
|
|
213
214
|
export { XRControllerModel } from "../webxr/controllers/XRControllerModel.js";
|
|
@@ -66,10 +66,19 @@ export class PlayableDirector extends Behaviour {
|
|
|
66
66
|
this.createTrackFunctions[type] = fn;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* The timeline asset that is played by this director.
|
|
71
|
+
*/
|
|
69
72
|
playableAsset?: Models.TimelineAssetModel;
|
|
73
|
+
|
|
70
74
|
/** Set to true to start playing the timeline when the scene starts */
|
|
71
75
|
@serializable()
|
|
72
76
|
playOnAwake?: boolean;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Determines how the timeline behaves when it reaches the end of its duration.
|
|
80
|
+
* @default DirectorWrapMode.Loop
|
|
81
|
+
*/
|
|
73
82
|
@serializable()
|
|
74
83
|
extrapolationMode: DirectorWrapMode = DirectorWrapMode.Loop;
|
|
75
84
|
|
|
@@ -106,7 +115,7 @@ export class PlayableDirector extends Behaviour {
|
|
|
106
115
|
/** @internal */
|
|
107
116
|
awake(): void {
|
|
108
117
|
if (debug)
|
|
109
|
-
console.log(this, this.playableAsset
|
|
118
|
+
console.log(this, this.playableAsset);
|
|
110
119
|
|
|
111
120
|
this.rebuildGraph();
|
|
112
121
|
|
|
@@ -92,4 +92,12 @@ export declare class SignalMarkerModel extends MarkerModel {
|
|
|
92
92
|
asset: string;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Marker with a name, used for scroll-driven timelines. It is used together with elements in your HTML to define what time in the timeline should be active when the element is in the scroll view.
|
|
97
|
+
*
|
|
98
|
+
* @example Mark html elements to define scroll positions
|
|
99
|
+
* ```html
|
|
100
|
+
* <div data-timeline-marker>...</div>
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export type ScrollMarkerModel = MarkerModel & { name: string };
|
|
@@ -175,8 +175,10 @@ export class AnimationTrackHandler extends TrackHandler {
|
|
|
175
175
|
// which means we want to notify the object that it's not animated anymore
|
|
176
176
|
// and the animator can then take over
|
|
177
177
|
onStateChanged() {
|
|
178
|
-
if (this._animator)
|
|
179
|
-
|
|
178
|
+
if (this._animator) {
|
|
179
|
+
// We can not check the *isPlaying* state here because the timeline might be paused and evaluated by e.g. ScrollFollow
|
|
180
|
+
setObjectAnimated(this._animator.gameObject, this, this.director.enabled && this.director.weight > 0);
|
|
181
|
+
}
|
|
180
182
|
}
|
|
181
183
|
|
|
182
184
|
createHooks(clipModel: Models.AnimationClipModel, clip) {
|
|
@@ -185,21 +187,22 @@ export class AnimationTrackHandler extends TrackHandler {
|
|
|
185
187
|
return;
|
|
186
188
|
}
|
|
187
189
|
// we only want to hook into the binding of the root object
|
|
188
|
-
// TODO: test with a clip with multiple roots
|
|
189
|
-
const parts = clip.tracks[0].name.split(".");
|
|
190
|
-
const rootName = parts[parts.length - 2];
|
|
191
|
-
const positionTrackName = rootName + ".position";
|
|
192
|
-
const rotationTrackName = rootName + ".quaternion";
|
|
193
190
|
let foundPositionTrack: boolean = false;
|
|
194
191
|
let foundRotationTrack: boolean = false;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
192
|
+
const parts = clip.tracks.find(t => t.name.includes(".position") || t.name.includes(".quaternion"))?.name.split(".");
|
|
193
|
+
if (parts) {
|
|
194
|
+
const rootName = parts[parts.length - 2];
|
|
195
|
+
const positionTrackName = rootName + ".position";
|
|
196
|
+
const rotationTrackName = rootName + ".quaternion";
|
|
197
|
+
for (const t of clip.tracks) {
|
|
198
|
+
if (!foundPositionTrack && t.name.endsWith(positionTrackName)) {
|
|
199
|
+
foundPositionTrack = true;
|
|
200
|
+
this.createPositionInterpolant(clip, clipModel, t);
|
|
201
|
+
}
|
|
202
|
+
else if (!foundRotationTrack && t.name.endsWith(rotationTrackName)) {
|
|
203
|
+
foundRotationTrack = true;
|
|
204
|
+
this.createRotationInterpolant(clip, clipModel, t);
|
|
205
|
+
}
|
|
203
206
|
}
|
|
204
207
|
}
|
|
205
208
|
|
|
@@ -224,16 +227,14 @@ export class AnimationTrackHandler extends TrackHandler {
|
|
|
224
227
|
const trackName = baseName + ".position";
|
|
225
228
|
if (debug) console.warn("Create position track", objName, targetObj);
|
|
226
229
|
// apply initial local position so it doesnt get flipped or otherwise changed
|
|
227
|
-
const
|
|
228
|
-
const track = new VectorKeyframeTrack(trackName, [0, clip.duration], [pos.x, pos.y, pos.z, pos.x, pos.y, pos.z]);
|
|
230
|
+
const track = new VectorKeyframeTrack(trackName, [0, clip.duration], [0, 0, 0, 0, 0, 0]);
|
|
229
231
|
clip.tracks.push(track);
|
|
230
232
|
this.createPositionInterpolant(clip, clipModel, track);
|
|
231
233
|
}
|
|
232
234
|
else if (!foundRotationTrack) {
|
|
233
235
|
const trackName = clip.tracks[0].name.substring(0, indexOfProperty) + ".quaternion";
|
|
234
236
|
if (debug) console.warn("Create quaternion track", objName, targetObj);
|
|
235
|
-
const
|
|
236
|
-
const track = new QuaternionKeyframeTrack(trackName, [0, clip.duration], [rot.x, rot.y, rot.z, rot.w, rot.x, rot.y, rot.z, rot.w]);
|
|
237
|
+
const track = new QuaternionKeyframeTrack(trackName, [0, clip.duration], [0, 0, 0, 1, 0, 0, 0, 1]);
|
|
237
238
|
clip.tracks.push(track);
|
|
238
239
|
this.createRotationInterpolant(clip, clipModel, track);
|
|
239
240
|
}
|
|
@@ -832,23 +833,27 @@ export class AudioTrackHandler extends TrackHandler {
|
|
|
832
833
|
|
|
833
834
|
export class MarkerTrackHandler extends TrackHandler {
|
|
834
835
|
models: Array<Models.MarkerModel & Record<string, any>> = [];
|
|
835
|
-
|
|
836
|
+
needsSorting = true;
|
|
836
837
|
|
|
837
838
|
*foreachMarker<T>(type: string | null = null) {
|
|
839
|
+
if(this.needsSorting) this.sort();
|
|
838
840
|
for (const model of this.models) {
|
|
839
841
|
if (model && model.type === type) yield model as T;
|
|
840
842
|
}
|
|
841
843
|
}
|
|
842
844
|
|
|
843
845
|
onEnable() {
|
|
844
|
-
this.
|
|
846
|
+
this.needsSorting = true;
|
|
845
847
|
}
|
|
846
848
|
|
|
847
849
|
evaluate(_time: number) {
|
|
848
|
-
if (this.
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
850
|
+
if (this.needsSorting) this.sort();
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
private sort() {
|
|
854
|
+
this.needsSorting = false;
|
|
855
|
+
this.models.sort((a, b) => a.time - b.time);
|
|
856
|
+
|
|
852
857
|
}
|
|
853
858
|
}
|
|
854
859
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Matrix4, Object3D, Quaternion, Vector3 } from "three";
|
|
2
2
|
|
|
3
|
+
import { isDevEnvironment } from "../../engine/debug/index.js";
|
|
3
4
|
import { serializable } from "../../engine/engine_serialization.js";
|
|
4
5
|
import { lookAtObject } from "../../engine/engine_three_utils.js";
|
|
5
6
|
import { type UsdzBehaviour } from "../../engine-components/export/usdz/extensions/behavior/Behaviour.js";
|
|
@@ -42,7 +43,10 @@ export class LookAt extends Behaviour implements UsdzBehaviour {
|
|
|
42
43
|
/** @internal */
|
|
43
44
|
onBeforeRender(): void {
|
|
44
45
|
let target: Object3D | null | undefined = this.target;
|
|
45
|
-
if (!target)
|
|
46
|
+
if (!target) {
|
|
47
|
+
target = this.context.mainCamera;
|
|
48
|
+
if (isDevEnvironment()) console.warn(`[LookAt] No target set on ${this.name}, using main camera as target.`);
|
|
49
|
+
}
|
|
46
50
|
if (!target) return;
|
|
47
51
|
|
|
48
52
|
let copyTargetRotation = this.copyTargetRotation;
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import { NEPointerEvent } from "../../engine/engine_input.js";
|
|
2
2
|
import { onStart } from "../../engine/engine_lifecycle_api.js";
|
|
3
|
+
import { addAttributeChangeCallback } from "../../engine/engine_utils.js";
|
|
3
4
|
import { Behaviour } from "../Component.js";
|
|
4
5
|
|
|
5
6
|
// Automatically add ClickThrough component if "clickthrough" attribute is present on the needle-engine element
|
|
6
7
|
onStart(ctx => {
|
|
7
8
|
const attribute = ctx.domElement.getAttribute("clickthrough");
|
|
8
|
-
if (attribute
|
|
9
|
-
ctx.scene.addComponent(ClickThrough);
|
|
9
|
+
if (clickthroughEnabled(attribute)) {
|
|
10
|
+
const comp = ctx.scene.addComponent(ClickThrough);
|
|
11
|
+
addAttributeChangeCallback(ctx.domElement, "clickthrough", () => {
|
|
12
|
+
const attribute = ctx.domElement.getAttribute("clickthrough");
|
|
13
|
+
comp.enabled = clickthroughEnabled(attribute);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function clickthroughEnabled(val: string | null) {
|
|
18
|
+
return val !== null && val !== "0" && val !== "false";
|
|
10
19
|
}
|
|
11
20
|
});
|
|
12
21
|
|