@needle-tools/engine 3.4.0-alpha → 3.5.1-alpha
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 +14 -0
- package/dist/needle-engine.js +59388 -59097
- package/dist/needle-engine.min.js +416 -391
- package/dist/needle-engine.umd.cjs +388 -363
- package/lib/engine/api.d.ts +1 -0
- package/lib/engine/api.js +1 -0
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/engine_context.d.ts +9 -4
- package/lib/engine/engine_context.js +57 -32
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_context_registry.d.ts +5 -3
- package/lib/engine/engine_context_registry.js +10 -2
- package/lib/engine/engine_context_registry.js.map +1 -1
- package/lib/engine/engine_element.js.map +1 -1
- package/lib/engine/engine_element_loading.js +2 -3
- package/lib/engine/engine_element_loading.js.map +1 -1
- package/lib/engine/engine_input.d.ts +2 -2
- package/lib/engine/engine_physics.d.ts +20 -93
- package/lib/engine/engine_physics.js +20 -892
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine/engine_physics.types.js.map +1 -1
- package/lib/engine/engine_physics_rapier.d.ts +103 -0
- package/lib/engine/engine_physics_rapier.js +1003 -0
- package/lib/engine/engine_physics_rapier.js.map +1 -0
- package/lib/engine/engine_types.d.ts +50 -1
- package/lib/engine/engine_types.js +8 -0
- package/lib/engine/engine_types.js.map +1 -1
- package/lib/engine-components/Collider.js +6 -6
- package/lib/engine-components/Collider.js.map +1 -1
- package/lib/engine-components/Joints.js +2 -2
- package/lib/engine-components/Joints.js.map +1 -1
- package/lib/engine-components/ReflectionProbe.js +16 -7
- package/lib/engine-components/ReflectionProbe.js.map +1 -1
- package/lib/engine-components/Renderer.js +3 -4
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/RigidBody.d.ts +0 -1
- package/lib/engine-components/RigidBody.js +24 -30
- package/lib/engine-components/RigidBody.js.map +1 -1
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +52 -26
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.js.map +1 -1
- package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.d.ts +8 -2
- package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js +44 -7
- package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js.map +1 -1
- package/lib/engine-components/ui/Canvas.js +29 -16
- package/lib/engine-components/ui/Canvas.js.map +1 -1
- package/lib/engine-components/ui/Layout.js +10 -5
- package/lib/engine-components/ui/Layout.js.map +1 -1
- package/lib/engine-components/ui/RectTransform.js +8 -3
- package/lib/engine-components/ui/RectTransform.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/plugins/vite/config.js +2 -1
- package/plugins/vite/defines.js +30 -0
- package/plugins/vite/dependency-watcher.js +173 -0
- package/plugins/vite/editor-connection.js +37 -39
- package/plugins/vite/index.js +5 -1
- package/plugins/vite/reload.js +3 -1
- package/src/engine/api.ts +1 -0
- package/src/engine/codegen/register_types.js +2 -2
- package/src/engine/engine_context.ts +75 -42
- package/src/engine/engine_context_registry.ts +13 -6
- package/src/engine/engine_element.ts +2 -1
- package/src/engine/engine_element_loading.ts +2 -3
- package/src/engine/engine_input.ts +2 -2
- package/src/engine/engine_physics.ts +25 -1020
- package/src/engine/engine_physics.types.ts +1 -3
- package/src/engine/engine_physics_rapier.ts +1127 -0
- package/src/engine/engine_types.ts +66 -4
- package/src/engine-components/Collider.ts +6 -6
- package/src/engine-components/Joints.ts +2 -2
- package/src/engine-components/ReflectionProbe.ts +17 -7
- package/src/engine-components/Renderer.ts +5 -5
- package/src/engine-components/RendererLightmap.ts +1 -1
- package/src/engine-components/RigidBody.ts +24 -31
- package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +58 -29
- package/src/engine-components/export/usdz/extensions/behavior/BehaviourComponents.ts +51 -9
- package/src/engine-components/ui/Canvas.ts +29 -16
- package/src/engine-components/ui/Layout.ts +10 -5
- package/src/engine-components/ui/RectTransform.ts +9 -4
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RenderTexture } from "./engine_texture";
|
|
2
|
-
import { Camera, Color, Material, Object3D, Vector3, Quaternion, Ray, Scene, Renderer, WebGLRenderer } from "three";
|
|
2
|
+
import { Camera, Color, Material, Object3D, Vector3, Quaternion, Ray, Scene, Renderer, WebGLRenderer, Mesh } from "three";
|
|
3
3
|
import { RGBAColor } from "../engine-components/js-extensions/RGBAColor";
|
|
4
4
|
import { CollisionDetectionMode, PhysicsMaterial, RigidbodyConstraints } from "./engine_physics.types";
|
|
5
5
|
import { CircularBuffer } from "./engine_utils";
|
|
@@ -20,7 +20,6 @@ export interface UIDProvider {
|
|
|
20
20
|
generateUUID(): string;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
24
23
|
export declare type CoroutineData = {
|
|
25
24
|
comp: IComponent,
|
|
26
25
|
main: Generator,
|
|
@@ -31,9 +30,17 @@ export interface ITime {
|
|
|
31
30
|
get time(): number;
|
|
32
31
|
}
|
|
33
32
|
|
|
33
|
+
export interface IInput {
|
|
34
|
+
convertScreenspaceToRaycastSpace(vec: Vec2): void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface IPhysics {
|
|
38
|
+
engine?: IPhysicsEngine;
|
|
39
|
+
}
|
|
40
|
+
|
|
34
41
|
export interface IContext {
|
|
35
42
|
alias?: string | null;
|
|
36
|
-
hash?:string;
|
|
43
|
+
hash?: string;
|
|
37
44
|
|
|
38
45
|
scene: Scene;
|
|
39
46
|
renderer: WebGLRenderer;
|
|
@@ -42,6 +49,8 @@ export interface IContext {
|
|
|
42
49
|
domElement: HTMLElement;
|
|
43
50
|
|
|
44
51
|
time: ITime;
|
|
52
|
+
input: IInput;
|
|
53
|
+
physics: IPhysics;
|
|
45
54
|
|
|
46
55
|
scripts: IComponent[];
|
|
47
56
|
scripts_pausedChanged: IComponent[];
|
|
@@ -343,4 +352,57 @@ export class Collision {
|
|
|
343
352
|
// }
|
|
344
353
|
// return this._point;
|
|
345
354
|
// }
|
|
346
|
-
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
export type RaycastResult = null | { point: Vector3, collider: ICollider, normal?: Vector3 };
|
|
358
|
+
|
|
359
|
+
export class SphereOverlapResult {
|
|
360
|
+
object: Object3D;
|
|
361
|
+
collider: ICollider;
|
|
362
|
+
constructor(object: Object3D, collider: ICollider) {
|
|
363
|
+
this.object = object;
|
|
364
|
+
this.collider = collider;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
export interface IPhysicsEngine {
|
|
370
|
+
initialize(ctx: IContext): Promise<boolean>;
|
|
371
|
+
step(dt: number): void;
|
|
372
|
+
postStep();
|
|
373
|
+
get isUpdating(): boolean;
|
|
374
|
+
/** clear all possibly cached data (e.g. mesh data when creating scaled mesh colliders) */
|
|
375
|
+
clearCaches();
|
|
376
|
+
|
|
377
|
+
// raycasting
|
|
378
|
+
/** fast raycast without getting the normal vector */
|
|
379
|
+
raycast(origin: Vec2 | Vec3, direction: Vec3 | undefined, maxDistance: number, solid: boolean): RaycastResult;
|
|
380
|
+
/** raycast that also gets the normal vector. If you don't need it use raycast() */
|
|
381
|
+
raycastAndGetNormal(origin: Vec2 | Vec3, direction: Vec3 | undefined, maxDistance: number, solid: boolean) : RaycastResult;
|
|
382
|
+
sphereOverlap(point: Vector3, radius: number): Array<SphereOverlapResult>;
|
|
383
|
+
|
|
384
|
+
// Collider methods
|
|
385
|
+
addSphereCollider(collider: ICollider, center: Vector3, radius: number);
|
|
386
|
+
addBoxCollider(collider: ICollider, center: Vector3, size: Vector3);
|
|
387
|
+
addCapsuleCollider(collider: ICollider, center: Vector3, radius: number, height: number);
|
|
388
|
+
addMeshCollider(collider: ICollider, mesh: Mesh, convex: boolean, scale: Vector3);
|
|
389
|
+
|
|
390
|
+
// Rigidbody methods
|
|
391
|
+
wakeup(rb: IRigidbody);
|
|
392
|
+
updateProperties(rb: IRigidbody);
|
|
393
|
+
resetForces(rb: IRigidbody, wakeup: boolean);
|
|
394
|
+
resetTorques(rb: IRigidbody, wakeup: boolean);
|
|
395
|
+
addForce(rb: IRigidbody, vec: Vec3, wakeup: boolean);
|
|
396
|
+
applyImpulse(rb: IRigidbody, vec: Vec3, wakeup: boolean);
|
|
397
|
+
getLinearVelocity(rb: IRigidbody): Vec3 | null;
|
|
398
|
+
getAngularVelocity(rb: IRigidbody): Vec3 | null;
|
|
399
|
+
setAngularVelocity(rb: IRigidbody, vec: Vec3, wakeup: boolean);
|
|
400
|
+
setLinearVelocity(rb: IRigidbody, vec: Vec3, wakeup: boolean);
|
|
401
|
+
|
|
402
|
+
updateBody(comp: ICollider | IRigidbody, translation: boolean, rotation: boolean);
|
|
403
|
+
removeBody(body: IComponent);
|
|
404
|
+
|
|
405
|
+
// Joints
|
|
406
|
+
addFixedJoint(body1: IRigidbody, body2: IRigidbody)
|
|
407
|
+
addHingeJoint(body1: IRigidbody, body2: IRigidbody, anchor: Vec3, axis: Vec3)
|
|
408
|
+
}
|
|
@@ -40,7 +40,7 @@ export class Collider extends Behaviour implements ICollider {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
onDisable() {
|
|
43
|
-
this.context.physics.removeBody(this);
|
|
43
|
+
this.context.physics.engine?.removeBody(this);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
}
|
|
@@ -55,7 +55,7 @@ export class SphereCollider extends Collider {
|
|
|
55
55
|
|
|
56
56
|
onEnable() {
|
|
57
57
|
super.onEnable();
|
|
58
|
-
this.context.physics.addSphereCollider(this, this.center, this.radius);
|
|
58
|
+
this.context.physics.engine?.addSphereCollider(this, this.center, this.radius);
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
@@ -68,7 +68,7 @@ export class BoxCollider extends Collider {
|
|
|
68
68
|
|
|
69
69
|
onEnable() {
|
|
70
70
|
super.onEnable();
|
|
71
|
-
this.context.physics.addBoxCollider(this, this.center, this.size);
|
|
71
|
+
this.context.physics.engine?.addBoxCollider(this, this.center, this.size);
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
@@ -90,7 +90,7 @@ export class MeshCollider extends Collider {
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
if (this.sharedMesh?.isMesh) {
|
|
93
|
-
this.context.physics.addMeshCollider(this, this.sharedMesh, this.convex, getWorldScale(this.gameObject));
|
|
93
|
+
this.context.physics.engine?.addMeshCollider(this, this.sharedMesh, this.convex, getWorldScale(this.gameObject));
|
|
94
94
|
}
|
|
95
95
|
else {
|
|
96
96
|
const group = this.sharedMesh as any as Group;
|
|
@@ -99,7 +99,7 @@ export class MeshCollider extends Collider {
|
|
|
99
99
|
for (const ch in group.children) {
|
|
100
100
|
const child = group.children[ch] as Mesh;
|
|
101
101
|
if (child.isMesh) {
|
|
102
|
-
this.context.physics.addMeshCollider(this, child, this.convex, getWorldScale(this.gameObject));
|
|
102
|
+
this.context.physics.engine?.addMeshCollider(this, child, this.convex, getWorldScale(this.gameObject));
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
}
|
|
@@ -119,7 +119,7 @@ export class CapsuleCollider extends Collider {
|
|
|
119
119
|
|
|
120
120
|
onEnable() {
|
|
121
121
|
super.onEnable();
|
|
122
|
-
this.context.physics.addCapsuleCollider(this, this.center, this.height, this.radius);
|
|
122
|
+
this.context.physics.engine?.addCapsuleCollider(this, this.center, this.height, this.radius);
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
}
|
|
@@ -32,7 +32,7 @@ export abstract class Joint extends Behaviour {
|
|
|
32
32
|
export class FixedJoint extends Joint {
|
|
33
33
|
|
|
34
34
|
protected createJoint(self: Rigidbody, other: Rigidbody) {
|
|
35
|
-
this.context.physics.addFixedJoint(self, other);
|
|
35
|
+
this.context.physics.engine?.addFixedJoint(self, other);
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -46,7 +46,7 @@ export class HingeJoint extends Joint {
|
|
|
46
46
|
|
|
47
47
|
protected createJoint(self: Rigidbody, other: Rigidbody) {
|
|
48
48
|
if (this.axis && this.anchor)
|
|
49
|
-
this.context.physics.addHingeJoint(self, other, this.anchor, this.axis);
|
|
49
|
+
this.context.physics.engine?.addHingeJoint(self, other, this.anchor, this.axis);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
}
|
|
@@ -129,17 +129,28 @@ export class ReflectionProbe extends Behaviour {
|
|
|
129
129
|
// otherwise some renderers outside of the probe will be affected or vice versa
|
|
130
130
|
for (let i = 0; i < _rend.sharedMaterials.length; i++) {
|
|
131
131
|
const material = _rend.sharedMaterials[i];
|
|
132
|
-
if (!material)
|
|
133
|
-
if (material["envMap"] === undefined) continue;
|
|
134
|
-
if (material["envMap"] === this.texture) {
|
|
132
|
+
if (!material) {
|
|
135
133
|
continue;
|
|
136
134
|
}
|
|
135
|
+
if (material["envMap"] === undefined) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
|
|
137
139
|
let cached = rendererCache[i];
|
|
138
140
|
|
|
139
141
|
// make sure we have the currently assigned material cached (and an up to date clone of that)
|
|
140
142
|
// TODO: this is causing problems with progressive textures sometimes (depending on the order) when the version changes and we re-create materials over and over. We might want to just set the material envmap instead of making a clone
|
|
141
|
-
|
|
142
|
-
|
|
143
|
+
let isCachedInstance = material === cached?.copy;
|
|
144
|
+
let hasChanged = !cached || cached.material.uuid !== material.uuid || cached.copy.version !== material.version;
|
|
145
|
+
if (!isCachedInstance && hasChanged) {
|
|
146
|
+
if (debug) {
|
|
147
|
+
let reason = "";
|
|
148
|
+
if (!cached) reason = "not cached";
|
|
149
|
+
else if (cached.material !== material) reason = "reference changed; cached instance?: " + isCachedInstance;
|
|
150
|
+
else if (cached.copy.version !== material.version) reason = "version changed";
|
|
151
|
+
console.warn("Cloning material", material.name, material.version, "Reason:", reason, "\n", material.uuid, "\n", cached?.copy.uuid, "\n", _rend.name);
|
|
152
|
+
}
|
|
153
|
+
|
|
143
154
|
const clone = material.clone();
|
|
144
155
|
clone.version = material.version;
|
|
145
156
|
|
|
@@ -158,8 +169,7 @@ export class ReflectionProbe extends Behaviour {
|
|
|
158
169
|
clone[$reflectionProbeKey] = this;
|
|
159
170
|
clone[$originalMaterial] = material;
|
|
160
171
|
|
|
161
|
-
if (debug)
|
|
162
|
-
console.log("Set reflection", _rend.name, _rend.guid);
|
|
172
|
+
if (debug) console.log("Set reflection", _rend.name, _rend.guid);
|
|
163
173
|
}
|
|
164
174
|
|
|
165
175
|
/** this is the material that we copied and that has the reflection probe */
|
|
@@ -605,15 +605,15 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
605
605
|
}
|
|
606
606
|
}
|
|
607
607
|
|
|
608
|
-
|
|
608
|
+
|
|
609
|
+
if (this.reflectionProbeUsage !== ReflectionProbeUsage.Off && this._reflectionProbe) {
|
|
610
|
+
this._reflectionProbe.onSet(this);
|
|
611
|
+
}
|
|
609
612
|
|
|
613
|
+
}
|
|
610
614
|
onBeforeRenderThree(_renderer, _scene, _camera, _geometry, material, _group) {
|
|
611
615
|
|
|
612
616
|
this.loadProgressiveTextures(material);
|
|
613
|
-
// TODO: we might want to just set the material.envMap for one material during rendering instead of cloning the material
|
|
614
|
-
if (this.reflectionProbeUsage !== ReflectionProbeUsage.Off && this._reflectionProbe) {
|
|
615
|
-
this._reflectionProbe.onSet(this);
|
|
616
|
-
}
|
|
617
617
|
|
|
618
618
|
if (material.envMapIntensity !== undefined) {
|
|
619
619
|
const factor = this.hasLightmap ? Math.PI : 1;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Behaviour, GameObject } from "./Component";
|
|
2
2
|
import * as THREE from "three";
|
|
3
3
|
import { Texture } from "three";
|
|
4
|
-
import { Context,
|
|
4
|
+
import { Context, OnRenderCallback } from "../engine/engine_setup";
|
|
5
5
|
|
|
6
6
|
// this component is automatically added by the Renderer if the object has lightmap uvs AND we have a lightmap
|
|
7
7
|
// for multimaterial objects GLTF exports a "Group" with the renderer component
|
|
@@ -89,7 +89,7 @@ class TransformWatch {
|
|
|
89
89
|
this.position = {};
|
|
90
90
|
// this.position = this.obj.position.clone();
|
|
91
91
|
this._positionWatch.subscribeWrite((val, prop) => {
|
|
92
|
-
if (this.context.physics.isUpdating || this.mute) return;
|
|
92
|
+
if (this.context.physics.engine?.isUpdating || this.mute) return;
|
|
93
93
|
const prev = this.position![prop];
|
|
94
94
|
if (Math.abs(prev - val) < .00001) return;
|
|
95
95
|
this.position![prop] = val;
|
|
@@ -103,7 +103,7 @@ class TransformWatch {
|
|
|
103
103
|
this.quaternion = {};
|
|
104
104
|
// this.quaternion = this.obj.quaternion.clone();
|
|
105
105
|
this._rotationWatch.subscribeWrite((val, prop) => {
|
|
106
|
-
if (this.context.physics.isUpdating || this.mute) return;
|
|
106
|
+
if (this.context.physics.engine?.isUpdating || this.mute) return;
|
|
107
107
|
const prev = this.quaternion![prop];
|
|
108
108
|
if (Math.abs(prev - val) < .00001) return;
|
|
109
109
|
this.quaternion![prop] = val;
|
|
@@ -245,11 +245,11 @@ export class Rigidbody extends Behaviour implements IRigidbody {
|
|
|
245
245
|
|
|
246
246
|
onDisable() {
|
|
247
247
|
this._watch?.stop();
|
|
248
|
-
this.context.physics.removeBody(this);
|
|
248
|
+
this.context.physics.engine?.removeBody(this);
|
|
249
249
|
}
|
|
250
250
|
|
|
251
251
|
onDestroy(): void {
|
|
252
|
-
this.context.physics.removeBody(this);
|
|
252
|
+
this.context.physics.engine?.removeBody(this);
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
onValidate() {
|
|
@@ -261,12 +261,12 @@ export class Rigidbody extends Behaviour implements IRigidbody {
|
|
|
261
261
|
while (true) {
|
|
262
262
|
if (this._propertiesChanged) {
|
|
263
263
|
this._propertiesChanged = false;
|
|
264
|
-
this.context.physics.updateProperties(this);
|
|
264
|
+
this.context.physics.engine?.updateProperties(this);
|
|
265
265
|
}
|
|
266
266
|
if (this._watch?.isDirty) {
|
|
267
267
|
this._watch.mute = true;
|
|
268
268
|
this._watch.applyValues();
|
|
269
|
-
this.context.physics.updateBody(this, this._watch.positionChanged, this._watch.rotationChanged);
|
|
269
|
+
this.context.physics.engine?.updateBody(this, this._watch.positionChanged, this._watch.rotationChanged);
|
|
270
270
|
this._watch.reset();
|
|
271
271
|
}
|
|
272
272
|
else this._watch?.syncValues();
|
|
@@ -275,10 +275,6 @@ export class Rigidbody extends Behaviour implements IRigidbody {
|
|
|
275
275
|
}
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
-
private get body() {
|
|
279
|
-
return this.context.physics.internal_getRigidbody(this);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
278
|
public teleport(pt: { x: number, y: number, z: number }, localspace: boolean = true) {
|
|
283
279
|
this._watch?.reset(true);
|
|
284
280
|
if (localspace) this.gameObject.position.set(pt.x, pt.y, pt.z);
|
|
@@ -288,11 +284,11 @@ export class Rigidbody extends Behaviour implements IRigidbody {
|
|
|
288
284
|
}
|
|
289
285
|
|
|
290
286
|
public resetForces() {
|
|
291
|
-
this.
|
|
287
|
+
this.context.physics.engine?.resetForces(this, true);
|
|
292
288
|
}
|
|
293
289
|
|
|
294
290
|
public resetTorques() {
|
|
295
|
-
this.
|
|
291
|
+
this.context.physics.engine?.resetTorques(this, true);
|
|
296
292
|
}
|
|
297
293
|
|
|
298
294
|
public resetVelocities() {
|
|
@@ -306,24 +302,24 @@ export class Rigidbody extends Behaviour implements IRigidbody {
|
|
|
306
302
|
}
|
|
307
303
|
|
|
308
304
|
public wakeUp() {
|
|
309
|
-
this.
|
|
305
|
+
this.context.physics.engine?.wakeup(this);
|
|
310
306
|
}
|
|
311
307
|
|
|
312
308
|
public applyForce(vec: Vector3, _rel?: THREE.Vector3) {
|
|
313
|
-
this.
|
|
309
|
+
this.context.physics.engine?.addForce(this, vec, true);
|
|
314
310
|
}
|
|
315
311
|
|
|
316
312
|
public applyImpulse(vec: Vector3) {
|
|
317
|
-
this.
|
|
313
|
+
this.context.physics.engine?.applyImpulse(this, vec, true);
|
|
318
314
|
}
|
|
319
315
|
|
|
320
316
|
public setForce(x: number, y: number, z: number) {
|
|
321
|
-
this.
|
|
322
|
-
this.
|
|
317
|
+
this.context.physics.engine?.resetForces(this, true);
|
|
318
|
+
this.context.physics.engine?.addForce(this, { x, y, z }, true);
|
|
323
319
|
}
|
|
324
320
|
|
|
325
321
|
public getVelocity(): Vector3 {
|
|
326
|
-
const vel = this.
|
|
322
|
+
const vel = this.context.physics.engine?.getLinearVelocity(this);
|
|
327
323
|
if (!vel) return this._currentVelocity.set(0, 0, 0);
|
|
328
324
|
this._currentVelocity.x = vel.x;
|
|
329
325
|
this._currentVelocity.y = vel.y;
|
|
@@ -334,25 +330,25 @@ export class Rigidbody extends Behaviour implements IRigidbody {
|
|
|
334
330
|
public setVelocity(x: number | Vector3, y?: number, z?: number) {
|
|
335
331
|
if (x instanceof Vector3) {
|
|
336
332
|
const vec = x;
|
|
337
|
-
this.
|
|
333
|
+
this.context.physics.engine?.setLinearVelocity(this,vec, true);
|
|
338
334
|
return;
|
|
339
335
|
}
|
|
340
336
|
if (y === undefined || z === undefined) return;
|
|
341
|
-
this.
|
|
337
|
+
this.context.physics.engine?.setLinearVelocity(this, { x: x, y: y, z: z }, true);
|
|
342
338
|
}
|
|
343
339
|
|
|
344
340
|
public setAngularVelocity(x: number | Vector3, y?: number, z?: number) {
|
|
345
341
|
if (x instanceof Vector3) {
|
|
346
342
|
const vec = x;
|
|
347
|
-
this.
|
|
343
|
+
this.context.physics.engine?.setAngularVelocity(this, vec, true);
|
|
348
344
|
return;
|
|
349
345
|
}
|
|
350
346
|
if (y === undefined || z === undefined) return;
|
|
351
|
-
this.
|
|
347
|
+
this.context.physics.engine?.setAngularVelocity(this, { x: x, y: y, z: z }, true);
|
|
352
348
|
}
|
|
353
349
|
|
|
354
350
|
public getAngularVelocity(): Vector3 {
|
|
355
|
-
const vel = this.
|
|
351
|
+
const vel = this.context.physics.engine?.getAngularVelocity(this);
|
|
356
352
|
if (!vel) return this._currentVelocity.set(0, 0, 0);
|
|
357
353
|
this._currentVelocity.x = vel.x;
|
|
358
354
|
this._currentVelocity.y = vel.y;
|
|
@@ -381,13 +377,10 @@ export class Rigidbody extends Behaviour implements IRigidbody {
|
|
|
381
377
|
|
|
382
378
|
|
|
383
379
|
private captureVelocity() {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
this._smoothedVelocity.lerp(vel, this.context.time.deltaTime / .1);
|
|
390
|
-
// this._smoothedVelocity.set(0, 1 / this.context.time.deltaTime, 0);
|
|
391
|
-
}
|
|
380
|
+
const wp = getWorldPosition(this.gameObject);
|
|
381
|
+
Rigidbody.tempPosition.copy(wp);
|
|
382
|
+
const vel = wp.sub(this._lastPosition);
|
|
383
|
+
this._lastPosition.copy(Rigidbody.tempPosition);
|
|
384
|
+
this._smoothedVelocity.lerp(vel, this.context.time.deltaTime / .1);
|
|
392
385
|
}
|
|
393
386
|
}
|
|
@@ -17,6 +17,8 @@ import {
|
|
|
17
17
|
Camera,
|
|
18
18
|
Color,
|
|
19
19
|
MeshStandardMaterial,
|
|
20
|
+
sRGBEncoding,
|
|
21
|
+
MeshPhysicalMaterial,
|
|
20
22
|
} from 'three';
|
|
21
23
|
import * as fflate from 'three/examples/jsm/libs/fflate.module.js';
|
|
22
24
|
|
|
@@ -400,13 +402,7 @@ class USDZExporter {
|
|
|
400
402
|
|
|
401
403
|
async parse( scene, options: USDZExporterOptions = new USDZExporterOptions() ) {
|
|
402
404
|
|
|
403
|
-
options = Object.assign(
|
|
404
|
-
ar: {
|
|
405
|
-
anchoring: { type: 'plane' },
|
|
406
|
-
planeAnchoring: { alignment: 'horizontal' }
|
|
407
|
-
},
|
|
408
|
-
extensions: []
|
|
409
|
-
}, options );
|
|
405
|
+
options = Object.assign( new USDZExporterOptions(), options );
|
|
410
406
|
|
|
411
407
|
this.sceneAnchoringOptions = options;
|
|
412
408
|
// @ts-ignore
|
|
@@ -598,7 +594,7 @@ function parseDocument( context: USDZExporterContext ) {
|
|
|
598
594
|
|
|
599
595
|
writer.appendLine( `token preliminary:anchoring:type = "${context.exporter.sceneAnchoringOptions.ar.anchoring.type}"` );
|
|
600
596
|
if (context.exporter.sceneAnchoringOptions.ar.anchoring.type === 'plane')
|
|
601
|
-
writer.appendLine( `token preliminary:planeAnchoring:alignment = "${context.exporter.sceneAnchoringOptions.
|
|
597
|
+
writer.appendLine( `token preliminary:planeAnchoring:alignment = "${context.exporter.sceneAnchoringOptions.planeAnchoring.alignment}"` );
|
|
602
598
|
// bit hacky as we don't have a callback here yet. Relies on the fact that the image is named identical in the ImageTracking extension.
|
|
603
599
|
if (context.exporter.sceneAnchoringOptions.ar.anchoring.type === 'image')
|
|
604
600
|
writer.appendLine( `rel preliminary:imageAnchoring:referenceImage = </${context.document.name}/Scenes/Scene/AnchoringReferenceImage>` );
|
|
@@ -679,21 +675,38 @@ function copyTexture( texture ) {
|
|
|
679
675
|
|
|
680
676
|
const geometry = new PlaneGeometry( 2, 2, 1, 1 );
|
|
681
677
|
const material = new ShaderMaterial( {
|
|
682
|
-
uniforms: {
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
678
|
+
uniforms: {
|
|
679
|
+
blitTexture: new Uniform( texture ),
|
|
680
|
+
},
|
|
681
|
+
defines: {
|
|
682
|
+
IS_SRGB: texture.encoding == sRGBEncoding,
|
|
683
|
+
},
|
|
684
|
+
vertexShader: `
|
|
685
|
+
varying vec2 vUv;
|
|
686
|
+
void main(){
|
|
687
|
+
vUv = uv;
|
|
688
|
+
vUv.y = 1. - vUv.y;
|
|
689
|
+
gl_Position = vec4(position.xy * 1.0,0.,.999999);
|
|
690
|
+
}`,
|
|
691
|
+
fragmentShader: `
|
|
692
|
+
uniform sampler2D blitTexture;
|
|
693
|
+
varying vec2 vUv;
|
|
694
|
+
|
|
695
|
+
// took from threejs 05fc79cd52b79e8c3e8dec1e7dca72c5c39983a4
|
|
696
|
+
vec4 conv_LinearTosRGB( in vec4 value ) {
|
|
697
|
+
return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
void main(){
|
|
701
|
+
gl_FragColor = vec4(vUv.xy, 0, 1);
|
|
702
|
+
|
|
703
|
+
#ifdef IS_SRGB
|
|
704
|
+
gl_FragColor = conv_LinearTosRGB( texture2D( blitTexture, vUv) );
|
|
705
|
+
#else
|
|
706
|
+
gl_FragColor = texture2D( blitTexture, vUv);
|
|
707
|
+
#endif
|
|
708
|
+
}`
|
|
709
|
+
} );
|
|
697
710
|
|
|
698
711
|
const mesh = new Mesh( geometry, material );
|
|
699
712
|
mesh.frustumCulled = false;
|
|
@@ -705,7 +718,9 @@ function copyTexture( texture ) {
|
|
|
705
718
|
renderer.clear();
|
|
706
719
|
renderer.render( scene, cam );
|
|
707
720
|
|
|
708
|
-
|
|
721
|
+
const tex = new Texture( renderer.domElement );
|
|
722
|
+
tex.encoding = texture.encoding;
|
|
723
|
+
return tex;
|
|
709
724
|
|
|
710
725
|
}
|
|
711
726
|
|
|
@@ -825,7 +840,10 @@ export function buildXform( model, writer, context ) {
|
|
|
825
840
|
}
|
|
826
841
|
|
|
827
842
|
if ( geometry )
|
|
828
|
-
writer.beginBlock( `def Xform "${name}" (
|
|
843
|
+
writer.beginBlock( `def Xform "${name}" (
|
|
844
|
+
prepend references = @./geometries/Geometry_${geometry.id}.usd@</Geometry>
|
|
845
|
+
prepend apiSchemas = ["MaterialBindingAPI"]
|
|
846
|
+
)` );
|
|
829
847
|
else if ( camera )
|
|
830
848
|
writer.beginBlock( `def Camera "${name}"` );
|
|
831
849
|
else
|
|
@@ -929,11 +947,11 @@ function buildMesh( geometry ) {
|
|
|
929
947
|
)
|
|
930
948
|
point3f[] points = [${buildVector3Array( attributes.position, count )}]
|
|
931
949
|
${attributes.uv ?
|
|
932
|
-
`
|
|
950
|
+
`texCoord2f[] primvars:st = [${buildVector2Array( attributes.uv, count )}] (
|
|
933
951
|
interpolation = "vertex"
|
|
934
952
|
)` : '' }
|
|
935
953
|
${attributes.uv2 ?
|
|
936
|
-
`
|
|
954
|
+
`texCoord2f[] primvars:st2 = [${buildVector2Array( attributes.uv2, count )}] (
|
|
937
955
|
interpolation = "vertex"
|
|
938
956
|
)` : '' }
|
|
939
957
|
uniform token subdivisionScheme = "none"
|
|
@@ -1051,7 +1069,7 @@ ${array.join( '' )}
|
|
|
1051
1069
|
|
|
1052
1070
|
}
|
|
1053
1071
|
|
|
1054
|
-
function buildMaterial( material, textures ) {
|
|
1072
|
+
function buildMaterial( material: MeshStandardMaterial, textures ) {
|
|
1055
1073
|
|
|
1056
1074
|
// https://graphics.pixar.com/usd/docs/UsdPreviewSurface-Proposal.html
|
|
1057
1075
|
|
|
@@ -1090,6 +1108,10 @@ function buildMaterial( material, textures ) {
|
|
|
1090
1108
|
const textureTransformInput = `</Materials/Material_${material.id}/${uvReader}.outputs:result>`;
|
|
1091
1109
|
const textureTransformOutput = `</Materials/Material_${material.id}/Transform2d_${mapType}.outputs:result>`;
|
|
1092
1110
|
|
|
1111
|
+
const needsTextureScale = mapType !== 'normal' && (color && (color.r !== 1 || color.g !== 1 || color.b !== 1 || opacity !== 1)) || false;
|
|
1112
|
+
const needsNormalScaleAndBias = mapType === 'normal';
|
|
1113
|
+
const normalScaleValueString = (material.normalScale ? material.normalScale.x * 2 : 2).toFixed( PRECISION );
|
|
1114
|
+
|
|
1093
1115
|
return `
|
|
1094
1116
|
${needsTextureTransform ? `def Shader "Transform2d_${mapType}" (
|
|
1095
1117
|
sdrMetadata = {
|
|
@@ -1108,8 +1130,15 @@ function buildMaterial( material, textures ) {
|
|
|
1108
1130
|
{
|
|
1109
1131
|
uniform token info:id = "UsdUVTexture"
|
|
1110
1132
|
asset inputs:file = @textures/Texture_${id}.${isRGBA ? 'png' : 'jpg'}@
|
|
1133
|
+
token inputs:sourceColorSpace = "${ texture.colorSpace === 'srgb' ? 'sRGB' : 'raw' }"
|
|
1111
1134
|
float2 inputs:st.connect = ${needsTextureTransform ? textureTransformOutput : textureTransformInput}
|
|
1135
|
+
${needsTextureScale ? `
|
|
1112
1136
|
float4 inputs:scale = (${color ? color.r + ', ' + color.g + ', ' + color.b : '1, 1, 1'}, ${opacity ? opacity : '1'})
|
|
1137
|
+
` : `` }
|
|
1138
|
+
${needsNormalScaleAndBias ? `
|
|
1139
|
+
float4 inputs:scale = (${normalScaleValueString}, ${normalScaleValueString}, ${normalScaleValueString}, 1)
|
|
1140
|
+
float4 inputs:bias = (-1, -1, -1, 0)
|
|
1141
|
+
` : `` }
|
|
1113
1142
|
token inputs:wrapS = "${wrapS}"
|
|
1114
1143
|
token inputs:wrapT = "${wrapT}"
|
|
1115
1144
|
float outputs:r
|
|
@@ -1221,7 +1250,7 @@ function buildMaterial( material, textures ) {
|
|
|
1221
1250
|
|
|
1222
1251
|
}
|
|
1223
1252
|
|
|
1224
|
-
if ( material
|
|
1253
|
+
if ( material instanceof MeshPhysicalMaterial ) {
|
|
1225
1254
|
|
|
1226
1255
|
inputs.push( `${pad}float inputs:clearcoat = ${material.clearcoat}` );
|
|
1227
1256
|
inputs.push( `${pad}float inputs:clearcoatRoughness = ${material.clearcoatRoughness}` );
|
|
@@ -6,11 +6,11 @@ import { IPointerClickHandler } from "../../../../ui/PointerEvents";
|
|
|
6
6
|
import { RegisteredAnimationInfo, UsdzAnimation } from "../Animation";
|
|
7
7
|
import { getWorldPosition, getWorldQuaternion, getWorldScale, setWorldPosition, setWorldQuaternion, setWorldScale } from "../../../../../engine/engine_three_utils";
|
|
8
8
|
|
|
9
|
-
import { Object3D, Material, Vector3, Quaternion } from "three";
|
|
9
|
+
import { Object3D, Material, Vector3, Quaternion, AnimationAction } from "three";
|
|
10
10
|
import { USDObject } from "../../ThreeUSDZExporter";
|
|
11
11
|
|
|
12
12
|
import { BehaviorExtension, UsdzBehaviour } from "./Behaviour";
|
|
13
|
-
import { ActionBuilder, ActionModel, BehaviorModel, MotionType, Space, TriggerBuilder } from "./BehavioursBuilder";
|
|
13
|
+
import { ActionBuilder, ActionModel, BehaviorModel, IBehaviorElement, MotionType, Space, TriggerBuilder } from "./BehavioursBuilder";
|
|
14
14
|
|
|
15
15
|
export class ChangeTransformOnClick extends Behaviour implements IPointerClickHandler, UsdzBehaviour {
|
|
16
16
|
|
|
@@ -417,6 +417,12 @@ export class PlayAnimationOnClick extends Behaviour implements IPointerClickHand
|
|
|
417
417
|
|
|
418
418
|
@serializable()
|
|
419
419
|
stateName?: string;
|
|
420
|
+
|
|
421
|
+
@serializable()
|
|
422
|
+
stateNameAfterPlaying?: string;
|
|
423
|
+
|
|
424
|
+
@serializable()
|
|
425
|
+
loopAfterPlaying: boolean = false;
|
|
420
426
|
|
|
421
427
|
onPointerClick() {
|
|
422
428
|
if (!this.target) return;
|
|
@@ -425,22 +431,53 @@ export class PlayAnimationOnClick extends Behaviour implements IPointerClickHand
|
|
|
425
431
|
}
|
|
426
432
|
|
|
427
433
|
private selfModel: any;
|
|
428
|
-
|
|
429
|
-
private
|
|
434
|
+
|
|
435
|
+
private stateAnimationModel: any;
|
|
436
|
+
private stateAnimation?: RegisteredAnimationInfo;
|
|
437
|
+
|
|
438
|
+
private stateAfterPlayingAnimationModel: any;
|
|
439
|
+
private stateAfterPlayingAnimation?: RegisteredAnimationInfo;
|
|
430
440
|
|
|
431
441
|
createBehaviours(_ext, model, _context) {
|
|
432
442
|
if (model.uuid === this.gameObject.uuid)
|
|
433
443
|
this.selfModel = model;
|
|
434
444
|
}
|
|
435
445
|
|
|
446
|
+
private static animationActions: ActionModel[] = [];
|
|
447
|
+
|
|
448
|
+
onAfterHierarchy() {
|
|
449
|
+
PlayAnimationOnClick.animationActions = [];
|
|
450
|
+
}
|
|
451
|
+
|
|
436
452
|
afterCreateDocument(ext, context) {
|
|
437
|
-
if (!this.
|
|
453
|
+
if (!this.stateAnimation || !this.stateAnimationModel) return;
|
|
438
454
|
const document = context.document;
|
|
439
455
|
document.traverse(model => {
|
|
440
|
-
if
|
|
456
|
+
// TODO we should probably check if a startAnimationAction already exists, and not have duplicates of identical ones;
|
|
457
|
+
// looks like otherwise we're getting some animation overlap that doesn't look good.
|
|
458
|
+
if (model.uuid === this.target?.uuid && this.stateAnimation) {
|
|
459
|
+
const sequence: IBehaviorElement[] = [];
|
|
460
|
+
let startAction = PlayAnimationOnClick.animationActions.find(a => a.affectedObjects == model && a.start == this.stateAnimation!.start && a.duration == this.stateAnimation!.duration);
|
|
461
|
+
if (!startAction) {
|
|
462
|
+
startAction = ActionBuilder.startAnimationAction(model, this.stateAnimation.start, this.stateAnimation.duration) as ActionModel;
|
|
463
|
+
PlayAnimationOnClick.animationActions.push(startAction);
|
|
464
|
+
}
|
|
465
|
+
sequence.push(startAction);
|
|
466
|
+
|
|
467
|
+
if (this.stateAfterPlayingAnimation && this.stateAfterPlayingAnimationModel) {
|
|
468
|
+
let endAction = PlayAnimationOnClick.animationActions.find(a => a.affectedObjects == model && a.start == this.stateAfterPlayingAnimation!.start && a.duration == this.stateAfterPlayingAnimation!.duration);
|
|
469
|
+
if (!endAction) {
|
|
470
|
+
endAction = ActionBuilder.startAnimationAction(model, this.stateAfterPlayingAnimation.start, this.stateAfterPlayingAnimation.duration) as ActionModel;
|
|
471
|
+
PlayAnimationOnClick.animationActions.push(endAction);
|
|
472
|
+
}
|
|
473
|
+
const idleAnim = ActionBuilder.sequence(endAction);
|
|
474
|
+
if (this.loopAfterPlaying)
|
|
475
|
+
idleAnim.makeLooping();
|
|
476
|
+
sequence.push(idleAnim);
|
|
477
|
+
}
|
|
441
478
|
const playAnimationOnTap = new BehaviorModel("tap " + this.name + " for " + this.stateName + " on " + this.target?.name,
|
|
442
479
|
TriggerBuilder.tapTrigger(this.selfModel),
|
|
443
|
-
ActionBuilder.
|
|
480
|
+
ActionBuilder.sequence(...sequence)
|
|
444
481
|
);
|
|
445
482
|
ext.addBehavior(playAnimationOnTap);
|
|
446
483
|
}
|
|
@@ -449,9 +486,14 @@ export class PlayAnimationOnClick extends Behaviour implements IPointerClickHand
|
|
|
449
486
|
|
|
450
487
|
createAnimation(ext, model, _context) {
|
|
451
488
|
if (this.target && this.animator) {
|
|
489
|
+
|
|
452
490
|
const state = this.animator?.runtimeAnimatorController?.findState(this.stateName);
|
|
453
|
-
this.
|
|
454
|
-
this.
|
|
491
|
+
this.stateAnimationModel = model;
|
|
492
|
+
this.stateAnimation = ext.registerAnimation(this.target, state?.motion.clip);
|
|
493
|
+
|
|
494
|
+
const stateAfter = this.animator?.runtimeAnimatorController?.findState(this.stateNameAfterPlaying);
|
|
495
|
+
this.stateAfterPlayingAnimationModel = model;
|
|
496
|
+
this.stateAfterPlayingAnimation = ext.registerAnimation(this.target, stateAfter?.motion.clip);
|
|
455
497
|
}
|
|
456
498
|
}
|
|
457
499
|
|