@needle-tools/engine 2.54.2-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 +17 -0
- package/dist/needle-engine.d.ts +39 -14
- package/dist/needle-engine.js +355 -355
- package/dist/needle-engine.js.map +4 -4
- package/dist/needle-engine.min.js +35 -35
- package/dist/needle-engine.min.js.map +4 -4
- package/dist/needle-engine.tsbuildinfo +1 -1
- package/lib/engine/engine_lightdata.js +1 -1
- package/lib/engine/engine_lightdata.js.map +1 -1
- package/lib/engine/engine_mainloop_utils.js +8 -0
- package/lib/engine/engine_mainloop_utils.js.map +1 -1
- package/lib/engine/engine_physics.d.ts +1 -1
- package/lib/engine/engine_physics.js +44 -3
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine/engine_physics.types.d.ts +13 -0
- package/lib/engine/engine_physics.types.js +7 -0
- package/lib/engine/engine_physics.types.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 +2 -2
- package/lib/engine/engine_setup.js.map +1 -1
- package/lib/engine/engine_time.d.ts +1 -0
- package/lib/engine/engine_time.js +7 -0
- package/lib/engine/engine_time.js.map +1 -1
- package/lib/engine/engine_types.d.ts +4 -1
- package/lib/engine/engine_types.js.map +1 -1
- package/lib/engine/engine_utils.d.ts +1 -0
- package/lib/engine/engine_utils.js +3 -0
- package/lib/engine/engine_utils.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/Collider.d.ts +2 -0
- package/lib/engine-components/Collider.js +4 -0
- package/lib/engine-components/Collider.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.d.ts +1 -0
- package/lib/engine-components/ParticleSystem.js +17 -6
- package/lib/engine-components/ParticleSystem.js.map +1 -1
- package/lib/engine-components/ParticleSystemModules.d.ts +2 -2
- package/lib/engine-components/ParticleSystemModules.js +27 -21
- package/lib/engine-components/ParticleSystemModules.js.map +1 -1
- package/lib/engine-components/Renderer.d.ts +1 -0
- package/lib/engine-components/Renderer.js +21 -2
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/RigidBody.js +1 -19
- package/lib/engine-components/RigidBody.js.map +1 -1
- package/lib/engine-components/SyncedTransform.js +1 -3
- package/lib/engine-components/SyncedTransform.js.map +1 -1
- package/lib/engine-components/VideoPlayer.d.ts +2 -1
- package/lib/engine-components/VideoPlayer.js +54 -51
- package/lib/engine-components/VideoPlayer.js.map +1 -1
- package/lib/engine-components/WebARSessionRoot.js +5 -0
- package/lib/engine-components/WebARSessionRoot.js.map +1 -1
- package/lib/engine-components/WebXR.js +13 -13
- package/lib/engine-components/WebXR.js.map +1 -1
- package/lib/engine-components/WebXRController.js +1 -2
- package/lib/engine-components/WebXRController.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_lightdata.ts +1 -1
- package/src/engine/engine_mainloop_utils.ts +6 -0
- package/src/engine/engine_physics.ts +47 -5
- package/src/engine/engine_physics.types.ts +17 -0
- package/src/engine/engine_serialization_core.ts +25 -13
- package/src/engine/engine_setup.ts +2 -2
- package/src/engine/engine_time.ts +7 -1
- package/src/engine/engine_types.ts +5 -2
- package/src/engine/engine_utils.ts +4 -0
- package/src/engine/extensions/NEEDLE_lightmaps.ts +3 -1
- package/src/engine-components/Camera.ts +10 -15
- package/src/engine-components/Collider.ts +3 -0
- package/src/engine-components/LODGroup.ts +9 -0
- package/src/engine-components/OrbitControls.ts +58 -19
- package/src/engine-components/ParticleSystem.ts +18 -6
- package/src/engine-components/ParticleSystemModules.ts +29 -22
- package/src/engine-components/Renderer.ts +25 -2
- package/src/engine-components/RigidBody.ts +1 -20
- package/src/engine-components/SyncedTransform.ts +1 -3
- package/src/engine-components/VideoPlayer.ts +55 -51
- package/src/engine-components/WebARSessionRoot.ts +5 -0
- package/src/engine-components/WebXR.ts +15 -13
- package/src/engine-components/WebXRController.ts +1 -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.
|
|
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);
|
|
@@ -33,7 +33,7 @@ export class LightDataRegistry implements ILightDataRegistry {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
registerTexture(sourceId: SourceIdentifier, type: LightmapType, tex: Texture, index: number) {
|
|
36
|
-
if (debugLightmap) console.log("Registering
|
|
36
|
+
if (debugLightmap) console.log("Registering ", LightmapType[type], tex, sourceId);
|
|
37
37
|
if (!this._lightmaps.has(sourceId))
|
|
38
38
|
this._lightmaps.set(sourceId, new Map());
|
|
39
39
|
const map = this._lightmaps.get(sourceId);
|
|
@@ -68,6 +68,12 @@ export function processNewScripts(context: Context) {
|
|
|
68
68
|
new_scripts_buffer.splice(i, 1);
|
|
69
69
|
i--; continue;
|
|
70
70
|
}
|
|
71
|
+
if (script.registering) {
|
|
72
|
+
try {
|
|
73
|
+
script.registering();
|
|
74
|
+
}
|
|
75
|
+
catch (err) { console.error(err); }
|
|
76
|
+
}
|
|
71
77
|
// console.log(script, script.gameObject)
|
|
72
78
|
// TODO: we should not call awake on components with inactive gameobjects
|
|
73
79
|
if (script.__internalAwake !== undefined) {
|
|
@@ -15,9 +15,10 @@ import {
|
|
|
15
15
|
import { InstancingUtil } from './engine_instancing';
|
|
16
16
|
import { foreachComponent } from './engine_gameobject';
|
|
17
17
|
|
|
18
|
-
import RAPIER, { ActiveEvents, Collider, ColliderDesc, EventQueue, JointData, RigidBody, RigidBodyType, World } from '@dimforge/rapier3d-compat';
|
|
19
|
-
import { CollisionDetectionMode } from '../engine/engine_physics.types';
|
|
18
|
+
import RAPIER, { ActiveEvents, CoefficientCombineRule, Collider, ColliderDesc, EventQueue, JointData, RigidBody, RigidBodyType, World } from '@dimforge/rapier3d-compat';
|
|
19
|
+
import { CollisionDetectionMode, PhysicsMaterialCombine } from '../engine/engine_physics.types';
|
|
20
20
|
import { Gizmos } from './engine_gizmos';
|
|
21
|
+
import { Mathf } from './engine_math';
|
|
21
22
|
export type Rapier = typeof RAPIER;
|
|
22
23
|
|
|
23
24
|
|
|
@@ -354,7 +355,7 @@ export class Physics {
|
|
|
354
355
|
this.createCollider(collider, desc, center);
|
|
355
356
|
}
|
|
356
357
|
|
|
357
|
-
addMeshCollider(collider: ICollider, mesh: Mesh, convex: boolean, scale:Vector3) {
|
|
358
|
+
addMeshCollider(collider: ICollider, mesh: Mesh, convex: boolean, scale: Vector3) {
|
|
358
359
|
const geo = mesh.geometry;
|
|
359
360
|
if (!geo) {
|
|
360
361
|
if (debugPhysics) console.warn("Missing mesh geometry", mesh.name);
|
|
@@ -405,7 +406,7 @@ export class Physics {
|
|
|
405
406
|
matrix.decompose(this._tempPosition, this._tempQuaternion, this._tempScale);
|
|
406
407
|
getWorldScale(collider.gameObject, this._tempScale);
|
|
407
408
|
if (center) {
|
|
408
|
-
center.multiply(
|
|
409
|
+
center.multiply(this._tempScale);
|
|
409
410
|
this._tempPosition.x -= center.x;
|
|
410
411
|
this._tempPosition.y += center.y;
|
|
411
412
|
this._tempPosition.z += center.z;
|
|
@@ -414,6 +415,42 @@ export class Physics {
|
|
|
414
415
|
desc.setRotation(this._tempQuaternion);
|
|
415
416
|
desc.setSensor(collider.isTrigger);
|
|
416
417
|
|
|
418
|
+
// TODO: we might want to update this if the material changes
|
|
419
|
+
const physicsMaterial = collider.sharedMaterial;
|
|
420
|
+
if (physicsMaterial) {
|
|
421
|
+
CoefficientCombineRule
|
|
422
|
+
desc.setRestitution(physicsMaterial.bounciness);
|
|
423
|
+
switch (physicsMaterial.bounceCombine) {
|
|
424
|
+
case PhysicsMaterialCombine.Average:
|
|
425
|
+
desc.setRestitutionCombineRule(CoefficientCombineRule.Average);
|
|
426
|
+
break;
|
|
427
|
+
case PhysicsMaterialCombine.Maximum:
|
|
428
|
+
desc.setRestitutionCombineRule(CoefficientCombineRule.Max);
|
|
429
|
+
break;
|
|
430
|
+
case PhysicsMaterialCombine.Minimum:
|
|
431
|
+
desc.setRestitutionCombineRule(CoefficientCombineRule.Min);
|
|
432
|
+
break;
|
|
433
|
+
case PhysicsMaterialCombine.Multiply:
|
|
434
|
+
desc.setRestitutionCombineRule(CoefficientCombineRule.Multiply);
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
desc.setFriction(physicsMaterial.dynamicFriction);
|
|
438
|
+
switch (physicsMaterial.frictionCombine) {
|
|
439
|
+
case PhysicsMaterialCombine.Average:
|
|
440
|
+
desc.setFrictionCombineRule(CoefficientCombineRule.Average);
|
|
441
|
+
break;
|
|
442
|
+
case PhysicsMaterialCombine.Maximum:
|
|
443
|
+
desc.setFrictionCombineRule(CoefficientCombineRule.Max);
|
|
444
|
+
break;
|
|
445
|
+
case PhysicsMaterialCombine.Minimum:
|
|
446
|
+
desc.setFrictionCombineRule(CoefficientCombineRule.Min);
|
|
447
|
+
break;
|
|
448
|
+
case PhysicsMaterialCombine.Multiply:
|
|
449
|
+
desc.setFrictionCombineRule(CoefficientCombineRule.Multiply);
|
|
450
|
+
break;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
417
454
|
// if we want to use explicit mass properties, we need to set the collider density to 0
|
|
418
455
|
// otherwise rapier will compute the mass properties based on the collider shape and density
|
|
419
456
|
// https://rapier.rs/docs/user_guides/javascript/rigid_bodies#mass-properties
|
|
@@ -583,12 +620,17 @@ export class Physics {
|
|
|
583
620
|
// private _lastStepTime: number | undefined = 0;
|
|
584
621
|
private lines?: LineSegments;
|
|
585
622
|
|
|
586
|
-
public step(
|
|
623
|
+
public step(dt?: number) {
|
|
587
624
|
if (!this.world) return;
|
|
588
625
|
this._isUpdatingPhysicsWorld = true;
|
|
589
626
|
if (!this.eventQueue) {
|
|
590
627
|
this.eventQueue = new EventQueue(false);
|
|
591
628
|
}
|
|
629
|
+
if (dt) {
|
|
630
|
+
// if we make to sudden changes to the timestep the physics can get unstable
|
|
631
|
+
// https://rapier.rs/docs/user_guides/javascript/integration_parameters/#dt
|
|
632
|
+
this.world.timestep = Mathf.lerp(this.world.timestep, dt, 0.8);
|
|
633
|
+
}
|
|
592
634
|
this.world.step(this.eventQueue);
|
|
593
635
|
this._isUpdatingPhysicsWorld = false;
|
|
594
636
|
this.updateDebugRendering(this.world);
|
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
export enum PhysicsMaterialCombine
|
|
5
|
+
{
|
|
6
|
+
Average = 0,
|
|
7
|
+
Multiply = 1,
|
|
8
|
+
Minimum = 2,
|
|
9
|
+
Maximum = 3,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type PhysicsMaterial = {
|
|
13
|
+
bounceCombine: PhysicsMaterialCombine;
|
|
14
|
+
bounciness: number;
|
|
15
|
+
frictionCombine: PhysicsMaterialCombine;
|
|
16
|
+
dynamicFriction: number;
|
|
17
|
+
staticFriction: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
3
20
|
export enum CollisionDetectionMode {
|
|
4
21
|
Discrete = 0,
|
|
5
22
|
Continuous = 1,
|
|
@@ -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));
|
|
@@ -315,8 +315,8 @@ export class Context {
|
|
|
315
315
|
this.renderer.domElement.style.width = "100%";
|
|
316
316
|
this.renderer.domElement.style.height = "100%";
|
|
317
317
|
if (this.composer) {
|
|
318
|
-
this.composer.setSize(width, height);
|
|
319
|
-
this.composer.setPixelRatio(window.devicePixelRatio);
|
|
318
|
+
this.composer.setSize?.call(this.composer, width, height);
|
|
319
|
+
this.composer.setPixelRatio?.call(this.composer, window.devicePixelRatio);
|
|
320
320
|
}
|
|
321
321
|
}
|
|
322
322
|
}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
|
|
2
1
|
import { Clock } from 'three'
|
|
2
|
+
import { getParam } from './engine_utils';
|
|
3
|
+
|
|
4
|
+
const debug = getParam("debugtime");
|
|
5
|
+
let timeScale = 1;
|
|
6
|
+
if(typeof debug === "number") timeScale = debug;
|
|
3
7
|
|
|
4
8
|
export class Time {
|
|
5
9
|
|
|
6
10
|
deltaTime = 0;
|
|
7
11
|
time = 0;
|
|
12
|
+
timeScale = 1;
|
|
8
13
|
|
|
9
14
|
/** same as frameCount */
|
|
10
15
|
frame = 0;
|
|
@@ -27,6 +32,7 @@ export class Time {
|
|
|
27
32
|
this.deltaTime = this.clock.getDelta();
|
|
28
33
|
// clamp delta time because if tab is not active clock.getDelta can get pretty big
|
|
29
34
|
this.deltaTime = Math.min(.1, this.deltaTime);
|
|
35
|
+
this.deltaTime *= timeScale * this.timeScale;
|
|
30
36
|
if(this.deltaTime <= 0) this.deltaTime = 0.000000000001;
|
|
31
37
|
this.frame += 1;
|
|
32
38
|
this.time += this.deltaTime;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Camera, Color, Material, Object3D, Vector3, Quaternion, Ray } from "three";
|
|
2
2
|
import { RGBAColor } from "../engine-components/js-extensions/RGBAColor";
|
|
3
|
-
import { CollisionDetectionMode, RigidbodyConstraints } from "./engine_physics.types";
|
|
3
|
+
import { CollisionDetectionMode, PhysicsMaterial, RigidbodyConstraints } from "./engine_physics.types";
|
|
4
4
|
import { getWorldPosition } from "./engine_three_utils";
|
|
5
5
|
import { CircularBuffer } from "./engine_utils";
|
|
6
6
|
|
|
@@ -67,6 +67,8 @@ export interface IComponent {
|
|
|
67
67
|
__internalDestroy();
|
|
68
68
|
resolveGuids?(guidsMap: GuidsMap): void;
|
|
69
69
|
|
|
70
|
+
/** experimental, called when the script is registered for the first time, this is called even if the component is not enabled. */
|
|
71
|
+
registering?();
|
|
70
72
|
awake();
|
|
71
73
|
onEnable();
|
|
72
74
|
onDisable();
|
|
@@ -78,7 +80,7 @@ export interface IComponent {
|
|
|
78
80
|
/** called when this.context.isPaused changes or when rendering loop changes due to changing DOM element visibility
|
|
79
81
|
* e.g. when the DOM element becomes hidden or out ot view
|
|
80
82
|
*/
|
|
81
|
-
onPausedChanged?(isPaused:boolean, wasPaused:boolean);
|
|
83
|
+
onPausedChanged?(isPaused: boolean, wasPaused: boolean);
|
|
82
84
|
|
|
83
85
|
start?(): void;
|
|
84
86
|
earlyUpdate?(): void;
|
|
@@ -138,6 +140,7 @@ export declare interface ICollider extends IComponent {
|
|
|
138
140
|
get isCollider();
|
|
139
141
|
attachedRigidbody: IRigidbody | null;
|
|
140
142
|
isTrigger: boolean;
|
|
143
|
+
sharedMaterial?: PhysicsMaterial;
|
|
141
144
|
}
|
|
142
145
|
|
|
143
146
|
export declare interface IRigidbody extends IComponent {
|
|
@@ -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
|
}
|
|
@@ -5,6 +5,7 @@ import { Event, Mesh, Object3D, Vector3 } from "three"
|
|
|
5
5
|
// import { IColliderProvider, registerColliderProvider } from "../engine/engine_physics";
|
|
6
6
|
import { ICollider } from "../engine/engine_types";
|
|
7
7
|
import { getWorldScale } from "../engine/engine_three_utils";
|
|
8
|
+
import { PhysicsMaterial } from "../engine/engine_physics.types";
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
export class Collider extends Behaviour implements ICollider {
|
|
@@ -18,6 +19,8 @@ export class Collider extends Behaviour implements ICollider {
|
|
|
18
19
|
@serializable()
|
|
19
20
|
isTrigger: boolean = false;
|
|
20
21
|
|
|
22
|
+
@serializable()
|
|
23
|
+
sharedMaterial?: PhysicsMaterial;
|
|
21
24
|
|
|
22
25
|
awake() {
|
|
23
26
|
super.awake();
|
|
@@ -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
|
// }
|