@needle-tools/engine 4.8.8 → 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 -45
- package/components.needle.json +1 -1
- 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-CK8rTkFm.umd.cjs → needle-engine.bundle-B8QgMEWj.umd.cjs} +145 -145
- package/dist/{needle-engine.bundle-C071tpzX.js → needle-engine.bundle-CBk4h0tH.js} +8352 -8106
- package/dist/{needle-engine.bundle--H5L0liy.min.js → needle-engine.bundle-CF7LvCm4.min.js} +148 -148
- package/dist/needle-engine.d.ts +7 -0
- 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/engine_addressables.js +2 -0
- package/lib/engine/engine_addressables.js.map +1 -1
- package/lib/engine/engine_animation.js +4 -4
- package/lib/engine/engine_animation.js.map +1 -1
- package/lib/engine/engine_assetdatabase.js +6 -6
- package/lib/engine/engine_assetdatabase.js.map +1 -1
- package/lib/engine/engine_camera.d.ts +15 -2
- package/lib/engine/engine_camera.js +9 -2
- package/lib/engine/engine_camera.js.map +1 -1
- package/lib/engine/engine_context.d.ts +8 -2
- package/lib/engine/engine_context.js +21 -3
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_create_objects.d.ts +3 -3
- package/lib/engine/engine_create_objects.js +5 -4
- package/lib/engine/engine_create_objects.js.map +1 -1
- package/lib/engine/engine_gameobject.js +2 -2
- package/lib/engine/engine_gameobject.js.map +1 -1
- package/lib/engine/engine_gltf_builtin_components.js +11 -11
- package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
- package/lib/engine/engine_loaders.callbacks.d.ts +1 -0
- package/lib/engine/engine_loaders.callbacks.js +1 -0
- package/lib/engine/engine_loaders.callbacks.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_lighting_settings.js +5 -2
- package/lib/engine/extensions/NEEDLE_lighting_settings.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_lightmaps.js +1 -1
- package/lib/engine/extensions/NEEDLE_lightmaps.js.map +1 -1
- package/lib/engine/js-extensions/Object3D.d.ts +1 -1
- package/lib/engine/js-extensions/Vector.d.ts +5 -0
- package/lib/engine/js-extensions/Vector.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/webcomponents/needle-engine.d.ts +2 -2
- package/lib/engine/webcomponents/needle-engine.js +11 -18
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine-components/Camera.d.ts +2 -0
- package/lib/engine-components/Camera.js +5 -1
- package/lib/engine-components/Camera.js.map +1 -1
- package/lib/engine-components/ContactShadows.d.ts +12 -2
- package/lib/engine-components/ContactShadows.js +24 -4
- package/lib/engine-components/ContactShadows.js.map +1 -1
- package/lib/engine-components/DropListener.d.ts +4 -3
- package/lib/engine-components/DropListener.js +4 -3
- package/lib/engine-components/DropListener.js.map +1 -1
- package/lib/engine-components/NestedGltf.d.ts +9 -4
- package/lib/engine-components/NestedGltf.js +32 -26
- package/lib/engine-components/NestedGltf.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +29 -6
- package/lib/engine-components/OrbitControls.js +45 -9
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/Renderer.js +2 -1
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/Skybox.js +8 -9
- package/lib/engine-components/Skybox.js.map +1 -1
- package/lib/engine-components/api.d.ts +2 -0
- 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 +4 -4
- package/plugins/common/files.js +6 -3
- package/plugins/vite/alias.js +3 -2
- package/plugins/vite/editor-connection.js +4 -4
- package/src/engine/codegen/register_types.ts +4 -0
- package/src/engine/engine_addressables.ts +2 -0
- package/src/engine/engine_animation.ts +4 -4
- package/src/engine/engine_assetdatabase.ts +7 -7
- package/src/engine/engine_camera.ts +15 -3
- package/src/engine/engine_context.ts +22 -4
- package/src/engine/engine_create_objects.ts +8 -7
- package/src/engine/engine_gameobject.ts +2 -2
- package/src/engine/engine_gltf_builtin_components.ts +12 -11
- package/src/engine/engine_loaders.callbacks.ts +1 -0
- package/src/engine/extensions/NEEDLE_lighting_settings.ts +5 -2
- package/src/engine/extensions/NEEDLE_lightmaps.ts +1 -1
- package/src/engine/js-extensions/Vector.ts +6 -0
- package/src/engine/js-extensions/index.ts +3 -2
- package/src/engine/webcomponents/needle-engine.ts +10 -17
- package/src/engine-components/Camera.ts +7 -1
- package/src/engine-components/ContactShadows.ts +27 -6
- package/src/engine-components/DropListener.ts +4 -3
- package/src/engine-components/NestedGltf.ts +33 -24
- package/src/engine-components/OrbitControls.ts +67 -21
- package/src/engine-components/Renderer.ts +2 -1
- package/src/engine-components/Skybox.ts +9 -10
- package/src/engine-components/api.ts +3 -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
|
@@ -889,6 +889,8 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
889
889
|
}
|
|
890
890
|
else this._fovLerpDuration = this.targetLerpDuration;
|
|
891
891
|
}
|
|
892
|
+
|
|
893
|
+
// if (this.context.mainCameraComponent) this.context.mainCameraComponent.fieldOfView = fov;
|
|
892
894
|
}
|
|
893
895
|
|
|
894
896
|
/** Moves the camera look-at target to a position smoothly.
|
|
@@ -984,22 +986,22 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
984
986
|
*/
|
|
985
987
|
fitCamera(options?: FitCameraOptions);
|
|
986
988
|
fitCamera(objects?: Object3D | Array<Object3D>, options?: Omit<FitCameraOptions, "objects">);
|
|
987
|
-
fitCamera(objectsOrOptions?: Object3D | Array<Object3D> | FitCameraOptions, options?: FitCameraOptions) {
|
|
989
|
+
fitCamera(objectsOrOptions?: Object3D | Array<Object3D> | FitCameraOptions, options?: FitCameraOptions): void {
|
|
988
990
|
|
|
989
991
|
if (this.context.isInXR) {
|
|
990
992
|
// camera fitting in XR is not supported
|
|
993
|
+
console.warn('[OrbitControls] Can not fit camera while XR session is active');
|
|
991
994
|
return;
|
|
992
995
|
}
|
|
993
996
|
|
|
994
997
|
let objects: Object3D | Array<Object3D> | undefined = undefined;
|
|
995
|
-
|
|
996
998
|
// If the user passed in an array as first argument
|
|
997
999
|
if (Array.isArray(objectsOrOptions)) {
|
|
998
1000
|
objects = objectsOrOptions;
|
|
999
1001
|
}
|
|
1000
1002
|
// If the user passed in an object as first argument
|
|
1001
1003
|
else if (objectsOrOptions && "type" in objectsOrOptions) {
|
|
1002
|
-
objects = objectsOrOptions
|
|
1004
|
+
objects = objectsOrOptions;
|
|
1003
1005
|
}
|
|
1004
1006
|
// If the user passed in an object as first argument and options as second argument
|
|
1005
1007
|
else if (objectsOrOptions && typeof objectsOrOptions === "object") {
|
|
@@ -1008,12 +1010,10 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1008
1010
|
objects = options.objects;
|
|
1009
1011
|
}
|
|
1010
1012
|
}
|
|
1011
|
-
|
|
1012
1013
|
// Ensure objects are setup correctly
|
|
1013
1014
|
if (objects && !Array.isArray(objects)) {
|
|
1014
|
-
objects = objects
|
|
1015
|
+
objects = [objects];
|
|
1015
1016
|
}
|
|
1016
|
-
|
|
1017
1017
|
if (!Array.isArray(objects) || objects && objects.length <= 0) {
|
|
1018
1018
|
objects = this.context.scene.children;
|
|
1019
1019
|
}
|
|
@@ -1032,7 +1032,7 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1032
1032
|
return;
|
|
1033
1033
|
}
|
|
1034
1034
|
if (!options) options = {}
|
|
1035
|
-
const { immediate = false, centerCamera
|
|
1035
|
+
const { immediate = false, centerCamera, cameraNearFar = "auto", fitOffset = 1.1, fov = camera?.fov } = options;
|
|
1036
1036
|
const size = new Vector3();
|
|
1037
1037
|
const center = new Vector3();
|
|
1038
1038
|
// TODO would be much better to calculate the bounds in camera space instead of world space -
|
|
@@ -1041,15 +1041,13 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1041
1041
|
// and thus we're just getting some maximum that will work for sure.
|
|
1042
1042
|
const box = getBoundingBox(objects, undefined, this._camera?.threeCamera?.layers);
|
|
1043
1043
|
const boxCopy = box.clone();
|
|
1044
|
-
|
|
1045
|
-
camera.updateMatrixWorld();
|
|
1046
|
-
camera.updateProjectionMatrix();
|
|
1047
1044
|
box.getCenter(center);
|
|
1048
1045
|
|
|
1049
1046
|
const box_size = new Vector3();
|
|
1050
1047
|
box.getSize(box_size);
|
|
1051
1048
|
|
|
1052
1049
|
// project this box into camera space
|
|
1050
|
+
camera.updateMatrixWorld();
|
|
1053
1051
|
box.applyMatrix4(camera.matrixWorldInverse);
|
|
1054
1052
|
|
|
1055
1053
|
box.getSize(size);
|
|
@@ -1078,9 +1076,18 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1078
1076
|
this.minZoom = distance * 0.01;
|
|
1079
1077
|
|
|
1080
1078
|
const verticalOffset = 0.05;
|
|
1081
|
-
|
|
1082
1079
|
const lookAt = center.clone();
|
|
1083
1080
|
lookAt.y -= size.y * verticalOffset;
|
|
1081
|
+
if (options.targetOffset) {
|
|
1082
|
+
if (options.targetOffset.x !== undefined) lookAt.x += options.targetOffset.x;
|
|
1083
|
+
if (options.targetOffset.y !== undefined) lookAt.y += options.targetOffset.y;
|
|
1084
|
+
if (options.targetOffset.z !== undefined) lookAt.z += options.targetOffset.z;
|
|
1085
|
+
}
|
|
1086
|
+
if (options.relativeTargetOffset) {
|
|
1087
|
+
if (options.relativeTargetOffset.x !== undefined) lookAt.x += options.relativeTargetOffset.x * size.x;
|
|
1088
|
+
if (options.relativeTargetOffset.y !== undefined) lookAt.y += options.relativeTargetOffset.y * size.y;
|
|
1089
|
+
if (options.relativeTargetOffset.z !== undefined) lookAt.z += options.relativeTargetOffset.z * size.z;
|
|
1090
|
+
}
|
|
1084
1091
|
this.setLookTargetPosition(lookAt, immediate);
|
|
1085
1092
|
this.setFieldOfView(options.fov, immediate);
|
|
1086
1093
|
|
|
@@ -1092,6 +1099,7 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1092
1099
|
// TODO: this doesnt take the Camera component nearClipPlane into account
|
|
1093
1100
|
camera.near = (distance / 100);
|
|
1094
1101
|
camera.far = boundsMax + distance * 10;
|
|
1102
|
+
camera.updateProjectionMatrix();
|
|
1095
1103
|
|
|
1096
1104
|
// adjust maxZoom so that the ground projection radius is always inside
|
|
1097
1105
|
if (groundprojection) {
|
|
@@ -1104,12 +1112,13 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1104
1112
|
if (currentZoom < this.minZoom) this.minZoom = currentZoom * 0.9;
|
|
1105
1113
|
if (currentZoom > this.maxZoom) this.maxZoom = currentZoom * 1.1;
|
|
1106
1114
|
|
|
1107
|
-
camera.updateMatrixWorld();
|
|
1108
|
-
camera.updateProjectionMatrix();
|
|
1109
|
-
|
|
1110
|
-
const cameraWp = getWorldPosition(camera);
|
|
1111
1115
|
const direction = center.clone();
|
|
1112
|
-
|
|
1116
|
+
if (options.fitDirection) {
|
|
1117
|
+
direction.sub(new Vector3().copy(options.fitDirection).multiplyScalar(1_000_000));
|
|
1118
|
+
}
|
|
1119
|
+
else {
|
|
1120
|
+
direction.sub(camera.worldPosition);
|
|
1121
|
+
}
|
|
1113
1122
|
if (centerCamera === "y")
|
|
1114
1123
|
direction.y = 0;
|
|
1115
1124
|
direction.normalize();
|
|
@@ -1118,6 +1127,16 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1118
1127
|
direction.y += -verticalOffset * 4 * distance;
|
|
1119
1128
|
|
|
1120
1129
|
let cameraLocalPosition = center.clone().sub(direction);
|
|
1130
|
+
if (options.cameraOffset) {
|
|
1131
|
+
if (options.cameraOffset.x !== undefined) cameraLocalPosition.x += options.cameraOffset.x;
|
|
1132
|
+
if (options.cameraOffset.y !== undefined) cameraLocalPosition.y += options.cameraOffset.y;
|
|
1133
|
+
if (options.cameraOffset.z !== undefined) cameraLocalPosition.z += options.cameraOffset.z;
|
|
1134
|
+
}
|
|
1135
|
+
if (options.relativeCameraOffset) {
|
|
1136
|
+
if (options.relativeCameraOffset.x !== undefined) cameraLocalPosition.x += options.relativeCameraOffset.x * size.x;
|
|
1137
|
+
if (options.relativeCameraOffset.y !== undefined) cameraLocalPosition.y += options.relativeCameraOffset.y * size.y;
|
|
1138
|
+
if (options.relativeCameraOffset.z !== undefined) cameraLocalPosition.z += options.relativeCameraOffset.z * size.z;
|
|
1139
|
+
}
|
|
1121
1140
|
if (camera.parent) {
|
|
1122
1141
|
cameraLocalPosition = camera.parent.worldToLocal(cameraLocalPosition);
|
|
1123
1142
|
}
|
|
@@ -1154,7 +1173,7 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
1154
1173
|
/**
|
|
1155
1174
|
* Options for fitting the camera to the scene. Used in {@link OrbitControls.fitCamera}
|
|
1156
1175
|
*/
|
|
1157
|
-
|
|
1176
|
+
export type FitCameraOptions = {
|
|
1158
1177
|
/** When enabled debug rendering will be shown */
|
|
1159
1178
|
debug?: boolean,
|
|
1160
1179
|
/**
|
|
@@ -1166,14 +1185,41 @@ declare type FitCameraOptions = {
|
|
|
1166
1185
|
*/
|
|
1167
1186
|
immediate?: boolean,
|
|
1168
1187
|
|
|
1188
|
+
/** Fit offset: A factor to multiply the distance to the objects by
|
|
1189
|
+
* @default 1.1
|
|
1190
|
+
*/
|
|
1191
|
+
fitOffset?: number,
|
|
1192
|
+
|
|
1193
|
+
/** The direction from which the camera should be fitted in worldspace. If not defined the current camera's position will be used */
|
|
1194
|
+
fitDirection?: Vector3Like,
|
|
1195
|
+
|
|
1169
1196
|
/** If set to "y" the camera will be centered in the y axis */
|
|
1170
1197
|
centerCamera?: "none" | "y",
|
|
1198
|
+
/** Set to 'auto' to update the camera near or far plane based on the fitted-objects bounds */
|
|
1171
1199
|
cameraNearFar?: "keep" | "auto",
|
|
1172
1200
|
|
|
1173
|
-
|
|
1201
|
+
/**
|
|
1202
|
+
* Offset the camera position in world space
|
|
1203
|
+
*/
|
|
1204
|
+
cameraOffset?: Partial<Vector3Like>,
|
|
1205
|
+
/**
|
|
1206
|
+
* Offset the camera position relative to the size of the objects being focused on (e.g. x: 0.5).
|
|
1207
|
+
* Value range: -1 to 1
|
|
1208
|
+
*/
|
|
1209
|
+
relativeCameraOffset?: Partial<Vector3Like>,
|
|
1174
1210
|
|
|
1175
|
-
/**
|
|
1176
|
-
*
|
|
1211
|
+
/**
|
|
1212
|
+
* Offset the camera target position in world space
|
|
1177
1213
|
*/
|
|
1178
|
-
|
|
1214
|
+
targetOffset?: Partial<Vector3Like>,
|
|
1215
|
+
/**
|
|
1216
|
+
* Offset the camera target position relative to the size of the objects being focused on.
|
|
1217
|
+
* Value range: -1 to 1
|
|
1218
|
+
*/
|
|
1219
|
+
relativeTargetOffset?: Partial<Vector3Like>,
|
|
1220
|
+
|
|
1221
|
+
/**
|
|
1222
|
+
* Field of view (FOV) for the camera
|
|
1223
|
+
*/
|
|
1224
|
+
fov?: number,
|
|
1179
1225
|
}
|
|
@@ -706,7 +706,8 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
706
706
|
}
|
|
707
707
|
|
|
708
708
|
if (this.reflectionProbeUsage !== ReflectionProbeUsage.Off && this._reflectionProbe) {
|
|
709
|
-
this.
|
|
709
|
+
if (!this._lightmaps?.length) // Currently reflectionprobes cant be used with lightmaps
|
|
710
|
+
this._reflectionProbe.onSet(this);
|
|
710
711
|
}
|
|
711
712
|
// since three 163 we need to set the envMap to the scene envMap if it is not set
|
|
712
713
|
// otherwise the envmapIntensity has no effect: https://github.com/mrdoob/three.js/pull/27903
|
|
@@ -48,21 +48,20 @@ function createRemoteSkyboxComponent(context: IContext, url: string, skybox: boo
|
|
|
48
48
|
const promises = new Array<Promise<any>>();
|
|
49
49
|
ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, (args) => {
|
|
50
50
|
const context = args.context;
|
|
51
|
-
const
|
|
51
|
+
const backgroundImage = context.domElement.getAttribute("background-image");
|
|
52
52
|
const environmentImage = context.domElement.getAttribute("environment-image");
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (debug) console.log("Creating remote skybox to load " + skyboxImage);
|
|
53
|
+
|
|
54
|
+
if (backgroundImage) {
|
|
55
|
+
if (debug) console.log("Creating RemoteSkybox to load background " + backgroundImage);
|
|
57
56
|
// if the user is loading a GLB without a camera then the CameraUtils (which creates the default camera)
|
|
58
57
|
// checks if we have this attribute set and then sets the skybox clearflags accordingly
|
|
59
58
|
// if the user has a GLB with a camera but set to solid color then the skybox image is not visible -> we will just warn then and not override the camera settings
|
|
60
|
-
const promise = createRemoteSkyboxComponent(context,
|
|
59
|
+
const promise = createRemoteSkyboxComponent(context, backgroundImage, true, false, "background-image");
|
|
61
60
|
if (promise) promises.push(promise);
|
|
62
61
|
}
|
|
63
62
|
if (environmentImage) {
|
|
64
|
-
if (debug) console.log("Creating
|
|
65
|
-
const promise = createRemoteSkyboxComponent(context, environmentImage,
|
|
63
|
+
if (debug) console.log("Creating RemoteSkybox to load environment " + environmentImage);
|
|
64
|
+
const promise = createRemoteSkyboxComponent(context, environmentImage, false, true, "environment-image");
|
|
66
65
|
if (promise) promises.push(promise);
|
|
67
66
|
}
|
|
68
67
|
});
|
|
@@ -200,7 +199,7 @@ export class RemoteSkybox extends Behaviour {
|
|
|
200
199
|
console.warn("Potentially invalid skybox URL: \"" + name + "\" on " + (this.name || this.gameObject?.name || "context"));
|
|
201
200
|
}
|
|
202
201
|
|
|
203
|
-
if (debug) console.log("Set
|
|
202
|
+
if (debug) console.log("Set RemoteSkybox url: " + url);
|
|
204
203
|
|
|
205
204
|
if (this._prevUrl === url && this._prevLoadedEnvironment) {
|
|
206
205
|
this.apply();
|
|
@@ -258,7 +257,7 @@ export class RemoteSkybox extends Behaviour {
|
|
|
258
257
|
this._prevBackground = this.context.scene.background;
|
|
259
258
|
if (this.context.scene.environment !== envMap)
|
|
260
259
|
this._prevEnvironment = this.context.scene.environment;
|
|
261
|
-
if (debug) console.log("Set
|
|
260
|
+
if (debug) console.log("Set RemoteSkybox (" + ((this.environment && this.background) ? "environment and background" : this.environment ? "environment" : this.background ? "background" : "none") + ")", this.url, !Camera.backgroundShouldBeTransparent(this.context));
|
|
262
261
|
if (this.environment)
|
|
263
262
|
this.context.scene.environment = envMap;
|
|
264
263
|
if (this.background && !Camera.backgroundShouldBeTransparent(this.context))
|
|
@@ -51,9 +51,11 @@ import "./CameraUtils.js"
|
|
|
51
51
|
import "./AnimationUtils.js"
|
|
52
52
|
import "./AnimationUtilsAutoplay.js"
|
|
53
53
|
|
|
54
|
-
export { DragMode } from "./DragControls.js"
|
|
54
|
+
export { DragMode } from "./DragControls.js";
|
|
55
55
|
export type { DropListenerNetworkEventArguments, DropListenerOnDropArguments } from "./DropListener.js";
|
|
56
|
+
export { type FitCameraOptions } from "./OrbitControls.js";
|
|
56
57
|
export * from "./particlesystem/api.js"
|
|
58
|
+
export * from "./splines/index.js";
|
|
57
59
|
|
|
58
60
|
// for correct type resolution in JSDoc
|
|
59
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
|
+
}
|