@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.
@@ -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 { getTempQuaternion, getTempVector } from "../../engine/engine_three_utils.js";
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, .3);
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, enabledGizmoColor, 0, true, this.gameObject.worldQuaternion);
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
- let runner = ViewBox.runners.get(this.context);
147
- if (!runner) {
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
- projectionMatrixCopy.copy(camera.projectionMatrix);
210
- projectionMatrixInverseCopy.copy(camera.projectionMatrixInverse);
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 = viewBox.referenceFieldOfView;
139
+ camera.fov = this.referenceFieldOfView;
219
140
  camera.updateProjectionMatrix();
220
141
 
221
142
 
222
- const boxPosition = viewBox.gameObject.worldPosition;
223
- const boxScale = viewBox.gameObject.worldScale;
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 (viewBox.debug || debugParam) console.warn("[ViewBox] Moving camera out of bounds", distance, "<", boxSizeMax);
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
- // const boxPositionInCameraSpace = getTempVector(boxPosition);
258
-
259
- // Ensure the camera looks at the box position
260
- // camera.worldToLocal(boxPositionInCameraSpace);
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 = viewBox.referenceFieldOfView * Math.PI / 180; // convert vertical fov to radians
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(viewBox, camera, 1);
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
- if (interpolationDelta < 1) {
296
- this.currentX = Mathf.lerp(this.currentX, vec.x, interpolationDelta);
297
- this.currentY = Mathf.lerp(this.currentY, vec.y, interpolationDelta);
298
- this.currentZoom = Mathf.lerp(this.currentZoom, rectZoom, interpolationDelta);
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(projectionMatrixCopy);
318
- camera.projectionMatrixInverse.copy(projectionMatrixInverseCopy);
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(comp: ViewBox, camera: Camera, _factor: number) {
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(comp.gameObject.matrixWorld);
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 !== comp.context.domElement)
365
- comp.context.domElement.appendChild(this._projectedBoxElement);
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) * comp.context.domWidth) + "px";
370
- this._projectedBoxElement.style.top = ((-maxY * .5 + .5) * comp.context.domHeight) + "px";
371
- this._projectedBoxElement.style.width = ((maxX - minX) * .5 * comp.context.domWidth) + "px";
372
- this._projectedBoxElement.style.height = ((maxY - minY) * .5 * comp.context.domHeight) + "px";
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
+ }