@needle-tools/engine 4.8.4 → 4.8.5
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 +4 -0
- package/README.md +5 -0
- package/dist/{gltf-progressive-PB_58h1b.umd.cjs → gltf-progressive-C-U_onhf.umd.cjs} +1 -1
- package/dist/{gltf-progressive-DorC035H.min.js → gltf-progressive-DViD_J_l.min.js} +1 -1
- package/dist/{gltf-progressive-B3JW4cAu.js → gltf-progressive-DXRy9EQz.js} +35 -35
- package/dist/loader.worker-CiTwpNPW.js +27 -0
- package/dist/{needle-engine.bundle-BWvmuHDE.umd.cjs → needle-engine.bundle-C-qzYkeq.umd.cjs} +134 -135
- package/dist/{needle-engine.bundle-F7Kw2jq3.min.js → needle-engine.bundle-CKG2fLvO.min.js} +138 -139
- package/dist/{needle-engine.bundle-DnjGFnfL.js → needle-engine.bundle-fEU9eTH-.js} +6363 -6394
- package/dist/needle-engine.js +4 -4
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/{postprocessing-BgC7XZwK.umd.cjs → postprocessing-61aXdqNz.umd.cjs} +1 -1
- package/dist/{postprocessing-ChsrvDkI.min.js → postprocessing-Be9Ds4NK.min.js} +1 -1
- package/dist/{postprocessing-DddlM3CK.js → postprocessing-D9jDHD0U.js} +2 -2
- package/dist/{three-DrqIzZTH.js → three-BRSLmpyi.js} +2966 -2958
- package/dist/{three-DuDKwKB8.min.js → three-CsmWHVn7.min.js} +172 -172
- package/dist/{three-B_hneGZr.umd.cjs → three-Dceyffus.umd.cjs} +176 -176
- package/dist/{three-examples-BIuXQPSf.js → three-examples-BihZ_R96.js} +2761 -2623
- package/dist/{three-examples-CNRuT27G.umd.cjs → three-examples-Ce6Th3bv.umd.cjs} +17 -17
- package/dist/three-examples-DKY9Nfge.min.js +501 -0
- package/dist/{three-mesh-ui-DWcMuyQ_.min.js → three-mesh-ui-Bwy12Qvg.min.js} +1 -1
- package/dist/{three-mesh-ui-tt0buEDC.umd.cjs → three-mesh-ui-Cdh2iW8b.umd.cjs} +1 -1
- package/dist/{three-mesh-ui-D6Mz5Yl7.js → three-mesh-ui-gqAXlGNB.js} +1 -1
- package/dist/{vendor-C31T0mYm.min.js → vendor-BRpzuoJE.min.js} +1 -1
- package/dist/{vendor-D51IT5ns.umd.cjs → vendor-Ja-vKV-a.umd.cjs} +1 -1
- package/dist/{vendor-B_ytQUuR.js → vendor-p_xp9KuJ.js} +1 -1
- package/lib/engine/debug/debug_console.js +3 -33
- package/lib/engine/debug/debug_console.js.map +1 -1
- package/lib/engine/engine_pmrem.d.ts +2 -0
- package/lib/engine/engine_pmrem.js +100 -0
- package/lib/engine/engine_pmrem.js.map +1 -0
- package/lib/engine-components/Camera.js +1 -1
- package/lib/engine-components/Camera.js.map +1 -1
- package/lib/engine-components/CameraUtils.js +0 -5
- package/lib/engine-components/CameraUtils.js.map +1 -1
- package/lib/engine-components/DragControls.js +0 -1
- package/lib/engine-components/DragControls.js.map +1 -1
- package/lib/engine-components/Duplicatable.js +5 -2
- package/lib/engine-components/Duplicatable.js.map +1 -1
- package/lib/engine-components/Skybox.d.ts +0 -2
- package/lib/engine-components/Skybox.js +26 -110
- package/lib/engine-components/Skybox.js.map +1 -1
- package/lib/engine-components/TransformGizmo.js +10 -2
- package/lib/engine-components/TransformGizmo.js.map +1 -1
- package/package.json +3 -3
- package/src/engine/debug/debug_console.ts +3 -33
- package/src/engine/engine_pmrem.ts +118 -0
- package/src/engine-components/Camera.ts +1 -1
- package/src/engine-components/CameraUtils.ts +0 -5
- package/src/engine-components/DragControls.ts +0 -1
- package/src/engine-components/Duplicatable.ts +3 -2
- package/src/engine-components/Skybox.ts +30 -102
- package/src/engine-components/TransformGizmo.ts +11 -2
- package/src/include/ktx2/basis_transcoder.js +8 -10
- package/src/include/ktx2/basis_transcoder.wasm +0 -0
- package/dist/loader.worker-CrU5fNbR.js +0 -27
- package/dist/three-examples-D2zemuAM.min.js +0 -501
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "4.8.
|
|
3
|
+
"version": "4.8.5",
|
|
4
4
|
"description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.",
|
|
5
5
|
"main": "dist/needle-engine.min.js",
|
|
6
6
|
"exports": {
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
],
|
|
94
94
|
"dependencies": {
|
|
95
95
|
"@dimforge/rapier3d-compat": "^0.14.0",
|
|
96
|
-
"@needle-tools/gltf-progressive": "
|
|
96
|
+
"@needle-tools/gltf-progressive": "3.3.2",
|
|
97
97
|
"@webxr-input-profiles/motion-controllers": "^1.0.0",
|
|
98
98
|
"flatbuffers": "2.0.4",
|
|
99
99
|
"md5": "^2.3.0",
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"postprocessing": "^6.36.6",
|
|
103
103
|
"simplex-noise": "^4.0.1",
|
|
104
104
|
"stats.js": "^0.17.0",
|
|
105
|
-
"three": "npm:@needle-tools/three@0.169.
|
|
105
|
+
"three": "npm:@needle-tools/three@0.169.8",
|
|
106
106
|
"three-mesh-bvh": "^0.9.1",
|
|
107
107
|
"three-mesh-ui": "npm:@needle-tools/three-mesh-ui@^7.1.5-alpha.5",
|
|
108
108
|
"three.quarks": "0.15.6",
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { isDevEnvironment } from "./debug.js";
|
|
4
|
-
import { getErrorCount, makeErrorsVisibleForDevelopment } from "./debug_overlay.js";
|
|
1
|
+
import { getParam } from "../engine_utils.js";
|
|
2
|
+
import { getErrorCount } from "./debug_overlay.js";
|
|
5
3
|
|
|
6
4
|
let consoleInstance: VConsole | null | undefined = undefined;
|
|
7
5
|
let consoleHtmlElement: HTMLElement | null = null;
|
|
@@ -12,38 +10,10 @@ let watchInterval: any = null;
|
|
|
12
10
|
const defaultButtonIcon = "terminal";
|
|
13
11
|
|
|
14
12
|
const showConsole = getParam("console");
|
|
15
|
-
const suppressConsole = getParam("noerrors") || getParam("noconsole") || window.crossOriginIsolated;
|
|
16
13
|
if (showConsole) {
|
|
17
14
|
showDebugConsole();
|
|
18
15
|
}
|
|
19
16
|
|
|
20
|
-
if (!suppressConsole && (showConsole || isLocalNetwork())) {
|
|
21
|
-
if (isLocalNetwork() && !showConsole) {
|
|
22
|
-
const consoleUrl = new URL(window.location.href);
|
|
23
|
-
consoleUrl.searchParams.set("console", "1");
|
|
24
|
-
console.log("🌵 Tip: You can add the \"?console\" query parameter to the url to show the debug console (on mobile it will automatically open in the bottom right corner when your get errors during development. In VR a spatial console will appear.)", "\nOpen this page to get the console: " + consoleUrl.toString());
|
|
25
|
-
}
|
|
26
|
-
const enableConsole = DeviceUtilities.isMobileDevice() || (DeviceUtilities.isQuest() && isDevEnvironment());
|
|
27
|
-
if (enableConsole || showConsole) {
|
|
28
|
-
// we need to invoke this here - otherwise we will miss errors that happen after the console is loaded
|
|
29
|
-
// and calling the method from the root needle-engine.ts import is evaluated later (if we import the method from the toplevel file and then invoke it)
|
|
30
|
-
makeErrorsVisibleForDevelopment();
|
|
31
|
-
beginWatchingLogs();
|
|
32
|
-
createConsole(true);
|
|
33
|
-
if (enableConsole) {
|
|
34
|
-
const engineElement = document.querySelector("needle-engine");
|
|
35
|
-
engineElement?.addEventListener("enter-ar", () => {
|
|
36
|
-
if (showConsole || consoleInstance || getErrorCount() > 0) {
|
|
37
|
-
if (getParam("noerrors")) return;
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
engineElement?.addEventListener("exit-ar", () => {
|
|
41
|
-
onResetConsoleElementToDefaultParent();
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
17
|
const $defaultConsoleParent = Symbol("consoleParent");
|
|
48
18
|
|
|
49
19
|
export function showDebugConsole() {
|
|
@@ -247,7 +217,7 @@ function createConsole(startHidden: boolean = false) {
|
|
|
247
217
|
isLoading = false;
|
|
248
218
|
consoleInstance = null;
|
|
249
219
|
};
|
|
250
|
-
script.src = "https://cdn.jsdelivr.net/npm/vconsole@3.
|
|
220
|
+
script.src = "https://cdn.jsdelivr.net/npm/vconsole@3.15.1/dist/vconsole.min.js";
|
|
251
221
|
document.body.appendChild(script);
|
|
252
222
|
}
|
|
253
223
|
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { createLoaders } from "@needle-tools/gltf-progressive";
|
|
2
|
+
import { CubeUVReflectionMapping, SRGBColorSpace, Texture, TextureLoader, WebGLRenderer } from "three";
|
|
3
|
+
import { EXRLoader } from "three/examples/jsm/loaders/EXRLoader";
|
|
4
|
+
import { KTX2Loader } from "three/examples/jsm/loaders/KTX2Loader";
|
|
5
|
+
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
|
|
6
|
+
import { disposeObjectResources, setDisposable } from "./engine_assetdatabase.js";
|
|
7
|
+
|
|
8
|
+
const running: Map<string, Promise<Texture | null>> = new Map();
|
|
9
|
+
|
|
10
|
+
// #region api
|
|
11
|
+
|
|
12
|
+
export function loadPMREM(url: string, renderer: WebGLRenderer): Promise<Texture | null> {
|
|
13
|
+
if (running.has(url)) {
|
|
14
|
+
return running.get(url)!;
|
|
15
|
+
}
|
|
16
|
+
const actualUrl = new URL(url, window.location.href);
|
|
17
|
+
const promise = internalLoadPMREM(actualUrl, renderer);
|
|
18
|
+
running.set(url, promise);
|
|
19
|
+
return promise;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
// #region Cache
|
|
25
|
+
|
|
26
|
+
declare type SkyboxCacheEntry = { src: string, texture: Promise<Texture | null> };
|
|
27
|
+
function ensureGlobalCache() {
|
|
28
|
+
if (!globalThis["NEEDLE_ENGINE_SKYBOX_TEXTURES"])
|
|
29
|
+
globalThis["NEEDLE_ENGINE_SKYBOX_TEXTURES"] = new Array<SkyboxCacheEntry>();
|
|
30
|
+
return globalThis["NEEDLE_ENGINE_SKYBOX_TEXTURES"] as Array<SkyboxCacheEntry>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function tryGetPreviouslyLoadedTexture(src: string) {
|
|
34
|
+
const cache = ensureGlobalCache();
|
|
35
|
+
const found = cache.find(x => x.src === src);
|
|
36
|
+
if (found) {
|
|
37
|
+
return found.texture;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
async function disposeCachedTexture(tex: Promise<Texture | null>) {
|
|
42
|
+
const texture = await tex;
|
|
43
|
+
if (!texture) return;
|
|
44
|
+
setDisposable(texture, true);
|
|
45
|
+
disposeObjectResources(texture);
|
|
46
|
+
}
|
|
47
|
+
function registerPromise(src: string, texture: Promise<Texture | null>) {
|
|
48
|
+
const cache = ensureGlobalCache();
|
|
49
|
+
// Make sure the cache doesnt get too big
|
|
50
|
+
while (cache.length > 5) {
|
|
51
|
+
const entry = cache.shift();
|
|
52
|
+
if (entry) { disposeCachedTexture(entry.texture); }
|
|
53
|
+
}
|
|
54
|
+
texture.then(t => { return setDisposable(t, false) });
|
|
55
|
+
cache.push({ src, texture });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
// #region loading
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
async function internalLoadPMREM(url: URL, renderer: WebGLRenderer) {
|
|
64
|
+
if (!url) return Promise.resolve(null);
|
|
65
|
+
|
|
66
|
+
const pathname = url.pathname;
|
|
67
|
+
const isPMREM_URL: boolean = url.toString().toLowerCase().includes("pmrem") || url.searchParams.get("pmrem") != null;
|
|
68
|
+
|
|
69
|
+
const cached = tryGetPreviouslyLoadedTexture(pathname);
|
|
70
|
+
if (cached) {
|
|
71
|
+
const res = await cached;
|
|
72
|
+
if (res?.source?.data?.length > 0 || res?.source?.data?.data?.length) return res;
|
|
73
|
+
}
|
|
74
|
+
const isEXR = pathname.endsWith(".exr");
|
|
75
|
+
const isHdr = pathname.endsWith(".hdr");
|
|
76
|
+
const isKtx2 = pathname.endsWith(".ktx2");
|
|
77
|
+
|
|
78
|
+
let loader: RGBELoader | EXRLoader | TextureLoader | KTX2Loader;
|
|
79
|
+
|
|
80
|
+
if (isEXR) {
|
|
81
|
+
loader = new EXRLoader();
|
|
82
|
+
}
|
|
83
|
+
else if (isHdr) {
|
|
84
|
+
loader = new RGBELoader();
|
|
85
|
+
}
|
|
86
|
+
else if (isKtx2) {
|
|
87
|
+
const { ktx2Loader } = createLoaders(renderer);
|
|
88
|
+
loader = ktx2Loader;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
loader = new TextureLoader();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const str = url.toString();
|
|
95
|
+
const promise = loader.loadAsync(str)
|
|
96
|
+
.then(tex => {
|
|
97
|
+
if (tex) {
|
|
98
|
+
const nameIndex = pathname.lastIndexOf("/");
|
|
99
|
+
tex.name = pathname.substring(nameIndex >= 0 ? nameIndex + 1 : 0);
|
|
100
|
+
|
|
101
|
+
if (isPMREM_URL) {
|
|
102
|
+
tex.mapping = CubeUVReflectionMapping;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (loader instanceof TextureLoader) {
|
|
106
|
+
tex.colorSpace = SRGBColorSpace;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return tex;
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
registerPromise(str, promise);
|
|
113
|
+
const texture = await promise.catch(_err => {
|
|
114
|
+
console.warn("Failed to load texture from url:", url);
|
|
115
|
+
return null;
|
|
116
|
+
});
|
|
117
|
+
return texture;
|
|
118
|
+
}
|
|
@@ -694,7 +694,7 @@ class CameraSkybox {
|
|
|
694
694
|
}
|
|
695
695
|
else if (this.context.scene.background !== this._skybox) {
|
|
696
696
|
|
|
697
|
-
const hasBackgroundAttribute = this.context.domElement.getAttribute("background-image") || this.context.domElement.getAttribute("background-color")
|
|
697
|
+
const hasBackgroundAttribute = this.context.domElement.getAttribute("background-image") || this.context.domElement.getAttribute("background-color");
|
|
698
698
|
|
|
699
699
|
if (debug) console.debug(`[Camera] Apply Skybox ${this._skybox?.name} ${hasBackgroundAttribute} - \"${this._camera.name}\"`);
|
|
700
700
|
if (!hasBackgroundAttribute?.length) {
|
|
@@ -39,11 +39,6 @@ ContextRegistry.registerCallback(ContextEvent.MissingCamera, (evt) => {
|
|
|
39
39
|
// Set the clearFlags to a skybox if we have one OR if the user set a background-image attribute
|
|
40
40
|
else if (evt.context.domElement.getAttribute("background-image")?.length || (evt.context as Context).lightmaps.tryGetSkybox(camInstance.sourceId)) {
|
|
41
41
|
camInstance.clearFlags = ClearFlags.Skybox;
|
|
42
|
-
// TODO: can we store the backgroundBlurriness in the gltf file somewhere except inside the camera?
|
|
43
|
-
// e.g. when we export a scene from blender without a camera in the scene
|
|
44
|
-
if (evt.context.domElement.getAttribute("background-blurriness") === null) {
|
|
45
|
-
evt.context.scene.backgroundBlurriness = 0.2; // default value, same as in Blender
|
|
46
|
-
}
|
|
47
42
|
}
|
|
48
43
|
else {
|
|
49
44
|
camInstance.clearFlags = ClearFlags.SolidColor;
|
|
@@ -454,7 +454,6 @@ export class DragControls extends Behaviour implements IPointerEventHandler {
|
|
|
454
454
|
const sync = GameObject.getComponentInChildren(evt.object, SyncedTransform);
|
|
455
455
|
if (sync) {
|
|
456
456
|
sync.fastMode = false;
|
|
457
|
-
// sync?.requestOwnership();
|
|
458
457
|
}
|
|
459
458
|
}
|
|
460
459
|
if (this._marker)
|
|
@@ -119,8 +119,9 @@ export class Duplicatable extends Behaviour implements IPointerEventHandler {
|
|
|
119
119
|
const res = this.handleDuplication();
|
|
120
120
|
if (res) {
|
|
121
121
|
const dragControls = GameObject.getComponent(res, DragControls);
|
|
122
|
-
if (!dragControls)
|
|
123
|
-
|
|
122
|
+
if (!dragControls) {
|
|
123
|
+
if (isDevEnvironment()) console.warn(`Duplicated object (${res.name}) does not have DragControls`);
|
|
124
|
+
} else {
|
|
124
125
|
dragControls.onPointerDown(args);
|
|
125
126
|
this._forwardPointerEvents.set(args.event.space, dragControls);
|
|
126
127
|
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { CompressedCubeTexture, CubeRefractionMapping, CubeTexture, EquirectangularRefractionMapping, SRGBColorSpace, Texture, TextureLoader } from "three"
|
|
1
|
+
import { CompressedCubeTexture, CubeRefractionMapping, CubeTexture, CubeUVReflectionMapping, EquirectangularRefractionMapping, SRGBColorSpace, Texture, TextureLoader } from "three"
|
|
3
2
|
import { EXRLoader } from "three/examples/jsm/loaders/EXRLoader.js";
|
|
4
3
|
import { KTX2Loader } from "three/examples/jsm/loaders/KTX2Loader.js";
|
|
5
4
|
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';
|
|
6
5
|
|
|
7
|
-
import { disposeObjectResources, setDisposable } from "../engine/engine_assetdatabase.js";
|
|
8
6
|
import { ContextEvent, ContextRegistry } from "../engine/engine_context_registry.js";
|
|
9
7
|
import { syncField } from "../engine/engine_networking_auto.js";
|
|
8
|
+
import { loadPMREM } from "../engine/engine_pmrem.js";
|
|
10
9
|
import { serializable } from "../engine/engine_serialization_decorator.js";
|
|
11
10
|
import { type IContext } from "../engine/engine_types.js";
|
|
12
11
|
import { addAttributeChangeCallback, getParam, PromiseAllWithErrors, removeAttributeChangeCallback } from "../engine/engine_utils.js";
|
|
@@ -51,7 +50,9 @@ ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, (args) => {
|
|
|
51
50
|
const context = args.context;
|
|
52
51
|
const skyboxImage = context.domElement.getAttribute("background-image");
|
|
53
52
|
const environmentImage = context.domElement.getAttribute("environment-image");
|
|
54
|
-
|
|
53
|
+
const envAndSkyboxAreSame = skyboxImage === environmentImage;
|
|
54
|
+
|
|
55
|
+
if (skyboxImage && !envAndSkyboxAreSame) {
|
|
55
56
|
if (debug) console.log("Creating remote skybox to load " + skyboxImage);
|
|
56
57
|
// if the user is loading a GLB without a camera then the CameraUtils (which creates the default camera)
|
|
57
58
|
// checks if we have this attribute set and then sets the skybox clearflags accordingly
|
|
@@ -61,7 +62,7 @@ ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, (args) => {
|
|
|
61
62
|
}
|
|
62
63
|
if (environmentImage) {
|
|
63
64
|
if (debug) console.log("Creating remote environment to load " + environmentImage);
|
|
64
|
-
const promise = createRemoteSkyboxComponent(context, environmentImage,
|
|
65
|
+
const promise = createRemoteSkyboxComponent(context, environmentImage, envAndSkyboxAreSame, true, "environment-image");
|
|
65
66
|
if (promise) promises.push(promise);
|
|
66
67
|
}
|
|
67
68
|
});
|
|
@@ -71,39 +72,6 @@ ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, () => {
|
|
|
71
72
|
})
|
|
72
73
|
});
|
|
73
74
|
|
|
74
|
-
declare type SkyboxCacheEntry = { src: string, texture: Promise<Texture | null> };
|
|
75
|
-
function ensureGlobalCache() {
|
|
76
|
-
if (!globalThis["NEEDLE_ENGINE_SKYBOX_TEXTURES"])
|
|
77
|
-
globalThis["NEEDLE_ENGINE_SKYBOX_TEXTURES"] = new Array<SkyboxCacheEntry>();
|
|
78
|
-
return globalThis["NEEDLE_ENGINE_SKYBOX_TEXTURES"] as Array<SkyboxCacheEntry>;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function tryGetPreviouslyLoadedTexture(src: string) {
|
|
82
|
-
const cache = ensureGlobalCache();
|
|
83
|
-
const found = cache.find(x => x.src === src);
|
|
84
|
-
if (found) {
|
|
85
|
-
if (debug) console.log("Skybox: Found previously loaded texture for " + src);
|
|
86
|
-
return found.texture;
|
|
87
|
-
}
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
async function disposeCachedTexture(tex: Promise<Texture | null>) {
|
|
91
|
-
const texture = await tex;
|
|
92
|
-
if (!texture) return;
|
|
93
|
-
setDisposable(texture, true);
|
|
94
|
-
disposeObjectResources(texture);
|
|
95
|
-
}
|
|
96
|
-
function registerLoadedTexture(src: string, texture: Promise<Texture | null>) {
|
|
97
|
-
const cache = ensureGlobalCache();
|
|
98
|
-
// Make sure the cache doesnt get too big
|
|
99
|
-
while (cache.length > 5) {
|
|
100
|
-
const entry = cache.shift();
|
|
101
|
-
if (entry) { disposeCachedTexture(entry.texture); }
|
|
102
|
-
}
|
|
103
|
-
texture.then(t => { return setDisposable(t, false) });
|
|
104
|
-
cache.push({ src, texture });
|
|
105
|
-
}
|
|
106
|
-
|
|
107
75
|
|
|
108
76
|
/**
|
|
109
77
|
* RemoteSkybox is a component that allows you to set the skybox of a scene from a URL or a local file.
|
|
@@ -177,7 +145,6 @@ export class RemoteSkybox extends Behaviour {
|
|
|
177
145
|
@serializable()
|
|
178
146
|
allowNetworking: boolean = true;
|
|
179
147
|
|
|
180
|
-
private _loader?: RGBELoader | EXRLoader | TextureLoader | KTX2Loader;
|
|
181
148
|
private _prevUrl?: string;
|
|
182
149
|
private _prevLoadedEnvironment?: Texture;
|
|
183
150
|
private _prevEnvironment: Texture | null = null;
|
|
@@ -245,7 +212,7 @@ export class RemoteSkybox extends Behaviour {
|
|
|
245
212
|
}
|
|
246
213
|
this._prevUrl = url;
|
|
247
214
|
|
|
248
|
-
const texture = await
|
|
215
|
+
const texture = await loadPMREM(url, this.context.renderer);
|
|
249
216
|
if (!texture) {
|
|
250
217
|
if (debug) console.warn("RemoteSkybox: Failed to load texture from url", url);
|
|
251
218
|
return false;
|
|
@@ -262,62 +229,18 @@ export class RemoteSkybox extends Behaviour {
|
|
|
262
229
|
}
|
|
263
230
|
// Update the current url
|
|
264
231
|
this.url = url;
|
|
265
|
-
const nameIndex = url.lastIndexOf("/");
|
|
266
|
-
texture.name = url.substring(nameIndex >= 0 ? nameIndex + 1 : 0);
|
|
267
|
-
if (this._loader instanceof TextureLoader) {
|
|
268
|
-
texture.colorSpace = SRGBColorSpace;
|
|
269
|
-
}
|
|
270
232
|
this._prevLoadedEnvironment = texture;
|
|
271
233
|
this.apply();
|
|
272
234
|
return true;
|
|
273
235
|
}
|
|
274
236
|
|
|
275
|
-
private async loadTexture(url: string, name?: string) {
|
|
276
|
-
if (!url) return Promise.resolve(null);
|
|
277
|
-
name ??= url;
|
|
278
|
-
const cached = tryGetPreviouslyLoadedTexture(name);
|
|
279
|
-
if (cached) {
|
|
280
|
-
const res = await cached;
|
|
281
|
-
if (res?.source?.data?.length > 0 || res?.source?.data?.data?.length) return res;
|
|
282
|
-
}
|
|
283
|
-
const isEXR = name.endsWith(".exr");
|
|
284
|
-
const isHdr = name.endsWith(".hdr");
|
|
285
|
-
const isKtx2 = name.endsWith(".ktx2");
|
|
286
|
-
if (isEXR) {
|
|
287
|
-
if (!(this._loader instanceof EXRLoader))
|
|
288
|
-
this._loader = new EXRLoader();
|
|
289
|
-
}
|
|
290
|
-
else if (isHdr) {
|
|
291
|
-
if (!(this._loader instanceof RGBELoader))
|
|
292
|
-
this._loader = new RGBELoader();
|
|
293
|
-
}
|
|
294
|
-
else if (isKtx2) {
|
|
295
|
-
if (!(this._loader instanceof KTX2Loader)) {
|
|
296
|
-
const { ktx2Loader } = createLoaders(this.context.renderer);
|
|
297
|
-
this._loader = ktx2Loader;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
else {
|
|
301
|
-
if (!(this._loader instanceof TextureLoader))
|
|
302
|
-
this._loader = new TextureLoader();
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
if (debug) console.log("Loading skybox: " + url);
|
|
306
|
-
const loadingTask = this._loader.loadAsync(url).catch(_err => {
|
|
307
|
-
console.warn("RemoteSkybox: Failed to load texture from url:", url);
|
|
308
|
-
return null;
|
|
309
|
-
});
|
|
310
|
-
registerLoadedTexture(name, loadingTask);
|
|
311
|
-
const envMap = await loadingTask;
|
|
312
|
-
return envMap;
|
|
313
|
-
}
|
|
314
237
|
|
|
315
238
|
private apply() {
|
|
316
239
|
const envMap = this._prevLoadedEnvironment;
|
|
317
240
|
if (!envMap) return;
|
|
318
241
|
|
|
319
242
|
|
|
320
|
-
if ((envMap instanceof CubeTexture || envMap instanceof CompressedCubeTexture)) {
|
|
243
|
+
if ((envMap instanceof CubeTexture || envMap instanceof CompressedCubeTexture) || envMap.mapping == CubeUVReflectionMapping) {
|
|
321
244
|
// Nothing to do
|
|
322
245
|
}
|
|
323
246
|
else {
|
|
@@ -437,13 +360,14 @@ export class RemoteSkybox extends Behaviour {
|
|
|
437
360
|
console.warn(`[RemoteSkybox]: File \"${file.name}\" is not supported. Supported files are ${this.validTextureTypes.join(", ")}`);
|
|
438
361
|
return;
|
|
439
362
|
}
|
|
440
|
-
if (tryGetPreviouslyLoadedTexture(file.name) === null) {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
}
|
|
446
|
-
else
|
|
363
|
+
// if (tryGetPreviouslyLoadedTexture(file.name) === null) {
|
|
364
|
+
// const blob = new Blob([file]);
|
|
365
|
+
// const url = URL.createObjectURL(blob);
|
|
366
|
+
// e.preventDefault();
|
|
367
|
+
// this.setSkybox(url, file.name);
|
|
368
|
+
// }
|
|
369
|
+
// else
|
|
370
|
+
{
|
|
447
371
|
e.preventDefault();
|
|
448
372
|
this.setSkybox(file.name);
|
|
449
373
|
}
|
|
@@ -458,31 +382,35 @@ export class RemoteSkybox extends Behaviour {
|
|
|
458
382
|
|
|
459
383
|
function tryParseMagicSkyboxName(str: string | null | undefined, environment: boolean, background: boolean): string | null {
|
|
460
384
|
|
|
385
|
+
if (str === null || str === undefined) return null;
|
|
386
|
+
|
|
461
387
|
const useLowRes = environment && !background;
|
|
462
388
|
|
|
463
|
-
switch (str
|
|
389
|
+
switch (str.toLowerCase()) {
|
|
464
390
|
case "studio":
|
|
465
391
|
if (useLowRes) {
|
|
466
|
-
return "https://cdn.needle.tools/static/skybox/modelviewer-Neutral-small.
|
|
392
|
+
return "https://cdn.needle.tools/static/skybox/modelviewer-Neutral-small.pmrem4x4.ktx2?pmrem";
|
|
467
393
|
}
|
|
468
|
-
|
|
394
|
+
return "https://cdn.needle.tools/static/skybox/modelviewer-Neutral.pmrem4x4.ktx2?pmrem";
|
|
469
395
|
|
|
470
396
|
case "blurred-skybox":
|
|
471
397
|
if (useLowRes) {
|
|
472
|
-
return "https://cdn.needle.tools/static/skybox/blurred-skybox-small.
|
|
398
|
+
return "https://cdn.needle.tools/static/skybox/blurred-skybox-small.pmrem4x4.ktx2?pmrem";
|
|
473
399
|
}
|
|
474
|
-
return "https://cdn.needle.tools/static/skybox/blurred-skybox.
|
|
400
|
+
return "https://cdn.needle.tools/static/skybox/blurred-skybox.pmrem4x4.ktx2?pmrem";
|
|
475
401
|
case "quicklook-ar":
|
|
476
402
|
if (useLowRes) {
|
|
477
|
-
return "https://cdn.needle.tools/static/skybox/QuickLook-ARMode-small.
|
|
403
|
+
return "https://cdn.needle.tools/static/skybox/QuickLook-ARMode-small.pmrem4x4.ktx2?pmrem";
|
|
478
404
|
}
|
|
479
|
-
return "https://cdn.needle.tools/static/skybox/QuickLook-ARMode.
|
|
405
|
+
return "https://cdn.needle.tools/static/skybox/QuickLook-ARMode.pmrem4x4.ktx2?pmrem";
|
|
480
406
|
case "quicklook":
|
|
481
407
|
if (useLowRes) {
|
|
482
|
-
return "https://cdn.needle.tools/static/skybox/QuickLook-ObjectMode-small.
|
|
408
|
+
return "https://cdn.needle.tools/static/skybox/QuickLook-ObjectMode-small.pmrem4x4.ktx2?pmrem";
|
|
483
409
|
}
|
|
484
|
-
return "https://cdn.needle.tools/static/skybox/QuickLook-ObjectMode.
|
|
410
|
+
return "https://cdn.needle.tools/static/skybox/QuickLook-ObjectMode.pmrem4x4.ktx2?pmrem";
|
|
485
411
|
}
|
|
486
|
-
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
|
|
487
415
|
return str;
|
|
488
416
|
}
|
|
@@ -129,13 +129,22 @@ export class TransformGizmo extends Behaviour {
|
|
|
129
129
|
private onControlChangedEvent = (event) => {
|
|
130
130
|
const orbit = this.orbit;
|
|
131
131
|
if (orbit) orbit.enabled = !event.value;
|
|
132
|
+
|
|
132
133
|
if (event.value) {
|
|
133
|
-
//
|
|
134
|
-
const sync =
|
|
134
|
+
// Start of interaction
|
|
135
|
+
const sync = this.gameObject.getComponentInParent(SyncedTransform);
|
|
135
136
|
if (sync) {
|
|
137
|
+
sync.fastMode = true;
|
|
136
138
|
sync.requestOwnership();
|
|
137
139
|
}
|
|
138
140
|
}
|
|
141
|
+
else {
|
|
142
|
+
// End of interaction
|
|
143
|
+
const sync = this.gameObject.getComponentInParent(SyncedTransform);
|
|
144
|
+
if (sync) {
|
|
145
|
+
sync.fastMode = false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
139
148
|
}
|
|
140
149
|
|
|
141
150
|
/**
|