@needle-tools/engine 4.8.8-next.7387ba3 → 4.8.8-next.8add297
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -5
- package/README.md +1 -3
- package/components.needle.json +1 -1
- package/dist/{needle-engine.bundle-fg_vGCYe.umd.cjs → needle-engine.bundle-DwiJRlay.umd.cjs} +108 -108
- package/dist/{needle-engine.bundle-D47vIqsQ.js → needle-engine.bundle-DwigPmVZ.js} +2654 -2627
- package/dist/{needle-engine.bundle-Dm2TtQhy.min.js → needle-engine.bundle-WO60MbmU.min.js} +109 -109
- package/dist/needle-engine.d.ts +7 -0
- 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_addressables.js +2 -0
- package/lib/engine/engine_addressables.js.map +1 -1
- package/lib/engine/engine_animation.js +4 -4
- package/lib/engine/engine_animation.js.map +1 -1
- package/lib/engine/engine_assetdatabase.js +6 -6
- package/lib/engine/engine_assetdatabase.js.map +1 -1
- package/lib/engine/engine_camera.d.ts +3 -0
- package/lib/engine/engine_camera.js.map +1 -1
- package/lib/engine/engine_context.d.ts +8 -2
- package/lib/engine/engine_context.js +21 -3
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_create_objects.d.ts +3 -3
- package/lib/engine/engine_create_objects.js +5 -4
- package/lib/engine/engine_create_objects.js.map +1 -1
- package/lib/engine/engine_gameobject.js +2 -2
- package/lib/engine/engine_gameobject.js.map +1 -1
- package/lib/engine/engine_gltf_builtin_components.js +11 -11
- package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
- package/lib/engine/engine_loaders.callbacks.d.ts +1 -0
- package/lib/engine/engine_loaders.callbacks.js +1 -0
- package/lib/engine/engine_loaders.callbacks.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_lighting_settings.js +5 -2
- package/lib/engine/extensions/NEEDLE_lighting_settings.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/js-extensions/Object3D.d.ts +1 -1
- package/lib/engine/js-extensions/Vector.d.ts +5 -0
- package/lib/engine/js-extensions/Vector.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.d.ts +2 -2
- package/lib/engine/webcomponents/needle-engine.js +11 -18
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine-components/Camera.d.ts +2 -0
- package/lib/engine-components/Camera.js +5 -1
- package/lib/engine-components/Camera.js.map +1 -1
- package/lib/engine-components/ContactShadows.d.ts +12 -2
- package/lib/engine-components/ContactShadows.js +24 -4
- package/lib/engine-components/ContactShadows.js.map +1 -1
- package/lib/engine-components/DropListener.d.ts +4 -3
- package/lib/engine-components/DropListener.js +4 -3
- package/lib/engine-components/DropListener.js.map +1 -1
- package/lib/engine-components/NestedGltf.d.ts +9 -4
- package/lib/engine-components/NestedGltf.js +32 -26
- package/lib/engine-components/NestedGltf.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +29 -6
- package/lib/engine-components/OrbitControls.js +43 -7
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/Renderer.js +2 -1
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/Skybox.js +8 -9
- package/lib/engine-components/Skybox.js.map +1 -1
- package/lib/engine-components/api.d.ts +1 -0
- package/lib/engine-components/api.js.map +1 -1
- package/package.json +1 -1
- package/plugins/common/files.js +6 -3
- package/plugins/vite/editor-connection.js +4 -4
- package/src/engine/engine_addressables.ts +2 -0
- package/src/engine/engine_animation.ts +4 -4
- package/src/engine/engine_assetdatabase.ts +7 -7
- package/src/engine/engine_camera.ts +3 -1
- package/src/engine/engine_context.ts +22 -4
- package/src/engine/engine_create_objects.ts +8 -7
- package/src/engine/engine_gameobject.ts +2 -2
- package/src/engine/engine_gltf_builtin_components.ts +12 -11
- package/src/engine/engine_loaders.callbacks.ts +1 -0
- package/src/engine/extensions/NEEDLE_lighting_settings.ts +5 -2
- package/src/engine/extensions/NEEDLE_lightmaps.ts +1 -1
- package/src/engine/js-extensions/Vector.ts +6 -0
- package/src/engine/webcomponents/needle-engine.ts +10 -17
- package/src/engine-components/Camera.ts +7 -1
- package/src/engine-components/ContactShadows.ts +27 -6
- package/src/engine-components/DropListener.ts +4 -3
- package/src/engine-components/NestedGltf.ts +33 -24
- package/src/engine-components/OrbitControls.ts +65 -16
- package/src/engine-components/Renderer.ts +2 -1
- package/src/engine-components/Skybox.ts +9 -10
- package/src/engine-components/api.ts +2 -1
|
@@ -42,13 +42,13 @@ export type ObjectOptions = {
|
|
|
42
42
|
/**
|
|
43
43
|
* The position of the object in local space
|
|
44
44
|
*/
|
|
45
|
-
position?: Vec3 | [number, number, number],
|
|
45
|
+
position?: Partial<Vec3> | [number, number, number],
|
|
46
46
|
/** The rotation of the object in local space */
|
|
47
|
-
rotation?: Vec3 | [number, number, number],
|
|
47
|
+
rotation?: Partial<Vec3> | [number, number, number],
|
|
48
48
|
/**
|
|
49
49
|
* The scale of the object in local space
|
|
50
50
|
*/
|
|
51
|
-
scale?: Vec3 | number | [number, number, number],
|
|
51
|
+
scale?: Partial<Vec3> | number | [number, number, number],
|
|
52
52
|
/**
|
|
53
53
|
* If the object should receive shadows
|
|
54
54
|
* @default true
|
|
@@ -251,14 +251,15 @@ export class ObjectUtils {
|
|
|
251
251
|
if (opts?.position) {
|
|
252
252
|
if (Array.isArray(opts.position))
|
|
253
253
|
obj.position.set(opts.position[0], opts.position[1], opts.position[2]);
|
|
254
|
-
else
|
|
255
|
-
obj.position.set(opts.position.x, opts.position.y, opts.position.z);
|
|
254
|
+
else {
|
|
255
|
+
obj.position.set(opts.position.x || 0, opts.position.y || 0, opts.position.z || 0);
|
|
256
|
+
}
|
|
256
257
|
}
|
|
257
258
|
if (opts?.rotation) {
|
|
258
259
|
if (Array.isArray(opts.rotation))
|
|
259
260
|
obj.rotation.set(opts.rotation[0], opts.rotation[1], opts.rotation[2]);
|
|
260
261
|
else
|
|
261
|
-
obj.rotation.set(opts.rotation.x, opts.rotation.y, opts.rotation.z);
|
|
262
|
+
obj.rotation.set(opts.rotation.x || 0, opts.rotation.y || 0, opts.rotation.z || 0);
|
|
262
263
|
}
|
|
263
264
|
if (opts?.scale) {
|
|
264
265
|
if (typeof opts.scale === "number")
|
|
@@ -267,7 +268,7 @@ export class ObjectUtils {
|
|
|
267
268
|
obj.scale.set(opts.scale[0], opts.scale[1], opts.scale[2]);
|
|
268
269
|
}
|
|
269
270
|
else {
|
|
270
|
-
obj.scale.set(opts.scale.x, opts.scale.y, opts.scale.z);
|
|
271
|
+
obj.scale.set(opts.scale.x || 1, opts.scale.y || 1, opts.scale.z || 1);
|
|
271
272
|
|
|
272
273
|
}
|
|
273
274
|
}
|
|
@@ -166,9 +166,9 @@ export function destroy(instance: Object3D | Component, recursive: boolean = tru
|
|
|
166
166
|
setDestroyed(obj, true);
|
|
167
167
|
if (dispose) {
|
|
168
168
|
disposeObjectResources(obj);
|
|
169
|
+
// This needs to be called after disposing because it removes the references to resources
|
|
170
|
+
__internalRemoveReferences(obj);
|
|
169
171
|
}
|
|
170
|
-
// This needs to be called after disposing because it removes the references to resources
|
|
171
|
-
__internalRemoveReferences(obj);
|
|
172
172
|
}
|
|
173
173
|
destroyed_objects.length = 0;
|
|
174
174
|
destroyed_components.length = 0;
|
|
@@ -72,13 +72,13 @@ export async function createBuiltinComponents(context: Context, gltfId: SourceId
|
|
|
72
72
|
|
|
73
73
|
if (gltf.scenes) {
|
|
74
74
|
for (const scene of gltf.scenes) {
|
|
75
|
-
await onCreateBuiltinComponents(serializationContext, scene, deserializeQueue, lateResolve);
|
|
75
|
+
await onCreateBuiltinComponents(serializationContext, scene, deserializeQueue, lateResolve, 0);
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
// TODO: when is the gltf here an object3d?
|
|
79
79
|
if (gltf.children) {
|
|
80
80
|
for (const ch of gltf.children) {
|
|
81
|
-
await onCreateBuiltinComponents(serializationContext, ch, deserializeQueue, lateResolve);
|
|
81
|
+
await onCreateBuiltinComponents(serializationContext, ch, deserializeQueue, lateResolve, 0);
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -202,7 +202,7 @@ const unknownComponentsBuffer: Array<string> = [];
|
|
|
202
202
|
|
|
203
203
|
|
|
204
204
|
async function onCreateBuiltinComponents(context: SerializationContext, obj: Object3D,
|
|
205
|
-
deserialize: DeserializeData[], lateResolve: LateResolveCallback[]) {
|
|
205
|
+
deserialize: DeserializeData[], lateResolve: LateResolveCallback[], level: number) {
|
|
206
206
|
if (!obj) return;
|
|
207
207
|
|
|
208
208
|
// iterate injected data
|
|
@@ -267,20 +267,21 @@ async function onCreateBuiltinComponents(context: SerializationContext, obj: Obj
|
|
|
267
267
|
}
|
|
268
268
|
// console.debug("finished adding gltf builtin components", obj);
|
|
269
269
|
}
|
|
270
|
-
if (unknownComponentsBuffer.length > 0) {
|
|
271
|
-
const unknown = unknownComponentsBuffer.join(", ");
|
|
272
|
-
console.warn("unknown components: " + unknown);
|
|
273
|
-
unknownComponentsBuffer.length = 0;
|
|
274
|
-
if (isLocalNetwork())
|
|
275
|
-
showBalloonMessage(`<strong>Unknown components in scene</strong>:\n\n${unknown}\n\nThis could mean you forgot to add a npmdef to your ExportInfo\n<a href="https://engine.needle.tools/docs/project_structure.html#creating-and-installing-a-npmdef" target="_blank">documentation</a>`, LogType.Warn);
|
|
276
|
-
}
|
|
277
270
|
}
|
|
278
271
|
|
|
279
272
|
if (obj.children) {
|
|
280
273
|
for (const ch of obj.children) {
|
|
281
|
-
await onCreateBuiltinComponents(context, ch, deserialize, lateResolve);
|
|
274
|
+
await onCreateBuiltinComponents(context, ch, deserialize, lateResolve, level + 1);
|
|
282
275
|
}
|
|
283
276
|
}
|
|
277
|
+
|
|
278
|
+
if (unknownComponentsBuffer.length > 0 && level === 0) {
|
|
279
|
+
const unknown = unknownComponentsBuffer.join(", ");
|
|
280
|
+
console.warn(`Unknown components in scene: ${unknown}`);
|
|
281
|
+
unknownComponentsBuffer.length = 0;
|
|
282
|
+
if (isLocalNetwork())
|
|
283
|
+
showBalloonMessage(`<strong>Unknown components in scene</strong>:\n\n${unknown}\n\nThis could mean you forgot to add a npmdef to your ExportInfo\n<a href="https://engine.needle.tools/docs/project_structure.html#creating-and-installing-a-npmdef" target="_blank">documentation</a>`, LogType.Warn);
|
|
284
|
+
}
|
|
284
285
|
}
|
|
285
286
|
|
|
286
287
|
function handleDeserialization(data: DeserializeData, context: SerializationContext) {
|
|
@@ -98,6 +98,7 @@ export namespace NeedleEngineModelLoader {
|
|
|
98
98
|
* }
|
|
99
99
|
* return null;
|
|
100
100
|
* });
|
|
101
|
+
* ```
|
|
101
102
|
*/
|
|
102
103
|
export function onCreateCustomModelLoader(callback: CustomLoaderCallback, opts?: CustomLoaderOptions) {
|
|
103
104
|
const entry = { name: opts?.name, priority: opts?.priority ?? 0, callback };
|
|
@@ -169,8 +169,11 @@ export class SceneLightSettings extends Behaviour {
|
|
|
169
169
|
this._hemisphereLightObj.removeFromParent();
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
if (this.sourceId)
|
|
173
|
-
this.context.
|
|
172
|
+
if (this.sourceId) {
|
|
173
|
+
if (!this.context.domElement.getAttribute("environment-image")) {
|
|
174
|
+
this.context.sceneLighting.internalEnableReflection(this.sourceId);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
174
177
|
}
|
|
175
178
|
|
|
176
179
|
onDisable() {
|
|
@@ -70,7 +70,7 @@ export class NEEDLE_lightmaps implements GLTFLoaderPlugin {
|
|
|
70
70
|
console.log(entry);
|
|
71
71
|
let res: Promise<any> | null = null;
|
|
72
72
|
// Check if the pointer is a json pointer:
|
|
73
|
-
if (entry.pointer.startsWith("/textures/")) {
|
|
73
|
+
if (entry.pointer.startsWith("/textures/") || /** legacy support e.g. SOC */entry.pointer.startsWith("textures/")) {
|
|
74
74
|
if (debug) console.log("Load texture from gltf", entry.pointer);
|
|
75
75
|
res = resolveReferences(this.parser, entry.pointer).then(res => this.resolveTexture(entry, res));
|
|
76
76
|
}
|
|
@@ -10,6 +10,12 @@ export function apply(object: Vector3) {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
// NOTE: keep in sync with method declarations below
|
|
14
|
+
declare module 'three' {
|
|
15
|
+
export interface Vector3 {
|
|
16
|
+
slerp(end: Vector3, t: number): Vector3;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
13
19
|
|
|
14
20
|
Vector3.prototype["slerp"] = function (end: Vector3, t: number) {
|
|
15
21
|
return slerp(this, end, t);
|
|
@@ -55,8 +55,8 @@ const observedAttributes = [
|
|
|
55
55
|
* The needle engine web component creates and manages a needle engine context which is responsible for rendering a 3D scene using threejs.
|
|
56
56
|
* The needle engine context is created when the src attribute is set and disposed when the needle engine is removed from the document (you can prevent this by setting the keep-alive attribute to true).
|
|
57
57
|
* The needle engine context is accessible via the context property on the needle engine element (e.g. document.querySelector("needle-engine").context).
|
|
58
|
-
* @link https://engine.needle.tools/docs/reference/needle-engine-attributes
|
|
59
|
-
*
|
|
58
|
+
* See {@link https://engine.needle.tools/docs/reference/needle-engine-attributes}
|
|
59
|
+
*
|
|
60
60
|
* @example
|
|
61
61
|
* <needle-engine src="https://example.com/scene.glb"></needle-engine>
|
|
62
62
|
* @example
|
|
@@ -65,7 +65,7 @@ const observedAttributes = [
|
|
|
65
65
|
export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngineComponent {
|
|
66
66
|
|
|
67
67
|
static get observedAttributes() {
|
|
68
|
-
return observedAttributes
|
|
68
|
+
return observedAttributes;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
public get loadingProgress01(): number { return this._loadingProgress01; }
|
|
@@ -95,7 +95,7 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
95
95
|
/**
|
|
96
96
|
* Get the current context for this web component instance. The context is created when the src attribute is set and the loading has finished.
|
|
97
97
|
* The context is disposed when the needle engine is removed from the document (you can prevent this by setting the keep-alive attribute to true).
|
|
98
|
-
* @returns
|
|
98
|
+
* @returns a promise that resolves to the context when the loading has finished
|
|
99
99
|
*/
|
|
100
100
|
public getContext(): Promise<Context> {
|
|
101
101
|
return new Promise((res, _rej) => {
|
|
@@ -328,19 +328,12 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
328
328
|
break;
|
|
329
329
|
|
|
330
330
|
case "tonemapping":
|
|
331
|
-
case "tone-mapping":
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
case "
|
|
336
|
-
|
|
337
|
-
break;
|
|
338
|
-
}
|
|
339
|
-
case "background-blurriness": {
|
|
340
|
-
this.applyAttributes();
|
|
341
|
-
break;
|
|
342
|
-
}
|
|
343
|
-
case "environment-intensity": {
|
|
331
|
+
case "tone-mapping":
|
|
332
|
+
case "tone-mapping-exposure":
|
|
333
|
+
case "background-blurriness":
|
|
334
|
+
case "background-color":
|
|
335
|
+
case "environment-intensity":
|
|
336
|
+
{
|
|
344
337
|
this.applyAttributes();
|
|
345
338
|
break;
|
|
346
339
|
}
|
|
@@ -10,6 +10,7 @@ import { getTempColor, getWorldPosition } from "../engine/engine_three_utils.js"
|
|
|
10
10
|
import type { ICamera } from "../engine/engine_types.js"
|
|
11
11
|
import { getParam } from "../engine/engine_utils.js";
|
|
12
12
|
import { RGBAColor } from "../engine/js-extensions/index.js";
|
|
13
|
+
import { NeedleXREventArgs } from "../engine/engine_xr.js";
|
|
13
14
|
import { Behaviour, GameObject } from "./Component.js";
|
|
14
15
|
import { OrbitControls } from "./OrbitControls.js";
|
|
15
16
|
|
|
@@ -446,6 +447,11 @@ export class Camera extends Behaviour implements ICamera {
|
|
|
446
447
|
this.context.removeCamera(this);
|
|
447
448
|
}
|
|
448
449
|
|
|
450
|
+
onLeaveXR(_args: NeedleXREventArgs): void {
|
|
451
|
+
// Restore previous FOV
|
|
452
|
+
this.fieldOfView = this._fov;
|
|
453
|
+
}
|
|
454
|
+
|
|
449
455
|
|
|
450
456
|
/** @internal */
|
|
451
457
|
onBeforeRender() {
|
|
@@ -553,7 +559,7 @@ export class Camera extends Behaviour implements ICamera {
|
|
|
553
559
|
}
|
|
554
560
|
|
|
555
561
|
// restore previous fov (e.g. when user was in VR or AR and the camera's fov has changed)
|
|
556
|
-
this.fieldOfView = this.
|
|
562
|
+
this.fieldOfView = this.fieldOfView;
|
|
557
563
|
|
|
558
564
|
if (debug) {
|
|
559
565
|
const msg = `[Camera] Apply ClearFlags: ${ClearFlags[this._clearFlags]} - \"${this.name}\"`;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BackSide, CustomBlending, DoubleSide, FrontSide, Group, Material, Matrix4, MaxEquation, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshStandardMaterial, MinEquation, Object3D, OrthographicCamera, PlaneGeometry, RenderItem, ShaderMaterial, Vector3, WebGLRenderTarget } from "three";
|
|
1
|
+
import { BackSide, CustomBlending, DoubleSide, FrontSide, Group, Material, Matrix4, MaxEquation, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshStandardMaterial, MinEquation, Object3D, OrthographicCamera, PlaneGeometry, RenderItem, ShaderMaterial, Vector3, Vector3Like, WebGLRenderTarget } from "three";
|
|
2
2
|
import { HorizontalBlurShader } from 'three/examples/jsm/shaders/HorizontalBlurShader.js';
|
|
3
3
|
import { VerticalBlurShader } from 'three/examples/jsm/shaders/VerticalBlurShader.js';
|
|
4
4
|
|
|
@@ -27,7 +27,14 @@ onStart(ctx => {
|
|
|
27
27
|
shadows.darkness = intensity;
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
})
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
type FitParameters = {
|
|
34
|
+
object?: Object3D | Object3D[];
|
|
35
|
+
positionOffset?: Partial<Vector3Like>;
|
|
36
|
+
scaleFactor?: Partial<Vector3Like>;
|
|
37
|
+
}
|
|
31
38
|
|
|
32
39
|
// Adapted from https://github.com/mrdoob/three.js/blob/master/examples/webgl_shadow_contact.html.
|
|
33
40
|
|
|
@@ -50,7 +57,7 @@ export class ContactShadows extends Behaviour {
|
|
|
50
57
|
* @param context The context to create the contact shadows in.
|
|
51
58
|
* @returns The instance of the contact shadows.
|
|
52
59
|
*/
|
|
53
|
-
static auto(context?: Context): ContactShadows {
|
|
60
|
+
static auto(context?: Context, params?: FitParameters): ContactShadows {
|
|
54
61
|
if (!context) context = Context.Current;
|
|
55
62
|
if (!context) {
|
|
56
63
|
throw new Error("No context provided and no current context set.");
|
|
@@ -65,12 +72,13 @@ export class ContactShadows extends Behaviour {
|
|
|
65
72
|
this._instances.set(context, instance);
|
|
66
73
|
}
|
|
67
74
|
context.scene.add(instance.gameObject);
|
|
68
|
-
instance.fitShadows();
|
|
75
|
+
instance.fitShadows(params);
|
|
69
76
|
return instance;
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
/**
|
|
73
80
|
* When enabled the contact shadows component will be created to fit the whole scene.
|
|
81
|
+
* @default false
|
|
74
82
|
*/
|
|
75
83
|
@serializable()
|
|
76
84
|
autoFit: boolean = false;
|
|
@@ -107,12 +115,14 @@ export class ContactShadows extends Behaviour {
|
|
|
107
115
|
|
|
108
116
|
/**
|
|
109
117
|
* The minimum size of the shadows box
|
|
118
|
+
* @default undefined
|
|
110
119
|
*/
|
|
111
120
|
minSize?: Partial<Vec3>;
|
|
112
121
|
|
|
113
122
|
/**
|
|
114
123
|
* When enabled the shadows will not be updated automatically. Use `needsUpdate()` to update the shadows manually.
|
|
115
124
|
* This is useful when you want to update the shadows only when the scene changes.
|
|
125
|
+
* @default false
|
|
116
126
|
*/
|
|
117
127
|
manualUpdate: boolean = false;
|
|
118
128
|
/**
|
|
@@ -150,10 +160,11 @@ export class ContactShadows extends Behaviour {
|
|
|
150
160
|
/**
|
|
151
161
|
* Call to fit the shadows to the scene.
|
|
152
162
|
*/
|
|
153
|
-
fitShadows() {
|
|
163
|
+
fitShadows(params: FitParameters = {}) {
|
|
154
164
|
if (debug) console.warn("Fitting shadows to scene");
|
|
155
165
|
setAutoFitEnabled(this.shadowsRoot, false);
|
|
156
|
-
const
|
|
166
|
+
const objectToFit = params.object || this.context.scene;
|
|
167
|
+
const box = getBoundingBox(objectToFit, [this.shadowsRoot]);
|
|
157
168
|
// expand box in all directions (except below ground)
|
|
158
169
|
// 0.75 expands by 75% in each direction
|
|
159
170
|
// The "32" is pretty much heuristically determined – adjusting the value until we don't get a visible border anymore.
|
|
@@ -175,6 +186,16 @@ export class ContactShadows extends Behaviour {
|
|
|
175
186
|
// We can't move GroundProjection down because of immersive-ar mesh/plane tracking where occlusion would otherwise hide GroundProjection
|
|
176
187
|
this.shadowsRoot.position.set((min.x + box.max.x) / 2, min.y - offset, (min.z + box.max.z) / 2);
|
|
177
188
|
this.shadowsRoot.scale.set(box.max.x - min.x, box.max.y - min.y, box.max.z - min.z);
|
|
189
|
+
if (params.positionOffset) {
|
|
190
|
+
if (params.positionOffset.x !== undefined) this.shadowsRoot.position.x += params.positionOffset.x;
|
|
191
|
+
if (params.positionOffset.y !== undefined) this.shadowsRoot.position.y += params.positionOffset.y;
|
|
192
|
+
if (params.positionOffset.z !== undefined) this.shadowsRoot.position.z += params.positionOffset.z;
|
|
193
|
+
}
|
|
194
|
+
if (params.scaleFactor) {
|
|
195
|
+
if (params.scaleFactor.x !== undefined) this.shadowsRoot.scale.x *= params.scaleFactor.x;
|
|
196
|
+
if (params.scaleFactor.y !== undefined) this.shadowsRoot.scale.y *= params.scaleFactor.y;
|
|
197
|
+
if (params.scaleFactor.z !== undefined) this.shadowsRoot.scale.z *= params.scaleFactor.z;
|
|
198
|
+
}
|
|
178
199
|
this.applyMinSize();
|
|
179
200
|
this.shadowsRoot.matrixWorldNeedsUpdate = true;
|
|
180
201
|
if (debug) console.log("Fitted shadows to scene", this.shadowsRoot.scale.clone());
|
|
@@ -399,10 +399,11 @@ export class DropListener extends Behaviour {
|
|
|
399
399
|
private _abort: AbortController | null = null;
|
|
400
400
|
|
|
401
401
|
/**
|
|
402
|
-
* Processes dropped files
|
|
403
|
-
*
|
|
402
|
+
* Processes dropped files and loads them as 3D models.
|
|
403
|
+
* When enabled, it also handles network drops (sending files between clients).
|
|
404
|
+
* Automatically handles cancelling previous uploads if new files are dropped.
|
|
404
405
|
* @param fileList Array of dropped files
|
|
405
|
-
* @param ctx Context information about where the drop occurred
|
|
406
|
+
* @param ctx Context information about where on the screen or in 3D space the drop occurred
|
|
406
407
|
*/
|
|
407
408
|
private async addFromFiles(fileList: Array<File>, ctx: DropContext) {
|
|
408
409
|
if (debug) console.log("Add files", fileList)
|
|
@@ -4,6 +4,7 @@ import { InstantiateIdProvider } from "../engine/engine_networking_instantiate.j
|
|
|
4
4
|
import { serializable } from "../engine/engine_serialization_decorator.js";
|
|
5
5
|
import { getParam } from "../engine/engine_utils.js";
|
|
6
6
|
import { Behaviour } from "../engine-components/Component.js";
|
|
7
|
+
import { EventList } from "./EventList.js";
|
|
7
8
|
|
|
8
9
|
const debug = getParam("debugnestedgltf");
|
|
9
10
|
|
|
@@ -11,17 +12,21 @@ const debug = getParam("debugnestedgltf");
|
|
|
11
12
|
* It will load the gltf file and instantiate it as a child of the parent of the GameObject that has this component
|
|
12
13
|
*/
|
|
13
14
|
export class NestedGltf extends Behaviour {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
*/
|
|
15
|
+
|
|
16
|
+
/** A reference to the gltf file that should be loaded */
|
|
17
17
|
@serializable(AssetReference)
|
|
18
18
|
filePath?: AssetReference;
|
|
19
19
|
|
|
20
|
+
/** Invoked when the nested glTF file has been instantiated */
|
|
21
|
+
@serializable(EventList)
|
|
22
|
+
loaded: EventList<{ component: NestedGltf, instance: any, asset: AssetReference }> = new EventList();
|
|
23
|
+
|
|
20
24
|
/**
|
|
21
25
|
* EXPERIMENTAL for cloud asset loading
|
|
22
26
|
*/
|
|
23
27
|
loadAssetInParent = true;
|
|
24
28
|
|
|
29
|
+
|
|
25
30
|
private _isLoadingOrDoneLoading: boolean = false;
|
|
26
31
|
|
|
27
32
|
/** Register a callback that will be called when the progress of the loading changes */
|
|
@@ -31,7 +36,7 @@ export class NestedGltf extends Behaviour {
|
|
|
31
36
|
|
|
32
37
|
/** Begin loading the referenced gltf file in filePath */
|
|
33
38
|
preload() {
|
|
34
|
-
this.filePath?.preload();
|
|
39
|
+
return this.filePath?.preload() || null;
|
|
35
40
|
}
|
|
36
41
|
|
|
37
42
|
/** @internal */
|
|
@@ -41,27 +46,31 @@ export class NestedGltf extends Behaviour {
|
|
|
41
46
|
|
|
42
47
|
const parent = this.gameObject.parent;
|
|
43
48
|
if (parent) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
res
|
|
56
|
-
|
|
57
|
-
res.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
49
|
+
|
|
50
|
+
if (this.filePath) {
|
|
51
|
+
|
|
52
|
+
this._isLoadingOrDoneLoading = true;
|
|
53
|
+
const opts = new InstantiateOptions();
|
|
54
|
+
// we need to provide stable guids for creating nested gltfs
|
|
55
|
+
opts.idProvider = new InstantiateIdProvider(this.hash(this.guid));
|
|
56
|
+
opts.parent = this.loadAssetInParent !== false ? parent : this.gameObject;
|
|
57
|
+
this.gameObject.updateMatrix();
|
|
58
|
+
const matrix = this.gameObject.matrix;
|
|
59
|
+
if (debug) console.log("Load nested:", this.filePath?.url ?? this.filePath, this.gameObject.position);
|
|
60
|
+
const res = await this.filePath?.instantiate?.call(this.filePath, opts);
|
|
61
|
+
if (debug) console.log("Nested loaded:", this.filePath?.url ?? this.filePath, res);
|
|
62
|
+
if (res && this.loadAssetInParent !== false) {
|
|
63
|
+
res.matrixAutoUpdate = false;
|
|
64
|
+
res.matrix.identity();
|
|
65
|
+
res.applyMatrix4(matrix);
|
|
66
|
+
res.matrixAutoUpdate = true;
|
|
67
|
+
res.layers.disableAll();
|
|
68
|
+
res.layers.set(this.layer);
|
|
69
|
+
this.loaded.invoke({ component: this, instance: res, asset: this.filePath });
|
|
70
|
+
}
|
|
71
|
+
if (debug) console.log("Nested loading done:", this.filePath?.url ?? this.filePath, res);
|
|
63
72
|
}
|
|
64
|
-
|
|
73
|
+
|
|
65
74
|
}
|
|
66
75
|
}
|
|
67
76
|
|
|
@@ -889,6 +889,8 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
889
889
|
}
|
|
890
890
|
else this._fovLerpDuration = this.targetLerpDuration;
|
|
891
891
|
}
|
|
892
|
+
|
|
893
|
+
// if (this.context.mainCameraComponent) this.context.mainCameraComponent.fieldOfView = fov;
|
|
892
894
|
}
|
|
893
895
|
|
|
894
896
|
/** Moves the camera look-at target to a position smoothly.
|
|
@@ -984,10 +986,11 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
984
986
|
*/
|
|
985
987
|
fitCamera(options?: FitCameraOptions);
|
|
986
988
|
fitCamera(objects?: Object3D | Array<Object3D>, options?: Omit<FitCameraOptions, "objects">);
|
|
987
|
-
fitCamera(objectsOrOptions?: Object3D | Array<Object3D> | FitCameraOptions, options?: FitCameraOptions) {
|
|
989
|
+
fitCamera(objectsOrOptions?: Object3D | Array<Object3D> | FitCameraOptions, options?: FitCameraOptions): void {
|
|
988
990
|
|
|
989
991
|
if (this.context.isInXR) {
|
|
990
992
|
// camera fitting in XR is not supported
|
|
993
|
+
console.warn('[OrbitControls] Can not fit camera while XR session is active');
|
|
991
994
|
return;
|
|
992
995
|
}
|
|
993
996
|
|
|
@@ -1032,7 +1035,7 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1032
1035
|
return;
|
|
1033
1036
|
}
|
|
1034
1037
|
if (!options) options = {}
|
|
1035
|
-
const { immediate = false, centerCamera
|
|
1038
|
+
const { immediate = false, centerCamera, cameraNearFar = "auto", fitOffset = 1.1, fov = camera?.fov } = options;
|
|
1036
1039
|
const size = new Vector3();
|
|
1037
1040
|
const center = new Vector3();
|
|
1038
1041
|
// TODO would be much better to calculate the bounds in camera space instead of world space -
|
|
@@ -1041,15 +1044,13 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1041
1044
|
// and thus we're just getting some maximum that will work for sure.
|
|
1042
1045
|
const box = getBoundingBox(objects, undefined, this._camera?.threeCamera?.layers);
|
|
1043
1046
|
const boxCopy = box.clone();
|
|
1044
|
-
|
|
1045
|
-
camera.updateMatrixWorld();
|
|
1046
|
-
camera.updateProjectionMatrix();
|
|
1047
1047
|
box.getCenter(center);
|
|
1048
1048
|
|
|
1049
1049
|
const box_size = new Vector3();
|
|
1050
1050
|
box.getSize(box_size);
|
|
1051
1051
|
|
|
1052
1052
|
// project this box into camera space
|
|
1053
|
+
camera.updateMatrixWorld();
|
|
1053
1054
|
box.applyMatrix4(camera.matrixWorldInverse);
|
|
1054
1055
|
|
|
1055
1056
|
box.getSize(size);
|
|
@@ -1078,9 +1079,18 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1078
1079
|
this.minZoom = distance * 0.01;
|
|
1079
1080
|
|
|
1080
1081
|
const verticalOffset = 0.05;
|
|
1081
|
-
|
|
1082
1082
|
const lookAt = center.clone();
|
|
1083
1083
|
lookAt.y -= size.y * verticalOffset;
|
|
1084
|
+
if (options.targetOffset) {
|
|
1085
|
+
if (options.targetOffset.x !== undefined) lookAt.x += options.targetOffset.x;
|
|
1086
|
+
if (options.targetOffset.y !== undefined) lookAt.y += options.targetOffset.y;
|
|
1087
|
+
if (options.targetOffset.z !== undefined) lookAt.z += options.targetOffset.z;
|
|
1088
|
+
}
|
|
1089
|
+
if (options.relativeTargetOffset) {
|
|
1090
|
+
if (options.relativeTargetOffset.x !== undefined) lookAt.x += options.relativeTargetOffset.x * size.x;
|
|
1091
|
+
if (options.relativeTargetOffset.y !== undefined) lookAt.y += options.relativeTargetOffset.y * size.y;
|
|
1092
|
+
if (options.relativeTargetOffset.z !== undefined) lookAt.z += options.relativeTargetOffset.z * size.z;
|
|
1093
|
+
}
|
|
1084
1094
|
this.setLookTargetPosition(lookAt, immediate);
|
|
1085
1095
|
this.setFieldOfView(options.fov, immediate);
|
|
1086
1096
|
|
|
@@ -1092,6 +1102,7 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1092
1102
|
// TODO: this doesnt take the Camera component nearClipPlane into account
|
|
1093
1103
|
camera.near = (distance / 100);
|
|
1094
1104
|
camera.far = boundsMax + distance * 10;
|
|
1105
|
+
camera.updateProjectionMatrix();
|
|
1095
1106
|
|
|
1096
1107
|
// adjust maxZoom so that the ground projection radius is always inside
|
|
1097
1108
|
if (groundprojection) {
|
|
@@ -1104,12 +1115,13 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1104
1115
|
if (currentZoom < this.minZoom) this.minZoom = currentZoom * 0.9;
|
|
1105
1116
|
if (currentZoom > this.maxZoom) this.maxZoom = currentZoom * 1.1;
|
|
1106
1117
|
|
|
1107
|
-
camera.updateMatrixWorld();
|
|
1108
|
-
camera.updateProjectionMatrix();
|
|
1109
|
-
|
|
1110
|
-
const cameraWp = getWorldPosition(camera);
|
|
1111
1118
|
const direction = center.clone();
|
|
1112
|
-
|
|
1119
|
+
if (options.fitDirection) {
|
|
1120
|
+
direction.sub(new Vector3().copy(options.fitDirection).multiplyScalar(1_000_000));
|
|
1121
|
+
}
|
|
1122
|
+
else {
|
|
1123
|
+
direction.sub(camera.worldPosition);
|
|
1124
|
+
}
|
|
1113
1125
|
if (centerCamera === "y")
|
|
1114
1126
|
direction.y = 0;
|
|
1115
1127
|
direction.normalize();
|
|
@@ -1118,6 +1130,16 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1118
1130
|
direction.y += -verticalOffset * 4 * distance;
|
|
1119
1131
|
|
|
1120
1132
|
let cameraLocalPosition = center.clone().sub(direction);
|
|
1133
|
+
if (options.cameraOffset) {
|
|
1134
|
+
if (options.cameraOffset.x !== undefined) cameraLocalPosition.x += options.cameraOffset.x;
|
|
1135
|
+
if (options.cameraOffset.y !== undefined) cameraLocalPosition.y += options.cameraOffset.y;
|
|
1136
|
+
if (options.cameraOffset.z !== undefined) cameraLocalPosition.z += options.cameraOffset.z;
|
|
1137
|
+
}
|
|
1138
|
+
if (options.relativeCameraOffset) {
|
|
1139
|
+
if (options.relativeCameraOffset.x !== undefined) cameraLocalPosition.x += options.relativeCameraOffset.x * size.x;
|
|
1140
|
+
if (options.relativeCameraOffset.y !== undefined) cameraLocalPosition.y += options.relativeCameraOffset.y * size.y;
|
|
1141
|
+
if (options.relativeCameraOffset.z !== undefined) cameraLocalPosition.z += options.relativeCameraOffset.z * size.z;
|
|
1142
|
+
}
|
|
1121
1143
|
if (camera.parent) {
|
|
1122
1144
|
cameraLocalPosition = camera.parent.worldToLocal(cameraLocalPosition);
|
|
1123
1145
|
}
|
|
@@ -1154,7 +1176,7 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1154
1176
|
/**
|
|
1155
1177
|
* Options for fitting the camera to the scene. Used in {@link OrbitControls.fitCamera}
|
|
1156
1178
|
*/
|
|
1157
|
-
|
|
1179
|
+
export type FitCameraOptions = {
|
|
1158
1180
|
/** When enabled debug rendering will be shown */
|
|
1159
1181
|
debug?: boolean,
|
|
1160
1182
|
/**
|
|
@@ -1166,14 +1188,41 @@ declare type FitCameraOptions = {
|
|
|
1166
1188
|
*/
|
|
1167
1189
|
immediate?: boolean,
|
|
1168
1190
|
|
|
1191
|
+
/** Fit offset: A factor to multiply the distance to the objects by
|
|
1192
|
+
* @default 1.1
|
|
1193
|
+
*/
|
|
1194
|
+
fitOffset?: number,
|
|
1195
|
+
|
|
1196
|
+
/** The direction from which the camera should be fitted in worldspace. If not defined the current camera's position will be used */
|
|
1197
|
+
fitDirection?: Vector3Like,
|
|
1198
|
+
|
|
1169
1199
|
/** If set to "y" the camera will be centered in the y axis */
|
|
1170
1200
|
centerCamera?: "none" | "y",
|
|
1201
|
+
/** Set to 'auto' to update the camera near or far plane based on the fitted-objects bounds */
|
|
1171
1202
|
cameraNearFar?: "keep" | "auto",
|
|
1172
1203
|
|
|
1173
|
-
|
|
1204
|
+
/**
|
|
1205
|
+
* Offset the camera position in world space
|
|
1206
|
+
*/
|
|
1207
|
+
cameraOffset?: Partial<Vector3Like>,
|
|
1208
|
+
/**
|
|
1209
|
+
* Offset the camera position relative to the size of the objects being focused on (e.g. x: 0.5).
|
|
1210
|
+
* Value range: -1 to 1
|
|
1211
|
+
*/
|
|
1212
|
+
relativeCameraOffset?: Partial<Vector3Like>,
|
|
1174
1213
|
|
|
1175
|
-
/**
|
|
1176
|
-
*
|
|
1214
|
+
/**
|
|
1215
|
+
* Offset the camera target position in world space
|
|
1177
1216
|
*/
|
|
1178
|
-
|
|
1217
|
+
targetOffset?: Partial<Vector3Like>,
|
|
1218
|
+
/**
|
|
1219
|
+
* Offset the camera target position relative to the size of the objects being focused on.
|
|
1220
|
+
* Value range: -1 to 1
|
|
1221
|
+
*/
|
|
1222
|
+
relativeTargetOffset?: Partial<Vector3Like>,
|
|
1223
|
+
|
|
1224
|
+
/**
|
|
1225
|
+
* Field of view (FOV) for the camera
|
|
1226
|
+
*/
|
|
1227
|
+
fov?: number,
|
|
1179
1228
|
}
|
|
@@ -706,7 +706,8 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
706
706
|
}
|
|
707
707
|
|
|
708
708
|
if (this.reflectionProbeUsage !== ReflectionProbeUsage.Off && this._reflectionProbe) {
|
|
709
|
-
this.
|
|
709
|
+
if (!this._lightmaps?.length) // Currently reflectionprobes cant be used with lightmaps
|
|
710
|
+
this._reflectionProbe.onSet(this);
|
|
710
711
|
}
|
|
711
712
|
// since three 163 we need to set the envMap to the scene envMap if it is not set
|
|
712
713
|
// otherwise the envmapIntensity has no effect: https://github.com/mrdoob/three.js/pull/27903
|