@needle-tools/engine 4.10.0-next.2abafea → 4.10.0-next.55c0bf9
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-p_i5rc9e.js → needle-engine.bundle-CUo74dPe.js} +7011 -7222
- package/dist/{needle-engine.bundle-7QhMyR9L.umd.cjs → needle-engine.bundle-Cf5H9Zy9.umd.cjs} +141 -152
- package/dist/{needle-engine.bundle-COzW_KEf.min.js → needle-engine.bundle-DlAVTipB.min.js} +159 -170
- package/dist/needle-engine.js +257 -259
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/lib/engine/codegen/register_types.js +0 -2
- package/lib/engine/codegen/register_types.js.map +1 -1
- package/lib/engine/engine_camera.d.ts +1 -7
- package/lib/engine/engine_camera.fit.d.ts +1 -1
- package/lib/engine/engine_camera.fit.js +30 -3
- package/lib/engine/engine_camera.fit.js.map +1 -1
- package/lib/engine/engine_camera.js +6 -46
- package/lib/engine/engine_camera.js.map +1 -1
- package/lib/engine/engine_context.d.ts +0 -6
- package/lib/engine/engine_context.js +9 -48
- 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 +0 -4
- 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 +5 -4
- package/lib/engine/engine_scenelighting.js.map +1 -1
- package/lib/engine/engine_utils.d.ts +1 -3
- package/lib/engine/engine_utils.js +0 -11
- 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 +5 -29
- package/lib/engine/webcomponents/logo-element.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.js +3 -4
- package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.js +0 -4
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.loading.d.ts +1 -0
- package/lib/engine/webcomponents/needle-engine.loading.js +36 -3
- package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +1 -4
- package/lib/engine-components/OrbitControls.js +6 -30
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/Renderer.js +1 -6
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/Skybox.js +4 -22
- package/lib/engine-components/Skybox.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +0 -1
- package/lib/engine-components/codegen/components.js +0 -1
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/timeline/PlayableDirector.d.ts +0 -7
- package/lib/engine-components/timeline/PlayableDirector.js +0 -7
- package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
- package/lib/engine-components/timeline/TimelineModels.d.ts +1 -9
- package/lib/engine-components/timeline/TimelineTracks.js +2 -4
- package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
- package/lib/engine-components/utils/LookAt.js +1 -5
- package/lib/engine-components/utils/LookAt.js.map +1 -1
- package/lib/engine-components/web/Clickthrough.js +2 -10
- package/lib/engine-components/web/Clickthrough.js.map +1 -1
- package/lib/engine-components/web/ScrollFollow.d.ts +0 -22
- package/lib/engine-components/web/ScrollFollow.js +38 -159
- package/lib/engine-components/web/ScrollFollow.js.map +1 -1
- package/lib/engine-components/web/index.d.ts +0 -1
- package/lib/engine-components/web/index.js +0 -1
- package/lib/engine-components/web/index.js.map +1 -1
- package/package.json +1 -1
- package/src/engine/codegen/register_types.ts +0 -2
- package/src/engine/engine_camera.fit.ts +32 -2
- package/src/engine/engine_camera.ts +8 -62
- package/src/engine/engine_context.ts +10 -50
- package/src/engine/engine_lightdata.ts +11 -11
- package/src/engine/engine_physics_rapier.ts +0 -3
- package/src/engine/engine_scenelighting.ts +6 -5
- package/src/engine/engine_utils.ts +0 -12
- package/src/engine/extensions/NEEDLE_lightmaps.ts +1 -1
- package/src/engine/webcomponents/logo-element.ts +4 -29
- package/src/engine/webcomponents/needle menu/needle-menu.ts +3 -4
- package/src/engine/webcomponents/needle-engine.loading.ts +32 -32
- package/src/engine/webcomponents/needle-engine.ts +0 -4
- package/src/engine-components/OrbitControls.ts +1 -40
- package/src/engine-components/Renderer.ts +1 -6
- package/src/engine-components/Skybox.ts +7 -26
- package/src/engine-components/codegen/components.ts +0 -1
- package/src/engine-components/timeline/PlayableDirector.ts +0 -9
- package/src/engine-components/timeline/TimelineModels.ts +1 -9
- package/src/engine-components/timeline/TimelineTracks.ts +2 -4
- package/src/engine-components/utils/LookAt.ts +1 -5
- package/src/engine-components/web/Clickthrough.ts +2 -11
- package/src/engine-components/web/ScrollFollow.ts +44 -190
- package/src/engine-components/web/index.ts +1 -2
- package/lib/engine-components/web/ViewBox.d.ts +0 -16
- package/lib/engine-components/web/ViewBox.js +0 -186
- package/lib/engine-components/web/ViewBox.js.map +0 -1
- package/src/engine-components/web/ViewBox.ts +0 -202
|
@@ -87,7 +87,7 @@ export type FitCameraReturnType = {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
|
|
90
|
-
export function fitCamera(options?: FitCameraOptions): null | FitCameraReturnType {
|
|
90
|
+
export function fitCamera(objectsOrOptions?: Object3D | Array<Object3D> | FitCameraOptions, options?: FitCameraOptions): null | FitCameraReturnType {
|
|
91
91
|
|
|
92
92
|
if (NeedleXRSession.active) {
|
|
93
93
|
// camera fitting in XR is not supported
|
|
@@ -102,6 +102,37 @@ export function fitCamera(options?: FitCameraOptions): null | FitCameraReturnTyp
|
|
|
102
102
|
}
|
|
103
103
|
const camera = options?.camera || context.mainCamera;
|
|
104
104
|
|
|
105
|
+
let objects: Object3D | Array<Object3D> | undefined = undefined;
|
|
106
|
+
// If the user passed in an array as first argument
|
|
107
|
+
if (Array.isArray(objectsOrOptions)) {
|
|
108
|
+
objects = objectsOrOptions;
|
|
109
|
+
}
|
|
110
|
+
// If the user passed in an object as first argument
|
|
111
|
+
else if (objectsOrOptions && "type" in objectsOrOptions) {
|
|
112
|
+
objects = objectsOrOptions;
|
|
113
|
+
}
|
|
114
|
+
// If the user passed in an object as first argument and options as second argument
|
|
115
|
+
else if (objectsOrOptions && typeof objectsOrOptions === "object") {
|
|
116
|
+
if (!(objectsOrOptions instanceof Object3D) && !Array.isArray(objectsOrOptions)) {
|
|
117
|
+
options = objectsOrOptions;
|
|
118
|
+
objects = options.objects;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Ensure objects are setup correctly
|
|
122
|
+
if (objects && !Array.isArray(objects)) {
|
|
123
|
+
objects = [objects];
|
|
124
|
+
}
|
|
125
|
+
if (!Array.isArray(objects) || objects && objects.length <= 0) {
|
|
126
|
+
objects = context.scene.children;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Make sure there's anything to fit to
|
|
130
|
+
if (!Array.isArray(objects) || objects.length <= 0) {
|
|
131
|
+
console.warn("No objects to fit camera to...");
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
|
|
105
136
|
// const controls = this._controls as ThreeOrbitControls | null;
|
|
106
137
|
|
|
107
138
|
if (!camera) {
|
|
@@ -124,7 +155,6 @@ export function fitCamera(options?: FitCameraOptions): null | FitCameraReturnTyp
|
|
|
124
155
|
const size = new Vector3();
|
|
125
156
|
const center = new Vector3();
|
|
126
157
|
const aspect = camera instanceof PerspectiveCamera ? camera.aspect : 1;
|
|
127
|
-
const objects = options.objects || context.scene;
|
|
128
158
|
// TODO would be much better to calculate the bounds in camera space instead of world space -
|
|
129
159
|
// we would get proper view-dependant fit.
|
|
130
160
|
// Right now it's independent from where the camera is actually looking from,
|
|
@@ -52,23 +52,15 @@ export type FocusRectSettings = {
|
|
|
52
52
|
/** Lower values will result in faster alignment with the rect (value ~= seconds to reach target)
|
|
53
53
|
* Minimum value is 0.
|
|
54
54
|
*/
|
|
55
|
-
damping: number
|
|
56
|
-
|
|
57
|
-
/** X offset in camera coordinates. Used by ViewBox component */
|
|
58
|
-
offsetX: number,
|
|
59
|
-
/** Y offset in camera coordinates. Used by ViewBox component */
|
|
60
|
-
offsetY: number,
|
|
61
|
-
/** Zoom factor. Used by ViewBox component */
|
|
62
|
-
zoom: number,
|
|
55
|
+
damping: number
|
|
63
56
|
}
|
|
64
57
|
export type FocusRect = DOMRect | Element | { x: number, y: number, width: number, height: number };
|
|
65
58
|
|
|
66
59
|
let rendererRect: DOMRect | undefined = undefined;
|
|
67
60
|
const overlapRect = { x: 0, y: 0, width: 0, height: 0 };
|
|
68
|
-
const _testTime = 1;
|
|
69
61
|
|
|
70
62
|
/** Used internally by the Needle Engine context via 'setFocusRect(<rect>)' */
|
|
71
|
-
export function updateCameraFocusRect(focusRect: FocusRect,
|
|
63
|
+
export function updateCameraFocusRect(focusRect: FocusRect, dt: number, camera: PerspectiveCamera, renderer: WebGLRenderer) {
|
|
72
64
|
|
|
73
65
|
if (focusRect instanceof Element) {
|
|
74
66
|
focusRect = focusRect.getBoundingClientRect();
|
|
@@ -84,62 +76,16 @@ export function updateCameraFocusRect(focusRect: FocusRect, settings: FocusRectS
|
|
|
84
76
|
rect.x -= rendererRect.x;
|
|
85
77
|
rect.y -= rendererRect.y;
|
|
86
78
|
|
|
87
|
-
const
|
|
88
|
-
const
|
|
79
|
+
const targetX = rect.width / -2 - (rect.x - (rendererRect.width / 2));
|
|
80
|
+
const targetY = rect.height / -2 - (rect.y - (rendererRect.height / 2));
|
|
89
81
|
|
|
90
|
-
const view = camera.view
|
|
82
|
+
const view = camera.view;
|
|
91
83
|
|
|
92
|
-
// Apply zoom
|
|
93
|
-
const zoom = settings.zoom;
|
|
94
84
|
let offsetX = view?.offsetX || 0;
|
|
95
85
|
let offsetY = view?.offsetY || 0;
|
|
86
|
+
offsetX = Mathf.lerp(offsetX, targetX, dt);
|
|
87
|
+
offsetY = Mathf.lerp(offsetY, targetY, dt);
|
|
96
88
|
|
|
97
|
-
|
|
98
|
-
let height = rendererRect.height;
|
|
99
|
-
width /= zoom;
|
|
100
|
-
height /= zoom;
|
|
101
|
-
offsetX = width * (zoom - 1) * .5;
|
|
102
|
-
offsetY = height * (zoom - 1) * .5;
|
|
103
|
-
|
|
104
|
-
const focusRectCenterX = rect.x + rect.width * .5;
|
|
105
|
-
const focusRectCenterY = rect.y + rect.height * .5;
|
|
106
|
-
const rendererCenterX = rendererRect.width * .5;
|
|
107
|
-
const rendererCenterY = rendererRect.height * .5;
|
|
108
|
-
|
|
109
|
-
const diffx = focusRectCenterX - rendererCenterX;
|
|
110
|
-
const diffy = focusRectCenterY - rendererCenterY;
|
|
111
|
-
offsetX -= diffx / zoom;
|
|
112
|
-
offsetY -= diffy / zoom;
|
|
113
|
-
if (settings.offsetX !== undefined) {
|
|
114
|
-
offsetX += settings.offsetX * (rendererRect.width * .5);
|
|
115
|
-
}
|
|
116
|
-
if (settings.offsetY !== undefined) {
|
|
117
|
-
offsetY -= settings.offsetY * (rendererRect.height * .5);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const currentOffsetX = view?.offsetX || offsetX;
|
|
122
|
-
const currentOffsetY = view?.offsetY || offsetY;
|
|
123
|
-
offsetX = Mathf.lerp(currentOffsetX, offsetX, dt);
|
|
124
|
-
offsetY = Mathf.lerp(currentOffsetY, offsetY, dt);
|
|
125
|
-
const currentWidth = view?.width || sourceWidth;
|
|
126
|
-
const currentHeight = view?.height || sourceHeight;
|
|
127
|
-
width = Mathf.lerp(currentWidth, width, dt);
|
|
128
|
-
height = Mathf.lerp(currentHeight, height, dt);
|
|
129
|
-
|
|
130
|
-
camera.setViewOffset(sourceWidth, sourceHeight, offsetX, offsetY, width, height);
|
|
89
|
+
camera.setViewOffset(rendererRect.width, rendererRect.height, offsetX, offsetY, rendererRect.width, rendererRect.height);
|
|
131
90
|
camera.updateProjectionMatrix();
|
|
132
|
-
|
|
133
|
-
if (settings.damping > 0) {
|
|
134
|
-
settings.damping *= (1.0 - dt);
|
|
135
|
-
if (settings.damping < 0.01) settings.damping = 0;
|
|
136
|
-
settings.damping = Math.max(0, settings.damping);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
function fit(width1: number, height1: number, width2: number, height2: number) {
|
|
142
|
-
const scaleX = width2 / width1;
|
|
143
|
-
const scaleY = height2 / height1;
|
|
144
|
-
return Math.max(scaleX, scaleY);
|
|
145
91
|
}
|
|
@@ -1382,61 +1382,21 @@ export class Context implements IContext {
|
|
|
1382
1382
|
* @param settings Optional settings for the focus rect. These will override the `focusRectSettings` property
|
|
1383
1383
|
*/
|
|
1384
1384
|
public setCameraFocusRect(rect: FocusRect | null, settings?: Partial<FocusRectSettings>) {
|
|
1385
|
-
const oldRect = this._focusRect;
|
|
1386
1385
|
this._focusRect = rect;
|
|
1387
1386
|
if (settings) {
|
|
1388
1387
|
Object.assign(this.focusRectSettings, settings);
|
|
1389
1388
|
}
|
|
1390
|
-
if (settings?.damping === undefined) {
|
|
1391
|
-
// if the new rect is on screen then set damping
|
|
1392
|
-
if (oldRect) {
|
|
1393
|
-
let domRect = oldRect as DOMRect;
|
|
1394
|
-
if (oldRect instanceof HTMLElement) {
|
|
1395
|
-
domRect = oldRect.getBoundingClientRect();
|
|
1396
|
-
}
|
|
1397
|
-
if (domRect && "top" in domRect) {
|
|
1398
|
-
const allowedDistance = 100;
|
|
1399
|
-
const isVisible = domRect.bottom >= -allowedDistance && domRect.right >= -allowedDistance && domRect.top <= window.innerHeight + allowedDistance && domRect.left <= window.innerWidth + allowedDistance;
|
|
1400
|
-
if (isVisible) this.focusRectSettings.damping = .2;
|
|
1401
|
-
}
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
|
|
1405
1389
|
}
|
|
1406
1390
|
get focusRect() { return this._focusRect; }
|
|
1407
|
-
get focusRectSize(): null | { x: number, y: number, width: number, height: number } {
|
|
1408
|
-
const rect = this._focusRect;
|
|
1409
|
-
if (rect && (rect instanceof DOMRect || ("width" in rect && "height" in rect && "x" in rect && "y" in rect))) {
|
|
1410
|
-
return { x: rect.x, y: rect.y, width: rect.width, height: rect.height };
|
|
1411
|
-
}
|
|
1412
|
-
else if (rect instanceof HTMLElement) {
|
|
1413
|
-
const r = rect.getBoundingClientRect();
|
|
1414
|
-
return { x: r.x, y: r.y, width: r.width, height: r.height };
|
|
1415
|
-
}
|
|
1416
|
-
return null;
|
|
1417
|
-
}
|
|
1418
1391
|
/** Settings when a focus rect is set. Use `setCameraFocusRect(...)` to do so.
|
|
1419
1392
|
* This can be used to offset the renderer center e.g. to a specific DOM element.
|
|
1420
1393
|
*/
|
|
1421
1394
|
readonly focusRectSettings: FocusRectSettings = {
|
|
1422
1395
|
/** Controls how fast the rect is centered. Smaller values mean the rect is centered faster.
|
|
1423
1396
|
* A minimum value of 0 means the rect is centered instantly.
|
|
1424
|
-
* @default
|
|
1397
|
+
* @default .05
|
|
1425
1398
|
*/
|
|
1426
|
-
damping:
|
|
1427
|
-
|
|
1428
|
-
/**
|
|
1429
|
-
* Zoom factor when a focus rect is set.
|
|
1430
|
-
*/
|
|
1431
|
-
zoom: 1,
|
|
1432
|
-
/**
|
|
1433
|
-
* Additional offset in pixels from the center of the rect
|
|
1434
|
-
*/
|
|
1435
|
-
offsetX: 0,
|
|
1436
|
-
/**
|
|
1437
|
-
* Additional offset in pixels from the center of the rect
|
|
1438
|
-
*/
|
|
1439
|
-
offsetY: 0,
|
|
1399
|
+
damping: .05
|
|
1440
1400
|
};
|
|
1441
1401
|
private _focusRect: FocusRect | null = null;
|
|
1442
1402
|
|
|
@@ -1568,6 +1528,14 @@ export class Context implements IContext {
|
|
|
1568
1528
|
|
|
1569
1529
|
if (this.isVisibleToUser || this.runInBackground) {
|
|
1570
1530
|
|
|
1531
|
+
if (this._focusRect) {
|
|
1532
|
+
if (this.mainCamera instanceof PerspectiveCamera) {
|
|
1533
|
+
const settings = this.focusRectSettings;
|
|
1534
|
+
const dt = settings.damping > 0 ? this.time.deltaTime / settings.damping : 1;
|
|
1535
|
+
updateCameraFocusRect(this._focusRect, dt, this.mainCamera, this.renderer);
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1571
1539
|
this._currentFrameEvent = FrameEvent.OnBeforeRender;
|
|
1572
1540
|
|
|
1573
1541
|
// should we move these callbacks in the regular three onBeforeRender events?
|
|
@@ -1584,14 +1552,6 @@ export class Context implements IContext {
|
|
|
1584
1552
|
this.executeCoroutines(FrameEvent.OnBeforeRender);
|
|
1585
1553
|
invokeLifecycleFunctions(this, FrameEvent.OnBeforeRender);
|
|
1586
1554
|
|
|
1587
|
-
if (this._focusRect) {
|
|
1588
|
-
if (this.mainCamera instanceof PerspectiveCamera) {
|
|
1589
|
-
const settings = this.focusRectSettings;
|
|
1590
|
-
const dt = settings.damping > 0 ? this.time.deltaTime / settings.damping : 1;
|
|
1591
|
-
updateCameraFocusRect(this._focusRect, this.focusRectSettings, dt, this.mainCamera, this.renderer);
|
|
1592
|
-
}
|
|
1593
|
-
}
|
|
1594
|
-
|
|
1595
1555
|
if (this._needsUpdateSize)
|
|
1596
1556
|
this.updateSize();
|
|
1597
1557
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ShaderChunk, Texture, UniformsLib, Vector4 } from "three";
|
|
2
2
|
|
|
3
3
|
import { setDisposable } from "./engine_assetdatabase.js";
|
|
4
|
-
import
|
|
4
|
+
import { Context } from "./engine_setup.js";
|
|
5
5
|
import type { SourceIdentifier } from "./engine_types.js";
|
|
6
6
|
import { getParam } from "./engine_utils.js";
|
|
7
7
|
import { LightmapType } from "./extensions/NEEDLE_lightmaps.js";
|
|
@@ -27,22 +27,22 @@ export interface ILightDataRegistry {
|
|
|
27
27
|
|
|
28
28
|
export class LightDataRegistry implements ILightDataRegistry {
|
|
29
29
|
|
|
30
|
-
private
|
|
31
|
-
private
|
|
30
|
+
private _context: Context;
|
|
31
|
+
private _lightmaps: Map<SourceIdentifier, Map<LightmapType, Texture[]>> = new Map();
|
|
32
32
|
|
|
33
33
|
clear() {
|
|
34
|
-
this.
|
|
34
|
+
this._lightmaps.clear();
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
constructor(context: Context) {
|
|
38
|
-
this.
|
|
38
|
+
this._context = context;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
registerTexture(sourceId: SourceIdentifier, type: LightmapType, tex: Texture, index: number) {
|
|
42
42
|
if (debugLightmap) console.log("Registering ", LightmapType[type] + " \"" + sourceId + "\"", tex);
|
|
43
|
-
if (!this.
|
|
44
|
-
this.
|
|
45
|
-
const map = this.
|
|
43
|
+
if (!this._lightmaps.has(sourceId))
|
|
44
|
+
this._lightmaps.set(sourceId, new Map());
|
|
45
|
+
const map = this._lightmaps.get(sourceId);
|
|
46
46
|
const arr = map?.get(type) ?? [];
|
|
47
47
|
if (arr.length < index) arr.length = index + 1;
|
|
48
48
|
setDisposable(tex, false);
|
|
@@ -55,12 +55,12 @@ export class LightDataRegistry implements ILightDataRegistry {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
tryGetSkybox(sourceId?: SourceIdentifier | null): Texture | null {
|
|
58
|
-
if (debugLightmap) console.log("[Get Skybox]", sourceId, this.
|
|
58
|
+
if (debugLightmap) console.log("[Get Skybox]", sourceId, this._lightmaps)
|
|
59
59
|
return this.tryGet(sourceId, LightmapType.Skybox, 0);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
tryGetReflection(sourceId?: SourceIdentifier | null): Texture | null {
|
|
63
|
-
if (debugLightmap) console.log("[Get Reflection]", sourceId, this.
|
|
63
|
+
if (debugLightmap) console.log("[Get Reflection]", sourceId, this._lightmaps)
|
|
64
64
|
return this.tryGet(sourceId, LightmapType.Reflection, 0);
|
|
65
65
|
}
|
|
66
66
|
|
|
@@ -69,7 +69,7 @@ export class LightDataRegistry implements ILightDataRegistry {
|
|
|
69
69
|
if (debugLightmap) console.warn("Missing source id");
|
|
70
70
|
return null;
|
|
71
71
|
}
|
|
72
|
-
const entry = this.
|
|
72
|
+
const entry = this._lightmaps.get(sourceId);
|
|
73
73
|
if (!entry) {
|
|
74
74
|
if (debugLightmap) console.warn(`[Lighting] No ${LightmapType[type]} texture entry for`, sourceId);
|
|
75
75
|
return null;
|
|
@@ -67,7 +67,6 @@ 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]);
|
|
71
70
|
if (!obj) return;
|
|
72
71
|
this.validate();
|
|
73
72
|
const body = obj[$bodyKey];
|
|
@@ -902,8 +901,6 @@ export class RapierPhysics implements IPhysicsEngine {
|
|
|
902
901
|
// set the collider layers
|
|
903
902
|
this.updateColliderCollisionGroups(collider);
|
|
904
903
|
|
|
905
|
-
if (debugPhysics) console.log("Created collider", collider.name, col);
|
|
906
|
-
|
|
907
904
|
return col;
|
|
908
905
|
}
|
|
909
906
|
catch (e) {
|
|
@@ -162,7 +162,7 @@ export class RendererData {
|
|
|
162
162
|
private __currentReflectionId: SourceIdentifier | null = null;
|
|
163
163
|
|
|
164
164
|
/** @internal */
|
|
165
|
-
internalEnableReflection(sourceId: SourceIdentifier)
|
|
165
|
+
internalEnableReflection(sourceId: SourceIdentifier) {
|
|
166
166
|
this.__currentReflectionId = sourceId;
|
|
167
167
|
const settings = this._sceneLightSettings?.get(sourceId);
|
|
168
168
|
|
|
@@ -181,7 +181,7 @@ export class RendererData {
|
|
|
181
181
|
const tex = existing.Source;
|
|
182
182
|
tex.mapping = EquirectangularReflectionMapping;
|
|
183
183
|
scene.environment = tex;
|
|
184
|
-
return
|
|
184
|
+
return;
|
|
185
185
|
}
|
|
186
186
|
else if (debug) console.warn("Could not find reflection for source", sourceId);
|
|
187
187
|
break;
|
|
@@ -196,21 +196,22 @@ export class RendererData {
|
|
|
196
196
|
tex.colorSpace = SRGBColorSpace;
|
|
197
197
|
tex.mapping = EquirectangularReflectionMapping;
|
|
198
198
|
this.context.scene.environment = tex;
|
|
199
|
-
return tex;
|
|
200
199
|
}
|
|
201
200
|
else console.error("Missing ambient trilight", settings.sourceId);
|
|
201
|
+
return;
|
|
202
202
|
case AmbientMode.Flat:
|
|
203
203
|
if (settings.ambientLight) {
|
|
204
204
|
const tex = createFlatTexture(settings.ambientLight, 64);
|
|
205
205
|
tex.colorSpace = SRGBColorSpace;
|
|
206
206
|
tex.mapping = EquirectangularReflectionMapping;
|
|
207
207
|
this.context.scene.environment = tex;
|
|
208
|
-
return tex;
|
|
209
208
|
}
|
|
210
209
|
else console.error("Missing ambientlight", settings.sourceId);
|
|
210
|
+
return;
|
|
211
|
+
default:
|
|
212
|
+
return;
|
|
211
213
|
}
|
|
212
214
|
}
|
|
213
|
-
return null;
|
|
214
215
|
}
|
|
215
216
|
|
|
216
217
|
/** @internal */
|
|
@@ -381,14 +381,6 @@ export function resolveUrl(source: SourceIdentifier | undefined, uri: string): s
|
|
|
381
381
|
}
|
|
382
382
|
return uri;
|
|
383
383
|
}
|
|
384
|
-
|
|
385
|
-
export function toSourceId(src: string | null): SourceIdentifier | undefined {
|
|
386
|
-
if (!src) return undefined;
|
|
387
|
-
src = src.trim();
|
|
388
|
-
src = src.split("?")[0]?.split("#")[0];
|
|
389
|
-
return src;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
384
|
// export function getPath(glbLocation: SourceIdentifier | undefined, path: string) {
|
|
393
385
|
// if (path && glbLocation && !path.includes("/")) {
|
|
394
386
|
// // get directory of glb and prepend it to the audio file path
|
|
@@ -801,7 +793,6 @@ const mutationObserverMap = new WeakMap<HTMLElement, HtmlElementExtra>();
|
|
|
801
793
|
/**
|
|
802
794
|
* Register a callback when an {@link HTMLElement} attribute changes.
|
|
803
795
|
* This is used, for example, by the Skybox component to watch for changes to the environment-* and skybox-* attributes.
|
|
804
|
-
* @returns A function that can be used to unregister the callback
|
|
805
796
|
*/
|
|
806
797
|
export function addAttributeChangeCallback(domElement: HTMLElement, name: string, callback: AttributeChangeCallback) {
|
|
807
798
|
if (!mutationObserverMap.get(domElement)) {
|
|
@@ -820,9 +811,6 @@ export function addAttributeChangeCallback(domElement: HTMLElement, name: string
|
|
|
820
811
|
listeners.set(name, []);
|
|
821
812
|
}
|
|
822
813
|
listeners.get(name)!.push(callback);
|
|
823
|
-
return () => {
|
|
824
|
-
removeAttributeChangeCallback(domElement, name, callback);
|
|
825
|
-
}
|
|
826
814
|
};
|
|
827
815
|
|
|
828
816
|
/**
|
|
@@ -107,7 +107,7 @@ export class NEEDLE_lightmaps implements GLTFLoaderPlugin {
|
|
|
107
107
|
|
|
108
108
|
private resolveTexture(entry: LightmapInfo, res: any) {
|
|
109
109
|
const tex: Texture = res as unknown as Texture;
|
|
110
|
-
if (debug) console.log("
|
|
110
|
+
if (debug) console.log("Lightmap loaded:", tex);
|
|
111
111
|
if (tex?.isTexture) {
|
|
112
112
|
if (!this.registry)
|
|
113
113
|
console.log(LightmapType[entry.type], entry.pointer, tex);
|
|
@@ -32,22 +32,10 @@ export class NeedleLogoElement extends HTMLElement {
|
|
|
32
32
|
cursor: pointer;
|
|
33
33
|
}
|
|
34
34
|
img {
|
|
35
|
+
width: 95px;
|
|
35
36
|
height: 100%;
|
|
36
37
|
align-self: end;
|
|
37
38
|
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
|
-
}
|
|
51
39
|
}
|
|
52
40
|
span {
|
|
53
41
|
font-size: 1rem;
|
|
@@ -55,14 +43,12 @@ export class NeedleLogoElement extends HTMLElement {
|
|
|
55
43
|
}
|
|
56
44
|
</style>
|
|
57
45
|
<div class="wrapper">
|
|
58
|
-
<img class="logo
|
|
46
|
+
<img class="logo" src=${needleLogoSVG} />
|
|
59
47
|
</div>
|
|
60
48
|
`;
|
|
61
49
|
this._root.appendChild(template.content.cloneNode(true));
|
|
62
50
|
this.wrapper = this._root.querySelector(".wrapper") as HTMLDivElement;
|
|
63
51
|
this._root.appendChild(this.wrapper);
|
|
64
|
-
this.logoElement = this._root.querySelector("img.logo") as HTMLImageElement;
|
|
65
|
-
|
|
66
52
|
// this.wrapper.classList.add("wrapper");
|
|
67
53
|
|
|
68
54
|
// this.wrapper.appendChild(this.logoElement);
|
|
@@ -81,24 +67,13 @@ export class NeedleLogoElement extends HTMLElement {
|
|
|
81
67
|
|
|
82
68
|
private readonly _root: ShadowRoot;
|
|
83
69
|
private readonly wrapper: HTMLDivElement;
|
|
84
|
-
private readonly logoElement: HTMLImageElement;
|
|
70
|
+
private readonly logoElement: HTMLImageElement = document.createElement("img");
|
|
71
|
+
private readonly textElement: HTMLSpanElement = document.createElement("span");
|
|
85
72
|
|
|
86
73
|
setLogoVisible(val: boolean) {
|
|
87
74
|
this.logoElement.style.display = val ? "block" : "none";
|
|
88
75
|
}
|
|
89
76
|
|
|
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
|
-
|
|
102
77
|
}
|
|
103
78
|
if (!customElements.get(elementName))
|
|
104
79
|
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.6rem;
|
|
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
|
|
668
|
-
<span class="madewith notranslate"
|
|
667
|
+
<div style="user-select:none" class="logo">
|
|
668
|
+
<span class="madewith notranslate">powered by</span>
|
|
669
669
|
</div>
|
|
670
670
|
</div>
|
|
671
671
|
<button class="compact-menu-button">
|
|
@@ -698,7 +698,6 @@ export class NeedleMenuElement extends HTMLElement {
|
|
|
698
698
|
this.wrapper.classList.add("wrapper");
|
|
699
699
|
|
|
700
700
|
const logo = NeedleLogoElement.create();
|
|
701
|
-
logo.setType("compact");
|
|
702
701
|
logo.style.minHeight = "1rem";
|
|
703
702
|
this.logoContainer.append(logo);
|
|
704
703
|
this.logoContainer.addEventListener("click", () => {
|
|
@@ -374,40 +374,40 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
374
374
|
// }
|
|
375
375
|
// }
|
|
376
376
|
|
|
377
|
-
|
|
377
|
+
this.handleRuntimeLicense(this._loadingElement);
|
|
378
378
|
|
|
379
379
|
return this._loadingElement;
|
|
380
380
|
}
|
|
381
381
|
|
|
382
|
-
|
|
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
|
}
|
|
@@ -570,10 +570,6 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
570
570
|
this._context.renderer.setClearColor(rgbaColor, rgbaColor.alpha);
|
|
571
571
|
this.context.scene.background = null;
|
|
572
572
|
}
|
|
573
|
-
// HACK: if we set background-color to a color and then back to null we want the background-image attribute to re-apply
|
|
574
|
-
else if(this.getAttribute("background-image")) {
|
|
575
|
-
this.setAttribute("background-image", this.getAttribute("background-image")!);
|
|
576
|
-
}
|
|
577
573
|
}
|
|
578
574
|
}
|
|
579
575
|
|
|
@@ -993,50 +993,11 @@ 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
|
-
|
|
997
996
|
/**
|
|
998
997
|
* 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.
|
|
1000
998
|
*/
|
|
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
|
-
|
|
999
|
+
fitCamera(options?: OrbitFitCameraOptions): void {
|
|
1038
1000
|
const res = fitCamera({
|
|
1039
|
-
objects: [...objects],
|
|
1040
1001
|
...options,
|
|
1041
1002
|
autoApply: false,
|
|
1042
1003
|
context: this.context,
|