@needle-tools/engine 4.10.0-beta → 4.10.0-beta.2
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-Dj6faVbC.js → needle-engine.bundle-BTgC7uAm.js} +7236 -7012
- package/dist/{needle-engine.bundle-42AmEGfk.umd.cjs → needle-engine.bundle-OTBqjiCd.umd.cjs} +152 -141
- package/dist/{needle-engine.bundle-C6zhyLF5.min.js → needle-engine.bundle-g2_JEHcF.min.js} +170 -159
- package/dist/needle-engine.js +259 -257
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- 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_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/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-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/timeline/PlayableDirector.d.ts +7 -0
- package/lib/engine-components/timeline/PlayableDirector.js +7 -0
- 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.js +4 -2
- 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 +22 -0
- package/lib/engine-components/web/ScrollFollow.js +159 -38
- package/lib/engine-components/web/ScrollFollow.js.map +1 -1
- package/lib/engine-components/web/ViewBox.d.ts +16 -0
- package/lib/engine-components/web/ViewBox.js +186 -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/package.json +1 -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 +62 -8
- package/src/engine/engine_context.ts +50 -10
- 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/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-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/timeline/PlayableDirector.ts +9 -0
- package/src/engine-components/timeline/TimelineModels.ts +9 -1
- package/src/engine-components/timeline/TimelineTracks.ts +4 -2
- 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 +190 -44
- package/src/engine-components/web/ViewBox.ts +202 -0
- package/src/engine-components/web/index.ts +2 -1
|
@@ -32,10 +32,22 @@ export class NeedleLogoElement extends HTMLElement {
|
|
|
32
32
|
cursor: pointer;
|
|
33
33
|
}
|
|
34
34
|
img {
|
|
35
|
-
width: 95px;
|
|
36
35
|
height: 100%;
|
|
37
36
|
align-self: end;
|
|
38
37
|
margin-left: 0.6rem;
|
|
38
|
+
transition: transform 0.2s;
|
|
39
|
+
}
|
|
40
|
+
img.with-text {
|
|
41
|
+
width: 11.5ch;
|
|
42
|
+
&:hover {
|
|
43
|
+
transform: scale(1.02);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
img.compact {
|
|
47
|
+
width: 1.7em;
|
|
48
|
+
&:hover {
|
|
49
|
+
transform: scale(1.1);
|
|
50
|
+
}
|
|
39
51
|
}
|
|
40
52
|
span {
|
|
41
53
|
font-size: 1rem;
|
|
@@ -43,12 +55,14 @@ export class NeedleLogoElement extends HTMLElement {
|
|
|
43
55
|
}
|
|
44
56
|
</style>
|
|
45
57
|
<div class="wrapper">
|
|
46
|
-
<img class="logo" src=${needleLogoSVG} />
|
|
58
|
+
<img class="logo with-text" src=${needleLogoSVG} />
|
|
47
59
|
</div>
|
|
48
60
|
`;
|
|
49
61
|
this._root.appendChild(template.content.cloneNode(true));
|
|
50
62
|
this.wrapper = this._root.querySelector(".wrapper") as HTMLDivElement;
|
|
51
63
|
this._root.appendChild(this.wrapper);
|
|
64
|
+
this.logoElement = this._root.querySelector("img.logo") as HTMLImageElement;
|
|
65
|
+
|
|
52
66
|
// this.wrapper.classList.add("wrapper");
|
|
53
67
|
|
|
54
68
|
// this.wrapper.appendChild(this.logoElement);
|
|
@@ -67,13 +81,24 @@ export class NeedleLogoElement extends HTMLElement {
|
|
|
67
81
|
|
|
68
82
|
private readonly _root: ShadowRoot;
|
|
69
83
|
private readonly wrapper: HTMLDivElement;
|
|
70
|
-
private readonly logoElement: HTMLImageElement
|
|
71
|
-
private readonly textElement: HTMLSpanElement = document.createElement("span");
|
|
84
|
+
private readonly logoElement: HTMLImageElement;
|
|
72
85
|
|
|
73
86
|
setLogoVisible(val: boolean) {
|
|
74
87
|
this.logoElement.style.display = val ? "block" : "none";
|
|
75
88
|
}
|
|
76
89
|
|
|
90
|
+
setType(type: "full" | "compact") {
|
|
91
|
+
if (type === "full") {
|
|
92
|
+
this.logoElement.src = needleLogoSVG;
|
|
93
|
+
this.logoElement.classList.remove("with-text");
|
|
94
|
+
this.logoElement.classList.remove("compact");
|
|
95
|
+
} else {
|
|
96
|
+
this.logoElement.src = needleLogoOnlySVG;
|
|
97
|
+
this.logoElement.classList.add("with-text");
|
|
98
|
+
this.logoElement.classList.add("compact");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
77
102
|
}
|
|
78
103
|
if (!customElements.get(elementName))
|
|
79
104
|
customElements.define(elementName, NeedleLogoElement);
|
|
@@ -459,7 +459,7 @@ export class NeedleMenuElement extends HTMLElement {
|
|
|
459
459
|
|
|
460
460
|
.logo {
|
|
461
461
|
cursor: pointer;
|
|
462
|
-
padding-left: 0.
|
|
462
|
+
padding-left: 0.0rem;
|
|
463
463
|
padding-bottom: .02rem;
|
|
464
464
|
margin-right: 0.5rem;
|
|
465
465
|
}
|
|
@@ -664,8 +664,8 @@ export class NeedleMenuElement extends HTMLElement {
|
|
|
664
664
|
<slot name="end"></slot>
|
|
665
665
|
</div>
|
|
666
666
|
</div>
|
|
667
|
-
<div style="user-select:none" class="logo">
|
|
668
|
-
<span class="madewith notranslate">powered by</span>
|
|
667
|
+
<div style="user-select:none;" class="logo">
|
|
668
|
+
<span class="madewith notranslate" style="display:none;">powered by</span>
|
|
669
669
|
</div>
|
|
670
670
|
</div>
|
|
671
671
|
<button class="compact-menu-button">
|
|
@@ -698,6 +698,7 @@ export class NeedleMenuElement extends HTMLElement {
|
|
|
698
698
|
this.wrapper.classList.add("wrapper");
|
|
699
699
|
|
|
700
700
|
const logo = NeedleLogoElement.create();
|
|
701
|
+
logo.setType("compact");
|
|
701
702
|
logo.style.minHeight = "1rem";
|
|
702
703
|
this.logoContainer.append(logo);
|
|
703
704
|
this.logoContainer.addEventListener("click", () => {
|
|
@@ -374,40 +374,40 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
374
374
|
// }
|
|
375
375
|
// }
|
|
376
376
|
|
|
377
|
-
this.handleRuntimeLicense(this._loadingElement);
|
|
377
|
+
// this.handleRuntimeLicense(this._loadingElement);
|
|
378
378
|
|
|
379
379
|
return this._loadingElement;
|
|
380
380
|
}
|
|
381
381
|
|
|
382
|
-
private async handleRuntimeLicense(loadingElement: HTMLElement) {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
382
|
+
// private async handleRuntimeLicense(loadingElement: HTMLElement) {
|
|
383
|
+
// // First check if we have a commercial license
|
|
384
|
+
// let commercialLicense = hasCommercialLicense();
|
|
385
|
+
// // if it's the case then we don't need to perform a runtime check
|
|
386
|
+
// if (commercialLicense) return;
|
|
387
|
+
|
|
388
|
+
// // If we don't have a commercial license, then we need to display our message
|
|
389
|
+
// if (debugLicense) console.log("Loading UI has commercial license?", commercialLicense);
|
|
390
|
+
// const nonCommercialContainer = document.createElement("div");
|
|
391
|
+
// nonCommercialContainer.style.paddingTop = ".6em";
|
|
392
|
+
// nonCommercialContainer.style.fontSize = ".8em";
|
|
393
|
+
// nonCommercialContainer.style.textTransform = "uppercase";
|
|
394
|
+
// nonCommercialContainer.innerText = "NEEDLE ENGINE NON COMMERCIAL VERSION\nCLICK HERE TO GET A LICENSE";
|
|
395
|
+
// nonCommercialContainer.style.cursor = "pointer";
|
|
396
|
+
// nonCommercialContainer.style.userSelect = "none";
|
|
397
|
+
// nonCommercialContainer.style.textAlign = "center";
|
|
398
|
+
// nonCommercialContainer.style.pointerEvents = "all";
|
|
399
|
+
// nonCommercialContainer.addEventListener("click", () => window.open("https://needle.tools/pricing", "_self"));
|
|
400
|
+
// nonCommercialContainer.style.opacity = "0";
|
|
401
|
+
// loadingElement.appendChild(nonCommercialContainer);
|
|
402
|
+
|
|
403
|
+
// // Use the runtime license check
|
|
404
|
+
// if (!isDevEnvironment() && runtimeLicenseCheckPromise) {
|
|
405
|
+
// if (debugLicense) console.log("Waiting for runtime license check");
|
|
406
|
+
// await runtimeLicenseCheckPromise;
|
|
407
|
+
// commercialLicense = hasCommercialLicense();
|
|
408
|
+
// }
|
|
409
|
+
// if (commercialLicense) return;
|
|
410
|
+
// nonCommercialContainer.style.transition = "opacity .5s ease-in-out";
|
|
411
|
+
// nonCommercialContainer.style.opacity = "1";
|
|
412
|
+
// }
|
|
413
413
|
}
|
|
@@ -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
|
|
|
@@ -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
|
|
|
@@ -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) {
|
|
@@ -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
|
|