@needle-tools/engine 4.10.1-next.ffb3f90 → 4.10.2-next.298bf98
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/dist/{needle-engine.bundle-rOOXObYF.js → needle-engine.bundle-BEhuJG_V.js} +4121 -4155
- package/dist/{needle-engine.bundle-Cya6w82Z.umd.cjs → needle-engine.bundle-CZxIzgIZ.umd.cjs} +111 -111
- package/dist/{needle-engine.bundle-Bn8PNDsX.min.js → needle-engine.bundle-w-nDhfZa.min.js} +112 -112
- package/dist/needle-engine.js +2 -2
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/lib/engine/engine_three_utils.d.ts +7 -1
- package/lib/engine/engine_three_utils.js +9 -7
- package/lib/engine/engine_three_utils.js.map +1 -1
- package/lib/engine-components/web/HoverAnimation.d.ts +4 -0
- package/lib/engine-components/web/HoverAnimation.js +5 -1
- package/lib/engine-components/web/HoverAnimation.js.map +1 -1
- package/lib/engine-components/web/ViewBox.d.ts +8 -18
- package/lib/engine-components/web/ViewBox.js +55 -135
- package/lib/engine-components/web/ViewBox.js.map +1 -1
- package/package.json +1 -1
- package/src/engine/engine_three_utils.ts +11 -1
- package/src/engine-components/web/HoverAnimation.ts +5 -1
- package/src/engine-components/web/ViewBox.ts +49 -142
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { Camera, Matrix4, PerspectiveCamera, Quaternion, Scene, Vector2, Vector3 } from "three";
|
|
2
2
|
|
|
3
3
|
import { isDevEnvironment } from "../../engine/debug/debug.js";
|
|
4
|
-
import type { Context } from "../../engine/engine_context.js";
|
|
5
4
|
import { Gizmos } from "../../engine/engine_gizmos.js";
|
|
6
|
-
import { Mathf } from "../../engine/engine_math.js";
|
|
7
5
|
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
|
8
|
-
import {
|
|
6
|
+
import { getTempVector } from "../../engine/engine_three_utils.js";
|
|
9
7
|
import { registerType } from "../../engine/engine_typestore.js";
|
|
10
8
|
import { getParam } from "../../engine/engine_utils.js";
|
|
11
9
|
import { RGBAColor } from "../../engine/js-extensions/RGBAColor.js";
|
|
@@ -13,8 +11,7 @@ import { Behaviour } from "../Component.js";
|
|
|
13
11
|
|
|
14
12
|
|
|
15
13
|
const debugParam = getParam("debugviewbox");
|
|
16
|
-
const disabledGizmoColor = new RGBAColor(.5, .5, .5, .
|
|
17
|
-
const enabledGizmoColor = new RGBAColor(.5, .5, 0, 1);
|
|
14
|
+
const disabledGizmoColor = new RGBAColor(.5, .5, .5, .5);
|
|
18
15
|
|
|
19
16
|
/**
|
|
20
17
|
* This component can be used to automatically fit a certain box area into the camera view - no matter your screen size or aspect ratio.
|
|
@@ -40,24 +37,8 @@ const enabledGizmoColor = new RGBAColor(.5, .5, 0, 1);
|
|
|
40
37
|
@registerType
|
|
41
38
|
export class ViewBox extends Behaviour {
|
|
42
39
|
|
|
43
|
-
/** All known viewbox instances */
|
|
44
40
|
static readonly instances: ViewBox[] = [];
|
|
45
41
|
|
|
46
|
-
/**
|
|
47
|
-
* The currently active viewbox (the last one that was set active). If you have multiple viewboxes in your scene, only the active one will be used.
|
|
48
|
-
* Note that the last viewbox may be inactive if its component is disabled or disabled in the hierarchy.
|
|
49
|
-
* @returns The active viewbox or null if none is active
|
|
50
|
-
*/
|
|
51
|
-
static get activeInstance(): ViewBox | null {
|
|
52
|
-
if (ViewBox.instances.length === 0) return null;
|
|
53
|
-
return ViewBox.instances[ViewBox.instances.length - 1];
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* A runner instance is used per context to update the viewbox
|
|
58
|
-
*/
|
|
59
|
-
private static readonly runners: WeakMap<Context, Runner> = new WeakMap();
|
|
60
|
-
|
|
61
42
|
/**
|
|
62
43
|
* The reference field of view is used to calculate the box size. This should usually be the same as your camera's fov.
|
|
63
44
|
* @default -1 (meaning it will use the camera fov on the first frame)
|
|
@@ -71,20 +52,6 @@ export class ViewBox extends Behaviour {
|
|
|
71
52
|
@serializable()
|
|
72
53
|
debug: boolean = false;
|
|
73
54
|
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Set this ViewBox as the active one (if you have multiple in your scene). The last active one will be used.
|
|
77
|
-
* @returns self for chaining
|
|
78
|
-
*/
|
|
79
|
-
setActive(): this {
|
|
80
|
-
this.enabled = true;
|
|
81
|
-
const idx = ViewBox.instances.indexOf(this);
|
|
82
|
-
if (idx !== -1) ViewBox.instances.splice(idx, 1);
|
|
83
|
-
ViewBox.instances.push(this);
|
|
84
|
-
return this;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/** @internal */
|
|
88
55
|
onEnable(): void {
|
|
89
56
|
if (debugParam || this.debug || isDevEnvironment()) console.debug("[ViewBox] Using camera fov:", this.referenceFieldOfView);
|
|
90
57
|
// register instance
|
|
@@ -94,12 +61,12 @@ export class ViewBox extends Behaviour {
|
|
|
94
61
|
this.context.pre_render_callbacks.push(this.internalUpdate);
|
|
95
62
|
}
|
|
96
63
|
|
|
97
|
-
/** @internal */
|
|
98
64
|
onDisable(): void {
|
|
99
65
|
if (debugParam || this.debug) console.debug("[ViewBox] Disabled");
|
|
100
66
|
// unregister instance
|
|
101
67
|
const idx = ViewBox.instances.indexOf(this);
|
|
102
68
|
if (idx !== -1) ViewBox.instances.splice(idx, 1);
|
|
69
|
+
this._projectedBoxElement?.remove();
|
|
103
70
|
this.removeUpdateCallback();
|
|
104
71
|
}
|
|
105
72
|
|
|
@@ -109,6 +76,9 @@ export class ViewBox extends Behaviour {
|
|
|
109
76
|
if (cbIdx !== -1) this.context.pre_render_callbacks.splice(cbIdx, 1);
|
|
110
77
|
}
|
|
111
78
|
|
|
79
|
+
private static readonly _tempProjectionMatrix: Matrix4 = new Matrix4();
|
|
80
|
+
private static readonly _tempProjectionMatrixInverse: Matrix4 = new Matrix4();
|
|
81
|
+
|
|
112
82
|
private internalUpdate = () => {
|
|
113
83
|
if (this.context.isInXR) return;
|
|
114
84
|
if (this.destroyed || !this.activeAndEnabled) return;
|
|
@@ -119,18 +89,13 @@ export class ViewBox extends Behaviour {
|
|
|
119
89
|
}
|
|
120
90
|
return;
|
|
121
91
|
}
|
|
122
|
-
if (debugParam || this.debug) Gizmos.DrawWireBox(this.gameObject.worldPosition, this.gameObject.worldScale,
|
|
123
|
-
|
|
92
|
+
if (debugParam || this.debug) Gizmos.DrawWireBox(this.gameObject.worldPosition, this.gameObject.worldScale, 0xdddd00, 0, true, this.gameObject.worldQuaternion);
|
|
124
93
|
|
|
125
94
|
// calculate box size to fit the camera frustrum size at the current position (just scale)
|
|
126
95
|
const camera = this.context.mainCamera;
|
|
127
96
|
if (!camera) return;
|
|
128
97
|
if (!(camera instanceof PerspectiveCamera)) {
|
|
129
98
|
// TODO: support orthographic camera
|
|
130
|
-
if (!this["__warnedOrthographic"]) {
|
|
131
|
-
console.warn("[ViewBox] Only perspective cameras are supported.");
|
|
132
|
-
this["__warnedOrthographic"] = true;
|
|
133
|
-
}
|
|
134
99
|
return;
|
|
135
100
|
}
|
|
136
101
|
|
|
@@ -138,65 +103,21 @@ export class ViewBox extends Behaviour {
|
|
|
138
103
|
this.referenceFieldOfView = camera.fov;
|
|
139
104
|
console.debug("[ViewBox] No referenceFieldOfView set, using camera fov:", this.referenceFieldOfView);
|
|
140
105
|
}
|
|
106
|
+
|
|
141
107
|
if (this.referenceFieldOfView === undefined || this.referenceFieldOfView <= 0) {
|
|
142
108
|
if (debugParam || this.debug) console.warn("[ViewBox] No valid referenceFieldOfView set, cannot adjust box size:", this.referenceFieldOfView);
|
|
143
109
|
return;
|
|
144
110
|
}
|
|
145
111
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
runner = new Runner();
|
|
149
|
-
ViewBox.runners.set(this.context, runner);
|
|
150
|
-
}
|
|
151
|
-
runner.update(this);
|
|
152
|
-
|
|
153
|
-
// BACKLOG: some code for box scale of an object (different component)
|
|
154
|
-
// this.gameObject.worldScale = getTempVector(width, height, worldscale.z);
|
|
155
|
-
// this.gameObject.scale.multiplyScalar(.98)
|
|
156
|
-
// const minscale = Math.min(width, height);
|
|
157
|
-
// console.log(width, height);
|
|
158
|
-
// this.gameObject.worldScale = getTempVector(scale, scale, scale);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const projectionMatrixCopy: Matrix4 = new Matrix4();
|
|
167
|
-
const projectionMatrixInverseCopy: Matrix4 = new Matrix4();
|
|
168
|
-
|
|
169
|
-
class Runner {
|
|
170
|
-
|
|
171
|
-
private lastActiveViewBox: ViewBox | null = null;
|
|
172
|
-
private lastViewBoxChangeTime: number = -1;
|
|
173
|
-
private currentX: number = 0;
|
|
174
|
-
private currentY: number = 0;
|
|
175
|
-
private currentZoom: number = 1;
|
|
176
|
-
|
|
177
|
-
update(viewBox: ViewBox) {
|
|
178
|
-
|
|
179
|
-
const context = viewBox.context;
|
|
180
|
-
const camera = viewBox.context.mainCamera;
|
|
181
|
-
if (!(camera instanceof PerspectiveCamera)) return;
|
|
182
|
-
|
|
183
|
-
if (this.lastActiveViewBox !== viewBox) {
|
|
184
|
-
if (this.lastActiveViewBox === null)
|
|
185
|
-
this.lastViewBoxChangeTime = -100; // long ago
|
|
186
|
-
else
|
|
187
|
-
this.lastViewBoxChangeTime = context.time.time;
|
|
188
|
-
this.lastActiveViewBox = viewBox;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const domWidth = context.domWidth;
|
|
192
|
-
const domHeight = context.domHeight;
|
|
112
|
+
const domWidth = this.context.domWidth;
|
|
113
|
+
const domHeight = this.context.domHeight;
|
|
193
114
|
|
|
194
115
|
let rectWidth = domWidth;
|
|
195
116
|
let rectHeight = domHeight;
|
|
196
117
|
let diffWidth = 1;
|
|
197
118
|
let diffHeight = 1;
|
|
198
119
|
// use focus rect if available
|
|
199
|
-
const focusRectSize = context.focusRectSize;
|
|
120
|
+
const focusRectSize = this.context.focusRectSize;
|
|
200
121
|
if (focusRectSize) {
|
|
201
122
|
rectWidth = focusRectSize.width;
|
|
202
123
|
rectHeight = focusRectSize.height;
|
|
@@ -206,8 +127,8 @@ class Runner {
|
|
|
206
127
|
|
|
207
128
|
|
|
208
129
|
// Copy the projection matrix and restore values so we can reset it later
|
|
209
|
-
|
|
210
|
-
|
|
130
|
+
ViewBox._tempProjectionMatrix.copy(camera.projectionMatrix);
|
|
131
|
+
ViewBox._tempProjectionMatrixInverse.copy(camera.projectionMatrixInverse);
|
|
211
132
|
const view = camera.view;
|
|
212
133
|
const zoom = camera.zoom;
|
|
213
134
|
const aspect = camera.aspect;
|
|
@@ -215,18 +136,16 @@ class Runner {
|
|
|
215
136
|
// Set values to default so we can calculate the box size correctly
|
|
216
137
|
camera.view = null;
|
|
217
138
|
camera.zoom = 1;
|
|
218
|
-
camera.fov =
|
|
139
|
+
camera.fov = this.referenceFieldOfView;
|
|
219
140
|
camera.updateProjectionMatrix();
|
|
220
141
|
|
|
221
142
|
|
|
222
|
-
const boxPosition =
|
|
223
|
-
const boxScale =
|
|
143
|
+
const boxPosition = this.gameObject.worldPosition;
|
|
144
|
+
const boxScale = this.gameObject.worldScale;
|
|
224
145
|
|
|
225
146
|
const cameraPosition = camera.worldPosition;
|
|
226
147
|
const distance = cameraPosition.distanceTo(boxPosition);
|
|
227
148
|
|
|
228
|
-
const timeSinceViewBoxChanged = context.time.time - this.lastViewBoxChangeTime;
|
|
229
|
-
const interpolationDelta = timeSinceViewBoxChanged < 1 ? (context.time.deltaTime / .1) : 1;
|
|
230
149
|
|
|
231
150
|
// #region camera fixes
|
|
232
151
|
// If the camera is inside the box, move it out
|
|
@@ -234,13 +153,13 @@ class Runner {
|
|
|
234
153
|
const direction = getTempVector(cameraPosition).sub(boxPosition);
|
|
235
154
|
if (distance < boxSizeMax) {
|
|
236
155
|
// move camera out of bounds
|
|
237
|
-
if (
|
|
156
|
+
if (this.debug || debugParam) console.warn("[ViewBox] Moving camera out of bounds", distance, "<", boxSizeMax);
|
|
238
157
|
const positionDirection = getTempVector(direction);
|
|
239
158
|
positionDirection.y *= .00000001; // stay on horizontal plane mostly
|
|
240
159
|
positionDirection.normalize();
|
|
241
160
|
const lengthToMove = (boxSizeMax - distance);
|
|
242
161
|
const newPosition = cameraPosition.add(positionDirection.multiplyScalar(lengthToMove));
|
|
243
|
-
camera.worldPosition = newPosition.lerp(cameraPosition, 1 - context.time.deltaTime);
|
|
162
|
+
camera.worldPosition = newPosition.lerp(cameraPosition, 1 - this.context.time.deltaTime);
|
|
244
163
|
}
|
|
245
164
|
|
|
246
165
|
// Ensure the camera looks at the ViewBox
|
|
@@ -254,26 +173,18 @@ class Runner {
|
|
|
254
173
|
// camera.worldQuaternion = rotation;
|
|
255
174
|
// camera.updateMatrixWorld();
|
|
256
175
|
// }
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
// if (interpolationDelta < 1) {
|
|
262
|
-
// const startRotation = interpolationDelta < 1 ? getTempQuaternion(camera.quaternion) : null;
|
|
263
|
-
// camera.lookAt(boxPosition);
|
|
264
|
-
// if (startRotation !== null) {
|
|
265
|
-
// camera.quaternion.slerpQuaternions(startRotation, camera.quaternion, interpolationDelta);
|
|
266
|
-
// }
|
|
267
|
-
// camera.updateMatrixWorld();
|
|
268
|
-
// }
|
|
176
|
+
const boxPositionInCameraSpace = getTempVector(boxPosition);
|
|
177
|
+
camera.worldToLocal(boxPositionInCameraSpace);
|
|
178
|
+
camera.lookAt(boxPosition);
|
|
179
|
+
camera.updateMatrixWorld();
|
|
269
180
|
|
|
270
181
|
|
|
271
182
|
// #region calculate fit
|
|
272
|
-
const vFOV =
|
|
183
|
+
const vFOV = this.referenceFieldOfView * Math.PI / 180; // convert vertical fov to radians
|
|
273
184
|
const height = 2 * Math.tan(vFOV / 2) * distance; // visible height
|
|
274
185
|
const width = height * camera.aspect; // visible width
|
|
275
186
|
|
|
276
|
-
const projectedBox = this.projectBoxIntoCamera(
|
|
187
|
+
const projectedBox = this.projectBoxIntoCamera(camera, 1);
|
|
277
188
|
// return
|
|
278
189
|
const boxWidth = (projectedBox.maxX - projectedBox.minX);
|
|
279
190
|
const boxHeight = (projectedBox.maxY - projectedBox.minY);
|
|
@@ -284,38 +195,33 @@ class Runner {
|
|
|
284
195
|
width / diffWidth,
|
|
285
196
|
height / diffHeight
|
|
286
197
|
);
|
|
287
|
-
const rectZoom = scale / (height * .5);
|
|
288
198
|
// console.log({ scale, width, height, boxWidth: boxWidth * camera.aspect, boxHeight, diffWidth, diffHeight, aspect: camera.aspect, distance })
|
|
289
199
|
// this.context.focusRectSettings.zoom = 1.39;
|
|
290
200
|
// if (!this.context.focusRect) this.context.setCameraFocusRect(this.context.domElement);
|
|
291
201
|
// return
|
|
292
202
|
const vec = getTempVector(boxPosition);
|
|
293
203
|
vec.project(camera);
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
}
|
|
300
|
-
else {
|
|
301
|
-
this.currentX = vec.x;
|
|
302
|
-
this.currentY = vec.y;
|
|
303
|
-
this.currentZoom = rectZoom;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Apply new values
|
|
307
|
-
context.focusRectSettings.offsetX = this.currentX;
|
|
308
|
-
context.focusRectSettings.offsetY = this.currentY;
|
|
309
|
-
context.focusRectSettings.zoom = this.currentZoom;
|
|
310
|
-
if (!context.focusRect) context.setCameraFocusRect(context.domElement); // if we don't have a focus rect yet, set it to the dom element
|
|
204
|
+
this.context.focusRectSettings.offsetX = vec.x;
|
|
205
|
+
this.context.focusRectSettings.offsetY = vec.y;
|
|
206
|
+
this.context.focusRectSettings.zoom = scale / (height * .5);
|
|
207
|
+
// if we don't have a focus rect yet, set it to the dom element
|
|
208
|
+
if (!this.context.focusRect) this.context.setCameraFocusRect(this.context.domElement);
|
|
311
209
|
|
|
312
210
|
// Reset values
|
|
313
211
|
camera.view = view;
|
|
314
212
|
camera.zoom = zoom;
|
|
315
213
|
camera.aspect = aspect;
|
|
316
214
|
camera.fov = fov;
|
|
317
|
-
camera.projectionMatrix.copy(
|
|
318
|
-
camera.projectionMatrixInverse.copy(
|
|
215
|
+
camera.projectionMatrix.copy(ViewBox._tempProjectionMatrix);
|
|
216
|
+
camera.projectionMatrixInverse.copy(ViewBox._tempProjectionMatrixInverse);
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
// BACKLOG: some code for box scale of an object (different component)
|
|
220
|
+
// this.gameObject.worldScale = getTempVector(width, height, worldscale.z);
|
|
221
|
+
// this.gameObject.scale.multiplyScalar(.98)
|
|
222
|
+
// const minscale = Math.min(width, height);
|
|
223
|
+
// console.log(width, height);
|
|
224
|
+
// this.gameObject.worldScale = getTempVector(scale, scale, scale);
|
|
319
225
|
}
|
|
320
226
|
|
|
321
227
|
|
|
@@ -330,7 +236,7 @@ class Runner {
|
|
|
330
236
|
|
|
331
237
|
|
|
332
238
|
|
|
333
|
-
private projectBoxIntoCamera(
|
|
239
|
+
private projectBoxIntoCamera(camera: Camera, _factor: number) {
|
|
334
240
|
const factor = .5 * _factor;
|
|
335
241
|
|
|
336
242
|
const corners = [
|
|
@@ -349,7 +255,7 @@ class Runner {
|
|
|
349
255
|
let maxY = Number.NEGATIVE_INFINITY;
|
|
350
256
|
for (let i = 0; i < corners.length; i++) {
|
|
351
257
|
const c = corners[i];
|
|
352
|
-
c.applyMatrix4(
|
|
258
|
+
c.applyMatrix4(this.gameObject.matrixWorld);
|
|
353
259
|
c.project(camera);
|
|
354
260
|
if (c.x < minX) minX = c.x;
|
|
355
261
|
if (c.x > maxX) maxX = c.x;
|
|
@@ -361,15 +267,15 @@ class Runner {
|
|
|
361
267
|
if (!this._projectedBoxElement) {
|
|
362
268
|
this._projectedBoxElement = document.createElement("div");
|
|
363
269
|
}
|
|
364
|
-
if (this._projectedBoxElement.parentElement !==
|
|
365
|
-
|
|
270
|
+
if (this._projectedBoxElement.parentElement !== this.context.domElement)
|
|
271
|
+
this.context.domElement.appendChild(this._projectedBoxElement);
|
|
366
272
|
this._projectedBoxElement.style.position = "fixed";
|
|
367
273
|
// dotted but with larger gaps
|
|
368
274
|
this._projectedBoxElement.style.outline = "2px dashed rgba(255,0,0,.5)";
|
|
369
|
-
this._projectedBoxElement.style.left = ((minX * .5 + .5) *
|
|
370
|
-
this._projectedBoxElement.style.top = ((-maxY * .5 + .5) *
|
|
371
|
-
this._projectedBoxElement.style.width = ((maxX - minX) * .5 *
|
|
372
|
-
this._projectedBoxElement.style.height = ((maxY - minY) * .5 *
|
|
275
|
+
this._projectedBoxElement.style.left = ((minX * .5 + .5) * this.context.domWidth) + "px";
|
|
276
|
+
this._projectedBoxElement.style.top = ((-maxY * .5 + .5) * this.context.domHeight) + "px";
|
|
277
|
+
this._projectedBoxElement.style.width = ((maxX - minX) * .5 * this.context.domWidth) + "px";
|
|
278
|
+
this._projectedBoxElement.style.height = ((maxY - minY) * .5 * this.context.domHeight) + "px";
|
|
373
279
|
this._projectedBoxElement.style.pointerEvents = "none";
|
|
374
280
|
this._projectedBoxElement.style.zIndex = "1000";
|
|
375
281
|
}
|
|
@@ -382,4 +288,5 @@ class Runner {
|
|
|
382
288
|
|
|
383
289
|
|
|
384
290
|
|
|
385
|
-
|
|
291
|
+
|
|
292
|
+
}
|