@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.
Files changed (68) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +50 -49
  3. package/dist/gltf-progressive-DWiyqrwB.umd.cjs +8 -0
  4. package/dist/gltf-progressive-DhE1A6hX.min.js +8 -0
  5. package/dist/{gltf-progressive-BcHT3Nyo.js → gltf-progressive-egsMzRdv.js} +384 -369
  6. package/dist/{needle-engine.bundle-DK1r3WiC.umd.cjs → needle-engine.bundle-B8QgMEWj.umd.cjs} +138 -138
  7. package/dist/{needle-engine.bundle-DfWoUjQM.js → needle-engine.bundle-CBk4h0tH.js} +7831 -7612
  8. package/dist/{needle-engine.bundle-IGziSts0.min.js → needle-engine.bundle-CF7LvCm4.min.js} +142 -142
  9. package/dist/needle-engine.js +305 -301
  10. package/dist/needle-engine.min.js +1 -1
  11. package/dist/needle-engine.umd.cjs +1 -1
  12. package/dist/{postprocessing-Ywv5oKkX.min.js → postprocessing-B_FzkwDz.min.js} +1 -1
  13. package/dist/{postprocessing-ORx-0eCx.js → postprocessing-DP1U_BpT.js} +2 -2
  14. package/dist/{postprocessing-CVb_x9YY.umd.cjs → postprocessing-DTX5VXrj.umd.cjs} +1 -1
  15. package/dist/{three-Dceyffus.umd.cjs → three-BK56xWDs.umd.cjs} +24 -24
  16. package/dist/{three-BRSLmpyi.js → three-CsHK73Zc.js} +1 -0
  17. package/dist/{three-CsmWHVn7.min.js → three-TNFQHSFa.min.js} +25 -25
  18. package/dist/{three-examples-BX_Sktc9.min.js → three-examples-Bph291U2.min.js} +1 -1
  19. package/dist/{three-examples-CNexix3E.js → three-examples-BvMpKSun.js} +1 -1
  20. package/dist/{three-examples-DWxXVnws.umd.cjs → three-examples-C9WfZu-X.umd.cjs} +1 -1
  21. package/dist/{three-mesh-ui-gqAXlGNB.js → three-mesh-ui-CN6aRT7i.js} +1 -1
  22. package/dist/{three-mesh-ui-Cdh2iW8b.umd.cjs → three-mesh-ui-DnxkZWNA.umd.cjs} +1 -1
  23. package/dist/{three-mesh-ui-Bwy12Qvg.min.js → three-mesh-ui-n_qS2BM-.min.js} +1 -1
  24. package/dist/{vendor-xfQ8tKF3.umd.cjs → vendor-8le8g4MS.umd.cjs} +1 -1
  25. package/dist/{vendor-Z4SPrTcP.js → vendor-Msb9AgYE.js} +1 -1
  26. package/dist/{vendor-C43vobGc.min.js → vendor-yDFiCnCw.min.js} +1 -1
  27. package/lib/engine/codegen/register_types.js +4 -0
  28. package/lib/engine/codegen/register_types.js.map +1 -1
  29. package/lib/engine/js-extensions/index.d.ts +2 -1
  30. package/lib/engine/js-extensions/index.js +1 -1
  31. package/lib/engine/js-extensions/index.js.map +1 -1
  32. package/lib/engine-components/Camera.d.ts +1 -1
  33. package/lib/engine-components/Camera.js.map +1 -1
  34. package/lib/engine-components/OrbitControls.js +2 -2
  35. package/lib/engine-components/OrbitControls.js.map +1 -1
  36. package/lib/engine-components/api.d.ts +2 -1
  37. package/lib/engine-components/api.js +1 -0
  38. package/lib/engine-components/api.js.map +1 -1
  39. package/lib/engine-components/codegen/components.d.ts +3 -0
  40. package/lib/engine-components/codegen/components.js +3 -0
  41. package/lib/engine-components/codegen/components.js.map +1 -1
  42. package/lib/engine-components/export/usdz/extensions/behavior/Behaviour.d.ts +1 -1
  43. package/lib/engine-components/splines/Spline.d.ts +58 -0
  44. package/lib/engine-components/splines/Spline.js +270 -0
  45. package/lib/engine-components/splines/Spline.js.map +1 -0
  46. package/lib/engine-components/splines/SplineUtils.d.ts +12 -0
  47. package/lib/engine-components/splines/SplineUtils.js +33 -0
  48. package/lib/engine-components/splines/SplineUtils.js.map +1 -0
  49. package/lib/engine-components/splines/SplineWalker.d.ts +47 -0
  50. package/lib/engine-components/splines/SplineWalker.js +113 -0
  51. package/lib/engine-components/splines/SplineWalker.js.map +1 -0
  52. package/lib/engine-components/splines/index.d.ts +3 -0
  53. package/lib/engine-components/splines/index.js +4 -0
  54. package/lib/engine-components/splines/index.js.map +1 -0
  55. package/package.json +2 -2
  56. package/plugins/vite/alias.js +3 -2
  57. package/src/engine/codegen/register_types.ts +4 -0
  58. package/src/engine/js-extensions/index.ts +3 -2
  59. package/src/engine-components/Camera.ts +1 -1
  60. package/src/engine-components/OrbitControls.ts +2 -5
  61. package/src/engine-components/api.ts +2 -1
  62. package/src/engine-components/codegen/components.ts +3 -0
  63. package/src/engine-components/splines/Spline.ts +284 -0
  64. package/src/engine-components/splines/SplineUtils.ts +32 -0
  65. package/src/engine-components/splines/SplineWalker.ts +106 -0
  66. package/src/engine-components/splines/index.ts +3 -0
  67. package/dist/gltf-progressive-CH3Q4H06.umd.cjs +0 -8
  68. 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,3 @@
1
+ export { SplineContainer } from "./Spline.js";
2
+ export { SplineUtils } from "./SplineUtils.js";
3
+ export { SplineWalker } from "./SplineWalker.js";
@@ -0,0 +1,4 @@
1
+ export { SplineContainer } from "./Spline.js";
2
+ export { SplineUtils } from "./SplineUtils.js";
3
+ export { SplineWalker } from "./SplineWalker.js";
4
+ //# sourceMappingURL=index.js.map
@@ -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.8-next.e80f4d7",
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.2",
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",
@@ -60,8 +60,9 @@ const packages_to_resolve = {
60
60
  'postprocessing': "auto-resolve",
61
61
  '@dimforge/rapier3d-compat': "auto-resolve",
62
62
 
63
- '@needle-tools/gltf-progressive': "auto-resolve",
64
- '@needle-tools/materialx': "auto-resolve",
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);
@@ -1,5 +1,6 @@
1
1
  import "./Layers.js";
2
2
  import "./Camera.js";
3
3
  export * from "./ExtensionUtils.js";
4
- export * from "./Object3D.js";
5
- export * from "./RGBAColor.js";
4
+ export { apply } from "./Object3D.js";
5
+ export * from "./RGBAColor.js";
6
+ export { } from "./Vector.js";
@@ -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.children;
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.children;
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
+ }