s3m-three 0.3.8 → 0.3.10
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/dist/browser/s3m-three.iife.ext-three.js +322 -47
- package/dist/browser/s3m-three.iife.js +322 -47
- package/dist/core/types.d.ts +20 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/render/EdgeLines.d.ts +18 -0
- package/dist/render/EdgeLines.d.ts.map +1 -1
- package/dist/render/EdgeLines.js +95 -13
- package/dist/render/EdgeLines.js.map +1 -1
- package/dist/render/FeatureStyleManager.d.ts +78 -0
- package/dist/render/FeatureStyleManager.d.ts.map +1 -1
- package/dist/render/FeatureStyleManager.js +407 -59
- package/dist/render/FeatureStyleManager.js.map +1 -1
- package/dist/render/GPUPathManager.d.ts +95 -0
- package/dist/render/GPUPathManager.d.ts.map +1 -0
- package/dist/render/GPUPathManager.js +265 -0
- package/dist/render/GPUPathManager.js.map +1 -0
- package/dist/render/OrthoProjection.d.ts +6 -0
- package/dist/render/OrthoProjection.d.ts.map +1 -1
- package/dist/render/OrthoProjection.js +48 -0
- package/dist/render/OrthoProjection.js.map +1 -1
- package/dist/render/S3MViewer.d.ts +66 -0
- package/dist/render/S3MViewer.d.ts.map +1 -1
- package/dist/render/S3MViewer.js +218 -6
- package/dist/render/S3MViewer.js.map +1 -1
- package/dist/render/StyleMaterial.d.ts +21 -0
- package/dist/render/StyleMaterial.d.ts.map +1 -1
- package/dist/render/StyleMaterial.js +256 -21
- package/dist/render/StyleMaterial.js.map +1 -1
- package/package.json +1 -1
- package/src/core/types.ts +10 -0
- package/src/index.ts +8 -0
- package/src/render/EdgeLines.ts +101 -13
- package/src/render/FeatureStyleManager.ts +524 -64
- package/src/render/GPUPathManager.ts +306 -0
- package/src/render/OrthoProjection.ts +52 -0
- package/src/render/S3MViewer.ts +272 -5
- package/src/render/StyleMaterial.ts +264 -21
package/src/render/S3MViewer.ts
CHANGED
|
@@ -41,6 +41,8 @@ import type { Channel, TransitionOptions } from '../anim/Animator.js';
|
|
|
41
41
|
import { Path } from '../anim/Path.js';
|
|
42
42
|
import type { EasingFn, EasingName } from '../anim/easing.js';
|
|
43
43
|
import type { LineSharedUniforms, ThickLineMaterial, ThickLineStyleUniforms } from './EdgeLines.js';
|
|
44
|
+
import { GPUPathManager } from './GPUPathManager.js';
|
|
45
|
+
import type { GPUPathOptions } from './FeatureStyleManager.js';
|
|
44
46
|
import {
|
|
45
47
|
buildFeatureEdgeSegments,
|
|
46
48
|
buildPositionBatchMap,
|
|
@@ -94,6 +96,8 @@ import {
|
|
|
94
96
|
type FieldElevationOptions,
|
|
95
97
|
type FieldElevationResult,
|
|
96
98
|
type S3MFilter,
|
|
99
|
+
resolveRotationMatrix,
|
|
100
|
+
extractEulerAngles,
|
|
97
101
|
} from './FeatureStyleManager.js';
|
|
98
102
|
|
|
99
103
|
import {
|
|
@@ -304,7 +308,7 @@ const STYLE_SCALAR_KEYS = [
|
|
|
304
308
|
const STYLE_COLOR_KEYS = ['colorA', 'colorB', 'colorC', 'selectColor', 'edgeColor'] as const;
|
|
305
309
|
|
|
306
310
|
/** 可动画的单体属性 */
|
|
307
|
-
const FEATURE_PROPS = ['translation', 'elevation', 'opacity', 'color'] as const;
|
|
311
|
+
const FEATURE_PROPS = ['translation', 'elevation', 'opacity', 'color', 'rotation'] as const;
|
|
308
312
|
type FeatureProp = (typeof FEATURE_PROPS)[number];
|
|
309
313
|
|
|
310
314
|
/** 单体沿折线运动的参数 */
|
|
@@ -368,6 +372,9 @@ export class S3MViewer {
|
|
|
368
372
|
private readonly _datasetManager = new DatasetManager();
|
|
369
373
|
/** 单体样式、专题着色与状态纹理管理器 */
|
|
370
374
|
private readonly _featureStyleManager: FeatureStyleManager;
|
|
375
|
+
/** GPU 路径动画管理器 */
|
|
376
|
+
readonly gpuPathManager: GPUPathManager = new GPUPathManager();
|
|
377
|
+
private _customPathTime = false;
|
|
371
378
|
|
|
372
379
|
/** 兼容 datasets 映射表暴露 */
|
|
373
380
|
get datasets(): Map<string, S3MDatasetEntry> {
|
|
@@ -948,6 +955,111 @@ export class S3MViewer {
|
|
|
948
955
|
this.moveFeature(smid, [cur[0] + delta[0], cur[1] + delta[1], cur[2] + delta[2]], transition);
|
|
949
956
|
}
|
|
950
957
|
|
|
958
|
+
/**
|
|
959
|
+
* 让单体进行刚体姿态旋转(在 GPU 顶点着色器中以 pivot 轴心进行 3x3 矩阵旋转变换)。
|
|
960
|
+
*
|
|
961
|
+
* @param smid 单体 SMID
|
|
962
|
+
* @param rotation 旋转弧度或姿态:数字(绕 Z 轴 yaw 弧度)| [rx, ry, rz] 欧拉角 | [x,y,z,w] 四元数 | Euler/Quaternion/Matrix
|
|
963
|
+
* @param pivot 旋转中心轴心点 [px, py, pz](局部坐标,默认 [0, 0, 0])
|
|
964
|
+
* @param transition 动画过渡参数
|
|
965
|
+
*/
|
|
966
|
+
rotateFeature(
|
|
967
|
+
smid: number,
|
|
968
|
+
rotation:
|
|
969
|
+
| number
|
|
970
|
+
| [number, number, number]
|
|
971
|
+
| [number, number, number, number]
|
|
972
|
+
| THREE.Euler
|
|
973
|
+
| THREE.Quaternion
|
|
974
|
+
| THREE.Matrix3
|
|
975
|
+
| THREE.Matrix4,
|
|
976
|
+
pivot?: [number, number, number],
|
|
977
|
+
transition?: TransitionOptions
|
|
978
|
+
): void {
|
|
979
|
+
const cur = this._featureStyleManager.getFeatureStyle(smid) ?? {};
|
|
980
|
+
if (pivot) {
|
|
981
|
+
this._featureStyleManager.setFeatureStyle(smid, { ...cur, pivot }, this._meshesOf([smid]));
|
|
982
|
+
}
|
|
983
|
+
const targetEuler = extractEulerAngles(rotation);
|
|
984
|
+
const key = this._ensureFeatureChannel(smid, 'rotation');
|
|
985
|
+
this.animator.to(key, targetEuler, transition);
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
/** 让单体增量旋转的便捷写法 */
|
|
989
|
+
rotateFeatureBy(
|
|
990
|
+
smid: number,
|
|
991
|
+
deltaRotation: number | [number, number, number],
|
|
992
|
+
pivot?: [number, number, number],
|
|
993
|
+
transition?: TransitionOptions
|
|
994
|
+
): void {
|
|
995
|
+
const curEuler = extractEulerAngles(this._featureStyleManager.getFeatureStyle(smid)?.rotation);
|
|
996
|
+
const d = typeof deltaRotation === 'number' ? [0, 0, deltaRotation] : deltaRotation;
|
|
997
|
+
this.rotateFeature(
|
|
998
|
+
smid,
|
|
999
|
+
[curEuler[0] + d[0], curEuler[1] + d[1], curEuler[2] + d[2]],
|
|
1000
|
+
pivot,
|
|
1001
|
+
transition
|
|
1002
|
+
);
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
/**
|
|
1006
|
+
* 双纹理 GPU 交叉淡化(跨状态 / 专题图平滑过渡)。
|
|
1007
|
+
*
|
|
1008
|
+
* 采用双纹理 (uBatchTex + uBatchTex2 + uBatchMix) 硬件混合,
|
|
1009
|
+
* 即使几千上万栋建筑全量切换配色/高度/显隐/姿态,也无需在 CPU 逐单体创建通道,
|
|
1010
|
+
* 由 GPU 顶点与片元着色器以 60FPS 零成本硬件插值完成过渡。
|
|
1011
|
+
*/
|
|
1012
|
+
crossFadeStyles(
|
|
1013
|
+
targetStyles: Map<number, FeatureStyle> | Record<string | number, FeatureStyle>,
|
|
1014
|
+
transition?: TransitionOptions
|
|
1015
|
+
): void {
|
|
1016
|
+
const targetMap =
|
|
1017
|
+
targetStyles instanceof Map
|
|
1018
|
+
? targetStyles
|
|
1019
|
+
: new Map(Object.entries(targetStyles).map(([k, v]) => [Number(k), v]));
|
|
1020
|
+
|
|
1021
|
+
const meshes = this.getAllMeshes();
|
|
1022
|
+
this._featureStyleManager.prepareCrossFade(targetMap, meshes);
|
|
1023
|
+
|
|
1024
|
+
const key = 'batch.mix';
|
|
1025
|
+
if (!this.animator.has(key)) {
|
|
1026
|
+
this.animator.register(key, {
|
|
1027
|
+
dim: 1,
|
|
1028
|
+
read: (out) => {
|
|
1029
|
+
out[0] = this.uniforms.uBatchMix?.value ?? 0;
|
|
1030
|
+
},
|
|
1031
|
+
write: (v) => {
|
|
1032
|
+
if (this.uniforms.uBatchMix) {
|
|
1033
|
+
this.uniforms.uBatchMix.value = v[0];
|
|
1034
|
+
}
|
|
1035
|
+
this.triggerRepaint();
|
|
1036
|
+
},
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
const duration = transition?.duration ?? 0;
|
|
1041
|
+
const wantAnim = duration > 0 || !!transition?.spring;
|
|
1042
|
+
if (!wantAnim) {
|
|
1043
|
+
if (this.animator.has(key)) this.animator.cancel(key);
|
|
1044
|
+
if (this.uniforms.uBatchMix) this.uniforms.uBatchMix.value = 0;
|
|
1045
|
+
this._featureStyleManager.commitCrossFade(targetMap, meshes);
|
|
1046
|
+
this.triggerRepaint();
|
|
1047
|
+
transition?.onComplete?.();
|
|
1048
|
+
return;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
if (this.uniforms.uBatchMix) this.uniforms.uBatchMix.value = 0;
|
|
1052
|
+
this.animator.to(key, 1, {
|
|
1053
|
+
...transition,
|
|
1054
|
+
onComplete: () => {
|
|
1055
|
+
if (this.uniforms.uBatchMix) this.uniforms.uBatchMix.value = 0;
|
|
1056
|
+
this._featureStyleManager.commitCrossFade(targetMap, meshes);
|
|
1057
|
+
this.triggerRepaint();
|
|
1058
|
+
transition?.onComplete?.();
|
|
1059
|
+
},
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
|
|
951
1063
|
/**
|
|
952
1064
|
* 让单体沿折线运动。
|
|
953
1065
|
*
|
|
@@ -1025,6 +1137,96 @@ export class S3MViewer {
|
|
|
1025
1137
|
this.animator.unregister(key);
|
|
1026
1138
|
this._pathSpecs.delete(key);
|
|
1027
1139
|
}
|
|
1140
|
+
|
|
1141
|
+
/**
|
|
1142
|
+
* 注册 GPU 路径到路径库
|
|
1143
|
+
* @param points 折线点数组或 Path 实例
|
|
1144
|
+
* @param opts 选项(可指定路径 ID 或闭合)
|
|
1145
|
+
* @returns 路径 ID
|
|
1146
|
+
*/
|
|
1147
|
+
registerGPUPath(
|
|
1148
|
+
points: Path | ArrayLike<number> | Array<[number, number, number]>,
|
|
1149
|
+
opts: { id?: number; name?: string; closed?: boolean } = {}
|
|
1150
|
+
): number {
|
|
1151
|
+
const id = this.gpuPathManager.registerPath(points, opts);
|
|
1152
|
+
this.gpuPathManager.updateUniforms(this.uniforms);
|
|
1153
|
+
return id;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
/**
|
|
1157
|
+
* 注销 GPU 路径
|
|
1158
|
+
*/
|
|
1159
|
+
unregisterGPUPath(id: number): boolean {
|
|
1160
|
+
const res = this.gpuPathManager.unregisterPath(id);
|
|
1161
|
+
this.gpuPathManager.updateUniforms(this.uniforms);
|
|
1162
|
+
return res;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
/**
|
|
1166
|
+
* 获取 GPUPathManager 实例
|
|
1167
|
+
*/
|
|
1168
|
+
getGPUPathManager(): GPUPathManager {
|
|
1169
|
+
return this.gpuPathManager;
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
/**
|
|
1173
|
+
* 将单体绑定到 GPU 路径动画(智慧交通车流 / 大批量巡检无人机)
|
|
1174
|
+
* @param smid 单体 ID
|
|
1175
|
+
* @param path 路径 ID 或新的路径折线
|
|
1176
|
+
* @param options 动画配置(速度、相位、循环模式、自动朝向等)
|
|
1177
|
+
*/
|
|
1178
|
+
bindGPUPath(
|
|
1179
|
+
smid: number,
|
|
1180
|
+
path: number | Path | ArrayLike<number> | Array<[number, number, number]>,
|
|
1181
|
+
options: Omit<GPUPathOptions, 'pathId'> = {}
|
|
1182
|
+
): number {
|
|
1183
|
+
let pathId: number;
|
|
1184
|
+
if (typeof path === 'number') {
|
|
1185
|
+
pathId = path;
|
|
1186
|
+
} else {
|
|
1187
|
+
pathId = this.registerGPUPath(path);
|
|
1188
|
+
}
|
|
1189
|
+
const meshes = this._meshesOf([smid]);
|
|
1190
|
+
this._featureStyleManager.bindGPUPath(smid, pathId, options, meshes);
|
|
1191
|
+
for (const mesh of meshes) mesh.frustumCulled = false;
|
|
1192
|
+
this.gpuPathManager.updateUniforms(this.uniforms);
|
|
1193
|
+
return pathId;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
/**
|
|
1197
|
+
* 解绑单体的 GPU 路径动画
|
|
1198
|
+
*/
|
|
1199
|
+
unbindGPUPath(smid: number): void {
|
|
1200
|
+
const meshes = this._meshesOf([smid]);
|
|
1201
|
+
this._featureStyleManager.unbindGPUPath(smid, meshes);
|
|
1202
|
+
this.gpuPathManager.updateUniforms(this.uniforms);
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
/**
|
|
1206
|
+
* 手动设置单体在 GPU 路径上的归一化进度(0.0 ~ 1.0)
|
|
1207
|
+
*/
|
|
1208
|
+
setGPUPathProgress(smid: number, progress: number): void {
|
|
1209
|
+
const meshes = this._meshesOf([smid]);
|
|
1210
|
+
this._featureStyleManager.setGPUPathProgress(smid, progress, meshes);
|
|
1211
|
+
for (const mesh of meshes) mesh.frustumCulled = false;
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
/**
|
|
1215
|
+
* 设置全局 GPU 路径时间(秒)
|
|
1216
|
+
*/
|
|
1217
|
+
setGPUPathTime(time: number, autoAdvance = false): void {
|
|
1218
|
+
if (this.uniforms.uPathTime) {
|
|
1219
|
+
this.uniforms.uPathTime.value = time;
|
|
1220
|
+
}
|
|
1221
|
+
this._customPathTime = !autoAdvance;
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
/**
|
|
1225
|
+
* 获取全局 GPU 路径时间(秒)
|
|
1226
|
+
*/
|
|
1227
|
+
getGPUPathTime(): number {
|
|
1228
|
+
return this.uniforms.uPathTime?.value ?? 0;
|
|
1229
|
+
}
|
|
1028
1230
|
/**
|
|
1029
1231
|
* 单体样式过渡:颜色 / 抬高 / 透明度 / 平移可以任意组合。
|
|
1030
1232
|
*
|
|
@@ -1034,6 +1236,7 @@ export class S3MViewer {
|
|
|
1034
1236
|
*/
|
|
1035
1237
|
animateFeature(smid: number, style: Partial<FeatureStyle>, transition?: TransitionOptions): void {
|
|
1036
1238
|
if (style.translation) this.moveFeature(smid, style.translation, transition);
|
|
1239
|
+
if (style.rotation != null) this.rotateFeature(smid, style.rotation, style.pivot, transition);
|
|
1037
1240
|
if (style.elevation != null) {
|
|
1038
1241
|
this.animator.to(this._ensureFeatureChannel(smid, 'elevation'), style.elevation, transition);
|
|
1039
1242
|
}
|
|
@@ -1127,7 +1330,7 @@ export class S3MViewer {
|
|
|
1127
1330
|
const key = `feature.${smid}.${prop}`;
|
|
1128
1331
|
if (this.animator.has(key)) return key;
|
|
1129
1332
|
|
|
1130
|
-
const channel: Channel = prop === 'translation' || prop === 'color'
|
|
1333
|
+
const channel: Channel = prop === 'translation' || prop === 'color' || prop === 'rotation'
|
|
1131
1334
|
? {
|
|
1132
1335
|
dim: 3,
|
|
1133
1336
|
read: (out) => {
|
|
@@ -1136,6 +1339,12 @@ export class S3MViewer {
|
|
|
1136
1339
|
out[0] = t?.[0] ?? 0;
|
|
1137
1340
|
out[1] = t?.[1] ?? 0;
|
|
1138
1341
|
out[2] = t?.[2] ?? 0;
|
|
1342
|
+
} else if (prop === 'rotation') {
|
|
1343
|
+
const r = this._featureStyleManager.getFeatureStyle(smid)?.rotation;
|
|
1344
|
+
const euler = extractEulerAngles(r);
|
|
1345
|
+
out[0] = euler[0];
|
|
1346
|
+
out[1] = euler[1];
|
|
1347
|
+
out[2] = euler[2];
|
|
1139
1348
|
} else {
|
|
1140
1349
|
// 没有自定义色时以图层主色为起点,插值才连续
|
|
1141
1350
|
const hex = this._featureStyleManager.getFeatureStyle(smid)?.color ?? this.style.colorA;
|
|
@@ -1154,9 +1363,21 @@ export class S3MViewer {
|
|
|
1154
1363
|
{ ...cur, translation: [v[0], v[1], v[2]] },
|
|
1155
1364
|
meshes
|
|
1156
1365
|
);
|
|
1157
|
-
//
|
|
1158
|
-
const
|
|
1159
|
-
|
|
1366
|
+
// 有位移或旋转就关掉视锥剔除,否则移出原始包围球后整块瓦片会凭空消失
|
|
1367
|
+
const transMoving = Math.abs(v[0]) > 1e-6 || Math.abs(v[1]) > 1e-6 || Math.abs(v[2]) > 1e-6;
|
|
1368
|
+
const rotEuler = extractEulerAngles(cur.rotation);
|
|
1369
|
+
const rotMoving = Math.abs(rotEuler[0]) > 1e-6 || Math.abs(rotEuler[1]) > 1e-6 || Math.abs(rotEuler[2]) > 1e-6;
|
|
1370
|
+
for (const mesh of meshes) mesh.frustumCulled = !(transMoving || rotMoving);
|
|
1371
|
+
} else if (prop === 'rotation') {
|
|
1372
|
+
this._featureStyleManager.setFeatureStyle(
|
|
1373
|
+
smid,
|
|
1374
|
+
{ ...cur, rotation: [v[0], v[1], v[2]] },
|
|
1375
|
+
meshes
|
|
1376
|
+
);
|
|
1377
|
+
const rotMoving = Math.abs(v[0]) > 1e-6 || Math.abs(v[1]) > 1e-6 || Math.abs(v[2]) > 1e-6;
|
|
1378
|
+
const t = cur.translation ?? [0, 0, 0];
|
|
1379
|
+
const transMoving = Math.abs(t[0]) > 1e-6 || Math.abs(t[1]) > 1e-6 || Math.abs(t[2]) > 1e-6;
|
|
1380
|
+
for (const mesh of meshes) mesh.frustumCulled = !(rotMoving || transMoving);
|
|
1160
1381
|
} else {
|
|
1161
1382
|
const c = this._colorScratch.setRGB(v[0], v[1], v[2]);
|
|
1162
1383
|
this._featureStyleManager.setFeatureStyle(
|
|
@@ -2322,8 +2543,14 @@ export class S3MViewer {
|
|
|
2322
2543
|
const batch = styled?.userData?.uBatchTex
|
|
2323
2544
|
? {
|
|
2324
2545
|
uBatchTex: styled.userData.uBatchTex,
|
|
2546
|
+
uBatchTex2: styled.userData.uBatchTex2,
|
|
2547
|
+
uBatchMix: this.uniforms.uBatchMix,
|
|
2325
2548
|
uBatchTexWidth: styled.userData.uBatchTexWidth,
|
|
2326
2549
|
uBatchTexActive: styled.userData.uBatchTexActive,
|
|
2550
|
+
uPathTex: this.uniforms.uPathTex,
|
|
2551
|
+
uPathCount: this.uniforms.uPathCount,
|
|
2552
|
+
uPathTexActive: this.uniforms.uPathTexActive,
|
|
2553
|
+
uPathTime: this.uniforms.uPathTime,
|
|
2327
2554
|
}
|
|
2328
2555
|
: undefined;
|
|
2329
2556
|
return createThickLineMaterial(this.lineShared, {}, this._edgeStyleUniforms, batch);
|
|
@@ -2335,8 +2562,14 @@ export class S3MViewer {
|
|
|
2335
2562
|
const batch = styled?.userData?.uBatchTex
|
|
2336
2563
|
? {
|
|
2337
2564
|
uBatchTex: styled.userData.uBatchTex,
|
|
2565
|
+
uBatchTex2: styled.userData.uBatchTex2,
|
|
2566
|
+
uBatchMix: this.uniforms.uBatchMix,
|
|
2338
2567
|
uBatchTexWidth: styled.userData.uBatchTexWidth,
|
|
2339
2568
|
uBatchTexActive: styled.userData.uBatchTexActive,
|
|
2569
|
+
uPathTex: this.uniforms.uPathTex,
|
|
2570
|
+
uPathCount: this.uniforms.uPathCount,
|
|
2571
|
+
uPathTexActive: this.uniforms.uPathTexActive,
|
|
2572
|
+
uPathTime: this.uniforms.uPathTime,
|
|
2340
2573
|
}
|
|
2341
2574
|
: undefined;
|
|
2342
2575
|
return createThickLineMaterial(this.lineShared, {}, this._selEdgeStyleUniforms, batch);
|
|
@@ -2501,6 +2734,20 @@ export class S3MViewer {
|
|
|
2501
2734
|
const trans = off.translation;
|
|
2502
2735
|
const elev = off.elevation;
|
|
2503
2736
|
const finalPos = hitPoint.clone();
|
|
2737
|
+
|
|
2738
|
+
if (off.rotation) {
|
|
2739
|
+
const rotMat = resolveRotationMatrix(off.rotation);
|
|
2740
|
+
if (rotMat) {
|
|
2741
|
+
const m3 = new THREE.Matrix3().set(
|
|
2742
|
+
rotMat[0], rotMat[1], rotMat[2],
|
|
2743
|
+
rotMat[3], rotMat[4], rotMat[5],
|
|
2744
|
+
rotMat[6], rotMat[7], rotMat[8]
|
|
2745
|
+
);
|
|
2746
|
+
const piv = off.pivot ? new THREE.Vector3(off.pivot[0], off.pivot[1], off.pivot[2]) : new THREE.Vector3(0, 0, 0);
|
|
2747
|
+
finalPos.sub(piv).applyMatrix3(m3).add(piv);
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
|
|
2504
2751
|
if (trans) finalPos.add(new THREE.Vector3(trans[0], trans[1], trans[2]));
|
|
2505
2752
|
else if (elev) finalPos.z += elev;
|
|
2506
2753
|
|
|
@@ -2731,7 +2978,20 @@ export class S3MViewer {
|
|
|
2731
2978
|
const trans = off.translation;
|
|
2732
2979
|
const elev = off.elevation;
|
|
2733
2980
|
|
|
2981
|
+
const rotMat = off.rotation ? resolveRotationMatrix(off.rotation) : null;
|
|
2982
|
+
let rotM3: THREE.Matrix3 | null = null;
|
|
2983
|
+
let rotPiv: THREE.Vector3 | null = null;
|
|
2984
|
+
if (rotMat) {
|
|
2985
|
+
rotM3 = new THREE.Matrix3().set(
|
|
2986
|
+
rotMat[0], rotMat[1], rotMat[2],
|
|
2987
|
+
rotMat[3], rotMat[4], rotMat[5],
|
|
2988
|
+
rotMat[6], rotMat[7], rotMat[8]
|
|
2989
|
+
);
|
|
2990
|
+
rotPiv = off.pivot ? new THREE.Vector3(off.pivot[0], off.pivot[1], off.pivot[2]) : new THREE.Vector3(0, 0, 0);
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2734
2993
|
for (const c of corners) {
|
|
2994
|
+
if (rotM3 && rotPiv) c.sub(rotPiv).applyMatrix3(rotM3).add(rotPiv);
|
|
2735
2995
|
if (trans) c.add(new THREE.Vector3(trans[0], trans[1], trans[2]));
|
|
2736
2996
|
else if (elev) c.z += elev;
|
|
2737
2997
|
|
|
@@ -3127,6 +3387,12 @@ export class S3MViewer {
|
|
|
3127
3387
|
this.uniforms.uTime.value += 0.016 * (this.style.speed ?? 1);
|
|
3128
3388
|
}
|
|
3129
3389
|
|
|
3390
|
+
this.gpuPathManager.updateUniforms(this.uniforms);
|
|
3391
|
+
const gpuPathActive = (this.uniforms.uPathTexActive?.value ?? 0) > 0;
|
|
3392
|
+
if (gpuPathActive && !this._customPathTime && this.uniforms.uPathTime) {
|
|
3393
|
+
this.uniforms.uPathTime.value += 0.016;
|
|
3394
|
+
}
|
|
3395
|
+
|
|
3130
3396
|
this._updateLights();
|
|
3131
3397
|
|
|
3132
3398
|
// 等宽棱线按设备像素撑开,分辨率每帧同步一次
|
|
@@ -3149,6 +3415,7 @@ export class S3MViewer {
|
|
|
3149
3415
|
return (
|
|
3150
3416
|
animating ||
|
|
3151
3417
|
this.style.mode === STYLE.DYNAMIC ||
|
|
3418
|
+
gpuPathActive ||
|
|
3152
3419
|
this.stats.loading > 0 ||
|
|
3153
3420
|
tilesetChanged
|
|
3154
3421
|
);
|