@needle-tools/engine 2.55.0-pre → 2.55.2-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 +13 -0
- package/dist/needle-engine.d.ts +143 -133
- package/dist/needle-engine.js +358 -358
- package/dist/needle-engine.js.map +4 -4
- package/dist/needle-engine.min.js +20 -20
- package/dist/needle-engine.min.js.map +4 -4
- package/dist/needle-engine.tsbuildinfo +1 -1
- package/lib/engine/engine_gizmos.d.ts +2 -0
- package/lib/engine/engine_gizmos.js +24 -1
- package/lib/engine/engine_gizmos.js.map +1 -1
- package/lib/engine/engine_physics.d.ts +1 -0
- package/lib/engine/engine_physics.js +5 -2
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine/engine_serialization_core.js +20 -10
- package/lib/engine/engine_serialization_core.js.map +1 -1
- package/lib/engine/engine_setup.js +7 -1
- package/lib/engine/engine_setup.js.map +1 -1
- package/lib/engine/engine_time.js +3 -3
- package/lib/engine/engine_time.js.map +1 -1
- package/lib/engine/engine_types.d.ts +1 -0
- package/lib/engine/engine_types.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 +10 -10
- package/lib/engine-components/Camera.js.map +1 -1
- package/lib/engine-components/CameraUtils.d.ts +2 -2
- package/lib/engine-components/CameraUtils.js +13 -4
- package/lib/engine-components/CameraUtils.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/RigidBody.d.ts +4 -0
- package/lib/engine-components/RigidBody.js +16 -0
- package/lib/engine-components/RigidBody.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/engine_gizmos.ts +27 -2
- package/src/engine/engine_physics.ts +5 -4
- package/src/engine/engine_serialization_core.ts +25 -13
- package/src/engine/engine_setup.ts +9 -4
- package/src/engine/engine_time.ts +2 -2
- package/src/engine/engine_types.ts +1 -0
- package/src/engine/extensions/NEEDLE_lightmaps.ts +3 -1
- package/src/engine-components/Camera.ts +12 -15
- package/src/engine-components/CameraUtils.ts +15 -5
- 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/RigidBody.ts +22 -5
- 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.2-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,10 +1,11 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
|
-
import { BufferAttribute, Line, BoxGeometry, EdgesGeometry, Color, LineSegments, LineBasicMaterial, Object3D, Mesh, SphereGeometry, ColorRepresentation, Vector3, Box3, Quaternion } from 'three';
|
|
2
|
+
import { BufferAttribute, Line, BoxGeometry, EdgesGeometry, Color, LineSegments, LineBasicMaterial, Object3D, Mesh, SphereGeometry, ColorRepresentation, Vector3, Box3, Quaternion, CylinderGeometry } from 'three';
|
|
3
3
|
import { Context } from './engine_setup';
|
|
4
4
|
import { setWorldPosition, setWorldPositionXYZ } from './engine_three_utils';
|
|
5
5
|
import { Vec3, Vec4 } from './engine_types';
|
|
6
6
|
|
|
7
7
|
const _tmp = new Vector3();
|
|
8
|
+
const _tmp2 = new Vector3();
|
|
8
9
|
const _quat = new Quaternion();
|
|
9
10
|
|
|
10
11
|
const defaultColor: ColorRepresentation = 0x888888;
|
|
@@ -76,7 +77,7 @@ export class Gizmos {
|
|
|
76
77
|
obj.material["wireframe"] = true;
|
|
77
78
|
}
|
|
78
79
|
|
|
79
|
-
static DrawBox3(box:Box3, color: ColorRepresentation = defaultColor, duration: number = 0, depthTest: boolean = true) {
|
|
80
|
+
static DrawBox3(box: Box3, color: ColorRepresentation = defaultColor, duration: number = 0, depthTest: boolean = true) {
|
|
80
81
|
const obj = Internal.getBox(duration);
|
|
81
82
|
obj.position.copy(box.getCenter(_tmp));
|
|
82
83
|
obj.scale.copy(box.getSize(_tmp));
|
|
@@ -84,6 +85,20 @@ export class Gizmos {
|
|
|
84
85
|
obj.material["depthTest"] = depthTest;
|
|
85
86
|
obj.material["wireframe"] = true;
|
|
86
87
|
}
|
|
88
|
+
|
|
89
|
+
private static _up = new Vector3(0, 1, 0);
|
|
90
|
+
static DrawArrow(pt0: Vec3, pt1: Vec3, color: ColorRepresentation = defaultColor, duration: number = 0, depthTest: boolean = true, wireframe: boolean = false) {
|
|
91
|
+
const obj = Internal.getArrowHead(duration);
|
|
92
|
+
obj.position.set(pt1.x, pt1.y, pt1.z);
|
|
93
|
+
obj.quaternion.setFromUnitVectors(this._up.set(0, 1, 0), _tmp.set(pt1.x, pt1.y, pt1.z).sub(_tmp2.set(pt0.x, pt0.y, pt0.z)).normalize());
|
|
94
|
+
const dist = _tmp.set(pt1.x, pt1.y, pt1.z).sub(_tmp2.set(pt0.x, pt0.y, pt0.z)).length();
|
|
95
|
+
const scale = dist * 0.1;
|
|
96
|
+
obj.scale.set(scale, scale, scale);
|
|
97
|
+
obj.material["color"].set(color);
|
|
98
|
+
obj.material["depthTest"] = depthTest;
|
|
99
|
+
obj.material["wireframe"] = wireframe;
|
|
100
|
+
this.DrawLine(pt0, pt1, color, duration, depthTest);
|
|
101
|
+
}
|
|
87
102
|
}
|
|
88
103
|
|
|
89
104
|
const box: BoxGeometry = new BoxGeometry(1, 1, 1);
|
|
@@ -141,9 +156,19 @@ class Internal {
|
|
|
141
156
|
return sphere;
|
|
142
157
|
}
|
|
143
158
|
|
|
159
|
+
static getArrowHead(duration: number): Mesh {
|
|
160
|
+
let arrowHead = this.arrowHeadsCache.pop();
|
|
161
|
+
if (!arrowHead) {
|
|
162
|
+
arrowHead = new Mesh(new CylinderGeometry(0, .5, 1, 8));
|
|
163
|
+
}
|
|
164
|
+
this.registerTimedObject(Context.Current, arrowHead, duration, this.arrowHeadsCache);
|
|
165
|
+
return arrowHead;
|
|
166
|
+
}
|
|
167
|
+
|
|
144
168
|
private static linesCache: Array<Line> = [];
|
|
145
169
|
private static spheresCache: Mesh[] = [];
|
|
146
170
|
private static boxesCache: Mesh[] = [];
|
|
171
|
+
private static arrowHeadsCache: Mesh[] = [];
|
|
147
172
|
|
|
148
173
|
private static registerTimedObject(context: Context, object: Object3D, duration: number, cache: Array<Object3D>) {
|
|
149
174
|
if (!this.contextPostRenderCallbacks.get(context)) {
|
|
@@ -386,10 +386,11 @@ export class Physics {
|
|
|
386
386
|
this._meshCache.set(key, scaledPositions);
|
|
387
387
|
}
|
|
388
388
|
}
|
|
389
|
-
|
|
390
389
|
const desc = convex ? ColliderDesc.convexMesh(positions) : ColliderDesc.trimesh(positions, indices);
|
|
391
390
|
if (desc) {
|
|
392
|
-
this.createCollider(collider, desc);
|
|
391
|
+
const col = this.createCollider(collider, desc);
|
|
392
|
+
col.setMassProperties(1, { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0, w: 1 });
|
|
393
|
+
// rb?.setTranslation({ x: 0, y: 2, z: 0 });
|
|
393
394
|
// col.setTranslationWrtParent(new Vector3(0,2,0));
|
|
394
395
|
|
|
395
396
|
}
|
|
@@ -593,7 +594,7 @@ export class Physics {
|
|
|
593
594
|
rigidbody.enableCcd(rb.collisionDetectionMode !== CollisionDetectionMode.Discrete);
|
|
594
595
|
rigidbody.setLinearDamping(rb.drag);
|
|
595
596
|
rigidbody.setAngularDamping(rb.angularDrag);
|
|
596
|
-
rigidbody.setGravityScale(rb.useGravity ?
|
|
597
|
+
rigidbody.setGravityScale(rb.useGravity ? rb.gravityScale : 0, true);
|
|
597
598
|
|
|
598
599
|
// https://rapier.rs/docs/user_guides/javascript/rigid_bodies#mass-properties
|
|
599
600
|
// rigidbody.setAdditionalMass(rb.mass, true);
|
|
@@ -807,7 +808,7 @@ export class Physics {
|
|
|
807
808
|
}
|
|
808
809
|
|
|
809
810
|
|
|
810
|
-
|
|
811
|
+
/** The joint prevents any relative movement between two rigid-bodies, except for relative rotations along one axis. This is typically used to simulate wheels, fans, etc. They are characterized by one local anchor as well as one local axis on each rigid-body. */
|
|
811
812
|
addHingeJoint(body1: IRigidbody, body2: IRigidbody, anchor: { x: number, y: number, z: number }, axis: { x: number, y: number, z: number }) {
|
|
812
813
|
if (!this.world) {
|
|
813
814
|
console.error("Physics world not initialized");
|
|
@@ -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));
|
|
@@ -26,6 +26,7 @@ import { PlayerViewManager } from './engine_playerview';
|
|
|
26
26
|
|
|
27
27
|
import { ICamera, IComponent, ILight } from "./engine_types"
|
|
28
28
|
import { destroy, foreachComponent } from './engine_gameobject';
|
|
29
|
+
import { createCameraWithOrbitControl } from '../engine-components/CameraUtils';
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
const debug = utils.getParam("debugSetup");
|
|
@@ -147,12 +148,12 @@ export class Context {
|
|
|
147
148
|
|
|
148
149
|
get domWidth(): number {
|
|
149
150
|
// for mozilla XR
|
|
150
|
-
if(this.isInAR) return window.innerWidth;
|
|
151
|
+
if (this.isInAR) return window.innerWidth;
|
|
151
152
|
return this.domElement.clientWidth;
|
|
152
153
|
}
|
|
153
154
|
get domHeight(): number {
|
|
154
155
|
// for mozilla XR
|
|
155
|
-
if(this.isInAR) return window.innerHeight;
|
|
156
|
+
if (this.isInAR) return window.innerHeight;
|
|
156
157
|
return this.domElement.clientHeight;
|
|
157
158
|
}
|
|
158
159
|
get domX(): number {
|
|
@@ -543,6 +544,8 @@ export class Context {
|
|
|
543
544
|
foreachComponent(this.scene, comp => {
|
|
544
545
|
const cam = comp as ICamera;
|
|
545
546
|
if (cam?.isCamera) {
|
|
547
|
+
looputils.updateActiveInHierarchyWithoutEventCall(cam.gameObject);
|
|
548
|
+
if (!cam.activeAndEnabled) return undefined;
|
|
546
549
|
if (cam.tag === "MainCamera") {
|
|
547
550
|
camera = cam;
|
|
548
551
|
return true;
|
|
@@ -554,8 +557,10 @@ export class Context {
|
|
|
554
557
|
if (camera) {
|
|
555
558
|
this.setCurrentCamera(camera);
|
|
556
559
|
}
|
|
557
|
-
else
|
|
560
|
+
else {
|
|
558
561
|
console.error("MISSING camera", this);
|
|
562
|
+
createCameraWithOrbitControl(this.scene, "unknown");
|
|
563
|
+
}
|
|
559
564
|
}
|
|
560
565
|
|
|
561
566
|
Context._current = this;
|
|
@@ -738,7 +743,7 @@ export class Context {
|
|
|
738
743
|
private onHandlePaused(): boolean {
|
|
739
744
|
const paused = this.evaluatePaused();
|
|
740
745
|
if (this._wasPaused !== paused) {
|
|
741
|
-
if(debugActive) console.log("Paused?", paused, "context:" + this.alias);
|
|
746
|
+
if (debugActive) console.log("Paused?", paused, "context:" + this.alias);
|
|
742
747
|
for (let i = 0; i < this.scripts_pausedChanged.length; i++) {
|
|
743
748
|
const script = this.scripts_pausedChanged[i];
|
|
744
749
|
if (!script.activeAndEnabled) continue;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Clock } from 'three'
|
|
2
2
|
import { getParam } from './engine_utils';
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const timescaleUrl = getParam("timescale");
|
|
5
5
|
let timeScale = 1;
|
|
6
|
-
if(typeof
|
|
6
|
+
if(typeof timescaleUrl === "number") timeScale = timescaleUrl;
|
|
7
7
|
|
|
8
8
|
export class Time {
|
|
9
9
|
|
|
@@ -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,14 @@ 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;
|
|
233
|
+
this.gameObject.add(cam);
|
|
236
234
|
}
|
|
237
235
|
else {
|
|
238
236
|
const factor = this.orthographicSize * 100;
|
|
239
|
-
cam = new
|
|
237
|
+
cam = new OrthographicCamera(window.innerWidth / -factor, window.innerWidth / factor, window.innerHeight / factor, window.innerHeight / -factor, this._nearClipPlane, this._farClipPlane);
|
|
238
|
+
this.gameObject.add(cam);
|
|
240
239
|
}
|
|
241
240
|
this._cam = cam;
|
|
242
241
|
|
|
@@ -312,7 +311,6 @@ export class Camera extends Behaviour implements ICamera {
|
|
|
312
311
|
return transparent;
|
|
313
312
|
}
|
|
314
313
|
|
|
315
|
-
|
|
316
314
|
private enableSkybox() {
|
|
317
315
|
if (!this._skybox)
|
|
318
316
|
this._skybox = new CameraSkybox(this);
|
|
@@ -340,10 +338,9 @@ class CameraSkybox {
|
|
|
340
338
|
else if(this.context.scene.background !== this._skybox) {
|
|
341
339
|
if (debug)
|
|
342
340
|
console.log("Set skybox", this._camera, this._skybox);
|
|
343
|
-
this._skybox.encoding =
|
|
344
|
-
this._skybox.mapping =
|
|
341
|
+
this._skybox.encoding = sRGBEncoding;
|
|
342
|
+
this._skybox.mapping = EquirectangularReflectionMapping;
|
|
345
343
|
this.context.scene.background = this._skybox;
|
|
346
344
|
}
|
|
347
345
|
}
|
|
348
|
-
|
|
349
346
|
}
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
import { OrbitControls } from "./OrbitControls";
|
|
2
2
|
import { Camera } from "./Camera";
|
|
3
3
|
import { addNewComponent } from "../engine/engine_components";
|
|
4
|
-
import { Object3D, Scene } from "three";
|
|
4
|
+
import { Color, Object3D, Scene, Vector3 } from "three";
|
|
5
|
+
import { ICamera, SourceIdentifier } from "../engine/engine_types";
|
|
6
|
+
import { lookAtInverse } from "../engine/engine_three_utils";
|
|
7
|
+
import { RGBAColor } from "./js-extensions/RGBAColor";
|
|
5
8
|
|
|
6
|
-
export function createCameraWithOrbitControl(scene: Scene):
|
|
7
|
-
const srcId =
|
|
9
|
+
export function createCameraWithOrbitControl(scene: Scene, source: SourceIdentifier): ICamera {
|
|
10
|
+
const srcId = source;
|
|
8
11
|
const go = new Object3D();
|
|
9
12
|
scene.add(go);
|
|
10
|
-
const
|
|
13
|
+
const camInstance = new Camera();
|
|
14
|
+
const cam = addNewComponent(go, camInstance, true) as ICamera
|
|
11
15
|
cam.sourceId = srcId;
|
|
12
|
-
|
|
16
|
+
cam.clearFlags = 2;
|
|
17
|
+
cam.backgroundColor = new RGBAColor(0.5, 0.5, 0.5, 1);
|
|
18
|
+
const orbit = addNewComponent(go, new OrbitControls(), false) as OrbitControls;
|
|
13
19
|
orbit.sourceId = srcId;
|
|
20
|
+
go.position.x = -2;
|
|
21
|
+
go.position.y = 2;
|
|
22
|
+
go.position.z = 2;
|
|
23
|
+
lookAtInverse(go, new Vector3(0, 0, 0));
|
|
14
24
|
return cam as Camera;
|
|
15
25
|
}
|
|
@@ -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;
|