s3m-three 0.4.25 → 0.4.27
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/assets/{s3mWorker-jc9Oly5K.js → s3mWorker-BfSBNvF5.js} +1 -1
- package/dist/browser/s3m-three.iife.ext-three.js +119 -36
- package/dist/browser/s3m-three.iife.js +119 -36
- package/dist/core/BakeMercator.d.ts +54 -0
- package/dist/core/BakeMercator.d.ts.map +1 -0
- package/dist/core/BakeMercator.js +65 -0
- package/dist/core/BakeMercator.js.map +1 -0
- package/dist/core/CustomAttributes.d.ts +7 -0
- package/dist/core/CustomAttributes.d.ts.map +1 -0
- package/dist/core/CustomAttributes.js +48 -0
- package/dist/core/CustomAttributes.js.map +1 -0
- package/dist/core/Draco.d.ts.map +1 -1
- package/dist/core/Draco.js +149 -2
- package/dist/core/Draco.js.map +1 -1
- package/dist/core/MeshOpt.d.ts.map +1 -1
- package/dist/core/MeshOpt.js +2 -0
- package/dist/core/MeshOpt.js.map +1 -1
- package/dist/core/S3M1Parser.d.ts.map +1 -1
- package/dist/core/S3M1Parser.js +114 -27
- package/dist/core/S3M1Parser.js.map +1 -1
- package/dist/core/S3MBParser.d.ts +5 -2
- package/dist/core/S3MBParser.d.ts.map +1 -1
- package/dist/core/S3MBParser.js +27 -12
- package/dist/core/S3MBParser.js.map +1 -1
- package/dist/core/TileGeometry.d.ts +8 -0
- package/dist/core/TileGeometry.d.ts.map +1 -1
- package/dist/core/TileGeometry.js +45 -7
- package/dist/core/TileGeometry.js.map +1 -1
- package/dist/core/types.d.ts +1 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/render/DatasetManager.d.ts +27 -0
- package/dist/render/DatasetManager.d.ts.map +1 -1
- package/dist/render/DatasetManager.js +18 -4
- package/dist/render/DatasetManager.js.map +1 -1
- package/dist/render/GeoAdapter.d.ts +49 -24
- package/dist/render/GeoAdapter.d.ts.map +1 -1
- package/dist/render/GeoAdapter.js +96 -8
- package/dist/render/GeoAdapter.js.map +1 -1
- package/dist/render/GeometryBuilder.d.ts +17 -0
- package/dist/render/GeometryBuilder.d.ts.map +1 -1
- package/dist/render/GeometryBuilder.js +67 -4
- package/dist/render/GeometryBuilder.js.map +1 -1
- package/dist/render/MotionBlurPass.d.ts +130 -0
- package/dist/render/MotionBlurPass.d.ts.map +1 -0
- package/dist/render/MotionBlurPass.js +394 -0
- package/dist/render/MotionBlurPass.js.map +1 -0
- package/dist/render/S3MViewer.d.ts +99 -2
- package/dist/render/S3MViewer.d.ts.map +1 -1
- package/dist/render/S3MViewer.js +345 -13
- package/dist/render/S3MViewer.js.map +1 -1
- package/dist/render/StyleMaterial.d.ts +5 -0
- package/dist/render/StyleMaterial.d.ts.map +1 -1
- package/dist/render/StyleMaterial.js +21 -0
- package/dist/render/StyleMaterial.js.map +1 -1
- package/dist/render/tilePlacement.d.ts +84 -0
- package/dist/render/tilePlacement.d.ts.map +1 -0
- package/dist/render/tilePlacement.js +71 -0
- package/dist/render/tilePlacement.js.map +1 -0
- package/dist/render/viewer/EdgeDecorator.d.ts +1 -0
- package/dist/render/viewer/EdgeDecorator.d.ts.map +1 -1
- package/dist/render/viewer/EdgeDecorator.js +3 -0
- package/dist/render/viewer/EdgeDecorator.js.map +1 -1
- package/dist/render/viewer/PickService.d.ts +13 -0
- package/dist/render/viewer/PickService.d.ts.map +1 -1
- package/dist/render/viewer/PickService.js +24 -15
- package/dist/render/viewer/PickService.js.map +1 -1
- package/dist/render/viewer/types.d.ts +75 -0
- package/dist/render/viewer/types.d.ts.map +1 -1
- package/dist/render/viewer/types.js.map +1 -1
- package/dist/tileset/S3MTileset.d.ts +62 -1
- package/dist/tileset/S3MTileset.d.ts.map +1 -1
- package/dist/tileset/S3MTileset.js +273 -6
- package/dist/tileset/S3MTileset.js.map +1 -1
- package/dist/worker/S3MWorkerClient.d.ts +1 -1
- package/dist/worker/S3MWorkerClient.d.ts.map +1 -1
- package/dist/worker/S3MWorkerClient.js +2 -2
- package/dist/worker/S3MWorkerClient.js.map +1 -1
- package/dist/worker/s3mWorker.js +844 -635
- package/dist/worker/s3mWorker.js.map +1 -1
- package/docs/API.md +36 -5
- package/docs/FORMAT-NOTES.md +10 -0
- package/package.json +1 -1
- package/src/core/BakeMercator.ts +96 -0
- package/src/core/CustomAttributes.ts +53 -0
- package/src/core/Draco.ts +168 -6
- package/src/core/MeshOpt.ts +2 -0
- package/src/core/S3M1Parser.ts +102 -22
- package/src/core/S3MBParser.ts +33 -14
- package/src/core/TileGeometry.ts +60 -7
- package/src/core/types.ts +1 -0
- package/src/index.ts +15 -3
- package/src/render/DatasetManager.ts +43 -5
- package/src/render/GeoAdapter.ts +139 -11
- package/src/render/GeometryBuilder.ts +90 -4
- package/src/render/MotionBlurPass.ts +453 -0
- package/src/render/S3MViewer.ts +384 -17
- package/src/render/StyleMaterial.ts +26 -0
- package/src/render/tilePlacement.ts +121 -0
- package/src/render/viewer/EdgeDecorator.ts +3 -0
- package/src/render/viewer/PickService.ts +44 -16
- package/src/render/viewer/types.ts +73 -0
- package/src/tileset/S3MTileset.ts +300 -6
- package/src/vendor/draco_decoder.module.d.ts +15 -1
- package/src/worker/S3MWorkerClient.ts +7 -2
- package/src/worker/s3mWorker.ts +6 -2
package/src/render/GeoAdapter.ts
CHANGED
|
@@ -6,39 +6,151 @@
|
|
|
6
6
|
* 这个文件只定义接口与默认实现,不依赖任何宿主:
|
|
7
7
|
*
|
|
8
8
|
* - `GeoAdapter` —— 宿主需要提供的两个转换函数
|
|
9
|
-
* - `mercatorFromLngLat` / `lngLatFromMercator` —— 标准 Web
|
|
9
|
+
* - `mercatorFromLngLat` / `lngLatFromMercator` —— 标准 Web 墨卡托换算(WGS84 椭球)
|
|
10
10
|
* - `worldFromLngLat` / `lngLatFromWorld` —— 带兜底的封装:
|
|
11
11
|
* 有 adapter 用 adapter(自动适配 MapLibre v5+ 任意 CRS / 自定义投影),
|
|
12
12
|
* 没有就平滑回退到标准 Web 墨卡托。
|
|
13
|
+
* - `enuToLngLat` / `lngLatToEnu` —— WGS84 椭球高精度局部坐标互转
|
|
13
14
|
*
|
|
14
15
|
* MapLibre / Mapbox 的 adapter 实现见 s3m-maplibre 包的 MapLibreGeoAdapter.ts。
|
|
15
16
|
*/
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
/** WGS84 椭球长半轴 a(米) */
|
|
19
|
+
export const WGS84_A = 6378137.0;
|
|
20
|
+
/** WGS84 椭球扁率 f */
|
|
21
|
+
export const WGS84_F = 1 / 298.257223563;
|
|
22
|
+
/** WGS84 椭球短半轴 b(米) */
|
|
23
|
+
export const WGS84_B = WGS84_A * (1 - WGS84_F);
|
|
24
|
+
/** WGS84 椭球第一偏心率平方 e² = 2f - f² ≈ 0.0066943799901413165 */
|
|
25
|
+
export const WGS84_E2 = 2 * WGS84_F - WGS84_F * WGS84_F;
|
|
26
|
+
|
|
27
|
+
/** 保持向下兼容:EARTH_RADIUS 对应 WGS84 长半轴 */
|
|
28
|
+
export const EARTH_RADIUS = WGS84_A;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 卯酉圈曲率半径 N(φ) = a / √(1 - e² sin²φ)(米)
|
|
32
|
+
*/
|
|
33
|
+
export function primeVerticalRadius(latRad: number): number {
|
|
34
|
+
const sin = Math.sin(latRad);
|
|
35
|
+
return WGS84_A / Math.sqrt(1 - WGS84_E2 * sin * sin);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 子午圈曲率半径 M(φ) = a(1 - e²) / (1 - e² sin²φ)^(3/2)(米)
|
|
40
|
+
*/
|
|
41
|
+
export function meridianRadius(latRad: number): number {
|
|
42
|
+
const sin = Math.sin(latRad);
|
|
43
|
+
const w2 = 1 - WGS84_E2 * sin * sin;
|
|
44
|
+
return (WGS84_A * (1 - WGS84_E2)) / (w2 * Math.sqrt(w2));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 局部 ENU 米坐标 (east, north) → 经纬度 [lon, lat] (度)
|
|
49
|
+
* 基于 WGS84 椭球中点曲率半径反解,在 100 km 范围内误差 < 1 cm。
|
|
50
|
+
*/
|
|
51
|
+
export function enuToLngLat(
|
|
52
|
+
anchorLon: number,
|
|
53
|
+
anchorLat: number,
|
|
54
|
+
east: number,
|
|
55
|
+
north: number
|
|
56
|
+
): [number, number] {
|
|
57
|
+
const lat0 = (anchorLat * Math.PI) / 180;
|
|
58
|
+
const M0 = meridianRadius(lat0);
|
|
59
|
+
// 中点迭代一步:在数百公里尺度即可将纬度子午线积分误差压到亚毫米
|
|
60
|
+
const dLatApprox = north / M0;
|
|
61
|
+
const latMid = lat0 + dLatApprox * 0.5;
|
|
62
|
+
const M_mid = meridianRadius(latMid);
|
|
63
|
+
const latRad = lat0 + north / M_mid;
|
|
64
|
+
|
|
65
|
+
const N_lat = primeVerticalRadius(latRad);
|
|
66
|
+
const cosLat = Math.cos(latRad);
|
|
67
|
+
const dLon = Math.abs(cosLat) < 1e-12 ? 0 : east / (N_lat * cosLat);
|
|
68
|
+
|
|
69
|
+
return [anchorLon + (dLon * 180) / Math.PI, (latRad * 180) / Math.PI];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 经纬度 (lon, lat) → 局部 ENU 米坐标 [east, north]
|
|
74
|
+
* enuToLngLat 的逆运算。
|
|
75
|
+
*/
|
|
76
|
+
export function lngLatToEnu(
|
|
77
|
+
anchorLon: number,
|
|
78
|
+
anchorLat: number,
|
|
79
|
+
lon: number,
|
|
80
|
+
lat: number
|
|
81
|
+
): [number, number] {
|
|
82
|
+
const lat0 = (anchorLat * Math.PI) / 180;
|
|
83
|
+
const lat1 = (lat * Math.PI) / 180;
|
|
84
|
+
const latMid = (lat0 + lat1) * 0.5;
|
|
85
|
+
const north = (lat1 - lat0) * meridianRadius(latMid);
|
|
86
|
+
|
|
87
|
+
const N_lat = primeVerticalRadius(lat1);
|
|
88
|
+
const cosLat = Math.cos(lat1);
|
|
89
|
+
const dLon = ((lon - anchorLon) * Math.PI) / 180;
|
|
90
|
+
const east = dLon * N_lat * cosLat;
|
|
91
|
+
|
|
92
|
+
return [east, north];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** 坐标转换结果类型 */
|
|
96
|
+
export interface WorldCoordinateResult {
|
|
97
|
+
x: number;
|
|
98
|
+
y: number;
|
|
99
|
+
z: number;
|
|
100
|
+
/** 东向:1 米 = 多少世界单位 (Web Mercator 东西向尺度 1 / (2π N cosφ)) */
|
|
101
|
+
meterInMercatorEast: number;
|
|
102
|
+
/** 北向:1 米 = 多少世界单位 (Web Mercator 南北向尺度 1 / (2π M cosφ)) */
|
|
103
|
+
meterInMercatorNorth: number;
|
|
104
|
+
/** 竖向(高程):1 米 = 多少世界单位(当前取东向尺度 meterInMercatorEast,以保持局部长方体水平与竖直比例) */
|
|
105
|
+
meterInMercatorUp: number;
|
|
106
|
+
/** 兼容旧代码:等同于 meterInMercatorEast。注意:从原先的正球近似更新为更精准的 WGS84 椭球东向尺度 */
|
|
107
|
+
meterInMercator: number;
|
|
108
|
+
altitude: number;
|
|
109
|
+
}
|
|
18
110
|
|
|
19
111
|
/** 宿主地理坐标系能力:S3M 渲染层用到的就只有这两个方向 */
|
|
20
112
|
export interface GeoAdapter {
|
|
21
|
-
/** 经纬度 + 高程 → 归一化世界坐标,并给出「1 米 =
|
|
113
|
+
/** 经纬度 + 高程 → 归一化世界坐标,并给出「1 米 = 多少世界单位」(含各向异性 East / North) */
|
|
22
114
|
worldFromLngLat(
|
|
23
115
|
lng: number,
|
|
24
116
|
lat: number,
|
|
25
117
|
altitude?: number
|
|
26
|
-
):
|
|
118
|
+
): WorldCoordinateResult;
|
|
27
119
|
/** 归一化世界坐标 → 经纬度 [lng, lat] */
|
|
28
120
|
lngLatFromWorld(x: number, y: number): [number, number];
|
|
29
121
|
}
|
|
30
122
|
|
|
31
|
-
/** 经纬度 → 墨卡托归一化坐标(世界为 1×1)——
|
|
123
|
+
/** 经纬度 → 墨卡托归一化坐标(世界为 1×1)—— 默认墨卡托兜底(WGS84 椭球曲率半径与各向异性尺度) */
|
|
32
124
|
export function mercatorFromLngLat(
|
|
33
125
|
lon: number,
|
|
34
126
|
lat: number,
|
|
35
127
|
altitude = 0
|
|
36
|
-
):
|
|
37
|
-
const
|
|
128
|
+
): WorldCoordinateResult {
|
|
129
|
+
const latRad = (lat * Math.PI) / 180;
|
|
130
|
+
const sinLat = Math.sin(latRad);
|
|
131
|
+
const cosLat = Math.cos(latRad);
|
|
132
|
+
const safeCosLat = Math.max(Math.abs(cosLat), 1e-12);
|
|
133
|
+
|
|
38
134
|
const x = (180 + lon) / 360;
|
|
39
135
|
const y = 0.5 - (0.25 * Math.log((1 + sinLat) / (1 - sinLat))) / Math.PI;
|
|
40
|
-
|
|
41
|
-
|
|
136
|
+
|
|
137
|
+
const N = primeVerticalRadius(latRad);
|
|
138
|
+
const M = meridianRadius(latRad);
|
|
139
|
+
|
|
140
|
+
const meterInMercatorEast = 1 / (2 * Math.PI * N * safeCosLat);
|
|
141
|
+
const meterInMercatorNorth = 1 / (2 * Math.PI * M * safeCosLat);
|
|
142
|
+
const meterInMercatorUp = meterInMercatorEast;
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
x,
|
|
146
|
+
y,
|
|
147
|
+
z: altitude * meterInMercatorUp,
|
|
148
|
+
meterInMercatorEast,
|
|
149
|
+
meterInMercatorNorth,
|
|
150
|
+
meterInMercatorUp,
|
|
151
|
+
meterInMercator: meterInMercatorEast,
|
|
152
|
+
altitude,
|
|
153
|
+
};
|
|
42
154
|
}
|
|
43
155
|
|
|
44
156
|
/** 墨卡托归一化坐标 → 经纬度 —— 默认墨卡托兜底 */
|
|
@@ -58,8 +170,24 @@ export function worldFromLngLat(
|
|
|
58
170
|
lon: number,
|
|
59
171
|
lat: number,
|
|
60
172
|
altitude = 0
|
|
61
|
-
):
|
|
62
|
-
if (adapter)
|
|
173
|
+
): WorldCoordinateResult {
|
|
174
|
+
if (adapter) {
|
|
175
|
+
const res = adapter.worldFromLngLat(lon, lat, altitude);
|
|
176
|
+
const east = res.meterInMercatorEast ?? res.meterInMercator;
|
|
177
|
+
const north = res.meterInMercatorNorth ?? res.meterInMercator ?? east;
|
|
178
|
+
const up = res.meterInMercatorUp ?? east;
|
|
179
|
+
const legacy = res.meterInMercator ?? east;
|
|
180
|
+
return {
|
|
181
|
+
x: res.x,
|
|
182
|
+
y: res.y,
|
|
183
|
+
z: res.z,
|
|
184
|
+
meterInMercatorEast: east,
|
|
185
|
+
meterInMercatorNorth: north,
|
|
186
|
+
meterInMercatorUp: up,
|
|
187
|
+
meterInMercator: legacy,
|
|
188
|
+
altitude: res.altitude,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
63
191
|
return mercatorFromLngLat(lon, lat, altitude);
|
|
64
192
|
}
|
|
65
193
|
|
|
@@ -18,6 +18,8 @@ import { createSharedUniforms, createStyledMaterial } from './StyleMaterial.js';
|
|
|
18
18
|
import { isTransparentMaterial, minVertexAlpha } from './materialAlpha.js';
|
|
19
19
|
import type { StyledMaterial } from './StyleMaterial.js';
|
|
20
20
|
import { assembleTileGeometry, LINE_PRIMITIVE, POINT_PRIMITIVE } from '../core/TileGeometry.js';
|
|
21
|
+
import { bakeMercatorOffsets } from '../core/BakeMercator.js';
|
|
22
|
+
import { mercatorFromLngLat } from './GeoAdapter.js';
|
|
21
23
|
import type { TileGeometryData, PrimitiveData } from '../core/TileGeometry.js';
|
|
22
24
|
import { decodeScale, decodeRotation } from '../core/GaussianSplat.js';
|
|
23
25
|
import { createSplatMaterial, createQuadGeometry, splatRaycast } from './SplatMaterial.js';
|
|
@@ -378,6 +380,15 @@ export interface BuildTileOptions {
|
|
|
378
380
|
* 不传 = 各自读模块级默认。同样由图层的渲染 profile 带下来。
|
|
379
381
|
*/
|
|
380
382
|
textureOptions?: TextureCreateOptions;
|
|
383
|
+
/**
|
|
384
|
+
* 是否烘焙精确 Web 墨卡托偏移属性(消除全球尺度下的视差游动)。
|
|
385
|
+
* 透传给 assembleTileGeometry 和 createStyledMaterial。
|
|
386
|
+
*/
|
|
387
|
+
bakeMercator?: boolean;
|
|
388
|
+
/** 瓦片锚点(经纬度),烘焙墨卡托时使用 */
|
|
389
|
+
tileAnchor?: { lon: number; lat: number; height?: number };
|
|
390
|
+
/** 瓦片中心偏移(ENU 米),烘焙墨卡托时使用 */
|
|
391
|
+
tileCenter?: { x: number; y: number; z?: number };
|
|
381
392
|
}
|
|
382
393
|
|
|
383
394
|
export interface BuildTileResult {
|
|
@@ -475,7 +486,8 @@ export async function buildTileObjects(
|
|
|
475
486
|
code?: string,
|
|
476
487
|
hasAtlasRect = false,
|
|
477
488
|
hasTexCoordZ = false,
|
|
478
|
-
vertexAlphaMin = 1
|
|
489
|
+
vertexAlphaMin = 1,
|
|
490
|
+
hasMercator = false
|
|
479
491
|
): StyledMaterial => {
|
|
480
492
|
const entry = materialList.find((e) => materialName(unwrapMaterial(e)) === code);
|
|
481
493
|
const m = unwrapMaterial(entry);
|
|
@@ -546,6 +558,19 @@ export async function buildTileObjects(
|
|
|
546
558
|
? Math.max((m?.alphaCutoff as number) ?? 0, 0.01)
|
|
547
559
|
: 0;
|
|
548
560
|
|
|
561
|
+
let initialInvScale: [number, number, number] | undefined;
|
|
562
|
+
if (options.tileAnchor) {
|
|
563
|
+
const tileMerc = mercatorFromLngLat(
|
|
564
|
+
options.tileAnchor.lon,
|
|
565
|
+
options.tileAnchor.lat,
|
|
566
|
+
options.tileAnchor.height
|
|
567
|
+
);
|
|
568
|
+
const sEast = tileMerc.meterInMercatorEast ?? tileMerc.meterInMercator;
|
|
569
|
+
const sNorth = tileMerc.meterInMercatorNorth ?? tileMerc.meterInMercator;
|
|
570
|
+
const sUp = tileMerc.meterInMercatorUp ?? sEast;
|
|
571
|
+
initialInvScale = [1.0 / sEast, 1.0 / sNorth, 1.0 / sUp];
|
|
572
|
+
}
|
|
573
|
+
|
|
549
574
|
const mat = createStyledMaterial({
|
|
550
575
|
uniforms,
|
|
551
576
|
map,
|
|
@@ -562,6 +587,9 @@ export async function buildTileObjects(
|
|
|
562
587
|
// 图层 / 数据集的档位;undefined 时 createStyledMaterial 自己回落到模块级默认
|
|
563
588
|
materialQuality: options.materialQuality,
|
|
564
589
|
colorPipeline: options.colorPipeline,
|
|
590
|
+
bakeMercator: hasMercator || options.bakeMercator,
|
|
591
|
+
tilePivot: options.tileCenter ? new THREE.Vector3(options.tileCenter.x, options.tileCenter.y, options.tileCenter.z) : undefined,
|
|
592
|
+
invTileScale: initialInvScale ? new THREE.Vector3(...initialInvScale) : undefined,
|
|
565
593
|
});
|
|
566
594
|
// 用户配置的深度偏移(共面摩尔纹 / 重合面归属的人工定序,见 BuildTileOptions 注释)
|
|
567
595
|
if (options.polygonOffset) {
|
|
@@ -574,11 +602,32 @@ export async function buildTileObjects(
|
|
|
574
602
|
|
|
575
603
|
// 3) 纯数据几何组装:Worker 解析时已顺带产出就直接用,否则主线程现场组装
|
|
576
604
|
// (core/TileGeometry 的同一份实现,两条路径产物一致)
|
|
605
|
+
if (options.assembled && options.bakeMercator && options.tileAnchor) {
|
|
606
|
+
for (const prim of options.assembled.primitives) {
|
|
607
|
+
if (!prim.attributes.aMercatorOffset && prim.attributes.position) {
|
|
608
|
+
const offsets = bakeMercatorOffsets(
|
|
609
|
+
prim.attributes.position.array,
|
|
610
|
+
prim.vertexCount,
|
|
611
|
+
options.tileAnchor,
|
|
612
|
+
options.tileCenter ?? { x: 0, y: 0, z: 0 }
|
|
613
|
+
|
|
614
|
+
);
|
|
615
|
+
prim.attributes.aMercatorOffset = {
|
|
616
|
+
array: offsets,
|
|
617
|
+
components: 3,
|
|
618
|
+
normalized: false,
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
577
623
|
const assembled =
|
|
578
624
|
options.assembled ??
|
|
579
625
|
assembleTileGeometry(tile, {
|
|
580
626
|
batching: options.batching !== false,
|
|
581
627
|
dedupeCoincident: options.dedupeCoincident,
|
|
628
|
+
bakeMercator: options.bakeMercator,
|
|
629
|
+
tileAnchor: options.tileAnchor,
|
|
630
|
+
tileCenter: options.tileCenter,
|
|
582
631
|
});
|
|
583
632
|
stats.vertices = assembled.stats.vertices;
|
|
584
633
|
stats.edgeLines = assembled.stats.edgeLines;
|
|
@@ -610,17 +659,19 @@ export async function buildTileObjects(
|
|
|
610
659
|
const geometry = packPrimitive(prim);
|
|
611
660
|
const geoRef = tile.geoPackage[prim.geoNames[0]] ?? null;
|
|
612
661
|
const vp = geoRef?.vertexPackage;
|
|
662
|
+
const hasMercator = !!prim.attributes.aMercatorOffset;
|
|
613
663
|
const material = makeMaterial(
|
|
614
664
|
prim.passNames[0],
|
|
615
665
|
!!prim.attributes.aAtlasRect,
|
|
616
666
|
!!prim.attributes.aTexCoordZ,
|
|
617
|
-
minVertexAlpha(prim.attributes.aColor)
|
|
667
|
+
minVertexAlpha(prim.attributes.aColor),
|
|
668
|
+
hasMercator
|
|
618
669
|
);
|
|
619
670
|
const matrix =
|
|
620
671
|
prim.matrix && prim.matrix.length === 16 ? new THREE.Matrix4().fromArray(prim.matrix) : null;
|
|
621
672
|
|
|
622
|
-
//
|
|
623
|
-
if (
|
|
673
|
+
// 棱线包(13):线段,不是三角面。默认隐藏,等 setEdges(true) 再显示
|
|
674
|
+
if (prim.primitiveType === LINE_PRIMITIVE) {
|
|
624
675
|
const lines = new THREE.LineSegments(geometry, edgeLineMaterial);
|
|
625
676
|
lines.visible = options.edges === true;
|
|
626
677
|
lines.renderOrder = EDGE_LINES_RENDER_ORDER;
|
|
@@ -636,6 +687,41 @@ export async function buildTileObjects(
|
|
|
636
687
|
continue;
|
|
637
688
|
}
|
|
638
689
|
|
|
690
|
+
// 实体线段 / 折线几何(2=线段,3=折线,如 3D-pipe 管线):实体几何,默认可见并取材质色
|
|
691
|
+
if (prim.primitiveType === 2 || prim.primitiveType === 3) {
|
|
692
|
+
const entry = materialList.find((e) => materialName(unwrapMaterial(e)) === prim.passNames[0]);
|
|
693
|
+
const m = unwrapMaterial(entry);
|
|
694
|
+
const diff = m?.diffuse;
|
|
695
|
+
const lineColor = diff
|
|
696
|
+
? new THREE.Color(diff.r ?? 1, diff.g ?? 1, diff.b ?? 1)
|
|
697
|
+
: new THREE.Color(0xffffff);
|
|
698
|
+
const hasVertColor = !!geometry.getAttribute('aColor') || !!geometry.getAttribute('color');
|
|
699
|
+
if (hasVertColor && !geometry.getAttribute('color')) {
|
|
700
|
+
geometry.setAttribute('color', geometry.getAttribute('aColor')!);
|
|
701
|
+
}
|
|
702
|
+
const lineMaterial = new THREE.LineBasicMaterial({
|
|
703
|
+
color: lineColor,
|
|
704
|
+
vertexColors: hasVertColor,
|
|
705
|
+
transparent: diff?.a !== undefined && diff.a < 1,
|
|
706
|
+
opacity: diff?.a ?? 1,
|
|
707
|
+
});
|
|
708
|
+
const lines = prim.primitiveType === 3
|
|
709
|
+
? new THREE.Line(geometry, lineMaterial)
|
|
710
|
+
: new THREE.LineSegments(geometry, lineMaterial);
|
|
711
|
+
lines.visible = true;
|
|
712
|
+
lines.userData.skeletonName = prim.skeletonName;
|
|
713
|
+
lines.userData.geoRef = geoRef;
|
|
714
|
+
lines.userData.tileRef = tile;
|
|
715
|
+
lines.userData.primitiveType = prim.primitiveType;
|
|
716
|
+
if (matrix && !matrix.equals(IDENTITY)) {
|
|
717
|
+
matrix.decompose(lines.position, lines.quaternion, lines.scale);
|
|
718
|
+
}
|
|
719
|
+
group.add(lines);
|
|
720
|
+
objects.push(lines);
|
|
721
|
+
stats.meshes++;
|
|
722
|
+
continue;
|
|
723
|
+
}
|
|
724
|
+
|
|
639
725
|
// 点云包:顶点即点,按 THREE.Points 渲染。索引只是点序号,直接走 drawRange。
|
|
640
726
|
if (isPointPrimitive(prim.primitiveType)) {
|
|
641
727
|
// 高斯泼溅:带 gsScale / gsRotation 的点云包不画点,画各向异性的高斯片。
|