@needle-tools/engine 4.11.5-next.753a642 → 4.11.5-next.7ddcc57
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 +7 -5
- package/components.needle.json +1 -1
- package/dist/generateMeshBVH.worker-D1Vr8UHG.js +21 -0
- package/dist/{gltf-progressive-GwdQV1Qx.umd.cjs → gltf-progressive-DWcmTMCh.umd.cjs} +1 -1
- package/dist/{gltf-progressive-CftVUJy3.min.js → gltf-progressive-DZrY8VT6.min.js} +2 -2
- package/dist/{gltf-progressive-BvlZQAkt.js → gltf-progressive-DgYz5BYa.js} +19 -19
- package/dist/loader.worker-Dip-PthR.js +23 -0
- package/dist/{needle-engine.bundle-DVXwSz-d.js → needle-engine.bundle-DdOG3e58.js} +4825 -4716
- package/dist/{needle-engine.bundle-OrbPGV3t.umd.cjs → needle-engine.bundle-diJ_X0v5.umd.cjs} +141 -146
- package/dist/{needle-engine.bundle-CAKvhOvZ.min.js → needle-engine.bundle-uqHJeR29.min.js} +147 -152
- package/dist/needle-engine.d.ts +15 -15
- package/dist/needle-engine.js +336 -335
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/{postprocessing-CJC0Npcd.js → postprocessing-BTW9pD_s.js} +1822 -1723
- package/dist/{postprocessing-DrM4PWU3.umd.cjs → postprocessing-CMgoN5t5.umd.cjs} +229 -158
- package/dist/{postprocessing-l7zsdO_Q.min.js → postprocessing-DYDtB188.min.js} +227 -156
- package/dist/rapier-B3oL1ap-.js +5217 -0
- package/dist/rapier-DJ-luMxr.min.js +1 -0
- package/dist/rapier-DQltNJbN.umd.cjs +1 -0
- package/dist/{three-BDW9I486.min.js → three-B7CT31Bt.min.js} +1 -5
- package/dist/{three-MHVqtJYj.js → three-DfMvBzXi.js} +0 -5
- package/dist/{three-examples-CgwGHSgz.umd.cjs → three-examples-CsW4_6LI.umd.cjs} +2 -7
- package/dist/{three-examples-fvEPSC8L.min.js → three-examples-D1P7eEhn.min.js} +2 -7
- package/dist/{three-examples-C5Ht-QFN.js → three-examples-D1SK93ek.js} +1 -7
- package/dist/{three-mesh-ui-BjWTTk1R.js → three-mesh-ui-C_uSB5dD.js} +1 -1
- package/dist/{three-mesh-ui-Bm32sS2a.umd.cjs → three-mesh-ui-DpATDXwU.umd.cjs} +1 -1
- package/dist/{three-mesh-ui-CLdkp21K.min.js → three-mesh-ui-LQ44s0AL.min.js} +1 -1
- package/dist/{three-iFaDq9U3.umd.cjs → three-qj71I7J3.umd.cjs} +2 -6
- package/dist/{vendor-6kAXU6fm.umd.cjs → vendor-DhTcel4c.umd.cjs} +2 -7
- package/dist/{vendor-petGQl0N.js → vendor-Dkpn1a8s.js} +1 -7
- package/dist/{vendor-CsyK1CFs.min.js → vendor-DtTGRuXh.min.js} +2 -7
- package/lib/engine/debug/debug_spector.d.ts +16 -0
- package/lib/engine/debug/debug_spector.js +28 -0
- package/lib/engine/debug/debug_spector.js.map +1 -0
- package/lib/engine/engine_application.d.ts +7 -0
- package/lib/engine/engine_application.js +8 -1
- package/lib/engine/engine_application.js.map +1 -1
- package/lib/engine/engine_context.d.ts +15 -5
- package/lib/engine/engine_context.js +29 -5
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_gltf_builtin_components.js +1 -1
- package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
- package/lib/engine/engine_loaders.d.ts +0 -6
- package/lib/engine/engine_loaders.js +5 -5
- package/lib/engine/engine_loaders.js.map +1 -1
- package/lib/engine/engine_physics.js +6 -2
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine/engine_physics_rapier.d.ts +11 -2
- package/lib/engine/engine_physics_rapier.js +9 -0
- package/lib/engine/engine_physics_rapier.js.map +1 -1
- package/lib/engine/engine_scenelighting.d.ts +12 -1
- package/lib/engine/engine_scenelighting.js +21 -1
- package/lib/engine/engine_scenelighting.js.map +1 -1
- package/lib/engine/engine_types.d.ts +16 -0
- package/lib/engine/extensions/NEEDLE_lightmaps.js +2 -2
- package/lib/engine/extensions/NEEDLE_lightmaps.js.map +1 -1
- package/lib/engine/extensions/extensions.d.ts +2 -2
- package/lib/engine/extensions/extensions.js +11 -5
- package/lib/engine/extensions/extensions.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.d.ts +1 -0
- package/lib/engine/webcomponents/needle-engine.js +3 -0
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine/xr/NeedleXRSession.js +2 -1
- package/lib/engine/xr/NeedleXRSession.js.map +1 -1
- package/lib/engine-components/ReflectionProbe.js +16 -10
- package/lib/engine-components/ReflectionProbe.js.map +1 -1
- package/lib/engine-components/Renderer.js +2 -2
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/RendererInstancing.d.ts +5 -3
- package/lib/engine-components/RendererInstancing.js +64 -31
- package/lib/engine-components/RendererInstancing.js.map +1 -1
- package/lib/engine-components/Skybox.d.ts +15 -5
- package/lib/engine-components/Skybox.js +37 -25
- package/lib/engine-components/Skybox.js.map +1 -1
- package/lib/engine-components/export/usdz/USDZExporter.d.ts +24 -3
- package/lib/engine-components/export/usdz/USDZExporter.js +36 -2
- package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
- package/lib/engine-components/webxr/WebXR.js +4 -0
- package/lib/engine-components/webxr/WebXR.js.map +1 -1
- package/lib/engine-components/webxr/controllers/XRControllerModel.js +1 -1
- package/lib/engine-components/webxr/controllers/XRControllerModel.js.map +1 -1
- package/lib/needle-engine.js +2 -1
- package/lib/needle-engine.js.map +1 -1
- package/package.json +1 -1
- package/src/engine/debug/debug_spector.ts +43 -0
- package/src/engine/engine_application.ts +16 -1
- package/src/engine/engine_context.ts +41 -7
- package/src/engine/engine_gltf_builtin_components.ts +1 -1
- package/src/engine/engine_loaders.ts +6 -6
- package/src/engine/engine_physics.ts +6 -2
- package/src/engine/engine_physics_rapier.ts +11 -2
- package/src/engine/engine_scenelighting.ts +30 -8
- package/src/engine/engine_types.ts +17 -0
- package/src/engine/extensions/NEEDLE_lightmaps.ts +2 -2
- package/src/engine/extensions/extensions.ts +11 -5
- package/src/engine/webcomponents/needle-engine.ts +4 -0
- package/src/engine/xr/NeedleXRSession.ts +3 -1
- package/src/engine-components/ReflectionProbe.ts +18 -10
- package/src/engine-components/Renderer.ts +2 -2
- package/src/engine-components/RendererInstancing.ts +69 -33
- package/src/engine-components/Skybox.ts +47 -36
- package/src/engine-components/export/usdz/USDZExporter.ts +52 -5
- package/src/engine-components/webxr/WebXR.ts +4 -0
- package/src/engine-components/webxr/controllers/XRControllerModel.ts +1 -1
- package/src/needle-engine.ts +4 -2
- package/dist/generateMeshBVH.worker-B9bjdr6J.js +0 -25
- package/dist/loader.worker-CiTwpNPW.js +0 -27
- package/dist/rapier-BqdcSmKY.umd.cjs +0 -1
- package/dist/rapier-Cg3w3nFI.min.js +0 -1
- package/dist/rapier-sU12SWAs.js +0 -5217
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Context } from "../engine_setup.js";
|
|
2
|
+
import { isDevEnvironment } from "./debug.js";
|
|
3
|
+
|
|
4
|
+
declare global {
|
|
5
|
+
interface Window {
|
|
6
|
+
SPECTOR?: {
|
|
7
|
+
Spector: new () => Spector;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
interface Spector {
|
|
11
|
+
displayUI: () => void;
|
|
12
|
+
setCanvas: (canvas: HTMLCanvasElement) => void;
|
|
13
|
+
spyCanvases: boolean;
|
|
14
|
+
startCaptureOnNextFrame: () => void;
|
|
15
|
+
captureCanvas: (canvas: HTMLCanvasElement) => any;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
export function initSpectorIfAvailable(_context: Context, canvas: HTMLCanvasElement): void {
|
|
21
|
+
if (typeof window !== undefined && window.SPECTOR) {
|
|
22
|
+
console.log(window.SPECTOR);
|
|
23
|
+
const params = new URLSearchParams(window.location.search);
|
|
24
|
+
if (params.has("spector")) {
|
|
25
|
+
const frame = Number.parseInt(params.get("spector") || "0") || 0;
|
|
26
|
+
console.log("Scheduled Spector capture at frame #" + frame);
|
|
27
|
+
const spector = new window.SPECTOR.Spector();
|
|
28
|
+
spector.spyCanvases = true;
|
|
29
|
+
waitForFrameAndCapture();
|
|
30
|
+
return;
|
|
31
|
+
|
|
32
|
+
function waitForFrameAndCapture() {
|
|
33
|
+
if (frame > _context.time.frame) return window.requestAnimationFrame(() => waitForFrameAndCapture());
|
|
34
|
+
const res = spector.captureCanvas(canvas);
|
|
35
|
+
if (res && res instanceof Promise) res.then(() => spector.displayUI());
|
|
36
|
+
else spector.displayUI();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else if (isDevEnvironment()) {
|
|
40
|
+
console.debug("Spector available: Add '?spector=<frame>' to the URL to enable it and capture a frame.");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -15,7 +15,7 @@ const userInteractionCallbacks: Function[] = [];
|
|
|
15
15
|
*/
|
|
16
16
|
export function internalOnUserInputRegistered() {
|
|
17
17
|
if (userInteractionRegistered) return;
|
|
18
|
-
if (isDevEnvironment()) console.debug("User
|
|
18
|
+
if (isDevEnvironment()) console.debug("[Needle Engine] User input registered: Media playback is now allowed.");
|
|
19
19
|
userInteractionRegistered = true;
|
|
20
20
|
const copy = [...userInteractionCallbacks];
|
|
21
21
|
userInteractionCallbacks.length = 0;
|
|
@@ -28,6 +28,21 @@ document.addEventListener('dragstart', internalOnUserInputRegistered);
|
|
|
28
28
|
document.addEventListener('touchend', internalOnUserInputRegistered);
|
|
29
29
|
document.addEventListener('keydown', internalOnUserInputRegistered);
|
|
30
30
|
|
|
31
|
+
|
|
32
|
+
declare global {
|
|
33
|
+
interface Navigator {
|
|
34
|
+
userActivation?: {
|
|
35
|
+
isActive: boolean;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// User Activation should be available across browsers since November 2023 https://developer.mozilla.org/en-US/docs/Web/API/UserActivation
|
|
40
|
+
if (typeof window !== "undefined" && "userActivation" in navigator && navigator.userActivation?.isActive) {
|
|
41
|
+
if (isDevEnvironment()) console.debug("[Needle Engine] User input already active: Media playback is now allowed.");
|
|
42
|
+
userInteractionCallbacks.length = 0;
|
|
43
|
+
userInteractionRegistered = true;
|
|
44
|
+
}
|
|
45
|
+
|
|
31
46
|
/**
|
|
32
47
|
* The Application class can be used to mute audio globally, and to check if the application (canvas) is currently visible (it's tab is active and not minimized).
|
|
33
48
|
*/
|
|
@@ -13,6 +13,7 @@ import * as Stats from 'three/examples/jsm/libs/stats.module.js';
|
|
|
13
13
|
import type { EffectComposer as ThreeEffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
|
|
14
14
|
import { nodeFrame } from "three/examples/jsm/renderers/webgl-legacy/nodes/WebGLNodeBuilder.js";
|
|
15
15
|
|
|
16
|
+
import { initSpectorIfAvailable } from './debug/debug_spector.js';
|
|
16
17
|
import { isDevEnvironment, LogType, showBalloonError, showBalloonMessage } from './debug/index.js';
|
|
17
18
|
import { Addressables } from './engine_addressables.js';
|
|
18
19
|
import { AnimationsRegistry } from './engine_animation.js';
|
|
@@ -37,7 +38,7 @@ import { RendererData as SceneLighting } from './engine_scenelighting.js';
|
|
|
37
38
|
import { getTempColor, logHierarchy } from './engine_three_utils.js';
|
|
38
39
|
import { Time } from './engine_time.js';
|
|
39
40
|
import { patchTonemapping } from './engine_tonemapping.js';
|
|
40
|
-
import type { CoroutineData, ICamera, IComponent, IContext, ILight, LoadedModel, Model, Vec2 } from "./engine_types.js";
|
|
41
|
+
import type { CoroutineData, ICamera, IComponent, IContext, ILight, LoadedModel, Model, SourceIdentifier, Vec2 } from "./engine_types.js";
|
|
41
42
|
import { deepClone, delay, DeviceUtilities, getParam } from './engine_utils.js';
|
|
42
43
|
import type { INeedleXRSessionEventReceiver, NeedleXRSession } from './engine_xr.js';
|
|
43
44
|
import { NeedleMenu } from './webcomponents/needle menu/needle-menu.js';
|
|
@@ -372,6 +373,7 @@ export class Context implements IContext {
|
|
|
372
373
|
*/
|
|
373
374
|
composer: EffectComposer | ThreeEffectComposer | null = null;
|
|
374
375
|
|
|
376
|
+
// #region internal script lists
|
|
375
377
|
/**
|
|
376
378
|
* @internal All known components. Don't use directly
|
|
377
379
|
*/
|
|
@@ -439,6 +441,9 @@ export class Context implements IContext {
|
|
|
439
441
|
/** @internal */
|
|
440
442
|
readonly new_scripts_xr: INeedleXRSessionEventReceiver[] = [];
|
|
441
443
|
|
|
444
|
+
// #endregion
|
|
445
|
+
// #region Properties
|
|
446
|
+
|
|
442
447
|
/**
|
|
443
448
|
* The **main camera component** of the scene - this camera is used for rendering.
|
|
444
449
|
* Use `setCurrentCamera` for updating the main camera.
|
|
@@ -483,25 +488,36 @@ export class Context implements IContext {
|
|
|
483
488
|
physics: Physics;
|
|
484
489
|
/** access networking methods (use it to send or listen to messages or join a networking backend) */
|
|
485
490
|
connection: NetworkConnection;
|
|
486
|
-
/**
|
|
487
|
-
* @deprecated AssetDataBase is deprecated
|
|
488
|
-
*/
|
|
491
|
+
/** @deprecated AssetDatabase is deprecated */
|
|
489
492
|
assets: AssetDatabase;
|
|
490
493
|
/** The main light in the scene */
|
|
491
494
|
mainLight: ILight | null = null;
|
|
492
495
|
/** @deprecated Use sceneLighting */
|
|
493
496
|
get rendererData() { return this.sceneLighting }
|
|
497
|
+
/** Access the scene lighting manager to control lighting settings in the context */
|
|
494
498
|
sceneLighting: SceneLighting;
|
|
495
499
|
addressables: Addressables;
|
|
496
500
|
lightmaps: ILightDataRegistry;
|
|
497
501
|
players: PlayerViewManager;
|
|
502
|
+
|
|
503
|
+
/** Access the LODs manager to control LOD behavior in the context */
|
|
498
504
|
readonly lodsManager: LODsManager;
|
|
499
505
|
/** Access the needle menu to add or remove buttons to the menu element */
|
|
500
506
|
readonly menu: NeedleMenu;
|
|
501
507
|
|
|
502
|
-
/**
|
|
508
|
+
/**
|
|
509
|
+
* Checks if the context is fully created and ready
|
|
510
|
+
* @returns true if the context is fully created and ready
|
|
511
|
+
*/
|
|
503
512
|
get isCreated() { return this._isCreated; }
|
|
504
513
|
|
|
514
|
+
/**
|
|
515
|
+
* The source identifier(s) of the root scene(s) loaded into this context.
|
|
516
|
+
* When using `<needle-engine>` web component this will be the `src` attribute(s).
|
|
517
|
+
* @returns The source identifier for of the root scene
|
|
518
|
+
*/
|
|
519
|
+
get rootSourceId(): SourceIdentifier | undefined { return this.rootSceneSourceIdentifiers[0] || undefined; }
|
|
520
|
+
|
|
505
521
|
private _needsUpdateSize: boolean = false;
|
|
506
522
|
private _isCreated: boolean = false;
|
|
507
523
|
private _isCreating: boolean = false;
|
|
@@ -556,6 +572,7 @@ export class Context implements IContext {
|
|
|
556
572
|
ContextRegistry.register(this);
|
|
557
573
|
}
|
|
558
574
|
|
|
575
|
+
// #region Renderer
|
|
559
576
|
/**
|
|
560
577
|
* Calling this function will dispose the current renderer and create a new one which will then be assigned to the context. It can be used to create a new renderer with custom WebGLRendererParameters.
|
|
561
578
|
* **Note**: Instead you can also modify the static `Context.DefaultWebGlRendererParameters` before the context is created.
|
|
@@ -606,6 +623,8 @@ export class Context implements IContext {
|
|
|
606
623
|
|
|
607
624
|
this.input.bindEvents();
|
|
608
625
|
|
|
626
|
+
initSpectorIfAvailable(this, this.renderer.domElement);
|
|
627
|
+
|
|
609
628
|
return this.renderer;
|
|
610
629
|
}
|
|
611
630
|
|
|
@@ -909,6 +928,7 @@ export class Context implements IContext {
|
|
|
909
928
|
}
|
|
910
929
|
}
|
|
911
930
|
|
|
931
|
+
// #region onBeforeRender / onAfterRender listeners
|
|
912
932
|
private readonly _onBeforeRenderListeners = new Map<string, OnRenderCallback[]>();
|
|
913
933
|
private readonly _onAfterRenderListeners = new Map<string, OnRenderCallback[]>();
|
|
914
934
|
|
|
@@ -1006,6 +1026,8 @@ export class Context implements IContext {
|
|
|
1006
1026
|
private _lastStyleComputedResult: boolean | undefined = undefined;
|
|
1007
1027
|
|
|
1008
1028
|
private _createId: number = 0;
|
|
1029
|
+
|
|
1030
|
+
// #region internal create
|
|
1009
1031
|
private async internalOnCreate(opts?: ContextCreateArgs): Promise<boolean> {
|
|
1010
1032
|
const createId = ++this._createId;
|
|
1011
1033
|
|
|
@@ -1215,6 +1237,11 @@ export class Context implements IContext {
|
|
|
1215
1237
|
if (opts?.abortSignal?.aborted) {
|
|
1216
1238
|
return false;
|
|
1217
1239
|
}
|
|
1240
|
+
|
|
1241
|
+
|
|
1242
|
+
const mainIdentifier = this.rootSourceId;
|
|
1243
|
+
if (mainIdentifier) this.sceneLighting.enable(mainIdentifier);
|
|
1244
|
+
|
|
1218
1245
|
invokeLifecycleFunctions(this, ContextEvent.ContextCreated);
|
|
1219
1246
|
if (debug) console.log("Context Created...", this.renderer, this.renderer.domElement)
|
|
1220
1247
|
|
|
@@ -1224,13 +1251,18 @@ export class Context implements IContext {
|
|
|
1224
1251
|
return true;
|
|
1225
1252
|
}
|
|
1226
1253
|
|
|
1254
|
+
|
|
1255
|
+
private readonly rootSceneSourceIdentifiers: SourceIdentifier[] = [];
|
|
1227
1256
|
private async internalLoadInitialContent(createId: number, args: ContextCreateArgs): Promise<Array<LoadedModel>> {
|
|
1257
|
+
this.rootSceneSourceIdentifiers.length = 0;
|
|
1258
|
+
|
|
1228
1259
|
const results = new Array<LoadedModel>();
|
|
1229
1260
|
// early out if we dont have any files to load
|
|
1230
1261
|
if (args.files.length === 0) return results;
|
|
1231
1262
|
|
|
1232
|
-
|
|
1233
1263
|
const files = [...args.files];
|
|
1264
|
+
this.rootSceneSourceIdentifiers.push(...files);
|
|
1265
|
+
|
|
1234
1266
|
const progressArg: LoadingProgressArgs = {
|
|
1235
1267
|
name: "",
|
|
1236
1268
|
progress: null!,
|
|
@@ -1238,6 +1270,7 @@ export class Context implements IContext {
|
|
|
1238
1270
|
count: files.length
|
|
1239
1271
|
}
|
|
1240
1272
|
|
|
1273
|
+
|
|
1241
1274
|
const loader = getLoader();
|
|
1242
1275
|
// this hash should be constant since it is used to initialize the UIDProvider per initially loaded scene
|
|
1243
1276
|
const loadingHash = 0;
|
|
@@ -1676,7 +1709,8 @@ export class Context implements IContext {
|
|
|
1676
1709
|
|
|
1677
1710
|
if (this._stats) {
|
|
1678
1711
|
this._stats.end();
|
|
1679
|
-
|
|
1712
|
+
const dt = this.time.fps < 20 ? 50 : 150;
|
|
1713
|
+
if (this.time.frameCount % dt === 0)
|
|
1680
1714
|
console.log(this.renderer.info.render.calls + " DrawCalls", "\nRender:", { ...this.renderer.info.render }, "\nMemory:", { ...this.renderer.info.memory }, "\nTarget Framerate: " + this.targetFrameRate);
|
|
1681
1715
|
}
|
|
1682
1716
|
|
|
@@ -119,7 +119,7 @@ declare type IHasResolveGuids = {
|
|
|
119
119
|
resolveGuids: (guidsMap: GuidsMap) => void;
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
const originalComponentNameKey = Symbol("original-component-name");
|
|
122
|
+
const originalComponentNameKey = "needle-component-name";// Symbol("original-component-name");
|
|
123
123
|
|
|
124
124
|
/**
|
|
125
125
|
* We want to create one id provider per component
|
|
@@ -13,7 +13,7 @@ import { registerPrewarmObject } from "./engine_mainloop_utils.js";
|
|
|
13
13
|
import { SerializationContext } from "./engine_serialization_core.js";
|
|
14
14
|
import { Context } from "./engine_setup.js"
|
|
15
15
|
import { postprocessFBXMaterials } from "./engine_three_utils.js";
|
|
16
|
-
import { CustomModel, isGLTFModel, Model, type UIDProvider } from "./engine_types.js";
|
|
16
|
+
import { CustomModel, isGLTFModel, Model, SourceIdentifier, type UIDProvider } from "./engine_types.js";
|
|
17
17
|
import * as utils from "./engine_utils.js";
|
|
18
18
|
import { tryDetermineMimetypeFromURL } from "./engine_utils_format.js"
|
|
19
19
|
import { invokeLoadedImportPluginHooks, registerComponentExtension, registerExtensions } from "./extensions/extensions.js";
|
|
@@ -43,7 +43,7 @@ const debugFileTypes = utils.getParam("debugfileformat");
|
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
async function onCreateLoader(url: string, context: Context, sourceId: SourceIdentifier): Promise<CustomLoader | GLTFLoader | FBXLoader | USDZLoader | OBJLoader | null> {
|
|
47
47
|
|
|
48
48
|
const type = await tryDetermineMimetypeFromURL(url, { useExtension: true }) || "unknown";
|
|
49
49
|
if (debugFileTypes) console.debug(`Determined file type: '${type}' for url '${url}'`, { registeredModelLoaderCallbacks });
|
|
@@ -67,7 +67,7 @@ export async function onCreateLoader(url: string, context: Context): Promise<Cus
|
|
|
67
67
|
{
|
|
68
68
|
console.warn(`Unknown file type (${type}). Needle Engine will fallback to the GLTFLoader - To support more model formats please create a Needle loader plugin.\nUse import { NeedleEngineModelLoader } from \"@needle-tools/engine\" namespace to register your loader.`, url);
|
|
69
69
|
const loader = new GLTFLoader();
|
|
70
|
-
await registerExtensions(loader, context, url);
|
|
70
|
+
await registerExtensions(loader, context, url, sourceId);
|
|
71
71
|
return loader;
|
|
72
72
|
}
|
|
73
73
|
case "model/fbx":
|
|
@@ -88,7 +88,7 @@ export async function onCreateLoader(url: string, context: Context): Promise<Cus
|
|
|
88
88
|
case "model/vrm":
|
|
89
89
|
{
|
|
90
90
|
const loader = new GLTFLoader();
|
|
91
|
-
await registerExtensions(loader, context, url);
|
|
91
|
+
await registerExtensions(loader, context, url, sourceId);
|
|
92
92
|
return loader;
|
|
93
93
|
}
|
|
94
94
|
}
|
|
@@ -117,7 +117,7 @@ export async function parseSync(context: Context, data: string | ArrayBuffer, pa
|
|
|
117
117
|
path = "";
|
|
118
118
|
}
|
|
119
119
|
if (printGltf) console.log("Parse glTF", path)
|
|
120
|
-
const loader = await onCreateLoader(path, context);
|
|
120
|
+
const loader = await onCreateLoader(path, context, path);
|
|
121
121
|
if (!loader) {
|
|
122
122
|
return undefined;
|
|
123
123
|
}
|
|
@@ -193,7 +193,7 @@ export async function loadSync(context: Context, url: string, sourceId: string,
|
|
|
193
193
|
// but due to the async nature and potentially triggering multiple loads at the same time
|
|
194
194
|
// we need to make sure the extensions dont override each other
|
|
195
195
|
// creating new loaders should not be expensive as well
|
|
196
|
-
const loader = await onCreateLoader(url, context);
|
|
196
|
+
const loader = await onCreateLoader(url, context, sourceId);
|
|
197
197
|
if (!loader) {
|
|
198
198
|
return undefined;
|
|
199
199
|
}
|
|
@@ -13,6 +13,7 @@ import type { IPhysicsEngine } from './engine_types.js';
|
|
|
13
13
|
import { getParam } from "./engine_utils.js"
|
|
14
14
|
|
|
15
15
|
const debugPhysics = getParam("debugphysics");
|
|
16
|
+
const debugWorker = getParam("debugworker");
|
|
16
17
|
const layerMaskHelper: Layers = new Layers();
|
|
17
18
|
|
|
18
19
|
|
|
@@ -654,6 +655,9 @@ namespace NEMeshBVH {
|
|
|
654
655
|
// if there are no workers available, create a new one
|
|
655
656
|
if (!workerInstance && workerInstances.length < 3) {
|
|
656
657
|
try {
|
|
658
|
+
if (debugWorker) {
|
|
659
|
+
console.warn("[GenerateMeshBVHWorker] Creating worker with import.meta.url:", import.meta.url);
|
|
660
|
+
}
|
|
657
661
|
workerInstance = new _GenerateMeshBVHWorker();
|
|
658
662
|
workerInstances.push(workerInstance);
|
|
659
663
|
}
|
|
@@ -665,8 +669,8 @@ namespace NEMeshBVH {
|
|
|
665
669
|
failedToCreateMeshBVHWorker += 10;
|
|
666
670
|
}
|
|
667
671
|
else {
|
|
668
|
-
console.error("Failed to create MeshBVH worker");
|
|
669
|
-
console.
|
|
672
|
+
console.error("Failed to create MeshBVH worker. Please see below for more details:");
|
|
673
|
+
console.log(err);
|
|
670
674
|
}
|
|
671
675
|
failedToCreateMeshBVHWorker++;
|
|
672
676
|
}
|
|
@@ -67,7 +67,7 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
67
67
|
debugRenderRaycasts: boolean = false;
|
|
68
68
|
|
|
69
69
|
removeBody(obj: IComponent) {
|
|
70
|
-
if(debugPhysics) console.log("REMOVE BODY", obj?.name, obj[$bodyKey]);
|
|
70
|
+
if (debugPhysics) console.log("REMOVE BODY", obj?.name, obj[$bodyKey]);
|
|
71
71
|
if (!obj) return;
|
|
72
72
|
this.validate();
|
|
73
73
|
const body = obj[$bodyKey];
|
|
@@ -817,7 +817,16 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
817
817
|
return component;
|
|
818
818
|
}
|
|
819
819
|
|
|
820
|
-
|
|
820
|
+
/**
|
|
821
|
+
* Creates a collider in the physics world.
|
|
822
|
+
*
|
|
823
|
+
* @param collider - The collider component.
|
|
824
|
+
* @param desc - The collider description.
|
|
825
|
+
* @returns The created collider.
|
|
826
|
+
*
|
|
827
|
+
* @throws Will throw an error if the physics world is not initialized. Make sure to call `initialize()` before creating colliders.
|
|
828
|
+
*/
|
|
829
|
+
createCollider(collider: ICollider, desc: ColliderDesc) {
|
|
821
830
|
if (!this.world) throw new Error("Physics world not initialized");
|
|
822
831
|
const matrix = this._tempMatrix;
|
|
823
832
|
let rigidBody: RigidBody | undefined = undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EquirectangularReflectionMapping, LightProbe, SphericalHarmonics3, SRGBColorSpace,Texture, Vector4, WebGLCubeRenderTarget } from "three";
|
|
1
|
+
import { EquirectangularReflectionMapping, LightProbe, Source, SphericalHarmonics3, SRGBColorSpace, Texture, Vector4, WebGLCubeRenderTarget } from "three";
|
|
2
2
|
|
|
3
3
|
import { AssetReference } from "./engine_addressables.js";
|
|
4
4
|
import { Context } from "./engine_setup.js";
|
|
@@ -44,9 +44,16 @@ export class RendererData {
|
|
|
44
44
|
this.context.pre_update_callbacks.push(this.preUpdate.bind(this))
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* The id of the currently active scene light settings (source identifier).
|
|
49
|
+
*/
|
|
47
50
|
private _currentLightSettingsId?: SourceIdentifier;
|
|
48
51
|
private _sceneLightSettings?: Map<SourceIdentifier, SceneLightSettings>;
|
|
49
52
|
|
|
53
|
+
get currentLightSettingsId(): SourceIdentifier | undefined {
|
|
54
|
+
return this._currentLightSettingsId;
|
|
55
|
+
}
|
|
56
|
+
|
|
50
57
|
private preUpdate() {
|
|
51
58
|
const time = this.context.time;
|
|
52
59
|
this._timevec4.x = time.time;
|
|
@@ -82,11 +89,11 @@ export class RendererData {
|
|
|
82
89
|
|
|
83
90
|
/** set the scene lighting from a specific scene. Will disable any previously enabled lighting settings */
|
|
84
91
|
enable(sourceId: SourceIdentifier | AssetReference) {
|
|
85
|
-
if(sourceId instanceof AssetReference)
|
|
92
|
+
if (sourceId instanceof AssetReference)
|
|
86
93
|
sourceId = sourceId.url;
|
|
87
94
|
const settings = this._sceneLightSettings?.get(sourceId);
|
|
88
95
|
if (!settings) {
|
|
89
|
-
if(debug) console.warn("No light settings found for", sourceId);
|
|
96
|
+
if (debug) console.warn("No light settings found for", sourceId);
|
|
90
97
|
return false;
|
|
91
98
|
}
|
|
92
99
|
if (debug) console.log("Enable scene light settings", sourceId, settings);
|
|
@@ -100,7 +107,7 @@ export class RendererData {
|
|
|
100
107
|
|
|
101
108
|
/** disable the lighting of a specific scene, will only have any effect if it is currently active */
|
|
102
109
|
disable(sourceId: SourceIdentifier | AssetReference) {
|
|
103
|
-
if(sourceId instanceof AssetReference)
|
|
110
|
+
if (sourceId instanceof AssetReference)
|
|
104
111
|
sourceId = sourceId.url;
|
|
105
112
|
if (sourceId === null || sourceId === undefined) return false;
|
|
106
113
|
const settings = this._sceneLightSettings?.get(sourceId);
|
|
@@ -112,8 +119,22 @@ export class RendererData {
|
|
|
112
119
|
return true;
|
|
113
120
|
}
|
|
114
121
|
|
|
115
|
-
/**
|
|
116
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Enables the currently active scene lighting (if any), returns the id of the enabled lighting.
|
|
124
|
+
* @returns The id of the enabled lighting, or null if no lighting is currently active.
|
|
125
|
+
*/
|
|
126
|
+
enableCurrent(): SourceIdentifier | null {
|
|
127
|
+
if (this._currentLightSettingsId) {
|
|
128
|
+
this.enable(this._currentLightSettingsId);
|
|
129
|
+
return this._currentLightSettingsId ?? null;
|
|
130
|
+
}
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Disables the currently active scene lighting (if any), returns the id of the previously active lighting
|
|
135
|
+
* @returns The id of the previously active lighting, or null if no lighting was active.
|
|
136
|
+
*/
|
|
137
|
+
disableCurrent(): SourceIdentifier | null {
|
|
117
138
|
if (this._currentLightSettingsId) {
|
|
118
139
|
const prev = this._currentLightSettingsId;
|
|
119
140
|
this.disable(this._currentLightSettingsId);
|
|
@@ -162,7 +183,7 @@ export class RendererData {
|
|
|
162
183
|
private __currentReflectionId: SourceIdentifier | null = null;
|
|
163
184
|
|
|
164
185
|
/** @internal */
|
|
165
|
-
internalEnableReflection(sourceId: SourceIdentifier)
|
|
186
|
+
internalEnableReflection(sourceId: SourceIdentifier): Texture | null {
|
|
166
187
|
this.__currentReflectionId = sourceId;
|
|
167
188
|
const settings = this._sceneLightSettings?.get(sourceId);
|
|
168
189
|
|
|
@@ -181,6 +202,7 @@ export class RendererData {
|
|
|
181
202
|
const tex = existing.Source;
|
|
182
203
|
tex.mapping = EquirectangularReflectionMapping;
|
|
183
204
|
scene.environment = tex;
|
|
205
|
+
scene.environmentIntensity = this.environmentIntensity || 1;
|
|
184
206
|
return tex;
|
|
185
207
|
}
|
|
186
208
|
else if (debug) console.warn("Could not find reflection for source", sourceId);
|
|
@@ -216,7 +238,7 @@ export class RendererData {
|
|
|
216
238
|
/** @internal */
|
|
217
239
|
internalDisableReflection(sourceId?: SourceIdentifier) {
|
|
218
240
|
if (sourceId && sourceId !== this.__currentReflectionId) {
|
|
219
|
-
if(debug) console.log("Not disabling reflection for", sourceId, "because it is not the current light settings id", this.__currentReflectionId)
|
|
241
|
+
if (debug) console.log("Not disabling reflection for", sourceId, "because it is not the current light settings id", this.__currentReflectionId)
|
|
220
242
|
return;
|
|
221
243
|
}
|
|
222
244
|
if (debug) console.log("Disable reflection", sourceId)
|
|
@@ -566,6 +566,23 @@ export interface IPhysicsEngine {
|
|
|
566
566
|
*/
|
|
567
567
|
boxOverlap(point: Vector3, size: Vector3, rotation: Vector4Like | null): Array<ShapeOverlapResult>;
|
|
568
568
|
|
|
569
|
+
/**
|
|
570
|
+
* Creates a collider in the physics world.
|
|
571
|
+
*
|
|
572
|
+
* @param collider - The collider component.
|
|
573
|
+
* @param desc - The collider description.
|
|
574
|
+
* @returns The created collider.
|
|
575
|
+
*
|
|
576
|
+
* @throws Will throw an error if the physics world is not initialized. Make sure to call `initialize()` before creating colliders.
|
|
577
|
+
*
|
|
578
|
+
* @example
|
|
579
|
+
* ```typescript
|
|
580
|
+
* const boxColliderDesc = NEEDLE_ENGINE_MODULES.RAPIER_PHYSICS.MODULE.ColliderDesc.cuboid(1, 1, 1);
|
|
581
|
+
* const collider = physicsEngine.createCollider(myBoxColliderComponent, boxColliderDesc);
|
|
582
|
+
* ```
|
|
583
|
+
*/
|
|
584
|
+
createCollider(collider: ICollider, desc: any): any;
|
|
585
|
+
|
|
569
586
|
// Collider methods
|
|
570
587
|
/**
|
|
571
588
|
* Adds a sphere collider to the physics world
|
|
@@ -95,8 +95,8 @@ export class NEEDLE_lightmaps implements GLTFLoaderPlugin {
|
|
|
95
95
|
}
|
|
96
96
|
const results = await PromiseAllWithErrors(dependencies);
|
|
97
97
|
if (results?.anyFailed) {
|
|
98
|
-
if (isDevEnvironment())
|
|
99
|
-
console.error("
|
|
98
|
+
if (isDevEnvironment() || debug)
|
|
99
|
+
console.error("[NEEDLE_lightmaps]Error during extension loading:", results);
|
|
100
100
|
}
|
|
101
101
|
resolve();
|
|
102
102
|
});
|
|
@@ -92,18 +92,24 @@ class PointerResolver {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
export async function registerExtensions(loader: GLTFLoader, context: Context, url: string) {
|
|
95
|
+
export async function registerExtensions(loader: GLTFLoader, context: Context, url: string, sourceId: SourceIdentifier) {
|
|
96
96
|
|
|
97
97
|
// Make sure to remove any url parameters from the sourceId (because the source id in the renderer does not have a ?v=xxx so it will not be able to register the resolved lightmap otherwise)
|
|
98
98
|
const idEnd = url.indexOf("?");
|
|
99
99
|
if (idEnd >= 0) url = url.substring(0, idEnd);
|
|
100
|
+
if (!sourceId) {
|
|
101
|
+
sourceId = url;
|
|
102
|
+
}
|
|
103
|
+
if (sourceId.startsWith("blob:") || sourceId.startsWith("data:")) {
|
|
104
|
+
console.debug("[GLTFLoader] Suspicious sourceId detected");
|
|
105
|
+
}
|
|
100
106
|
|
|
101
107
|
loader.register(p => new NEEDLE_gameobject_data(p));
|
|
102
108
|
loader.register(p => new NEEDLE_persistent_assets(p));
|
|
103
|
-
loader.register(p => new NEEDLE_lightmaps(p, context.lightmaps,
|
|
104
|
-
loader.register(p => new NEEDLE_lighting_settings(p,
|
|
105
|
-
loader.register(p => new NEEDLE_techniques_webgl(p,
|
|
106
|
-
loader.register(p => new NEEDLE_render_objects(p,
|
|
109
|
+
loader.register(p => new NEEDLE_lightmaps(p, context.lightmaps, sourceId));
|
|
110
|
+
loader.register(p => new NEEDLE_lighting_settings(p, sourceId, context));
|
|
111
|
+
loader.register(p => new NEEDLE_techniques_webgl(p, sourceId));
|
|
112
|
+
loader.register(p => new NEEDLE_render_objects(p, sourceId));
|
|
107
113
|
loader.register(p => new NEEDLE_progressive(p));
|
|
108
114
|
loader.register(p => new EXT_texture_exr(p));
|
|
109
115
|
if (isResourceTrackingEnabled()) loader.register(p => new InternalUsageTrackerPlugin(p))
|
|
@@ -296,6 +296,10 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
296
296
|
}
|
|
297
297
|
}
|
|
298
298
|
|
|
299
|
+
connectedMoveCallback() {
|
|
300
|
+
// we dont want needle-engine to cleanup JUST because the element is moved in the DOM. See https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks
|
|
301
|
+
}
|
|
302
|
+
|
|
299
303
|
/**
|
|
300
304
|
* @internal
|
|
301
305
|
*/
|
|
@@ -527,7 +527,9 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
527
527
|
else
|
|
528
528
|
console.log("%c" + `Requesting ${mode} session`, "font-weight:bold;");
|
|
529
529
|
for (const script of scripts) {
|
|
530
|
-
if (script.onBeforeXR
|
|
530
|
+
if (script.onBeforeXR && script.activeAndEnabled && !script.destroyed) {
|
|
531
|
+
script.onBeforeXR(mode, init);
|
|
532
|
+
}
|
|
531
533
|
}
|
|
532
534
|
for (const listener of this._sessionRequestStartListeners) {
|
|
533
535
|
listener({ mode, init });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EquirectangularReflectionMapping, LinearSRGBColorSpace, Material, MeshBasicMaterial, Object3D, SRGBColorSpace, Texture, Vector3 } from "three";
|
|
1
|
+
import { CubeReflectionMapping, CubeTexture, EquirectangularReflectionMapping, LinearSRGBColorSpace, Material, MeshBasicMaterial, Object3D, SRGBColorSpace, Texture, Vector3 } from "three";
|
|
2
2
|
|
|
3
3
|
import { isDevEnvironment, showBalloonWarning } from "../engine/debug/index.js";
|
|
4
4
|
import { serializable } from "../engine/engine_serialization.js";
|
|
@@ -63,13 +63,19 @@ export class ReflectionProbe extends Behaviour {
|
|
|
63
63
|
|
|
64
64
|
// @serializable(Texture)
|
|
65
65
|
set texture(tex: Texture) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
66
|
+
|
|
67
|
+
if (this._texture === tex) return;
|
|
70
68
|
this._texture = tex;
|
|
69
|
+
|
|
70
|
+
if (debug) console.debug("[ReflectionProbe] Set reflection probe texture " + (tex?.name || "(removed)"));
|
|
71
|
+
|
|
71
72
|
if (tex) {
|
|
72
|
-
tex
|
|
73
|
+
if (tex instanceof CubeTexture) {
|
|
74
|
+
// cube textures use CubeReflectionMapping by default
|
|
75
|
+
}
|
|
76
|
+
else if (tex.mapping !== EquirectangularReflectionMapping) {
|
|
77
|
+
tex.mapping = EquirectangularReflectionMapping;
|
|
78
|
+
}
|
|
73
79
|
tex.colorSpace = LinearSRGBColorSpace;
|
|
74
80
|
tex.needsUpdate = true;
|
|
75
81
|
}
|
|
@@ -110,9 +116,8 @@ export class ReflectionProbe extends Behaviour {
|
|
|
110
116
|
}
|
|
111
117
|
}
|
|
112
118
|
start(): void {
|
|
113
|
-
if (!this._texture
|
|
119
|
+
if (!this._texture) {
|
|
114
120
|
console.warn(`[ReflectionProbe] Missing texture. Please assign a custom cubemap texture. To use reflection probes assign them to your renderer's "anchor" property.`);
|
|
115
|
-
showBalloonWarning("ReflectionProbe configuration hint: See browser console for details")
|
|
116
121
|
}
|
|
117
122
|
}
|
|
118
123
|
|
|
@@ -206,8 +211,11 @@ export class ReflectionProbe extends Behaviour {
|
|
|
206
211
|
/** this is the material that we copied and that has the reflection probe */
|
|
207
212
|
const copy = cached?.copy;
|
|
208
213
|
|
|
209
|
-
|
|
210
|
-
|
|
214
|
+
if ("envMap" in copy) {
|
|
215
|
+
// make sure the reflection probe is assigned
|
|
216
|
+
copy.envMap = this.texture;
|
|
217
|
+
copy.needsUpdate = true;
|
|
218
|
+
}
|
|
211
219
|
|
|
212
220
|
_rend.sharedMaterials[i] = copy;
|
|
213
221
|
}
|
|
@@ -702,7 +702,6 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
702
702
|
// If the material has a envMap and is NOT using a reflection probe we set the envMap to the scene environment
|
|
703
703
|
if (mat && "envMap" in mat && "envMapIntensity" in mat && !ReflectionProbe.isUsingReflectionProbe(mat)) {
|
|
704
704
|
mat.envMap = this.context.scene.environment;
|
|
705
|
-
mat.envMapIntensity = this.context.scene.environmentIntensity;
|
|
706
705
|
mat.envMapRotation = this.context.scene.environmentRotation;
|
|
707
706
|
}
|
|
708
707
|
}
|
|
@@ -713,8 +712,9 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
713
712
|
private onBeforeRenderThree = (_renderer, _scene, _camera, _geometry, material, _group) => {
|
|
714
713
|
if (material.envMapIntensity !== undefined) {
|
|
715
714
|
const factor = this.hasLightmap ? Math.PI : 1;
|
|
716
|
-
const environmentIntensity = this.context.
|
|
715
|
+
const environmentIntensity = this.context.scene.environmentIntensity;
|
|
717
716
|
material.envMapIntensity = Math.max(0, environmentIntensity * this.context.sceneLighting.environmentIntensity / factor);
|
|
717
|
+
// console.log(this.context.sceneLighting.environmentIntensity);
|
|
718
718
|
}
|
|
719
719
|
if (this._lightmaps) {
|
|
720
720
|
for (const lm of this._lightmaps) {
|