@needle-tools/engine 4.8.8-next.e80f4d7 → 4.8.9-next.5e888f7
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 +10 -0
- package/README.md +50 -49
- package/dist/gltf-progressive-DWiyqrwB.umd.cjs +8 -0
- package/dist/gltf-progressive-DhE1A6hX.min.js +8 -0
- package/dist/{gltf-progressive-BcHT3Nyo.js → gltf-progressive-egsMzRdv.js} +384 -369
- package/dist/{needle-engine.bundle-DK1r3WiC.umd.cjs → needle-engine.bundle-B8QgMEWj.umd.cjs} +138 -138
- package/dist/{needle-engine.bundle-DfWoUjQM.js → needle-engine.bundle-CBk4h0tH.js} +7831 -7612
- package/dist/{needle-engine.bundle-IGziSts0.min.js → needle-engine.bundle-CF7LvCm4.min.js} +142 -142
- package/dist/needle-engine.js +305 -301
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/{postprocessing-Ywv5oKkX.min.js → postprocessing-B_FzkwDz.min.js} +1 -1
- package/dist/{postprocessing-ORx-0eCx.js → postprocessing-DP1U_BpT.js} +2 -2
- package/dist/{postprocessing-CVb_x9YY.umd.cjs → postprocessing-DTX5VXrj.umd.cjs} +1 -1
- package/dist/{three-Dceyffus.umd.cjs → three-BK56xWDs.umd.cjs} +24 -24
- package/dist/{three-BRSLmpyi.js → three-CsHK73Zc.js} +1 -0
- package/dist/{three-CsmWHVn7.min.js → three-TNFQHSFa.min.js} +25 -25
- package/dist/{three-examples-BX_Sktc9.min.js → three-examples-Bph291U2.min.js} +1 -1
- package/dist/{three-examples-CNexix3E.js → three-examples-BvMpKSun.js} +1 -1
- package/dist/{three-examples-DWxXVnws.umd.cjs → three-examples-C9WfZu-X.umd.cjs} +1 -1
- package/dist/{three-mesh-ui-gqAXlGNB.js → three-mesh-ui-CN6aRT7i.js} +1 -1
- package/dist/{three-mesh-ui-Cdh2iW8b.umd.cjs → three-mesh-ui-DnxkZWNA.umd.cjs} +1 -1
- package/dist/{three-mesh-ui-Bwy12Qvg.min.js → three-mesh-ui-n_qS2BM-.min.js} +1 -1
- package/dist/{vendor-xfQ8tKF3.umd.cjs → vendor-8le8g4MS.umd.cjs} +1 -1
- package/dist/{vendor-Z4SPrTcP.js → vendor-Msb9AgYE.js} +1 -1
- package/dist/{vendor-C43vobGc.min.js → vendor-yDFiCnCw.min.js} +1 -1
- package/lib/engine/codegen/register_types.js +4 -0
- package/lib/engine/codegen/register_types.js.map +1 -1
- package/lib/engine/js-extensions/index.d.ts +2 -1
- package/lib/engine/js-extensions/index.js +1 -1
- package/lib/engine/js-extensions/index.js.map +1 -1
- package/lib/engine-components/Camera.d.ts +1 -1
- package/lib/engine-components/Camera.js.map +1 -1
- package/lib/engine-components/OrbitControls.js +2 -2
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/api.d.ts +2 -1
- package/lib/engine-components/api.js +1 -0
- package/lib/engine-components/api.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/lib/engine-components/export/usdz/extensions/behavior/Behaviour.d.ts +1 -1
- package/lib/engine-components/splines/Spline.d.ts +58 -0
- package/lib/engine-components/splines/Spline.js +270 -0
- package/lib/engine-components/splines/Spline.js.map +1 -0
- package/lib/engine-components/splines/SplineUtils.d.ts +12 -0
- package/lib/engine-components/splines/SplineUtils.js +33 -0
- package/lib/engine-components/splines/SplineUtils.js.map +1 -0
- package/lib/engine-components/splines/SplineWalker.d.ts +47 -0
- package/lib/engine-components/splines/SplineWalker.js +113 -0
- package/lib/engine-components/splines/SplineWalker.js.map +1 -0
- package/lib/engine-components/splines/index.d.ts +3 -0
- package/lib/engine-components/splines/index.js +4 -0
- package/lib/engine-components/splines/index.js.map +1 -0
- package/package.json +2 -2
- package/plugins/vite/alias.js +3 -2
- package/src/engine/codegen/register_types.ts +4 -0
- package/src/engine/js-extensions/index.ts +3 -2
- package/src/engine-components/Camera.ts +1 -1
- package/src/engine-components/OrbitControls.ts +2 -5
- package/src/engine-components/api.ts +2 -1
- package/src/engine-components/codegen/components.ts +3 -0
- package/src/engine-components/splines/Spline.ts +284 -0
- package/src/engine-components/splines/SplineUtils.ts +32 -0
- package/src/engine-components/splines/SplineWalker.ts +106 -0
- package/src/engine-components/splines/index.ts +3 -0
- package/dist/gltf-progressive-CH3Q4H06.umd.cjs +0 -8
- package/dist/gltf-progressive-DR6HqF_h.min.js +0 -8
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Vector3 } from "three";
|
|
2
|
+
import { Mathf } from "../../engine/engine_math.js";
|
|
3
|
+
import { SplineContainer, SplineData } from "./Spline.js";
|
|
4
|
+
export var SplineUtils;
|
|
5
|
+
(function (SplineUtils) {
|
|
6
|
+
/**
|
|
7
|
+
* Creates a SplineContainer from an array of points.
|
|
8
|
+
* @param positions The positions of the knots.
|
|
9
|
+
* @param closed Whether the spline is closed (the last knot connects to the first).
|
|
10
|
+
* @param tension The tension of the spline. 0 is no tension, 1 is high tension (straight lines between knots). Default is 0.75.
|
|
11
|
+
* @return The created SplineContainer component - add it to an Object3D to use it.
|
|
12
|
+
*/
|
|
13
|
+
function createFromPoints(positions, closed = false, tension = .75) {
|
|
14
|
+
const spline = new SplineContainer();
|
|
15
|
+
const tangentFactor = 1 - Mathf.clamp(tension, 0, 1);
|
|
16
|
+
positions.forEach((pos, index) => {
|
|
17
|
+
const tangent = new Vector3();
|
|
18
|
+
if (index < positions.length - 1)
|
|
19
|
+
tangent.subVectors(positions[index + 1], pos).normalize().multiplyScalar(tangentFactor);
|
|
20
|
+
else if (closed && positions.length > 1)
|
|
21
|
+
tangent.subVectors(positions[0], pos).normalize().multiplyScalar(tangentFactor);
|
|
22
|
+
const knot = new SplineData();
|
|
23
|
+
knot.position.copy(pos);
|
|
24
|
+
knot.tangentIn.copy(tangent);
|
|
25
|
+
knot.tangentOut.copy(tangent);
|
|
26
|
+
spline.addKnot(knot);
|
|
27
|
+
});
|
|
28
|
+
spline.closed = closed;
|
|
29
|
+
return spline;
|
|
30
|
+
}
|
|
31
|
+
SplineUtils.createFromPoints = createFromPoints;
|
|
32
|
+
})(SplineUtils || (SplineUtils = {}));
|
|
33
|
+
//# sourceMappingURL=SplineUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SplineUtils.js","sourceRoot":"","sources":["../../../src/engine-components/splines/SplineUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG1D,MAAM,KAAW,WAAW,CAyB3B;AAzBD,WAAiB,WAAW;IAExB;;;;;;OAMG;IACH,SAAgB,gBAAgB,CAAC,SAAoB,EAAE,SAAkB,KAAK,EAAE,UAAkB,GAAG;QACjG,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;QACrC,MAAM,aAAa,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACrD,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YAC7B,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;YAC9B,IAAI,KAAK,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;iBACrH,IAAI,MAAM,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;YACzH,MAAM,IAAI,GAAG,IAAI,UAAU,EAAE,CAAC;YAC9B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACxB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC7B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC9B,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACvB,OAAO,MAAM,CAAC;IAClB,CAAC;IAfe,4BAAgB,mBAe/B,CAAA;AACL,CAAC,EAzBgB,WAAW,KAAX,WAAW,QAyB3B"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Object3D } from "three";
|
|
2
|
+
import { Behaviour } from "../Component.js";
|
|
3
|
+
import { SplineContainer } from "./Spline.js";
|
|
4
|
+
/**
|
|
5
|
+
* Moves an object along a spline. Use this with a SplineContainer component.
|
|
6
|
+
*/
|
|
7
|
+
export declare class SplineWalker extends Behaviour {
|
|
8
|
+
/**
|
|
9
|
+
* The spline to use/walk along. Add a SplineContainer component to an object and assign it here.
|
|
10
|
+
*/
|
|
11
|
+
spline: SplineContainer | null;
|
|
12
|
+
/** The object to move along the spline. If object is undefined then the spline walker will use the gameObject the component has been added to
|
|
13
|
+
* @default undefined
|
|
14
|
+
*/
|
|
15
|
+
object?: Object3D | null;
|
|
16
|
+
/** The object to look at while moving along the spline
|
|
17
|
+
* @default null
|
|
18
|
+
*/
|
|
19
|
+
lookAt: Object3D | null;
|
|
20
|
+
/**
|
|
21
|
+
* When clamp is set to true, the position01 value will be clamped between 0 and 1 and the object will not loop the spline.
|
|
22
|
+
* @default false
|
|
23
|
+
*/
|
|
24
|
+
clamp: boolean;
|
|
25
|
+
/** The current position on the spline. The value ranges from 0 (start of the spline curve) to 1 (end of the spline curve)
|
|
26
|
+
* @default 0
|
|
27
|
+
*/
|
|
28
|
+
get position01(): number;
|
|
29
|
+
set position01(v: number);
|
|
30
|
+
/** Resets the position to 0 */
|
|
31
|
+
reset(): void;
|
|
32
|
+
/**
|
|
33
|
+
* If true the SplineWalker will automatically move along the spline
|
|
34
|
+
* @default true
|
|
35
|
+
*/
|
|
36
|
+
autoRun: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* The duration in seconds it takes to complete the whole spline when autoWalk is enabled.
|
|
39
|
+
* @default 10
|
|
40
|
+
*/
|
|
41
|
+
duration: number;
|
|
42
|
+
private _position01;
|
|
43
|
+
/** @internal */
|
|
44
|
+
start(): void;
|
|
45
|
+
update(): void;
|
|
46
|
+
private updateFromPosition;
|
|
47
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { Object3D } from "three";
|
|
8
|
+
import { Mathf } from "../../engine/engine_math.js";
|
|
9
|
+
import { serializeable } from "../../engine/engine_serialization_decorator.js";
|
|
10
|
+
import { Behaviour } from "../Component.js";
|
|
11
|
+
import { SplineContainer } from "./Spline.js";
|
|
12
|
+
/**
|
|
13
|
+
* Moves an object along a spline. Use this with a SplineContainer component.
|
|
14
|
+
*/
|
|
15
|
+
export class SplineWalker extends Behaviour {
|
|
16
|
+
/**
|
|
17
|
+
* The spline to use/walk along. Add a SplineContainer component to an object and assign it here.
|
|
18
|
+
*/
|
|
19
|
+
spline = null;
|
|
20
|
+
/** The object to move along the spline. If object is undefined then the spline walker will use the gameObject the component has been added to
|
|
21
|
+
* @default undefined
|
|
22
|
+
*/
|
|
23
|
+
object = undefined;
|
|
24
|
+
/** The object to look at while moving along the spline
|
|
25
|
+
* @default null
|
|
26
|
+
*/
|
|
27
|
+
lookAt = null;
|
|
28
|
+
/**
|
|
29
|
+
* When clamp is set to true, the position01 value will be clamped between 0 and 1 and the object will not loop the spline.
|
|
30
|
+
* @default false
|
|
31
|
+
*/
|
|
32
|
+
clamp = false;
|
|
33
|
+
/** The current position on the spline. The value ranges from 0 (start of the spline curve) to 1 (end of the spline curve)
|
|
34
|
+
* @default 0
|
|
35
|
+
*/
|
|
36
|
+
// @type float
|
|
37
|
+
get position01() {
|
|
38
|
+
return this._position01;
|
|
39
|
+
}
|
|
40
|
+
set position01(v) {
|
|
41
|
+
this._position01 = v;
|
|
42
|
+
this.updateFromPosition();
|
|
43
|
+
}
|
|
44
|
+
/** Resets the position to 0 */
|
|
45
|
+
reset() {
|
|
46
|
+
this._position01 = 0;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* If true the SplineWalker will automatically move along the spline
|
|
50
|
+
* @default true
|
|
51
|
+
*/
|
|
52
|
+
autoRun = true;
|
|
53
|
+
/**
|
|
54
|
+
* The duration in seconds it takes to complete the whole spline when autoWalk is enabled.
|
|
55
|
+
* @default 10
|
|
56
|
+
*/
|
|
57
|
+
duration = 10;
|
|
58
|
+
// #region internal
|
|
59
|
+
_position01 = 0;
|
|
60
|
+
/** @internal */
|
|
61
|
+
start() {
|
|
62
|
+
if (this.object === undefined)
|
|
63
|
+
this.object = this.gameObject;
|
|
64
|
+
this.updateFromPosition();
|
|
65
|
+
}
|
|
66
|
+
update() {
|
|
67
|
+
if (this.autoRun) {
|
|
68
|
+
this._position01 += this.context.time.deltaTime / this.duration;
|
|
69
|
+
this.updateFromPosition();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
updateFromPosition() {
|
|
73
|
+
if (!this.spline || !this.spline.curve)
|
|
74
|
+
return;
|
|
75
|
+
if (!this.object)
|
|
76
|
+
return;
|
|
77
|
+
if (this.clamp)
|
|
78
|
+
this._position01 = Mathf.clamp01(this._position01);
|
|
79
|
+
else
|
|
80
|
+
this._position01 = this._position01 % 1;
|
|
81
|
+
const t = this._position01 >= 1 ? 1 : this._position01 % 1;
|
|
82
|
+
const pt = this.spline.getPointAt(t);
|
|
83
|
+
this.object.worldPosition = pt;
|
|
84
|
+
if (!this.lookAt) {
|
|
85
|
+
const tan = this.spline.getTangentAt(t);
|
|
86
|
+
this.object.lookAt(pt.add(tan));
|
|
87
|
+
}
|
|
88
|
+
else
|
|
89
|
+
this.object.lookAt(this.lookAt.worldPosition);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
__decorate([
|
|
93
|
+
serializeable(SplineContainer)
|
|
94
|
+
], SplineWalker.prototype, "spline", void 0);
|
|
95
|
+
__decorate([
|
|
96
|
+
serializeable(Object3D)
|
|
97
|
+
], SplineWalker.prototype, "object", void 0);
|
|
98
|
+
__decorate([
|
|
99
|
+
serializeable(Object3D)
|
|
100
|
+
], SplineWalker.prototype, "lookAt", void 0);
|
|
101
|
+
__decorate([
|
|
102
|
+
serializeable()
|
|
103
|
+
], SplineWalker.prototype, "clamp", void 0);
|
|
104
|
+
__decorate([
|
|
105
|
+
serializeable()
|
|
106
|
+
], SplineWalker.prototype, "position01", null);
|
|
107
|
+
__decorate([
|
|
108
|
+
serializeable()
|
|
109
|
+
], SplineWalker.prototype, "autoRun", void 0);
|
|
110
|
+
__decorate([
|
|
111
|
+
serializeable()
|
|
112
|
+
], SplineWalker.prototype, "duration", void 0);
|
|
113
|
+
//# sourceMappingURL=SplineWalker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SplineWalker.js","sourceRoot":"","sources":["../../../src/engine-components/splines/SplineWalker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine-components/splines/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "4.8.
|
|
3
|
+
"version": "4.8.9-next.5e888f7",
|
|
4
4
|
"description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.",
|
|
5
5
|
"main": "dist/needle-engine.min.js",
|
|
6
6
|
"exports": {
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
],
|
|
94
94
|
"dependencies": {
|
|
95
95
|
"@dimforge/rapier3d-compat": "^0.14.0",
|
|
96
|
-
"@needle-tools/gltf-progressive": "3.3.
|
|
96
|
+
"@needle-tools/gltf-progressive": "3.3.3",
|
|
97
97
|
"@needle-tools/three-animation-pointer": "1.0.2",
|
|
98
98
|
"@webxr-input-profiles/motion-controllers": "^1.0.0",
|
|
99
99
|
"flatbuffers": "2.0.4",
|
package/plugins/vite/alias.js
CHANGED
|
@@ -60,8 +60,9 @@ const packages_to_resolve = {
|
|
|
60
60
|
'postprocessing': "auto-resolve",
|
|
61
61
|
'@dimforge/rapier3d-compat': "auto-resolve",
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
'@needle-tools/
|
|
63
|
+
// Note: this isnt necessary anymore since we exclude needle-engine from optimization when locally installed in the dev server
|
|
64
|
+
// '@needle-tools/gltf-progressive': "auto-resolve",
|
|
65
|
+
// '@needle-tools/materialx': "auto-resolve",
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
/**
|
|
@@ -95,6 +95,8 @@ import { SmoothFollow } from "../../engine-components/SmoothFollow.js";
|
|
|
95
95
|
import { SpatialTriggerReceiver } from "../../engine-components/SpatialTrigger.js";
|
|
96
96
|
import { SpatialTrigger } from "../../engine-components/SpatialTrigger.js";
|
|
97
97
|
import { SpectatorCamera } from "../../engine-components/SpectatorCamera.js";
|
|
98
|
+
import { SplineContainer } from "../../engine-components/splines/Spline.js";
|
|
99
|
+
import { SplineWalker } from "../../engine-components/splines/SplineWalker.js";
|
|
98
100
|
import { SpriteRenderer } from "../../engine-components/SpriteRenderer.js";
|
|
99
101
|
import { SyncedCamera } from "../../engine-components/SyncedCamera.js";
|
|
100
102
|
import { SyncedRoom } from "../../engine-components/SyncedRoom.js";
|
|
@@ -245,6 +247,8 @@ TypeStore.add("SmoothFollow", SmoothFollow);
|
|
|
245
247
|
TypeStore.add("SpatialTriggerReceiver", SpatialTriggerReceiver);
|
|
246
248
|
TypeStore.add("SpatialTrigger", SpatialTrigger);
|
|
247
249
|
TypeStore.add("SpectatorCamera", SpectatorCamera);
|
|
250
|
+
TypeStore.add("SplineContainer", SplineContainer);
|
|
251
|
+
TypeStore.add("SplineWalker", SplineWalker);
|
|
248
252
|
TypeStore.add("SpriteRenderer", SpriteRenderer);
|
|
249
253
|
TypeStore.add("SyncedCamera", SyncedCamera);
|
|
250
254
|
TypeStore.add("SyncedRoom", SyncedRoom);
|
|
@@ -9,8 +9,8 @@ import { RenderTexture } from "../engine/engine_texture.js";
|
|
|
9
9
|
import { getTempColor, getWorldPosition } from "../engine/engine_three_utils.js";
|
|
10
10
|
import type { ICamera } from "../engine/engine_types.js"
|
|
11
11
|
import { getParam } from "../engine/engine_utils.js";
|
|
12
|
-
import { RGBAColor } from "../engine/js-extensions/index.js";
|
|
13
12
|
import { NeedleXREventArgs } from "../engine/engine_xr.js";
|
|
13
|
+
import { RGBAColor } from "../engine/js-extensions/index.js";
|
|
14
14
|
import { Behaviour, GameObject } from "./Component.js";
|
|
15
15
|
import { OrbitControls } from "./OrbitControls.js";
|
|
16
16
|
|
|
@@ -995,14 +995,13 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
995
995
|
}
|
|
996
996
|
|
|
997
997
|
let objects: Object3D | Array<Object3D> | undefined = undefined;
|
|
998
|
-
|
|
999
998
|
// If the user passed in an array as first argument
|
|
1000
999
|
if (Array.isArray(objectsOrOptions)) {
|
|
1001
1000
|
objects = objectsOrOptions;
|
|
1002
1001
|
}
|
|
1003
1002
|
// If the user passed in an object as first argument
|
|
1004
1003
|
else if (objectsOrOptions && "type" in objectsOrOptions) {
|
|
1005
|
-
objects = objectsOrOptions
|
|
1004
|
+
objects = objectsOrOptions;
|
|
1006
1005
|
}
|
|
1007
1006
|
// If the user passed in an object as first argument and options as second argument
|
|
1008
1007
|
else if (objectsOrOptions && typeof objectsOrOptions === "object") {
|
|
@@ -1011,12 +1010,10 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1011
1010
|
objects = options.objects;
|
|
1012
1011
|
}
|
|
1013
1012
|
}
|
|
1014
|
-
|
|
1015
1013
|
// Ensure objects are setup correctly
|
|
1016
1014
|
if (objects && !Array.isArray(objects)) {
|
|
1017
|
-
objects = objects
|
|
1015
|
+
objects = [objects];
|
|
1018
1016
|
}
|
|
1019
|
-
|
|
1020
1017
|
if (!Array.isArray(objects) || objects && objects.length <= 0) {
|
|
1021
1018
|
objects = this.context.scene.children;
|
|
1022
1019
|
}
|
|
@@ -52,9 +52,10 @@ import "./AnimationUtils.js"
|
|
|
52
52
|
import "./AnimationUtilsAutoplay.js"
|
|
53
53
|
|
|
54
54
|
export { DragMode } from "./DragControls.js";
|
|
55
|
-
export { type FitCameraOptions } from "./OrbitControls.js";
|
|
56
55
|
export type { DropListenerNetworkEventArguments, DropListenerOnDropArguments } from "./DropListener.js";
|
|
56
|
+
export { type FitCameraOptions } from "./OrbitControls.js";
|
|
57
57
|
export * from "./particlesystem/api.js"
|
|
58
|
+
export * from "./splines/index.js";
|
|
58
59
|
|
|
59
60
|
// for correct type resolution in JSDoc
|
|
60
61
|
import type { PhysicsMaterial } from "../engine/engine_physics.types.js";
|
|
@@ -150,6 +150,9 @@ export { SmoothFollow } from "../SmoothFollow.js";
|
|
|
150
150
|
export { SpatialTriggerReceiver } from "../SpatialTrigger.js";
|
|
151
151
|
export { SpatialTrigger } from "../SpatialTrigger.js";
|
|
152
152
|
export { SpectatorCamera } from "../SpectatorCamera.js";
|
|
153
|
+
export { SplineData } from "../splines/Spline.js";
|
|
154
|
+
export { SplineContainer } from "../splines/Spline.js";
|
|
155
|
+
export { SplineWalker } from "../splines/SplineWalker.js";
|
|
153
156
|
export { Sprite } from "../SpriteRenderer.js";
|
|
154
157
|
export { SpriteSheet } from "../SpriteRenderer.js";
|
|
155
158
|
export { SpriteData } from "../SpriteRenderer.js";
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
|
|
2
|
+
import { BufferGeometry, CatmullRomCurve3, CubicBezierCurve3, Curve, Line, LineBasicMaterial,LineCurve3, Object3D, Quaternion, Vector3 } from "three";
|
|
3
|
+
|
|
4
|
+
import { Mathf } from "../../engine/engine_math.js";
|
|
5
|
+
import { serializeable } from "../../engine/engine_serialization.js";
|
|
6
|
+
import { getParam } from "../../engine/engine_utils.js";
|
|
7
|
+
import { Behaviour } from "../Component.js";
|
|
8
|
+
|
|
9
|
+
const debug = getParam("debugsplines");
|
|
10
|
+
|
|
11
|
+
export class SplineData {
|
|
12
|
+
@serializeable(Vector3)
|
|
13
|
+
position: Vector3 = new Vector3();
|
|
14
|
+
|
|
15
|
+
@serializeable(Quaternion)
|
|
16
|
+
rotation: Quaternion = new Quaternion();
|
|
17
|
+
|
|
18
|
+
@serializeable(Vector3)
|
|
19
|
+
tangentIn: Vector3 = new Vector3();
|
|
20
|
+
|
|
21
|
+
@serializeable(Vector3)
|
|
22
|
+
tangentOut: Vector3 = new Vector3();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// enum SplineTypeEnum {
|
|
26
|
+
// CatmullRom = 0,
|
|
27
|
+
// Bezier = 1,
|
|
28
|
+
// Linear = 2
|
|
29
|
+
// }
|
|
30
|
+
// type SplineType = "CatmullRom" | "Bezier" | "Linear";
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
//@dont-generate-component
|
|
34
|
+
/**
|
|
35
|
+
* Holds spline data and generates a spline curve. Use with SplineWalker to move objects along the spline or call getPointAt to sample points on the spline.
|
|
36
|
+
* The spline is defined by an array of knots (SplineData) which define position, rotation and tangents.
|
|
37
|
+
*
|
|
38
|
+
* You can create a SplineContainer from an array of points using the static method 'createFromPoints'.
|
|
39
|
+
*/
|
|
40
|
+
export class SplineContainer extends Behaviour {
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Adds a knot to the end of the spline.
|
|
44
|
+
*/
|
|
45
|
+
addKnot(knot: SplineData | { position: Vector3 }): SplineContainer {
|
|
46
|
+
if (knot instanceof SplineData) {
|
|
47
|
+
this.spline.push(knot);
|
|
48
|
+
this._isDirty = true;
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
const k = new SplineData();
|
|
52
|
+
k.position.copy(knot.position);
|
|
53
|
+
this.spline.push(k);
|
|
54
|
+
this._isDirty = true;
|
|
55
|
+
}
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Removes a knot by index or by reference.
|
|
61
|
+
*/
|
|
62
|
+
removeKnot(index: number | SplineData): SplineContainer {
|
|
63
|
+
if (typeof index === "number") {
|
|
64
|
+
this.spline.splice(index, 1);
|
|
65
|
+
this._isDirty = true;
|
|
66
|
+
} else {
|
|
67
|
+
const i = this.spline.indexOf(index);
|
|
68
|
+
if (i !== -1) {
|
|
69
|
+
this.spline.splice(i, 1);
|
|
70
|
+
this._isDirty = true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Gets a point on the spline in world space.
|
|
78
|
+
*/
|
|
79
|
+
getPointAt(t: number, target?: Vector3): Vector3 {
|
|
80
|
+
if (!this.curve) return new Vector3();
|
|
81
|
+
const pos = this.curve.getPointAt(Mathf.clamp01(t), target);
|
|
82
|
+
const worldMatrix = this.gameObject.matrixWorld ?? undefined;
|
|
83
|
+
if (worldMatrix) {
|
|
84
|
+
pos.applyMatrix4(worldMatrix);
|
|
85
|
+
}
|
|
86
|
+
return pos;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Marks the spline as dirty, causing it to be rebuilt on the next update.
|
|
91
|
+
*/
|
|
92
|
+
markDirty() {
|
|
93
|
+
this._isDirty = true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Gets the tangent vector on the spline in world space.
|
|
98
|
+
*/
|
|
99
|
+
getTangentAt(t: number, target?: Vector3): Vector3 {
|
|
100
|
+
if (!this.curve) return target ?? new Vector3();
|
|
101
|
+
const wr = this.gameObject.worldQuaternion;
|
|
102
|
+
return this.curve.getTangentAt(Mathf.clamp01(t), target).applyQuaternion(wr);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@serializeable()
|
|
106
|
+
set closed(value: boolean) {
|
|
107
|
+
this._closed = value;
|
|
108
|
+
this._isDirty = true;
|
|
109
|
+
}
|
|
110
|
+
get closed() { return this._closed; }
|
|
111
|
+
private _closed: boolean = false;
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
/** Spline data. Call 'markDirty' if modified */
|
|
115
|
+
@serializeable(SplineData)
|
|
116
|
+
spline: SplineData[] = [];
|
|
117
|
+
|
|
118
|
+
/** Enable to render the spline curve for debugging */
|
|
119
|
+
set debug(debug: boolean) {
|
|
120
|
+
if (debug && !this._builtCurve) this.buildCurve();
|
|
121
|
+
if (!this._debugLine) return;
|
|
122
|
+
this._debugLine.visible = debug;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Gets the spline curve generated from the 'spline' data */
|
|
126
|
+
get curve(): Curve<Vector3> | null {
|
|
127
|
+
return this._curve;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
get isDirty() { return this._isDirty; }
|
|
131
|
+
|
|
132
|
+
private _isDirty: boolean = false;
|
|
133
|
+
|
|
134
|
+
private _curve: Curve<Vector3> | null = null;
|
|
135
|
+
private _builtCurve: boolean = false;
|
|
136
|
+
private _debugLine: Object3D | null = null;
|
|
137
|
+
|
|
138
|
+
/** @internal */
|
|
139
|
+
awake() {
|
|
140
|
+
if (debug) {
|
|
141
|
+
console.log(`[Spline] ${this.name}`, this);
|
|
142
|
+
this.buildCurve();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** @internal */
|
|
147
|
+
update() {
|
|
148
|
+
if (this._isDirty) {
|
|
149
|
+
this.buildCurve(true);
|
|
150
|
+
}
|
|
151
|
+
if (this._debugLine && this._debugLine.parent !== this.gameObject) this.gameObject.add(this._debugLine);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
private buildCurve(force: boolean = false) {
|
|
155
|
+
if (this._builtCurve && !force) return;
|
|
156
|
+
this._builtCurve = true;
|
|
157
|
+
|
|
158
|
+
if (!this.spline) {
|
|
159
|
+
console.error("[Spline] Can not build curve, no spline data", this.name);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
this._isDirty = false;
|
|
163
|
+
this._curve = createCatmullRomCurve(this.spline, this.closed);
|
|
164
|
+
this.buildDebugCurve();
|
|
165
|
+
// TODO: Unity supports spline interpolation type per knot which we don't support right now. Additionally EditType is deprecated. For simplicity we're just supporting CatmullRom for now.
|
|
166
|
+
// switch (this.editType) {
|
|
167
|
+
// case SplineType.CatmullRom:
|
|
168
|
+
// this.createCatmullRomCurve();
|
|
169
|
+
// break;
|
|
170
|
+
// case SplineType.Bezier:
|
|
171
|
+
// console.warn("Bezier spline not implemented yet", this.name);
|
|
172
|
+
// this.createCatmullRomCurve();
|
|
173
|
+
// // this.createBezierCurve();
|
|
174
|
+
// break;
|
|
175
|
+
// case SplineType.Linear:
|
|
176
|
+
// this.createLinearCurve();
|
|
177
|
+
// break;
|
|
178
|
+
// }
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private buildDebugCurve() {
|
|
182
|
+
if (debug && this.spline && this._curve) {
|
|
183
|
+
this._debugLine?.removeFromParent();
|
|
184
|
+
this._debugLine = null;
|
|
185
|
+
|
|
186
|
+
const material = new LineBasicMaterial({
|
|
187
|
+
color: 0x6600ff,
|
|
188
|
+
});
|
|
189
|
+
const res = this.spline.length * 10;
|
|
190
|
+
const splinePoints = this._curve.getPoints(res);
|
|
191
|
+
const geometry = new BufferGeometry().setFromPoints(splinePoints);
|
|
192
|
+
this._debugLine = new Line(geometry, material);
|
|
193
|
+
this.gameObject?.add(this._debugLine);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
function createCatmullRomCurve(data: SplineData[], closed: boolean): CatmullRomCurve3 {
|
|
200
|
+
const points = data.map(knot => new Vector3(-knot.position.x, knot.position.y, knot.position.z));
|
|
201
|
+
if (points.length === 1) points.push(points[0]);
|
|
202
|
+
const averageTension = data.reduce((acc, knot) => acc + Math.abs(knot.tangentOut.x) + Math.abs(knot.tangentOut.y) + Math.abs(knot.tangentOut.z), 0) / data.length;
|
|
203
|
+
const tension = Mathf.remap(averageTension, 0, 0.3, 0, .5);
|
|
204
|
+
return new CatmullRomCurve3(points, closed, "catmullrom", tension);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function createLinearCurve(data: SplineData[], closed: boolean): LineCurve3 | null {
|
|
208
|
+
if (!data || data.length < 2) return null;
|
|
209
|
+
const points = data.map(knot => new Vector3(-knot.position.x, knot.position.y, knot.position.z));
|
|
210
|
+
if (closed) points.push(points[0]);
|
|
211
|
+
return new LineCurve3(points.at(0), points.at(1));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
// function createBezierCurve(data: SplineData[], closed: boolean): CubicBezierCurve3 | null {
|
|
216
|
+
// if (!data || data.length < 2) return null;
|
|
217
|
+
|
|
218
|
+
// for (let k = 0; k < data.length; k++) {
|
|
219
|
+
// const k0 = data[k];
|
|
220
|
+
// let nextIndex = k + 1;
|
|
221
|
+
// if (nextIndex >= data.length) {
|
|
222
|
+
// if (!closed) break;
|
|
223
|
+
// nextIndex = 0;
|
|
224
|
+
// }
|
|
225
|
+
// const k1 = data[nextIndex];
|
|
226
|
+
// // points
|
|
227
|
+
// const p0 = new Vector3(-k0.position.x, k0.position.y, k0.position.z);
|
|
228
|
+
// const p1 = new Vector3(-k1.position.x, k1.position.y, k1.position.z);
|
|
229
|
+
// // tangents
|
|
230
|
+
// const t0 = new Vector3(-k0.tangentOut.x, k0.tangentOut.y, k0.tangentOut.z);
|
|
231
|
+
// const t1 = new Vector3(-k1.tangentIn.x, k1.tangentIn.y, k1.tangentIn.z);
|
|
232
|
+
// // rotations
|
|
233
|
+
// // const q0 = k0.rotation;// new Quaternion(k0.rotation.value.x, k0.rotation.value.y, k0.rotation.value.z, k0.rotation.value.w);
|
|
234
|
+
// // const q1 = k1.rotation;// new Quaternion(k1.rotation.value.x, k1.rotation.value.y, k1.rotation.value.z, k1.rotation.value.w);
|
|
235
|
+
// // const a = new Vector3(0,1,0);
|
|
236
|
+
// // const angle = Math.PI*.5;
|
|
237
|
+
// // t0.sub(p0).applyQuaternion(q0).add(p0);
|
|
238
|
+
// // t1.sub(p1).applyQuaternion(q1).add(p1);
|
|
239
|
+
// t0.add(p0);
|
|
240
|
+
// // t0.applyQuaternion(q0);
|
|
241
|
+
// t1.add(p1);
|
|
242
|
+
// const curve = new CubicBezierCurve3(p0, t0, t1, p1);
|
|
243
|
+
// return curve;
|
|
244
|
+
// }
|
|
245
|
+
// return null;
|
|
246
|
+
// }
|
|
247
|
+
|
|
248
|
+
// class SplineCurve {
|
|
249
|
+
|
|
250
|
+
// private spline: Spline;
|
|
251
|
+
|
|
252
|
+
// constructor(spline: Spline) {
|
|
253
|
+
// this.spline = spline;
|
|
254
|
+
// }
|
|
255
|
+
|
|
256
|
+
// getPoints(num: number): Vector3[] {
|
|
257
|
+
// const points: Vector3[] = [];
|
|
258
|
+
// const samplePerKnot = num / this.spline.length;
|
|
259
|
+
// for (let k = 1; k < this.spline.length; k++) {
|
|
260
|
+
// const cur = this.spline[k];
|
|
261
|
+
// const prev = this.spline[k - 1];
|
|
262
|
+
|
|
263
|
+
// for (let i = 0; i < samplePerKnot; i++) {
|
|
264
|
+
// const t = i / (samplePerKnot - 1);
|
|
265
|
+
// console.log(CurveUtils);
|
|
266
|
+
// const x = this.interpolate(-prev.Position.x, -cur.Position.x, -prev.tangentOut.x, -cur.TangentIn.x, t);
|
|
267
|
+
// const y = this.interpolate(prev.Position.y, cur.Position.y, prev.tangentOut.y, cur.TangentIn.y, t);
|
|
268
|
+
// const z = this.interpolate(prev.Position.z, cur.Position.z, prev.tangentOut.z, cur.TangentIn.z, t);
|
|
269
|
+
// points.push(new Vector3(x, y, z));
|
|
270
|
+
// }
|
|
271
|
+
// }
|
|
272
|
+
|
|
273
|
+
// return points;
|
|
274
|
+
// }
|
|
275
|
+
|
|
276
|
+
// interpolate(p0, p1, p2, p3, t) {
|
|
277
|
+
|
|
278
|
+
// var v0 = (p2 - p0) * 0.5;
|
|
279
|
+
// var v1 = (p3 - p1) * 0.5;
|
|
280
|
+
// var t2 = t * t;
|
|
281
|
+
// var t3 = t * t2;
|
|
282
|
+
// return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (- 3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1;
|
|
283
|
+
// }
|
|
284
|
+
// }
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Vector3 } from "three";
|
|
2
|
+
|
|
3
|
+
import { Mathf } from "../../engine/engine_math.js";
|
|
4
|
+
import { SplineContainer, SplineData } from "./Spline.js";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export namespace SplineUtils {
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates a SplineContainer from an array of points.
|
|
11
|
+
* @param positions The positions of the knots.
|
|
12
|
+
* @param closed Whether the spline is closed (the last knot connects to the first).
|
|
13
|
+
* @param tension The tension of the spline. 0 is no tension, 1 is high tension (straight lines between knots). Default is 0.75.
|
|
14
|
+
* @return The created SplineContainer component - add it to an Object3D to use it.
|
|
15
|
+
*/
|
|
16
|
+
export function createFromPoints(positions: Vector3[], closed: boolean = false, tension: number = .75): SplineContainer {
|
|
17
|
+
const spline = new SplineContainer();
|
|
18
|
+
const tangentFactor = 1 - Mathf.clamp(tension, 0, 1);
|
|
19
|
+
positions.forEach((pos, index) => {
|
|
20
|
+
const tangent = new Vector3();
|
|
21
|
+
if (index < positions.length - 1) tangent.subVectors(positions[index + 1], pos).normalize().multiplyScalar(tangentFactor);
|
|
22
|
+
else if (closed && positions.length > 1) tangent.subVectors(positions[0], pos).normalize().multiplyScalar(tangentFactor);
|
|
23
|
+
const knot = new SplineData();
|
|
24
|
+
knot.position.copy(pos);
|
|
25
|
+
knot.tangentIn.copy(tangent);
|
|
26
|
+
knot.tangentOut.copy(tangent);
|
|
27
|
+
spline.addKnot(knot);
|
|
28
|
+
});
|
|
29
|
+
spline.closed = closed;
|
|
30
|
+
return spline;
|
|
31
|
+
}
|
|
32
|
+
}
|