@needle-tools/engine 2.55.0-pre → 2.55.1-pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/needle-engine.d.ts +12 -10
- package/dist/needle-engine.js +346 -346
- package/dist/needle-engine.js.map +4 -4
- package/dist/needle-engine.min.js +22 -22
- package/dist/needle-engine.min.js.map +4 -4
- package/dist/needle-engine.tsbuildinfo +1 -1
- package/lib/engine/engine_serialization_core.js +20 -10
- package/lib/engine/engine_serialization_core.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_lightmaps.js +3 -1
- package/lib/engine/extensions/NEEDLE_lightmaps.js.map +1 -1
- package/lib/engine-components/Camera.d.ts +1 -2
- package/lib/engine-components/Camera.js +8 -10
- package/lib/engine-components/Camera.js.map +1 -1
- package/lib/engine-components/LODGroup.js +9 -0
- package/lib/engine-components/LODGroup.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +8 -7
- package/lib/engine-components/OrbitControls.js +38 -7
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/ParticleSystem.js +7 -1
- package/lib/engine-components/ParticleSystem.js.map +1 -1
- package/lib/engine-components/ParticleSystemModules.d.ts +1 -1
- package/lib/engine-components/ParticleSystemModules.js +2 -2
- package/lib/engine-components/ParticleSystemModules.js.map +1 -1
- package/lib/engine-components/Renderer.js +16 -2
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/js-extensions/RGBAColor.d.ts +2 -0
- package/lib/engine-components/js-extensions/RGBAColor.js +2 -0
- package/lib/engine-components/js-extensions/RGBAColor.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/engine/codegen/register_types.js +2 -2
- package/src/engine/engine_serialization_core.ts +25 -13
- package/src/engine/extensions/NEEDLE_lightmaps.ts +3 -1
- package/src/engine-components/Camera.ts +10 -15
- package/src/engine-components/LODGroup.ts +9 -0
- package/src/engine-components/OrbitControls.ts +58 -19
- package/src/engine-components/ParticleSystem.ts +9 -2
- package/src/engine-components/ParticleSystemModules.ts +2 -2
- package/src/engine-components/Renderer.ts +19 -2
- package/src/engine-components/js-extensions/RGBAColor.ts +3 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "2.55.
|
|
3
|
+
"version": "2.55.1-pre",
|
|
4
4
|
"description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development, and can be deployed anywhere. It is flexible, extensible, and collaboration and XR come naturally.",
|
|
5
5
|
"main": "dist/needle-engine.js",
|
|
6
6
|
"module": "src/needle-engine.ts",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TypeStore } from "./../engine_typestore"
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
// Import types
|
|
4
4
|
import { __Ignore } from "../../engine-components/codegen/components.ts";
|
|
5
5
|
import { AlignmentConstraint } from "../../engine-components/AlignmentConstraint.ts";
|
|
@@ -172,7 +172,7 @@ import { XRGrabModel } from "../../engine-components/WebXRGrabRendering.ts";
|
|
|
172
172
|
import { XRGrabRendering } from "../../engine-components/WebXRGrabRendering.ts";
|
|
173
173
|
import { XRRig } from "../../engine-components/WebXRRig.ts";
|
|
174
174
|
import { XRState } from "../../engine-components/XRFlag.ts";
|
|
175
|
-
|
|
175
|
+
|
|
176
176
|
// Register types
|
|
177
177
|
TypeStore.add("__Ignore", __Ignore);
|
|
178
178
|
TypeStore.add("AlignmentConstraint", AlignmentConstraint);
|
|
@@ -5,7 +5,7 @@ import { Context } from "./engine_setup";
|
|
|
5
5
|
import { isPersistentAsset } from "./extensions/NEEDLE_persistent_assets";
|
|
6
6
|
import { IComponent, SourceIdentifier } from "./engine_types";
|
|
7
7
|
import { debugExtension } from "../engine/engine_default_parameters";
|
|
8
|
-
import { LogType, showBalloonMessage } from "./debug/debug";
|
|
8
|
+
import { LogType, showBalloonMessage, showBalloonWarning } from "./debug/debug";
|
|
9
9
|
import { isLocalNetwork } from "./engine_networking_utils";
|
|
10
10
|
import { $BuiltInTypeFlag } from "./engine_typestore";
|
|
11
11
|
|
|
@@ -357,7 +357,7 @@ export function deserializeObject(obj: ISerializable, serializedData: object, co
|
|
|
357
357
|
const blockChecks = getParam("noerrors");
|
|
358
358
|
function checkObjectAssignments(obj: any, serializedData: any, implementationInformation?: ImplementationInformation) {
|
|
359
359
|
if (blockChecks) return;
|
|
360
|
-
if(!serializedData) return;
|
|
360
|
+
if (!serializedData) return;
|
|
361
361
|
if (isLocalNetwork() === false) return;
|
|
362
362
|
if (!obj) return;
|
|
363
363
|
|
|
@@ -371,7 +371,17 @@ function checkObjectAssignments(obj: any, serializedData: any, implementationInf
|
|
|
371
371
|
if (key === "sourceId") continue;
|
|
372
372
|
const value = obj[key];
|
|
373
373
|
const serialized = serializedData[key];
|
|
374
|
+
// check if the field is defined in the class
|
|
374
375
|
if (implementationInformation?.getDefinedKey(typeName, key) === false) {
|
|
376
|
+
|
|
377
|
+
// if the field is defined but the defined key is uppercase we need to show a warning
|
|
378
|
+
// because all fields are serialized in lowercase
|
|
379
|
+
const firstCharUppercase = key.charAt(0).toUpperCase() + key.slice(1);
|
|
380
|
+
if (implementationInformation.getDefinedKey(typeName, firstCharUppercase)) {
|
|
381
|
+
showBalloonWarning("<strong>Please rename</strong> \"" + firstCharUppercase + "\" to \"" + key + "\" in " + typeName);
|
|
382
|
+
console.warn("Please use lowercase for field: \"" + firstCharUppercase + "\" in " + typeName, serialized, obj);
|
|
383
|
+
}
|
|
384
|
+
|
|
375
385
|
continue;
|
|
376
386
|
}
|
|
377
387
|
if (serialized === undefined || serialized === null) continue;
|
|
@@ -385,14 +395,16 @@ function checkObjectAssignments(obj: any, serializedData: any, implementationInf
|
|
|
385
395
|
if (!hasOtherKeys) {
|
|
386
396
|
showBalloonMessage(`<strong>Missing serialization for object reference!</strong>\n\nPlease change to: \n@serializable(Object3D)\n${key}? : Object3D;\n\nin script ${typeName}.ts\n<a href="https://docs.needle.tools/serializable" target="_blank">documentation</a>`, LogType.Warn);
|
|
387
397
|
console.warn(typeName, key, obj[key], obj);
|
|
398
|
+
continue;
|
|
388
399
|
}
|
|
389
400
|
}
|
|
390
401
|
}
|
|
391
402
|
}
|
|
392
|
-
|
|
403
|
+
if (typeof value === "string") {
|
|
393
404
|
if (serialized.endsWith(".gltf") || serialized.endsWith(".glb")) {
|
|
394
405
|
showBalloonMessage(`<strong>Missing serialization for object reference!</strong>\n\nPlease change to: \n@serializable(AssetReference)\n${key}? : AssetReference;\n\nin script ${typeName}.ts\n<a href="https://docs.needle.tools/serializable" target="_blank">documentation</a>`, LogType.Warn);
|
|
395
406
|
console.warn(typeName, key, obj[key], obj);
|
|
407
|
+
continue;
|
|
396
408
|
}
|
|
397
409
|
}
|
|
398
410
|
}
|
|
@@ -421,16 +433,16 @@ function implictlyAssignPrimitiveTypes(obj: any, serializedData: any) {
|
|
|
421
433
|
}
|
|
422
434
|
}
|
|
423
435
|
}
|
|
436
|
+
}
|
|
424
437
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
}
|
|
432
|
-
return false;
|
|
438
|
+
function isPrimitiveType(val): boolean {
|
|
439
|
+
switch (typeof val) {
|
|
440
|
+
case "number":
|
|
441
|
+
case "string":
|
|
442
|
+
case "boolean":
|
|
443
|
+
return true;
|
|
433
444
|
}
|
|
445
|
+
return false;
|
|
434
446
|
}
|
|
435
447
|
|
|
436
448
|
// this is a wrapper for the cached serializer
|
|
@@ -459,7 +471,7 @@ function deserializeObjectWithType(data: any, typeOrConstructor: Constructor<any
|
|
|
459
471
|
}
|
|
460
472
|
}
|
|
461
473
|
context.type = type;
|
|
462
|
-
|
|
474
|
+
|
|
463
475
|
// e.g. when @serializable(Texture) and the texture is already resolved via json pointer from gltf
|
|
464
476
|
// then we dont need to do anything else
|
|
465
477
|
if (!typeIsFunction && currentValue instanceof type) return currentValue;
|
|
@@ -531,7 +543,7 @@ function deserializeObjectWithType(data: any, typeOrConstructor: Constructor<any
|
|
|
531
543
|
}
|
|
532
544
|
else {
|
|
533
545
|
// happens when exporting e.g. Animation component with only clip assigned (clips array is marked as serialized but it might be undefined if no clips are assigned in e.g. blender)
|
|
534
|
-
if(data === undefined) return undefined;
|
|
546
|
+
if (data === undefined) return undefined;
|
|
535
547
|
// the fallback - this assumes that the type has a constructor that accepts the serialized arguments
|
|
536
548
|
// made originally with THREE.Vector3 in mind but SHOULD actually not be used/called anymore
|
|
537
549
|
instance = new type(...setBuffer(data));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ILightDataRegistry } from "../engine_lightdata";
|
|
2
|
-
import { FloatType, HalfFloatType, sRGBEncoding, Texture } from "three";
|
|
2
|
+
import { FloatType, HalfFloatType, LinearEncoding, sRGBEncoding, Texture } from "three";
|
|
3
3
|
import { GLTF, GLTFLoaderPlugin, GLTFParser } from "three/examples/jsm/loaders/GLTFLoader";
|
|
4
4
|
import { SourceIdentifier } from "../engine_types";
|
|
5
5
|
import { resolveReferences } from "./extension_utils";
|
|
@@ -70,6 +70,8 @@ export class NEEDLE_lightmaps implements GLTFLoaderPlugin {
|
|
|
70
70
|
// TODO this is most likely wrong for floating point textures
|
|
71
71
|
if (entry.type !== LightmapType.Lightmap)
|
|
72
72
|
tex.encoding = sRGBEncoding;
|
|
73
|
+
else
|
|
74
|
+
tex.encoding = LinearEncoding;
|
|
73
75
|
|
|
74
76
|
// not sure why, but seems EXR-loaded float textures need to be flipped
|
|
75
77
|
if (entry.type === LightmapType.Skybox) {
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import { Behaviour
|
|
2
|
-
import * as THREE from "three";
|
|
3
|
-
// import { OrbitControls } from "./OrbitControls";
|
|
1
|
+
import { Behaviour } from "./Component";
|
|
4
2
|
import { getParam } from "../engine/engine_utils";
|
|
5
3
|
import { serializable } from "../engine/engine_serialization_decorator";
|
|
6
4
|
import { RGBAColor } from "./js-extensions/RGBAColor";
|
|
7
|
-
import { PerspectiveCamera, Ray } from "three";
|
|
8
5
|
import { XRSessionMode } from "../engine/engine_setup";
|
|
9
6
|
import { ICamera } from "../engine/engine_types"
|
|
10
7
|
import { showBalloonMessage } from "../engine/debug/debug";
|
|
11
8
|
import { getWorldPosition } from "../engine/engine_three_utils";
|
|
12
9
|
import { Gizmos } from "../engine/engine_gizmos";
|
|
13
10
|
|
|
11
|
+
import { EquirectangularReflectionMapping, OrthographicCamera, PerspectiveCamera, Ray, sRGBEncoding, Vector3 } from "three";
|
|
12
|
+
|
|
14
13
|
export enum ClearFlags {
|
|
15
14
|
Skybox = 1,
|
|
16
15
|
SolidColor = 2,
|
|
@@ -37,7 +36,7 @@ export class Camera extends Behaviour implements ICamera {
|
|
|
37
36
|
const changed = this._fov != val;
|
|
38
37
|
this._fov = val;
|
|
39
38
|
if (changed && this._cam) {
|
|
40
|
-
if (this._cam instanceof
|
|
39
|
+
if (this._cam instanceof PerspectiveCamera) {
|
|
41
40
|
this._cam.fov = this._fov;
|
|
42
41
|
this._cam.updateProjectionMatrix();
|
|
43
42
|
}
|
|
@@ -148,16 +147,14 @@ export class Camera extends Behaviour implements ICamera {
|
|
|
148
147
|
private _clearFlags: ClearFlags = ClearFlags.SolidColor;
|
|
149
148
|
private _skybox?: CameraSkybox;
|
|
150
149
|
|
|
151
|
-
|
|
152
150
|
public get cam(): THREE.PerspectiveCamera | THREE.OrthographicCamera {
|
|
153
151
|
if (this.activeAndEnabled)
|
|
154
152
|
this.buildCamera();
|
|
155
153
|
return this._cam!;
|
|
156
154
|
}
|
|
157
155
|
|
|
158
|
-
|
|
159
|
-
private static
|
|
160
|
-
private static _direction: THREE.Vector3 = new THREE.Vector3();
|
|
156
|
+
private static _origin: THREE.Vector3 = new Vector3();
|
|
157
|
+
private static _direction: THREE.Vector3 = new Vector3();
|
|
161
158
|
public screenPointToRay(x: number, y: number, ray?: Ray): Ray {
|
|
162
159
|
let cam = this.cam;
|
|
163
160
|
const origin = Camera._origin;
|
|
@@ -231,12 +228,12 @@ export class Camera extends Behaviour implements ICamera {
|
|
|
231
228
|
}
|
|
232
229
|
}
|
|
233
230
|
else if (!this.orthographic) {
|
|
234
|
-
cam = new
|
|
231
|
+
cam = new PerspectiveCamera(this.fieldOfView, window.innerWidth / window.innerHeight, this._nearClipPlane, this._farClipPlane);
|
|
235
232
|
cam.fov = this.fieldOfView;
|
|
236
233
|
}
|
|
237
234
|
else {
|
|
238
235
|
const factor = this.orthographicSize * 100;
|
|
239
|
-
cam = new
|
|
236
|
+
cam = new OrthographicCamera(window.innerWidth / -factor, window.innerWidth / factor, window.innerHeight / factor, window.innerHeight / -factor, this._nearClipPlane, this._farClipPlane);
|
|
240
237
|
}
|
|
241
238
|
this._cam = cam;
|
|
242
239
|
|
|
@@ -312,7 +309,6 @@ export class Camera extends Behaviour implements ICamera {
|
|
|
312
309
|
return transparent;
|
|
313
310
|
}
|
|
314
311
|
|
|
315
|
-
|
|
316
312
|
private enableSkybox() {
|
|
317
313
|
if (!this._skybox)
|
|
318
314
|
this._skybox = new CameraSkybox(this);
|
|
@@ -340,10 +336,9 @@ class CameraSkybox {
|
|
|
340
336
|
else if(this.context.scene.background !== this._skybox) {
|
|
341
337
|
if (debug)
|
|
342
338
|
console.log("Set skybox", this._camera, this._skybox);
|
|
343
|
-
this._skybox.encoding =
|
|
344
|
-
this._skybox.mapping =
|
|
339
|
+
this._skybox.encoding = sRGBEncoding;
|
|
340
|
+
this._skybox.mapping = EquirectangularReflectionMapping;
|
|
345
341
|
this.context.scene.background = this._skybox;
|
|
346
342
|
}
|
|
347
343
|
}
|
|
348
|
-
|
|
349
344
|
}
|
|
@@ -108,6 +108,7 @@ export class LODGroup extends Behaviour {
|
|
|
108
108
|
this.gameObject.add(handler);
|
|
109
109
|
}
|
|
110
110
|
const empty = new THREE.Object3D();
|
|
111
|
+
empty.name = "Cull " + this.name;
|
|
111
112
|
if (debug)
|
|
112
113
|
console.log(renderers);
|
|
113
114
|
for (let i = 0; i < renderers.length; i++) {
|
|
@@ -132,6 +133,10 @@ export class LODGroup extends Behaviour {
|
|
|
132
133
|
const dist = lod.model.distance;
|
|
133
134
|
lodDistanceDiff = dist - maxDistance;
|
|
134
135
|
maxDistance = Math.max(dist, maxDistance);
|
|
136
|
+
if (object.type === "Group") {
|
|
137
|
+
console.warn("LODGroup: Group is not supported as LOD object", obj.name, object);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
135
140
|
this.onAddLodLevel(handler, object, dist);
|
|
136
141
|
}
|
|
137
142
|
const cullDistance = maxDistance + lodDistanceDiff;
|
|
@@ -155,6 +160,10 @@ export class LODGroup extends Behaviour {
|
|
|
155
160
|
}
|
|
156
161
|
|
|
157
162
|
private onAddLodLevel(lod: THREE.LOD, obj: THREE.Object3D, dist: number) {
|
|
163
|
+
if(obj === this.gameObject) {
|
|
164
|
+
console.warn("LODGroup component must be on parent object and not mesh directly at the moment", obj.name, obj)
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
158
167
|
lod.addLevel(obj, dist * this._distanceFactor);
|
|
159
168
|
const setting = { lod: lod, levelIndex: lod.levels.length - 1, distance: dist };
|
|
160
169
|
this._settings.push(setting)
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Behaviour, GameObject } from "./Component";
|
|
2
|
-
|
|
3
|
-
import { OrbitControls as ThreeOrbitControls } from "three/examples/jsm/controls/OrbitControls";
|
|
2
|
+
import { Camera } from "./Camera";
|
|
4
3
|
import { LookAtConstraint } from "./LookAtConstraint";
|
|
5
|
-
import
|
|
6
|
-
import { getWorldPosition, setWorldPosition, slerp } from "../engine/engine_three_utils";
|
|
4
|
+
import { getWorldPosition, slerp } from "../engine/engine_three_utils";
|
|
7
5
|
import { RaycastOptions } from "../engine/engine_physics";
|
|
8
6
|
import { serializable } from "../engine/engine_serialization_decorator";
|
|
9
|
-
import { Camera } from "./Camera";
|
|
10
7
|
import { getParam, isMobileDevice } from "../engine/engine_utils";
|
|
11
8
|
|
|
9
|
+
import { Box3, Object3D, PerspectiveCamera, Vector2, Vector3 } from "three";
|
|
10
|
+
import { OrbitControls as ThreeOrbitControls } from "three/examples/jsm/controls/OrbitControls";
|
|
11
|
+
|
|
12
12
|
const freeCam = getParam("freecam");
|
|
13
13
|
|
|
14
14
|
const disabledKeys = { LEFT: "", UP: "", RIGHT: "", BOTTOM: "" };
|
|
@@ -19,7 +19,7 @@ export class OrbitControls extends Behaviour {
|
|
|
19
19
|
return this._controls;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
public get controllerObject():
|
|
22
|
+
public get controllerObject(): Object3D | null {
|
|
23
23
|
return this._cameraObject;
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -45,29 +45,27 @@ export class OrbitControls extends Behaviour {
|
|
|
45
45
|
// remove once slerp works correctly
|
|
46
46
|
useSlerp: boolean = true;
|
|
47
47
|
|
|
48
|
-
|
|
49
48
|
debugLog: boolean = false;
|
|
50
49
|
targetLerpSpeed = 5;
|
|
51
50
|
|
|
52
|
-
private _lookTargetPosition!:
|
|
51
|
+
private _lookTargetPosition!: Vector3;
|
|
53
52
|
private _controls: ThreeOrbitControls | null = null;
|
|
54
|
-
private _cameraObject:
|
|
53
|
+
private _cameraObject: Object3D | null = null;
|
|
55
54
|
|
|
56
55
|
private _lerpToTargetPosition: boolean = false;
|
|
57
56
|
private _lerpCameraToTarget: boolean = false;
|
|
58
|
-
private _cameraTargetPosition:
|
|
57
|
+
private _cameraTargetPosition: Vector3 | null = null;
|
|
59
58
|
|
|
60
59
|
private _inputs: number = 0;
|
|
61
60
|
private _enableTime: number = 0; // use to disable double click when double clicking on UI
|
|
62
61
|
private _startedListeningToKeyEvents: boolean = false;
|
|
63
62
|
|
|
64
63
|
awake(): void {
|
|
65
|
-
this._lookTargetPosition = new
|
|
64
|
+
this._lookTargetPosition = new Vector3();
|
|
66
65
|
this._startedListeningToKeyEvents = false;
|
|
67
66
|
}
|
|
68
67
|
|
|
69
68
|
onEnable() {
|
|
70
|
-
|
|
71
69
|
this._enableTime = this.context.time.time;
|
|
72
70
|
const camGo = GameObject.getComponent(this.gameObject, Camera);
|
|
73
71
|
const cam = camGo?.cam;
|
|
@@ -119,7 +117,6 @@ export class OrbitControls extends Behaviour {
|
|
|
119
117
|
}
|
|
120
118
|
}
|
|
121
119
|
|
|
122
|
-
|
|
123
120
|
onDisable() {
|
|
124
121
|
if (this._controls) {
|
|
125
122
|
this._controls.enabled = false;
|
|
@@ -138,7 +135,7 @@ export class OrbitControls extends Behaviour {
|
|
|
138
135
|
if (camGo && !this.setFromTargetPosition()) {
|
|
139
136
|
if (this.debugLog)
|
|
140
137
|
console.log("NO TARGET");
|
|
141
|
-
const forward = new
|
|
138
|
+
const forward = new Vector3(0, 0, -1).applyMatrix4(camGo.cam.matrixWorld);
|
|
142
139
|
this.setTarget(forward, true);
|
|
143
140
|
}
|
|
144
141
|
}
|
|
@@ -151,7 +148,7 @@ export class OrbitControls extends Behaviour {
|
|
|
151
148
|
if (!this.setFromTargetPosition()) {
|
|
152
149
|
const opts = new RaycastOptions();
|
|
153
150
|
// center of the screen:
|
|
154
|
-
opts.screenPoint = new
|
|
151
|
+
opts.screenPoint = new Vector2(0, 0);
|
|
155
152
|
opts.lineThreshold = 0.1;
|
|
156
153
|
const hits = this.context.physics.raycast(opts);
|
|
157
154
|
if (hits.length > 0) {
|
|
@@ -229,7 +226,7 @@ export class OrbitControls extends Behaviour {
|
|
|
229
226
|
}
|
|
230
227
|
}
|
|
231
228
|
|
|
232
|
-
public setCameraTarget(position?:
|
|
229
|
+
public setCameraTarget(position?: Vector3 | null, immediate: boolean = false) {
|
|
233
230
|
if (!position) this._lerpCameraToTarget = false;
|
|
234
231
|
else {
|
|
235
232
|
this._lerpCameraToTarget = true;
|
|
@@ -254,7 +251,7 @@ export class OrbitControls extends Behaviour {
|
|
|
254
251
|
return false;
|
|
255
252
|
}
|
|
256
253
|
|
|
257
|
-
public setTarget(position:
|
|
254
|
+
public setTarget(position: Vector3 | null = null, immediate: boolean = false) {
|
|
258
255
|
if (!this._controls) return;
|
|
259
256
|
if (position !== null) this._lookTargetPosition.copy(position);
|
|
260
257
|
if (immediate)
|
|
@@ -262,12 +259,12 @@ export class OrbitControls extends Behaviour {
|
|
|
262
259
|
else this._lerpToTargetPosition = true;
|
|
263
260
|
}
|
|
264
261
|
|
|
265
|
-
public lerpTarget(position:
|
|
262
|
+
public lerpTarget(position: Vector3, delta: number) {
|
|
266
263
|
if (!this._controls) return;
|
|
267
264
|
this._controls.target.lerp(position, delta);
|
|
268
265
|
}
|
|
269
266
|
|
|
270
|
-
public distanceToTarget(position:
|
|
267
|
+
public distanceToTarget(position: Vector3): number {
|
|
271
268
|
if (!this._controls) return -1;
|
|
272
269
|
return this._controls.target.distanceTo(position);
|
|
273
270
|
}
|
|
@@ -296,6 +293,48 @@ export class OrbitControls extends Behaviour {
|
|
|
296
293
|
}
|
|
297
294
|
}
|
|
298
295
|
|
|
296
|
+
// Adapted from https://discourse.threejs.org/t/camera-zoom-to-fit-object/936/24
|
|
297
|
+
// 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
|
|
298
|
+
fitCameraToObjects(objects: Array<Object3D>, fitOffset: number = 1.5) {
|
|
299
|
+
const camera = this._cameraObject as PerspectiveCamera;
|
|
300
|
+
const controls = this._controls as ThreeOrbitControls | null;
|
|
301
|
+
|
|
302
|
+
if (!camera || !controls) return;
|
|
303
|
+
|
|
304
|
+
const size = new Vector3();
|
|
305
|
+
const center = new Vector3();
|
|
306
|
+
const box = new Box3();
|
|
307
|
+
|
|
308
|
+
box.makeEmpty();
|
|
309
|
+
for (const object of objects)
|
|
310
|
+
box.expandByObject(object);
|
|
311
|
+
|
|
312
|
+
box.getSize( size );
|
|
313
|
+
box.getCenter( center );
|
|
314
|
+
|
|
315
|
+
const maxSize = Math.max(size.x, size.y, size.z);
|
|
316
|
+
const fitHeightDistance = maxSize / (2 * Math.atan( Math.PI * camera.fov / 360 ));
|
|
317
|
+
const fitWidthDistance = fitHeightDistance / camera.aspect;
|
|
318
|
+
const distance = fitOffset * Math.max(fitHeightDistance, fitWidthDistance);
|
|
319
|
+
|
|
320
|
+
const direction = controls.target.clone()
|
|
321
|
+
.sub(camera.position)
|
|
322
|
+
.normalize()
|
|
323
|
+
.multiplyScalar(distance);
|
|
324
|
+
|
|
325
|
+
controls.maxDistance = distance * 10;
|
|
326
|
+
controls.minDistance = distance * 0.01;
|
|
327
|
+
controls.target.copy(center);
|
|
328
|
+
|
|
329
|
+
camera.near = distance / 100;
|
|
330
|
+
camera.far = distance * 100;
|
|
331
|
+
camera.updateProjectionMatrix();
|
|
332
|
+
|
|
333
|
+
camera.position.copy(controls.target).sub(direction);
|
|
334
|
+
|
|
335
|
+
controls.update();
|
|
336
|
+
}
|
|
337
|
+
|
|
299
338
|
// private onPositionDrag(){
|
|
300
339
|
|
|
301
340
|
// }
|
|
@@ -153,6 +153,7 @@ class ParticleSystemEmissionOverTime extends BaseValueGenerator {
|
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
genValue(): number {
|
|
156
|
+
if (!this.system.emission.enabled) return 0;
|
|
156
157
|
if (this.system.currentParticles >= this.system.maxParticles) return 0;
|
|
157
158
|
// emission over time
|
|
158
159
|
let emission = this.system.emission.rateOverTime.evaluate(this.system.time / this.system.duration, Math.random());
|
|
@@ -225,9 +226,15 @@ class TextureSheetAnimationBehaviour extends ParticleSystemBaseBehaviour {
|
|
|
225
226
|
|
|
226
227
|
}
|
|
227
228
|
|
|
229
|
+
const $particleRotation = Symbol("particleRotation")
|
|
230
|
+
|
|
228
231
|
class RotationBehaviour extends ParticleSystemBaseBehaviour {
|
|
229
232
|
type: string = "NeedleRotation"
|
|
230
233
|
|
|
234
|
+
initialize(particle: Particle) {
|
|
235
|
+
particle[$particleRotation] = Math.random();
|
|
236
|
+
}
|
|
237
|
+
|
|
231
238
|
update(particle: Particle, delta: number) {
|
|
232
239
|
if (particle.rotation === undefined) return;
|
|
233
240
|
|
|
@@ -235,7 +242,7 @@ class RotationBehaviour extends ParticleSystemBaseBehaviour {
|
|
|
235
242
|
|
|
236
243
|
if (typeof particle.rotation === "number") {
|
|
237
244
|
if (this.system.rotationOverLifetime.enabled) {
|
|
238
|
-
particle.rotation += this.system.rotationOverLifetime.evaluate(t) * delta;
|
|
245
|
+
particle.rotation += this.system.rotationOverLifetime.evaluate(t, particle[$particleRotation]) * delta;
|
|
239
246
|
}
|
|
240
247
|
else {
|
|
241
248
|
if (this.system.renderer.renderMode === ParticleSystemRenderMode.Billboard)
|
|
@@ -777,7 +784,7 @@ export class ParticleSystem extends Behaviour implements IParticleSystem {
|
|
|
777
784
|
if (this._time > this.duration) this._time = 0;
|
|
778
785
|
}
|
|
779
786
|
|
|
780
|
-
private onUpdate(){
|
|
787
|
+
private onUpdate() {
|
|
781
788
|
if (this._bursts) {
|
|
782
789
|
this.emission.bursts = this._bursts;
|
|
783
790
|
delete this._bursts;
|
|
@@ -1117,10 +1117,10 @@ export class RotationOverLifetimeModule {
|
|
|
1117
1117
|
@serializable()
|
|
1118
1118
|
zMultiplier!: number;
|
|
1119
1119
|
|
|
1120
|
-
evaluate(t01: number): number {
|
|
1120
|
+
evaluate(t01: number, t:number): number {
|
|
1121
1121
|
if (!this.enabled) return 0;
|
|
1122
1122
|
if (!this.separateAxes) {
|
|
1123
|
-
const rot = this.z.evaluate(t01) * -1;
|
|
1123
|
+
const rot = this.z.evaluate(t01, t) * -1;
|
|
1124
1124
|
return rot;
|
|
1125
1125
|
}
|
|
1126
1126
|
return 0;
|
|
@@ -22,6 +22,7 @@ const debugInstancing = getParam("debuginstancing");
|
|
|
22
22
|
const debugProgressiveLoading = getParam("debugprogressive");
|
|
23
23
|
const suppressProgressiveLoading = getParam("noprogressive");
|
|
24
24
|
|
|
25
|
+
const showWireframe = getParam("wireframe");
|
|
25
26
|
|
|
26
27
|
export enum ReflectionProbeUsage {
|
|
27
28
|
Off = 0,
|
|
@@ -285,15 +286,20 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
285
286
|
this._lightmaps = [];
|
|
286
287
|
|
|
287
288
|
if (type === "Mesh") {
|
|
288
|
-
|
|
289
|
+
const mat = this.gameObject["material"];
|
|
290
|
+
if (!mat?.isMeshBasicMaterial) {
|
|
289
291
|
const rm = new RendererLightmap(this.gameObject, this.context);// GameObject.addNewComponent(this.gameObject, RendererLightmap);
|
|
290
292
|
this._lightmaps.push(rm);
|
|
291
293
|
rm.init(this.lightmapIndex, this.lightmapScaleOffset, tex, debugLightmap);
|
|
292
294
|
}
|
|
295
|
+
else {
|
|
296
|
+
if (mat)
|
|
297
|
+
console.warn("Lightmapping is not supported on MeshBasicMaterial", mat.name)
|
|
298
|
+
}
|
|
293
299
|
}
|
|
294
300
|
// for multi materials we need to loop through children
|
|
295
301
|
// and then we add a lightmap renderer component to each of them
|
|
296
|
-
else if (this.isMultiMaterialObject(this.gameObject)) {
|
|
302
|
+
else if (this.isMultiMaterialObject(this.gameObject) && this.sharedMaterials.length > 0) {
|
|
297
303
|
for (const child of this.gameObject.children) {
|
|
298
304
|
if (!child["material"]?.isMeshBasicMaterial) {
|
|
299
305
|
const rm = new RendererLightmap(child as GameObject, this.context);
|
|
@@ -309,6 +315,17 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
309
315
|
}
|
|
310
316
|
}
|
|
311
317
|
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
if (showWireframe) {
|
|
321
|
+
for (let i = 0; i < this.sharedMaterials.length; i++) {
|
|
322
|
+
const mat: any = this.sharedMaterials[i];
|
|
323
|
+
if (mat) {
|
|
324
|
+
mat.wireframe = true;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
312
329
|
}
|
|
313
330
|
|
|
314
331
|
private _isInstancingEnabled: boolean = false;
|