@needle-tools/engine 2.37.0-pre → 2.38.0-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 +21 -0
- package/dist/needle-engine.d.ts +80 -13
- package/dist/needle-engine.js +349 -349
- package/dist/needle-engine.js.map +4 -4
- package/dist/needle-engine.min.js +25 -25
- package/dist/needle-engine.min.js.map +4 -4
- package/lib/engine/engine_addressables.d.ts +3 -1
- package/lib/engine/engine_addressables.js +12 -5
- package/lib/engine/engine_addressables.js.map +1 -1
- package/lib/engine/engine_element.js +3 -2
- package/lib/engine/engine_element.js.map +1 -1
- package/lib/engine/engine_element_overlay.js +4 -3
- package/lib/engine/engine_element_overlay.js.map +1 -1
- package/lib/engine/engine_input.d.ts +2 -0
- package/lib/engine/engine_input.js +14 -3
- package/lib/engine/engine_input.js.map +1 -1
- package/lib/engine/engine_physics.d.ts +2 -4
- package/lib/engine/engine_physics.js +75 -30
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine/engine_physics.types.d.ts +7 -0
- package/lib/engine/engine_physics.types.js +8 -0
- package/lib/engine/engine_physics.types.js.map +1 -1
- package/lib/engine/engine_setup.d.ts +7 -1
- package/lib/engine/engine_setup.js +10 -2
- package/lib/engine/engine_setup.js.map +1 -1
- package/lib/engine/engine_types.d.ts +1 -1
- package/lib/engine/engine_types.js.map +1 -1
- package/lib/engine-components/Animation.d.ts +1 -0
- package/lib/engine-components/Animation.js +7 -0
- package/lib/engine-components/Animation.js.map +1 -1
- package/lib/engine-components/AnimatorController.js +14 -7
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/Camera.d.ts +1 -0
- package/lib/engine-components/Camera.js +20 -5
- package/lib/engine-components/Camera.js.map +1 -1
- package/lib/engine-components/CharacterController.d.ts +31 -0
- package/lib/engine-components/CharacterController.js +167 -0
- package/lib/engine-components/CharacterController.js.map +1 -0
- package/lib/engine-components/Collider.d.ts +10 -4
- package/lib/engine-components/Collider.js +18 -8
- package/lib/engine-components/Collider.js.map +1 -1
- package/lib/engine-components/Light.d.ts +2 -0
- package/lib/engine-components/Light.js +13 -2
- package/lib/engine-components/Light.js.map +1 -1
- package/lib/engine-components/Renderer.js +4 -0
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/RigidBody.d.ts +6 -1
- package/lib/engine-components/RigidBody.js +62 -25
- package/lib/engine-components/RigidBody.js.map +1 -1
- package/lib/engine-components/SmoothFollow.d.ts +2 -1
- package/lib/engine-components/SmoothFollow.js +25 -17
- package/lib/engine-components/SmoothFollow.js.map +1 -1
- package/lib/engine-components/WebXR.js +3 -4
- package/lib/engine-components/WebXR.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +3 -0
- package/lib/engine-components/codegen/components.js +3 -0
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/package.json +1 -1
- package/src/engine/codegen/register_types.js +12 -0
- package/src/engine/dist/engine_physics.js +739 -0
- package/src/engine/dist/engine_setup.js +777 -0
- package/src/engine/engine_addressables.ts +18 -8
- package/src/engine/engine_element.ts +3 -2
- package/src/engine/engine_element_overlay.ts +4 -3
- package/src/engine/engine_input.ts +12 -3
- package/src/engine/engine_physics.ts +82 -47
- package/src/engine/engine_physics.types.ts +9 -0
- package/src/engine/engine_setup.ts +26 -17
- package/src/engine/engine_types.ts +2 -1
- package/src/engine-components/Animation.ts +8 -0
- package/src/engine-components/AnimatorController.ts +16 -11
- package/src/engine-components/Camera.ts +21 -4
- package/src/engine-components/CharacterController.ts +171 -0
- package/src/engine-components/Collider.ts +22 -12
- package/src/engine-components/Light.ts +17 -3
- package/src/engine-components/Renderer.ts +5 -1
- package/src/engine-components/RigidBody.ts +63 -29
- package/src/engine-components/SmoothFollow.ts +21 -18
- package/src/engine-components/WebXR.ts +3 -4
- package/src/engine-components/codegen/components.ts +3 -0
- package/src/engine-components/dist/CharacterController.js +123 -0
- package/src/engine-components/dist/RigidBody.js +458 -0
|
@@ -7,6 +7,7 @@ import { RGBAColor } from "./js-extensions/RGBAColor";
|
|
|
7
7
|
import { PerspectiveCamera } from "three";
|
|
8
8
|
import { XRSessionMode } from "../engine/engine_setup";
|
|
9
9
|
import { ICamera } from "../engine/engine_types"
|
|
10
|
+
import { showBalloonMessage } from "../engine/debug/debug";
|
|
10
11
|
|
|
11
12
|
export enum ClearFlags {
|
|
12
13
|
Skybox = 1,
|
|
@@ -127,6 +128,10 @@ export class Camera extends Behaviour implements ICamera {
|
|
|
127
128
|
this.applyClearFlagsIfIsActiveCamera();
|
|
128
129
|
}
|
|
129
130
|
|
|
131
|
+
onDisable() {
|
|
132
|
+
this.context.removeCamera(this);
|
|
133
|
+
}
|
|
134
|
+
|
|
130
135
|
buildCamera() {
|
|
131
136
|
if (this._cam) return;
|
|
132
137
|
|
|
@@ -168,6 +173,8 @@ export class Camera extends Behaviour implements ICamera {
|
|
|
168
173
|
}
|
|
169
174
|
|
|
170
175
|
applyClearFlagsIfIsActiveCamera() {
|
|
176
|
+
if (debug)
|
|
177
|
+
showBalloonMessage("apply Camera clear flags");
|
|
171
178
|
if (this._cam && this.context.mainCameraComponent === this) {
|
|
172
179
|
switch (this._clearFlags) {
|
|
173
180
|
case ClearFlags.Skybox:
|
|
@@ -203,12 +210,22 @@ export class Camera extends Behaviour implements ICamera {
|
|
|
203
210
|
const session = this.context.renderer.xr?.getSession();
|
|
204
211
|
if (!session) return false;
|
|
205
212
|
const environmentBlendMode = session.environmentBlendMode;
|
|
213
|
+
if (debug)
|
|
214
|
+
showBalloonMessage("Environment blend mode: " + environmentBlendMode + " on " + navigator.userAgent);
|
|
206
215
|
const transparent = environmentBlendMode === 'additive' || environmentBlendMode === 'alpha-blend';
|
|
207
|
-
// workaround for Quest 2 returning opaque when it should be alpha-blend
|
|
208
|
-
// check user agent if this is the Quest browser and return true if so
|
|
209
216
|
|
|
210
|
-
if (
|
|
211
|
-
if (
|
|
217
|
+
if (this.context.xrSessionMode === XRSessionMode.ImmersiveAR) {
|
|
218
|
+
if (environmentBlendMode === "opaque") {
|
|
219
|
+
// workaround for Quest 2 returning opaque when it should be alpha-blend
|
|
220
|
+
// check user agent if this is the Quest browser and return true if so
|
|
221
|
+
if (navigator.userAgent?.includes("OculusBrowser")) {
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
// Mozilla WebXR Viewer
|
|
225
|
+
else if (navigator.userAgent?.includes("Mozilla") && navigator.userAgent?.includes("Mobile WebXRViewer/v2")) {
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
212
229
|
}
|
|
213
230
|
return transparent;
|
|
214
231
|
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { Ray, Vector3 } from "three";
|
|
2
|
+
import { Mathf } from "../engine/engine_math";
|
|
3
|
+
import { serializeable } from "../engine/engine_serialization";
|
|
4
|
+
import { Collision } from "../engine/engine_types";
|
|
5
|
+
import { CapsuleCollider } from "./Collider";
|
|
6
|
+
import { Behaviour, GameObject } from "./Component";
|
|
7
|
+
import { Rigidbody } from "./RigidBody";
|
|
8
|
+
import { Animator } from "./Animator"
|
|
9
|
+
import { RaycastOptions } from "../engine/engine_physics";
|
|
10
|
+
import { getWorldPosition } from "../engine/engine_three_utils";
|
|
11
|
+
|
|
12
|
+
export class CharacterController extends Behaviour {
|
|
13
|
+
|
|
14
|
+
@serializeable(Vector3)
|
|
15
|
+
center: Vector3 = new Vector3(0, 0, 0);
|
|
16
|
+
@serializeable()
|
|
17
|
+
radius: number = .5;
|
|
18
|
+
@serializeable()
|
|
19
|
+
height: number = 2;
|
|
20
|
+
|
|
21
|
+
private _rigidbody: Rigidbody | null = null;
|
|
22
|
+
get rigidbody(): Rigidbody {
|
|
23
|
+
if (this._rigidbody) return this._rigidbody;
|
|
24
|
+
this._rigidbody = this.gameObject.getComponent(Rigidbody);
|
|
25
|
+
if (!this._rigidbody)
|
|
26
|
+
this._rigidbody = this.gameObject.addNewComponent(Rigidbody) as Rigidbody;
|
|
27
|
+
return this.rigidbody;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
onEnable() {
|
|
31
|
+
let rb = this.rigidbody;
|
|
32
|
+
let collider = this.gameObject.getComponent(CapsuleCollider);
|
|
33
|
+
if (!collider)
|
|
34
|
+
collider = this.gameObject.addNewComponent(CapsuleCollider) as CapsuleCollider;
|
|
35
|
+
// rb.isKinematic = true;
|
|
36
|
+
collider.center.copy(this.center);
|
|
37
|
+
collider.radius = this.radius;
|
|
38
|
+
collider.height = this.height;
|
|
39
|
+
this.gameObject.rotation.x = 0;
|
|
40
|
+
this.gameObject.rotation.z = 0;
|
|
41
|
+
rb.lockRotationX = true;
|
|
42
|
+
rb.lockRotationY = true;
|
|
43
|
+
rb.lockRotationZ = true;
|
|
44
|
+
|
|
45
|
+
// TODO: this doesnt work yet
|
|
46
|
+
// setInterval(()=>{
|
|
47
|
+
// this.rigidbody.isKinematic = !this.rigidbody.isKinematic;
|
|
48
|
+
// console.log(this.rigidbody.isKinematic);
|
|
49
|
+
// }, 1000)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
move(vec: Vector3) {
|
|
53
|
+
this.gameObject.position.add(vec);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private _activeGroundCollisions: Set<Collision> = new Set();
|
|
57
|
+
|
|
58
|
+
onCollisionEnter(col: Collision) {
|
|
59
|
+
for (const contact of col.contacts) {
|
|
60
|
+
// console.log(contact.normal);
|
|
61
|
+
if (contact.normal.y > .1) {
|
|
62
|
+
this._activeGroundCollisions.add(col);
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
onCollisionExit(col: Collision) {
|
|
69
|
+
this._activeGroundCollisions.delete(col);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get isGrounded(): boolean { return this._activeGroundCollisions.size > 0; }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export class CharacterControllerInput extends Behaviour {
|
|
76
|
+
|
|
77
|
+
@serializeable(CharacterController)
|
|
78
|
+
controller?: CharacterController;
|
|
79
|
+
|
|
80
|
+
@serializeable()
|
|
81
|
+
movementSpeed: number = 2;
|
|
82
|
+
|
|
83
|
+
@serializeable()
|
|
84
|
+
rotationSpeed: number = 2;
|
|
85
|
+
|
|
86
|
+
@serializeable()
|
|
87
|
+
jumpForce: number = 1;
|
|
88
|
+
|
|
89
|
+
@serializeable(Animator)
|
|
90
|
+
animator?: Animator;
|
|
91
|
+
|
|
92
|
+
private _currentSpeed: Vector3 = new Vector3(0, 0, 0);
|
|
93
|
+
private _currentAngularSpeed: Vector3 = new Vector3(0, 0, 0);
|
|
94
|
+
|
|
95
|
+
private _temp: Vector3 = new Vector3(0, 0, 0);
|
|
96
|
+
private _jumpCount: number = 0;
|
|
97
|
+
|
|
98
|
+
update() {
|
|
99
|
+
|
|
100
|
+
if (this.controller?.isGrounded) {
|
|
101
|
+
this._jumpCount = 0;
|
|
102
|
+
this.animator?.SetBool("doubleJump", false);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const forward = this.context.input.isKeyPressed("w");
|
|
106
|
+
const backward = this.context.input.isKeyPressed("s");
|
|
107
|
+
const rotateLeft = this.context.input.isKeyPressed("a");
|
|
108
|
+
const rotateRight = this.context.input.isKeyPressed("d");
|
|
109
|
+
const jump = this.context.input.isKeyDown(" ");
|
|
110
|
+
// if (jumpDown) this._jumpDownTime = this.context.time.time;
|
|
111
|
+
// const jumpUp = this.context.input.isKeyUp(" ");
|
|
112
|
+
|
|
113
|
+
const step = forward ? 1 : 0 + backward ? -1 : 0;
|
|
114
|
+
this._currentSpeed.z += step * this.movementSpeed * this.context.time.deltaTime;
|
|
115
|
+
|
|
116
|
+
// if (!this.controller || this.controller.isGrounded)
|
|
117
|
+
this.animator?.SetBool("running", step != 0);
|
|
118
|
+
this.animator?.SetBool("jumping", this.controller?.isGrounded === true && jump);
|
|
119
|
+
|
|
120
|
+
this._temp.copy(this._currentSpeed);
|
|
121
|
+
this._temp.applyQuaternion(this.gameObject.quaternion);
|
|
122
|
+
if (this.controller) this.controller.move(this._temp);
|
|
123
|
+
else this.gameObject.position.add(this._temp);
|
|
124
|
+
|
|
125
|
+
const rotation = rotateLeft ? 1 : 0 + rotateRight ? -1 : 0;
|
|
126
|
+
this._currentAngularSpeed.y += Mathf.toRadians(rotation * this.rotationSpeed) * this.context.time.deltaTime;
|
|
127
|
+
this.gameObject.rotateY(this._currentAngularSpeed.y);
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
this._currentSpeed.multiplyScalar(1 - this.context.time.deltaTime * 10);
|
|
131
|
+
this._currentAngularSpeed.y *= 1 - this.context.time.deltaTime * 10;
|
|
132
|
+
|
|
133
|
+
if (this.controller && jump && this.jumpForce > 0) {
|
|
134
|
+
let canJump = this.controller?.isGrounded;
|
|
135
|
+
if (!this.controller?.isGrounded && this._jumpCount === 1) {
|
|
136
|
+
canJump = true;
|
|
137
|
+
this.animator?.SetBool("doubleJump", true);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (canJump) {
|
|
141
|
+
this._jumpCount += 1;
|
|
142
|
+
// TODO: factor in mass
|
|
143
|
+
const rb = this.controller.rigidbody;
|
|
144
|
+
// const fullJumpHoldLength = .1;
|
|
145
|
+
const factor = this._jumpCount === 2 ? 2 : 1;// Mathf.clamp((this.context.time.time - this._jumpDownTime), 0, fullJumpHoldLength) / fullJumpHoldLength;
|
|
146
|
+
rb.applyImpulse(new Vector3(0, 1, 0).multiplyScalar(this.jumpForce * factor));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (this.controller) {
|
|
151
|
+
// TODO: should probably raycast to the ground or check if we're still in the jump animation
|
|
152
|
+
const verticalSpeed = this.controller?.rigidbody.getVelocity().y;
|
|
153
|
+
if (verticalSpeed < -1) {
|
|
154
|
+
if (!this._raycastOptions.ray) this._raycastOptions.ray = new Ray();
|
|
155
|
+
this._raycastOptions.ray.origin.copy(getWorldPosition(this.gameObject));
|
|
156
|
+
this._raycastOptions.ray.direction.set(0, -1, 0);
|
|
157
|
+
const currentLayer = this.layer;
|
|
158
|
+
this.gameObject.layers.disableAll();
|
|
159
|
+
this.gameObject.layers.set(2);
|
|
160
|
+
const hits = this.context.physics.raycast(this._raycastOptions);
|
|
161
|
+
this.gameObject.layers.set(currentLayer);
|
|
162
|
+
if ((hits.length && hits[0].distance > 2 || verticalSpeed < -10)) {
|
|
163
|
+
this.animator?.SetBool("falling", true);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
else this.animator?.SetBool("falling", false);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
private _raycastOptions = new RaycastOptions();
|
|
171
|
+
}
|
|
@@ -2,16 +2,9 @@ import { Behaviour } from "./Component";
|
|
|
2
2
|
import { Rigidbody } from "./RigidBody";
|
|
3
3
|
import { serializeable } from "../engine/engine_serialization_decorator";
|
|
4
4
|
import { Event, Mesh, Object3D, Vector3 } from "three"
|
|
5
|
-
import { IColliderProvider, registerColliderProvider } from "../engine/engine_physics";
|
|
5
|
+
// import { IColliderProvider, registerColliderProvider } from "../engine/engine_physics";
|
|
6
6
|
import { ICollider } from "../engine/engine_types";
|
|
7
|
-
import { getComponentInChildren } from "../engine/engine_components";
|
|
8
7
|
|
|
9
|
-
class ColliderProvider implements IColliderProvider {
|
|
10
|
-
getCollider(obj: Object3D): ICollider {
|
|
11
|
-
return getComponentInChildren<Collider>(obj, Collider);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
registerColliderProvider(new ColliderProvider());
|
|
15
8
|
|
|
16
9
|
export class Collider extends Behaviour implements ICollider {
|
|
17
10
|
|
|
@@ -54,7 +47,7 @@ export class SphereCollider extends Collider {
|
|
|
54
47
|
@serializeable()
|
|
55
48
|
radius: number = .5;
|
|
56
49
|
@serializeable(Vector3)
|
|
57
|
-
center:
|
|
50
|
+
center: Vector3 = new Vector3(0, 0, 0);
|
|
58
51
|
|
|
59
52
|
onEnable() {
|
|
60
53
|
super.onEnable();
|
|
@@ -65,9 +58,9 @@ export class SphereCollider extends Collider {
|
|
|
65
58
|
export class BoxCollider extends Collider {
|
|
66
59
|
|
|
67
60
|
@serializeable(Vector3)
|
|
68
|
-
size:
|
|
61
|
+
size: Vector3 = new Vector3(1, 1, 1);
|
|
69
62
|
@serializeable(Vector3)
|
|
70
|
-
center:
|
|
63
|
+
center: Vector3 = new Vector3(0, 0, 0);
|
|
71
64
|
|
|
72
65
|
onEnable() {
|
|
73
66
|
super.onEnable();
|
|
@@ -83,7 +76,7 @@ export class MeshCollider extends Collider {
|
|
|
83
76
|
@serializeable()
|
|
84
77
|
convex: boolean = false;
|
|
85
78
|
|
|
86
|
-
awake(){
|
|
79
|
+
awake() {
|
|
87
80
|
console.log(this);
|
|
88
81
|
}
|
|
89
82
|
|
|
@@ -98,4 +91,21 @@ export class MeshCollider extends Collider {
|
|
|
98
91
|
if (this.sharedMesh?.isMesh)
|
|
99
92
|
this.context.physics.addMeshCollider(this, this.sharedMesh, this.convex);
|
|
100
93
|
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
export class CapsuleCollider extends Collider {
|
|
98
|
+
@serializeable(Vector3)
|
|
99
|
+
center: Vector3 = new Vector3(0, 0, 0);
|
|
100
|
+
|
|
101
|
+
@serializeable()
|
|
102
|
+
radius: number = .5;
|
|
103
|
+
@serializeable()
|
|
104
|
+
height: number = 2;
|
|
105
|
+
|
|
106
|
+
onEnable() {
|
|
107
|
+
super.onEnable();
|
|
108
|
+
this.context.physics.addCapsuleCollider(this, this.center, this.height, this.radius);
|
|
109
|
+
}
|
|
110
|
+
|
|
101
111
|
}
|
|
@@ -130,6 +130,9 @@ export class Light extends Behaviour implements ILight {
|
|
|
130
130
|
get shadowNormalBias(): number { return this._shadowNormalBias; }
|
|
131
131
|
private _shadowNormalBias: number = 1;
|
|
132
132
|
|
|
133
|
+
/** when enabled this will remove the multiplication when setting the shadow bias settings initially */
|
|
134
|
+
private _overrideShadowBiasSettings: boolean = false;
|
|
135
|
+
|
|
133
136
|
@serializeable()
|
|
134
137
|
set shadows(val: LightShadows) {
|
|
135
138
|
this._shadows = val;
|
|
@@ -338,7 +341,7 @@ export class Light extends Behaviour implements ILight {
|
|
|
338
341
|
|
|
339
342
|
if (this.light !== undefined) {
|
|
340
343
|
this._intensity = this.light.intensity;
|
|
341
|
-
|
|
344
|
+
|
|
342
345
|
if (this.shadows !== LightShadows.None) {
|
|
343
346
|
this.light.castShadow = true;
|
|
344
347
|
}
|
|
@@ -353,8 +356,19 @@ export class Light extends Behaviour implements ILight {
|
|
|
353
356
|
this.light.shadow.mapSize.width = 2048;
|
|
354
357
|
this.light.shadow.mapSize.height = 2048;
|
|
355
358
|
}
|
|
356
|
-
|
|
357
|
-
|
|
359
|
+
|
|
360
|
+
if (debug)
|
|
361
|
+
console.log("Override shadow bias?", this._overrideShadowBiasSettings, this.shadowBias, this.shadowNormalBias);
|
|
362
|
+
|
|
363
|
+
// shadow bias settings
|
|
364
|
+
if (this._overrideShadowBiasSettings === true) {
|
|
365
|
+
this.light.shadow.bias = this.shadowBias;
|
|
366
|
+
this.light.shadow.normalBias = this.shadowNormalBias;
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
this.light.shadow.bias = this.shadowBias * 0.00001;
|
|
370
|
+
this.light.shadow.normalBias = this.shadowNormalBias * .0001;
|
|
371
|
+
}
|
|
358
372
|
|
|
359
373
|
// console.log(this.light.shadow, this);
|
|
360
374
|
const cam = this.light.shadow.camera as THREE.OrthographicCamera;
|
|
@@ -5,7 +5,7 @@ import { RendererLightmap } from "./RendererLightmap";
|
|
|
5
5
|
import { Context } from "../engine/engine_setup";
|
|
6
6
|
import { getParam } from "../engine/engine_utils";
|
|
7
7
|
import { serializeable } from "../engine/engine_serialization_decorator";
|
|
8
|
-
import { AxesHelper, Material, Mesh, Object3D, Texture, Vector4 } from "three";
|
|
8
|
+
import { AxesHelper, Material, Mesh, Object3D, SkinnedMesh, Texture, Vector4 } from "three";
|
|
9
9
|
import { NEEDLE_render_objects } from "../engine/extensions/NEEDLE_render_objects";
|
|
10
10
|
import { NEEDLE_deferred_texture } from "../engine/extensions/NEEDLE_deferred_texture";
|
|
11
11
|
import { NEED_UPDATE_INSTANCE_KEY } from "../engine/engine_instancing";
|
|
@@ -67,6 +67,7 @@ class SharedMaterialArray implements ISharedMaterials {
|
|
|
67
67
|
case "Group":
|
|
68
68
|
this._targets = [...go.children];
|
|
69
69
|
break;
|
|
70
|
+
case "SkinnedMesh":
|
|
70
71
|
case "Mesh":
|
|
71
72
|
this._targets.push(go);
|
|
72
73
|
break;
|
|
@@ -155,6 +156,9 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
155
156
|
if (this.gameObject.type === "Mesh") {
|
|
156
157
|
return this.gameObject as unknown as Mesh
|
|
157
158
|
}
|
|
159
|
+
else if (this.gameObject.type === "SkinnesMesh") {
|
|
160
|
+
return this.gameObject as unknown as SkinnedMesh;
|
|
161
|
+
}
|
|
158
162
|
else if (this.gameObject.type === "Group") {
|
|
159
163
|
return this.gameObject.children[0] as unknown as Mesh;
|
|
160
164
|
}
|
|
@@ -7,7 +7,7 @@ import { Object3D, Vector3 } from "three";
|
|
|
7
7
|
import { IRigidbody } from "../engine/engine_types";
|
|
8
8
|
import { CollisionDetectionMode, RigidbodyConstraints } from "../engine/engine_physics.types";
|
|
9
9
|
import { validate } from "../engine/engine_util_decorator";
|
|
10
|
-
import { Context } from "../engine/engine_setup";
|
|
10
|
+
import { Context, FrameEvent } from "../engine/engine_setup";
|
|
11
11
|
|
|
12
12
|
class TransformWatch {
|
|
13
13
|
|
|
@@ -16,23 +16,48 @@ class TransformWatch {
|
|
|
16
16
|
}
|
|
17
17
|
positionChanged: boolean = false;
|
|
18
18
|
rotationChanged: boolean = false;
|
|
19
|
-
position?: Vector3;
|
|
20
|
-
quaternion?: THREE.Quaternion;
|
|
21
19
|
|
|
22
|
-
|
|
20
|
+
position?: { x?: number, y?: number, z?: number };
|
|
21
|
+
quaternion?: { _x?: number, _y?: number, _z?: number, _w?: number };
|
|
22
|
+
|
|
23
|
+
private _positionKeys: string[] = ["x", "y", "z"];
|
|
24
|
+
private _quaternionKeys: string[] = ["_x", "_y", "_z", "_w"];
|
|
25
|
+
|
|
26
|
+
reset(clearPreviousValues: boolean = false) {
|
|
23
27
|
this.positionChanged = false;
|
|
24
28
|
this.rotationChanged = false;
|
|
25
29
|
this.mute = false;
|
|
30
|
+
|
|
31
|
+
if (clearPreviousValues) {
|
|
32
|
+
if (this.position)
|
|
33
|
+
for (const key of this._positionKeys)
|
|
34
|
+
delete this.position[key];
|
|
35
|
+
if (this.quaternion)
|
|
36
|
+
for (const key of this._quaternionKeys)
|
|
37
|
+
delete this.quaternion[key];
|
|
38
|
+
}
|
|
26
39
|
}
|
|
27
40
|
|
|
28
41
|
mute: boolean = false;
|
|
29
42
|
|
|
30
43
|
applyValues() {
|
|
31
|
-
|
|
32
|
-
|
|
44
|
+
// only apply the values that actually changed
|
|
45
|
+
// since we want to still control all the other values via physics
|
|
46
|
+
if (this.positionChanged && this.position) {
|
|
47
|
+
for (const key of this._positionKeys) {
|
|
48
|
+
const val = this.position[key];
|
|
49
|
+
if (val !== undefined)
|
|
50
|
+
this.obj.position[key] = val;
|
|
51
|
+
}
|
|
33
52
|
}
|
|
34
53
|
if (this.rotationChanged) {
|
|
35
|
-
|
|
54
|
+
if (this.quaternion) {
|
|
55
|
+
for (const key of this._quaternionKeys) {
|
|
56
|
+
const val = this.quaternion[key];
|
|
57
|
+
if (val !== undefined)
|
|
58
|
+
this.obj.quaternion[key] = val;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
36
61
|
}
|
|
37
62
|
}
|
|
38
63
|
|
|
@@ -52,26 +77,28 @@ class TransformWatch {
|
|
|
52
77
|
if (!this._positionWatch)
|
|
53
78
|
this._positionWatch = new Watch(this.obj.position, ["x", "y", "z"]);
|
|
54
79
|
this._positionWatch.apply();
|
|
55
|
-
this.position =
|
|
80
|
+
this.position = {};
|
|
81
|
+
// this.position = this.obj.position.clone();
|
|
56
82
|
this._positionWatch.subscribeWrite((val, prop) => {
|
|
57
83
|
if (this.context.physics.isUpdating || this.mute) return;
|
|
58
|
-
|
|
84
|
+
const prev = this.position![prop];
|
|
85
|
+
if (Math.abs(prev - val) < .00001) return;
|
|
59
86
|
this.position![prop] = val;
|
|
60
87
|
this.positionChanged = true;
|
|
61
|
-
// }
|
|
62
88
|
})
|
|
63
89
|
}
|
|
64
90
|
if (rotation) {
|
|
65
91
|
if (!this._rotationWatch)
|
|
66
92
|
this._rotationWatch = new Watch(this.obj.quaternion, ["_x", "_y", "_z", "_w"]);
|
|
67
93
|
this._rotationWatch.apply();
|
|
68
|
-
this.quaternion =
|
|
94
|
+
this.quaternion = {};
|
|
95
|
+
// this.quaternion = this.obj.quaternion.clone();
|
|
69
96
|
this._rotationWatch.subscribeWrite((val, prop) => {
|
|
70
97
|
if (this.context.physics.isUpdating || this.mute) return;
|
|
71
|
-
|
|
98
|
+
const prev = this.quaternion![prop];
|
|
99
|
+
if (Math.abs(prev - val) < .00001) return;
|
|
72
100
|
this.quaternion![prop] = val;
|
|
73
101
|
this.rotationChanged = true;
|
|
74
|
-
// }
|
|
75
102
|
})
|
|
76
103
|
}
|
|
77
104
|
}
|
|
@@ -188,6 +215,7 @@ export class Rigidbody extends Behaviour implements IRigidbody {
|
|
|
188
215
|
this._watch = new TransformWatch(this.gameObject, this.context);
|
|
189
216
|
}
|
|
190
217
|
this._watch.start(true, true);
|
|
218
|
+
this.startCoroutine(this.beforePhysics(), FrameEvent.LateUpdate);
|
|
191
219
|
}
|
|
192
220
|
|
|
193
221
|
onDisable() {
|
|
@@ -203,29 +231,35 @@ export class Rigidbody extends Behaviour implements IRigidbody {
|
|
|
203
231
|
this._propertiesChanged = true;
|
|
204
232
|
}
|
|
205
233
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
this.
|
|
234
|
+
// need to do this right before updating physics to prevent rendered object glitching through physical bodies
|
|
235
|
+
*beforePhysics() {
|
|
236
|
+
while (true) {
|
|
237
|
+
if (this._propertiesChanged) {
|
|
238
|
+
this._propertiesChanged = false;
|
|
239
|
+
this.context.physics.updateProperties(this);
|
|
240
|
+
}
|
|
241
|
+
if (this._watch?.isDirty) {
|
|
242
|
+
this._watch.mute = true;
|
|
243
|
+
this._watch.applyValues();
|
|
244
|
+
this.context.physics.updateBody(this, this._watch.positionChanged, this._watch.rotationChanged);
|
|
245
|
+
this._watch.reset();
|
|
246
|
+
}
|
|
247
|
+
this.captureVelocity();
|
|
248
|
+
yield;
|
|
210
249
|
}
|
|
211
|
-
if (this._watch?.isDirty) {
|
|
212
|
-
this._watch.mute = true;
|
|
213
|
-
this._watch.applyValues();
|
|
214
|
-
this.context.physics.updateBody(this, this._watch.positionChanged, this._watch.rotationChanged);
|
|
215
|
-
this._watch.reset();
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
this.captureVelocity();
|
|
219
250
|
}
|
|
220
251
|
|
|
221
252
|
private get body() {
|
|
222
253
|
return this.context.physics.internal_getRigidbody(this);
|
|
223
254
|
}
|
|
224
255
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
256
|
+
public teleport(pt: { x: number, y: number, z: number }, localspace:boolean = true) {
|
|
257
|
+
this._watch?.reset(true);
|
|
258
|
+
if(localspace) this.gameObject.position.set(pt.x, pt.y, pt.z);
|
|
259
|
+
else this.setWorldPosition(pt.x, pt.y, pt.z);
|
|
260
|
+
this.resetForcesAndTorques();
|
|
261
|
+
this.resetVelocities();
|
|
262
|
+
}
|
|
229
263
|
|
|
230
264
|
public resetForces() {
|
|
231
265
|
this.body?.resetForces(true);
|
|
@@ -1,53 +1,56 @@
|
|
|
1
1
|
import { Camera } from "./Camera";
|
|
2
2
|
import { Behaviour, GameObject } from "./Component";
|
|
3
|
-
import * as utils from "../engine/engine_three_utils";
|
|
4
3
|
import * as THREE from "three";
|
|
5
4
|
import { Mathf } from "../engine/engine_math";
|
|
6
5
|
import { serializeable } from "../engine/engine_serialization_decorator";
|
|
7
6
|
import { Object3D } from "three";
|
|
7
|
+
import { getWorldPosition, getWorldQuaternion } from "../engine/engine_three_utils";
|
|
8
|
+
import { Axes } from "../engine/engine_physics.types";
|
|
8
9
|
|
|
9
10
|
export class SmoothFollow extends Behaviour {
|
|
10
11
|
|
|
11
12
|
@serializeable(Object3D)
|
|
12
13
|
target: THREE.Object3D | null = null;
|
|
13
14
|
|
|
15
|
+
@serializeable()
|
|
14
16
|
followFactor = .1;
|
|
17
|
+
@serializeable()
|
|
15
18
|
rotateFactor = .1;
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
@serializeable()
|
|
21
|
+
positionAxes : Axes = Axes.All;
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
// @serializeable()
|
|
24
|
+
// rotationAxes : Axes = Axes.All;
|
|
21
25
|
|
|
26
|
+
flipForward: boolean = false;
|
|
27
|
+
|
|
28
|
+
private static _invertForward: THREE.Quaternion = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI);
|
|
29
|
+
private _firstUpdate = true;
|
|
22
30
|
|
|
23
|
-
onEnable(): void {
|
|
24
|
-
const cam = GameObject.getComponentInChildren(this.gameObject, Camera) as Camera;
|
|
25
|
-
if (cam && cam.cam) {
|
|
26
|
-
cam.gameObject.position.set(0, 0, 0);
|
|
27
|
-
cam.cam.position.set(0, 0, 0);
|
|
28
|
-
cam.gameObject.quaternion.identity();
|
|
29
|
-
cam.cam.quaternion.setFromEuler(new THREE.Euler(0, Math.PI, 0));
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
31
|
|
|
33
32
|
onBeforeRender(): void {
|
|
34
|
-
if (this.followFactor <= 0) return;
|
|
35
33
|
this.updateNow(false);
|
|
36
34
|
}
|
|
37
35
|
|
|
38
36
|
updateNow(hard: boolean) {
|
|
39
37
|
if (!this.target || this.target === this.gameObject) return;
|
|
40
38
|
if (this.followFactor > 0) {
|
|
41
|
-
const wp =
|
|
39
|
+
const wp = getWorldPosition(this.target);
|
|
42
40
|
const fpos = this._firstUpdate || hard ? 1 : Mathf.clamp01(this.context.time.deltaTime * this.followFactor);
|
|
43
|
-
|
|
41
|
+
const currentPosition = this.worldPosition;
|
|
42
|
+
if(this.positionAxes & Axes.X) currentPosition.x = Mathf.lerp(currentPosition.x, wp.x, fpos);
|
|
43
|
+
if(this.positionAxes & Axes.Y) currentPosition.y = Mathf.lerp(currentPosition.y, wp.y, fpos);
|
|
44
|
+
if(this.positionAxes & Axes.Z) currentPosition.z = Mathf.lerp(currentPosition.z, wp.z, fpos);
|
|
45
|
+
this.worldPosition = currentPosition;
|
|
44
46
|
}
|
|
45
47
|
if (this.rotateFactor > 0) {
|
|
46
|
-
const wr =
|
|
47
|
-
if(this.flipForward){
|
|
48
|
+
const wr = getWorldQuaternion(this.target);
|
|
49
|
+
if (this.flipForward) {
|
|
48
50
|
wr.premultiply(SmoothFollow._invertForward);
|
|
49
51
|
}
|
|
50
52
|
const frot = this._firstUpdate || hard ? 1 : Mathf.clamp01(this.context.time.deltaTime * this.rotateFactor);
|
|
53
|
+
|
|
51
54
|
this.worldQuaternion = this.worldQuaternion.slerp(wr, frot);
|
|
52
55
|
}
|
|
53
56
|
this._firstUpdate = false;
|
|
@@ -505,6 +505,7 @@ export class WebAR {
|
|
|
505
505
|
const context = this.webxr.context;
|
|
506
506
|
this.reticleActive = true;
|
|
507
507
|
this.didPlaceARSessionRoot = false;
|
|
508
|
+
this.getAROverlayContainer();
|
|
508
509
|
|
|
509
510
|
const deviceType = navigator.userAgent?.includes("OculusBrowser") ? ControllerType.PhysicalDevice : ControllerType.Touch;
|
|
510
511
|
const controllerCount = deviceType === ControllerType.Touch ? 4 : 2;
|
|
@@ -563,10 +564,8 @@ export class WebAR {
|
|
|
563
564
|
}
|
|
564
565
|
else console.warn("No WebARSessionRoot found in scene")
|
|
565
566
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
el.onEnterAR?.call(el, session, this.arOverlayElement);
|
|
569
|
-
}
|
|
567
|
+
const eng = this.context.domElement as INeedleEngineComponent;
|
|
568
|
+
eng?.onEnterAR?.call(eng, session, this.arOverlayElement!);
|
|
570
569
|
|
|
571
570
|
this.context.mainCameraComponent?.applyClearFlagsIfIsActiveCamera();
|
|
572
571
|
}
|
|
@@ -13,10 +13,13 @@ export { AxesHelper } from "../AxesHelper";
|
|
|
13
13
|
export { BasicIKConstraint } from "../BasicIKConstraint";
|
|
14
14
|
export { BoxHelperComponent } from "../BoxHelperComponent";
|
|
15
15
|
export { Camera } from "../Camera";
|
|
16
|
+
export { CharacterController } from "../CharacterController";
|
|
17
|
+
export { CharacterControllerInput } from "../CharacterController";
|
|
16
18
|
export { Collider } from "../Collider";
|
|
17
19
|
export { SphereCollider } from "../Collider";
|
|
18
20
|
export { BoxCollider } from "../Collider";
|
|
19
21
|
export { MeshCollider } from "../Collider";
|
|
22
|
+
export { CapsuleCollider } from "../Collider";
|
|
20
23
|
export { DeleteBox } from "../DeleteBox";
|
|
21
24
|
export { Deletable } from "../DeleteBox";
|
|
22
25
|
export { DeviceFlag } from "../DeviceFlag";
|