@reearth/core 0.0.7-alpha.43 → 0.0.7-alpha.45
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/core.js +4440 -4401
- package/dist/core.umd.cjs +68 -68
- package/package.json +1 -1
- package/src/Visualizer/hooks.ts +1 -1
- package/src/engines/Cesium/Feature/Tileset/hooks.ts +16 -8
- package/src/engines/Cesium/core/Globe/index.tsx +73 -0
- package/src/engines/Cesium/core/Globe/useTerrainProviderPromise.ts +79 -0
- package/src/engines/Cesium/hooks/useOverrideGlobeShader/useOverrideGlobeShader.ts +95 -49
- package/src/engines/Cesium/core/Globe.tsx +0 -113
package/package.json
CHANGED
package/src/Visualizer/hooks.ts
CHANGED
|
@@ -82,7 +82,7 @@ export default function useHooks(
|
|
|
82
82
|
info: SelectedFeatureInfo | undefined,
|
|
83
83
|
) => {
|
|
84
84
|
const isSketchLayer =
|
|
85
|
-
selectedLayer.layer?.layer
|
|
85
|
+
selectedLayer.layer?.layer?.type === "simple" &&
|
|
86
86
|
selectedLayer.layer?.layer?.data?.isSketchLayer;
|
|
87
87
|
// Sketch layer feature has a fixed featureId, we need to exclude it from the skip condition
|
|
88
88
|
if (
|
|
@@ -177,7 +177,7 @@ const convertStyle = (val: any, convert: StyleProperty["convert"]) => {
|
|
|
177
177
|
|
|
178
178
|
const useFeature = ({
|
|
179
179
|
id,
|
|
180
|
-
|
|
180
|
+
tilesetRef,
|
|
181
181
|
idProperty,
|
|
182
182
|
layer,
|
|
183
183
|
viewer,
|
|
@@ -189,7 +189,7 @@ const useFeature = ({
|
|
|
189
189
|
isTilesetReady,
|
|
190
190
|
}: {
|
|
191
191
|
id?: string;
|
|
192
|
-
|
|
192
|
+
tilesetRef: MutableRefObject<Cesium3DTileset | undefined>;
|
|
193
193
|
idProperty?: string;
|
|
194
194
|
layer?: ComputedLayer;
|
|
195
195
|
viewer?: Viewer;
|
|
@@ -327,10 +327,10 @@ const useFeature = ({
|
|
|
327
327
|
handleTilesetLoadRef.current = handleTilesetLoad;
|
|
328
328
|
useEffect(
|
|
329
329
|
() =>
|
|
330
|
-
|
|
330
|
+
tilesetRef.current?.tileLoad.addEventListener((t: Cesium3DTile) =>
|
|
331
331
|
handleTilesetLoadRef.current(t),
|
|
332
332
|
),
|
|
333
|
-
[
|
|
333
|
+
[tilesetRef, isTilesetReady],
|
|
334
334
|
);
|
|
335
335
|
|
|
336
336
|
const handleTilesetUnload = useCallback(
|
|
@@ -346,10 +346,10 @@ const useFeature = ({
|
|
|
346
346
|
handleTilesetUnloadRef.current = handleTilesetUnload;
|
|
347
347
|
useEffect(
|
|
348
348
|
() =>
|
|
349
|
-
|
|
349
|
+
tilesetRef.current?.tileUnload.addEventListener((t: Cesium3DTile) =>
|
|
350
350
|
handleTilesetUnloadRef.current(t),
|
|
351
351
|
),
|
|
352
|
-
[
|
|
352
|
+
[tilesetRef, isTilesetReady],
|
|
353
353
|
);
|
|
354
354
|
|
|
355
355
|
useEffect(() => {
|
|
@@ -487,6 +487,8 @@ export const useHooks = ({
|
|
|
487
487
|
const shouldUseFeatureIndex = !disableIndexingFeature && !!idProperty;
|
|
488
488
|
|
|
489
489
|
const [isTilesetReady, setIsTilesetReady] = useState(false);
|
|
490
|
+
const [isTilesetCompReady, setIsTilesetCompReady] = useState(false);
|
|
491
|
+
const [isTilesetRefReady, setIsTilesetRefReady] = useState(false);
|
|
490
492
|
|
|
491
493
|
const prevPlanes = useRef(_planes);
|
|
492
494
|
const planes = useMemo(() => {
|
|
@@ -566,6 +568,7 @@ export const useHooks = ({
|
|
|
566
568
|
(tileset?.cesiumElement as any)[layerIdField] = layer.id;
|
|
567
569
|
}
|
|
568
570
|
tilesetRef.current = tileset?.cesiumElement;
|
|
571
|
+
setIsTilesetRefReady(!!tileset?.cesiumElement);
|
|
569
572
|
},
|
|
570
573
|
[id, layer?.id, featureIndex, shouldUseFeatureIndex],
|
|
571
574
|
);
|
|
@@ -602,7 +605,7 @@ export const useHooks = ({
|
|
|
602
605
|
|
|
603
606
|
useFeature({
|
|
604
607
|
id,
|
|
605
|
-
|
|
608
|
+
tilesetRef,
|
|
606
609
|
layer,
|
|
607
610
|
idProperty,
|
|
608
611
|
viewer,
|
|
@@ -806,13 +809,18 @@ export const useHooks = ({
|
|
|
806
809
|
|
|
807
810
|
const handleReady = useCallback(
|
|
808
811
|
(tileset: Cesium3DTileset) => {
|
|
809
|
-
|
|
812
|
+
setIsTilesetCompReady(true);
|
|
810
813
|
onLayerFetch?.({ properties: tileset.properties });
|
|
811
814
|
onLayerLoad?.({ layerId: layerIdRef.current });
|
|
812
815
|
},
|
|
813
816
|
[onLayerFetch, onLayerLoad],
|
|
814
817
|
);
|
|
815
818
|
|
|
819
|
+
useEffect(() => {
|
|
820
|
+
if (!isTilesetCompReady || !isTilesetRefReady) return;
|
|
821
|
+
setIsTilesetReady(true);
|
|
822
|
+
}, [isTilesetCompReady, isTilesetRefReady]);
|
|
823
|
+
|
|
816
824
|
useEffect(() => {
|
|
817
825
|
updateCredits?.();
|
|
818
826
|
return () => {
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
2
|
+
import { Globe as CesiumGlobe } from "resium";
|
|
3
|
+
|
|
4
|
+
import type { ViewerProperty } from "../../..";
|
|
5
|
+
import { toColor } from "../../common";
|
|
6
|
+
|
|
7
|
+
import useTerrainProviderPromise from "./useTerrainProviderPromise";
|
|
8
|
+
|
|
9
|
+
export type Props = {
|
|
10
|
+
property?: ViewerProperty;
|
|
11
|
+
cesiumIonAccessToken?: string;
|
|
12
|
+
onTerrainProviderChange?: () => void;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default function Globe({
|
|
16
|
+
property,
|
|
17
|
+
cesiumIonAccessToken,
|
|
18
|
+
onTerrainProviderChange,
|
|
19
|
+
}: Props): JSX.Element | null {
|
|
20
|
+
const providerPromise = useTerrainProviderPromise({
|
|
21
|
+
terrain: property?.terrain?.enabled,
|
|
22
|
+
terrainType: property?.terrain?.type,
|
|
23
|
+
normal: property?.terrain?.normal,
|
|
24
|
+
ionAccessToken: property?.assets?.cesium?.terrain?.ionAccessToken || cesiumIonAccessToken,
|
|
25
|
+
ionAsset: property?.assets?.cesium?.terrain?.ionAsset,
|
|
26
|
+
ionUrl: property?.assets?.cesium?.terrain?.ionUrl,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const baseColor = useMemo(
|
|
30
|
+
() => toColor(property?.globe?.baseColor),
|
|
31
|
+
[property?.globe?.baseColor],
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const lastResolvedProviderRef = useRef<any>(null);
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
let isCancelled = false;
|
|
38
|
+
|
|
39
|
+
providerPromise
|
|
40
|
+
.then(resolvedProvider => {
|
|
41
|
+
if (isCancelled) return;
|
|
42
|
+
|
|
43
|
+
// Only trigger callback if the resolved provider is actually different
|
|
44
|
+
if (lastResolvedProviderRef.current !== resolvedProvider) {
|
|
45
|
+
lastResolvedProviderRef.current = resolvedProvider;
|
|
46
|
+
onTerrainProviderChange?.();
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
.catch(error => {
|
|
50
|
+
if (!isCancelled) {
|
|
51
|
+
console.warn("Terrain provider failed to load:", error);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return () => {
|
|
56
|
+
isCancelled = true;
|
|
57
|
+
};
|
|
58
|
+
}, [providerPromise, onTerrainProviderChange]);
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<CesiumGlobe
|
|
62
|
+
baseColor={baseColor}
|
|
63
|
+
enableLighting={!!property?.globe?.enableLighting}
|
|
64
|
+
showGroundAtmosphere={property?.globe?.atmosphere?.enabled ?? true}
|
|
65
|
+
atmosphereLightIntensity={property?.globe?.atmosphere?.lightIntensity}
|
|
66
|
+
atmosphereSaturationShift={property?.globe?.atmosphere?.saturationShift}
|
|
67
|
+
atmosphereHueShift={property?.globe?.atmosphere?.hueShift}
|
|
68
|
+
atmosphereBrightnessShift={property?.globe?.atmosphere?.brightnessShift}
|
|
69
|
+
terrainProvider={providerPromise}
|
|
70
|
+
depthTestAgainstTerrain={!!property?.globe?.depthTestAgainstTerrain}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ArcGISTiledElevationTerrainProvider,
|
|
3
|
+
CesiumTerrainProvider,
|
|
4
|
+
EllipsoidTerrainProvider,
|
|
5
|
+
IonResource,
|
|
6
|
+
TerrainProvider,
|
|
7
|
+
} from "cesium";
|
|
8
|
+
import { useMemo, useRef } from "react";
|
|
9
|
+
|
|
10
|
+
import { TerrainProperty } from "../../..";
|
|
11
|
+
import { AssetsCesiumProperty } from "../../../../Map";
|
|
12
|
+
|
|
13
|
+
type TerrainType = NonNullable<TerrainProperty["type"]>;
|
|
14
|
+
|
|
15
|
+
type ProviderOpts = Pick<TerrainProperty, "normal"> &
|
|
16
|
+
AssetsCesiumProperty["terrain"] & {
|
|
17
|
+
terrain?: boolean;
|
|
18
|
+
terrainType?: TerrainType | null | undefined;
|
|
19
|
+
ionAccessToken?: string | undefined;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default function useTerrainProviderPromise(opts: ProviderOpts) {
|
|
23
|
+
// Cache promises so we don’t recreate providers on every toggle
|
|
24
|
+
const cacheRef = useRef(new Map<string, Promise<TerrainProvider>>());
|
|
25
|
+
const ellipsoidRef = useRef<TerrainProvider>();
|
|
26
|
+
|
|
27
|
+
return useMemo<Promise<TerrainProvider>>(() => {
|
|
28
|
+
if (!opts.terrain) {
|
|
29
|
+
// single shared ellipsoid provider
|
|
30
|
+
if (!ellipsoidRef.current) ellipsoidRef.current = new EllipsoidTerrainProvider();
|
|
31
|
+
return Promise.resolve(ellipsoidRef.current);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const kind = (opts.terrainType ?? "cesium") as TerrainType;
|
|
35
|
+
const key = makeKey(kind, opts);
|
|
36
|
+
let p = cacheRef.current.get(key);
|
|
37
|
+
if (!p) {
|
|
38
|
+
p = createProvider(kind, opts);
|
|
39
|
+
cacheRef.current.set(key, p);
|
|
40
|
+
}
|
|
41
|
+
return p;
|
|
42
|
+
}, [opts]);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function makeKey(type: TerrainType, opts: ProviderOpts) {
|
|
46
|
+
// Key should change when output provider would differ
|
|
47
|
+
const asset = opts.ionAsset ?? "";
|
|
48
|
+
const url = opts.ionUrl ?? "";
|
|
49
|
+
const normal = String(!!opts.normal);
|
|
50
|
+
return `${type}|asset:${asset}|url:${url}|normal:${normal}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function createProvider(type: TerrainType, opts: ProviderOpts): Promise<TerrainProvider> {
|
|
54
|
+
switch (type) {
|
|
55
|
+
case "cesium":
|
|
56
|
+
return CesiumTerrainProvider.fromUrl(
|
|
57
|
+
IonResource.fromAssetId(1, { accessToken: opts.ionAccessToken }),
|
|
58
|
+
{ requestVertexNormals: !!opts.normal, requestWaterMask: false },
|
|
59
|
+
) as Promise<TerrainProvider>;
|
|
60
|
+
|
|
61
|
+
case "arcgis":
|
|
62
|
+
return ArcGISTiledElevationTerrainProvider.fromUrl(
|
|
63
|
+
"https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer",
|
|
64
|
+
) as Promise<TerrainProvider>;
|
|
65
|
+
|
|
66
|
+
case "cesiumion":
|
|
67
|
+
if (!opts.ionAsset && !opts.ionUrl) {
|
|
68
|
+
// Fallback to ellipsoid when misconfigured
|
|
69
|
+
return Promise.resolve(new EllipsoidTerrainProvider());
|
|
70
|
+
}
|
|
71
|
+
return CesiumTerrainProvider.fromUrl(
|
|
72
|
+
opts.ionUrl ??
|
|
73
|
+
IonResource.fromAssetId(parseInt(String(opts.ionAsset), 10), {
|
|
74
|
+
accessToken: opts.ionAccessToken,
|
|
75
|
+
}),
|
|
76
|
+
{ requestVertexNormals: !!opts.normal },
|
|
77
|
+
) as Promise<TerrainProvider>;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -63,6 +63,12 @@ function makeGlobeShadersDirty(globe: Globe): void {
|
|
|
63
63
|
// reset surface shader source to the initial state (assuming that we never
|
|
64
64
|
// use custom material on globe).
|
|
65
65
|
// ref: https://github.com/CesiumGS/cesium/blob/1.106/packages/engine/Source/Scene/Globe.js#L562-L572
|
|
66
|
+
|
|
67
|
+
// Safety check: ensure globe's internal properties exist before manipulation
|
|
68
|
+
if (!globe || globe.isDestroyed() || !(globe as any)._surface) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
66
72
|
const material = globe.material;
|
|
67
73
|
if (material == null) {
|
|
68
74
|
globe.material = Material.fromType("Color");
|
|
@@ -73,6 +79,18 @@ function makeGlobeShadersDirty(globe: Globe): void {
|
|
|
73
79
|
}
|
|
74
80
|
}
|
|
75
81
|
|
|
82
|
+
function withUniforms(globe: PrivateCesiumGlobe, add?: Record<string, () => any>) {
|
|
83
|
+
if (!globe._surface?._tileProvider) return;
|
|
84
|
+
const mm = (globe._surface._tileProvider as any)?.materialUniformMap ?? {};
|
|
85
|
+
(globe._surface._tileProvider as any).materialUniformMap = { ...mm, ...(add ?? {}) };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function removeUniforms(globe: PrivateCesiumGlobe, keys: string[]) {
|
|
89
|
+
const tp = globe._surface?._tileProvider as any;
|
|
90
|
+
if (!tp?.materialUniformMap) return;
|
|
91
|
+
for (const k of keys) delete tp.materialUniformMap[k];
|
|
92
|
+
}
|
|
93
|
+
|
|
76
94
|
const useIBL = ({
|
|
77
95
|
sphericalHarmonicCoefficients,
|
|
78
96
|
globeImageBasedLighting,
|
|
@@ -184,6 +202,18 @@ const useTerrainHeatmap = ({
|
|
|
184
202
|
return { isCustomHeatmapEnabled, shaderForTerrainHeatmap };
|
|
185
203
|
};
|
|
186
204
|
|
|
205
|
+
async function waitTerrainReady(scene: any) {
|
|
206
|
+
const t = scene.terrain;
|
|
207
|
+
if (t?.ready) return;
|
|
208
|
+
await new Promise<void>(resolve => {
|
|
209
|
+
if (!t) return resolve();
|
|
210
|
+
const off = t.readyEvent.addEventListener(() => {
|
|
211
|
+
off();
|
|
212
|
+
resolve();
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
187
217
|
export const useOverrideGlobeShader = ({
|
|
188
218
|
cesium,
|
|
189
219
|
sphericalHarmonicCoefficients,
|
|
@@ -201,6 +231,8 @@ export const useOverrideGlobeShader = ({
|
|
|
201
231
|
enableLighting?: boolean;
|
|
202
232
|
terrain: TerrainProperty | undefined;
|
|
203
233
|
}) => {
|
|
234
|
+
const applyingRef = useRef(false);
|
|
235
|
+
|
|
204
236
|
const { uniformMapForIBL, isIBLEnabled, shaderForIBL } = useIBL({
|
|
205
237
|
sphericalHarmonicCoefficients,
|
|
206
238
|
globeImageBasedLighting,
|
|
@@ -223,75 +255,85 @@ export const useOverrideGlobeShader = ({
|
|
|
223
255
|
|
|
224
256
|
const needUpdateGlobeRef = useRef(false);
|
|
225
257
|
|
|
226
|
-
const handleGlobeShader = useCallback(() => {
|
|
258
|
+
const handleGlobeShader = useCallback(async () => {
|
|
227
259
|
// NOTE: Support the spherical harmonic coefficient only when the terrain normal is enabled.
|
|
228
260
|
// Because it's difficult to control the shader for the entire globe.
|
|
229
261
|
// ref: https://github.com/CesiumGS/cesium/blob/af4e2bebbef25259f049b05822adf2958fce11ff/packages/engine/Source/Shaders/GlobeFS.glsl#L408
|
|
230
262
|
if (!cesium.current?.cesiumElement || !needUpdateGlobeRef.current) return;
|
|
231
263
|
|
|
232
|
-
|
|
264
|
+
if (applyingRef.current) return;
|
|
265
|
+
applyingRef.current = true;
|
|
233
266
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
throw new Error("`globe._surfaceShaderSet` could not found");
|
|
238
|
-
}
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
267
|
+
try {
|
|
268
|
+
const { scene } = cesium.current.cesiumElement;
|
|
269
|
+
await waitTerrainReady(scene);
|
|
241
270
|
|
|
242
|
-
|
|
271
|
+
const globe = cesium.current.cesiumElement.scene.globe as PrivateCesiumGlobe;
|
|
243
272
|
|
|
244
|
-
|
|
273
|
+
// Reset shaders first so we patch the freshest base
|
|
274
|
+
makeGlobeShadersDirty(globe);
|
|
245
275
|
|
|
246
|
-
|
|
247
|
-
if (
|
|
248
|
-
|
|
276
|
+
const surfaceShaderSet = globe._surfaceShaderSet;
|
|
277
|
+
if (!surfaceShaderSet) {
|
|
278
|
+
if (import.meta.env.DEV) {
|
|
279
|
+
throw new Error("`globe._surfaceShaderSet` could not found");
|
|
280
|
+
}
|
|
281
|
+
return;
|
|
249
282
|
}
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
283
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
matchers.push(shaderForIBL);
|
|
257
|
-
shaders.push(IBLFS);
|
|
258
|
-
}
|
|
284
|
+
const baseFragmentShaderSource = surfaceShaderSet.baseFragmentShaderSource;
|
|
285
|
+
const GlobeFS =
|
|
286
|
+
baseFragmentShaderSource?.sources[baseFragmentShaderSource.sources.length - 1];
|
|
259
287
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
288
|
+
if (!GlobeFS || !baseFragmentShaderSource) {
|
|
289
|
+
if (import.meta.env.DEV) {
|
|
290
|
+
throw new Error("GlobeFS could not find.");
|
|
291
|
+
}
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
266
294
|
|
|
267
|
-
|
|
268
|
-
|
|
295
|
+
const matchers: StringMatcher[] = [];
|
|
296
|
+
const shaders: string[] = [];
|
|
297
|
+
const terrainHasNormals = !!(globe.terrainProvider as any)?.hasVertexNormals;
|
|
269
298
|
|
|
270
|
-
|
|
299
|
+
if (isIBLEnabled && globe.enableLighting && terrainHasNormals) {
|
|
300
|
+
matchers.push(shaderForIBL);
|
|
301
|
+
shaders.push(IBLFS);
|
|
302
|
+
}
|
|
271
303
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
304
|
+
if (isCustomHeatmapEnabled && terrainHasNormals) {
|
|
305
|
+
// This will log the variables needed in the shader below.
|
|
306
|
+
// we need the minHeight, maxHeight and logarithmic
|
|
307
|
+
matchers.push(shaderForTerrainHeatmap);
|
|
308
|
+
shaders.push(HeatmapForTerrainFS);
|
|
275
309
|
}
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
310
|
|
|
279
|
-
|
|
311
|
+
// This means there is no overridden shader.
|
|
312
|
+
if (!matchers.length) return;
|
|
280
313
|
|
|
281
|
-
|
|
314
|
+
needUpdateGlobeRef.current = false;
|
|
282
315
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
316
|
+
if (!globe?._surface?._tileProvider) {
|
|
317
|
+
if (import.meta.env.DEV) {
|
|
318
|
+
throw new Error("`globe._surface._tileProvider.materialUniformMap` could not found");
|
|
319
|
+
}
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
287
322
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
323
|
+
const replacedGlobeFS = defaultMatcher.concat(...matchers).execute(GlobeFS);
|
|
324
|
+
|
|
325
|
+
withUniforms(globe, isIBLEnabled ? uniformMapForIBL : undefined);
|
|
326
|
+
|
|
327
|
+
surfaceShaderSet.baseFragmentShaderSource = new ShaderSource({
|
|
328
|
+
sources: [
|
|
329
|
+
...baseFragmentShaderSource.sources.slice(0, -1),
|
|
330
|
+
GlobeFSDefinitions + replacedGlobeFS + shaders.join(""),
|
|
331
|
+
],
|
|
332
|
+
defines: baseFragmentShaderSource.defines,
|
|
333
|
+
});
|
|
334
|
+
} finally {
|
|
335
|
+
applyingRef.current = false;
|
|
336
|
+
}
|
|
295
337
|
}, [
|
|
296
338
|
cesium,
|
|
297
339
|
isCustomHeatmapEnabled,
|
|
@@ -317,6 +359,10 @@ export const useOverrideGlobeShader = ({
|
|
|
317
359
|
|
|
318
360
|
return () => {
|
|
319
361
|
if (!globe.isDestroyed()) {
|
|
362
|
+
removeUniforms(globe, [
|
|
363
|
+
"u_reearth_sphericalHarmonicCoefficients",
|
|
364
|
+
"u_reearth_globeImageBasedLighting",
|
|
365
|
+
]);
|
|
320
366
|
// Reset customized shader to default
|
|
321
367
|
makeGlobeShadersDirty(globe);
|
|
322
368
|
}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ArcGISTiledElevationTerrainProvider,
|
|
3
|
-
CesiumTerrainProvider,
|
|
4
|
-
EllipsoidTerrainProvider,
|
|
5
|
-
IonResource,
|
|
6
|
-
TerrainProvider,
|
|
7
|
-
} from "cesium";
|
|
8
|
-
import { useEffect, useMemo } from "react";
|
|
9
|
-
import { Globe as CesiumGlobe } from "resium";
|
|
10
|
-
|
|
11
|
-
import type { ViewerProperty, TerrainProperty } from "../..";
|
|
12
|
-
import { AssetsCesiumProperty } from "../../../Map";
|
|
13
|
-
import { toColor } from "../common";
|
|
14
|
-
|
|
15
|
-
export type Props = {
|
|
16
|
-
property?: ViewerProperty;
|
|
17
|
-
cesiumIonAccessToken?: string;
|
|
18
|
-
onTerrainProviderChange?: () => void;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export default function Globe({
|
|
22
|
-
property,
|
|
23
|
-
cesiumIonAccessToken,
|
|
24
|
-
onTerrainProviderChange,
|
|
25
|
-
}: Props): JSX.Element | null {
|
|
26
|
-
const terrainProperty = useMemo(
|
|
27
|
-
(): TerrainProperty => ({
|
|
28
|
-
...property?.terrain,
|
|
29
|
-
}),
|
|
30
|
-
[property?.terrain],
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
const terrainProvider = useMemo((): Promise<TerrainProvider> | TerrainProvider | undefined => {
|
|
34
|
-
const opts = {
|
|
35
|
-
terrain: terrainProperty?.enabled,
|
|
36
|
-
terrainType: terrainProperty?.type,
|
|
37
|
-
normal: terrainProperty?.normal,
|
|
38
|
-
ionAccessToken: property?.assets?.cesium?.terrain?.ionAccessToken || cesiumIonAccessToken,
|
|
39
|
-
ionAsset: property?.assets?.cesium?.terrain?.ionAsset,
|
|
40
|
-
ionUrl: property?.assets?.cesium?.terrain?.ionUrl,
|
|
41
|
-
};
|
|
42
|
-
const provider = opts.terrain ? terrainProviders[opts.terrainType || "cesium"] : undefined;
|
|
43
|
-
return (typeof provider === "function" ? provider(opts) : provider) ?? defaultTerrainProvider;
|
|
44
|
-
}, [
|
|
45
|
-
terrainProperty?.enabled,
|
|
46
|
-
terrainProperty?.type,
|
|
47
|
-
terrainProperty?.normal,
|
|
48
|
-
property?.assets?.cesium?.terrain?.ionAccessToken,
|
|
49
|
-
property?.assets?.cesium?.terrain?.ionAsset,
|
|
50
|
-
property?.assets?.cesium?.terrain?.ionUrl,
|
|
51
|
-
cesiumIonAccessToken,
|
|
52
|
-
]);
|
|
53
|
-
|
|
54
|
-
const baseColor = useMemo(
|
|
55
|
-
() => toColor(property?.globe?.baseColor),
|
|
56
|
-
[property?.globe?.baseColor],
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
useEffect(() => {
|
|
60
|
-
onTerrainProviderChange?.();
|
|
61
|
-
}, [terrainProvider, onTerrainProviderChange]);
|
|
62
|
-
|
|
63
|
-
return (
|
|
64
|
-
<CesiumGlobe
|
|
65
|
-
baseColor={baseColor}
|
|
66
|
-
enableLighting={!!property?.globe?.enableLighting}
|
|
67
|
-
showGroundAtmosphere={property?.globe?.atmosphere?.enabled ?? true}
|
|
68
|
-
atmosphereLightIntensity={property?.globe?.atmosphere?.lightIntensity}
|
|
69
|
-
atmosphereSaturationShift={property?.globe?.atmosphere?.saturationShift}
|
|
70
|
-
atmosphereHueShift={property?.globe?.atmosphere?.hueShift}
|
|
71
|
-
atmosphereBrightnessShift={property?.globe?.atmosphere?.brightnessShift}
|
|
72
|
-
terrainProvider={terrainProvider}
|
|
73
|
-
depthTestAgainstTerrain={!!property?.globe?.depthTestAgainstTerrain}
|
|
74
|
-
/>
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const defaultTerrainProvider = new EllipsoidTerrainProvider();
|
|
79
|
-
|
|
80
|
-
const terrainProviders: {
|
|
81
|
-
[k in NonNullable<TerrainProperty["type"]>]:
|
|
82
|
-
| TerrainProvider
|
|
83
|
-
| ((
|
|
84
|
-
opts: Pick<TerrainProperty, "normal"> & AssetsCesiumProperty["terrain"],
|
|
85
|
-
) => Promise<TerrainProvider> | TerrainProvider | null);
|
|
86
|
-
} = {
|
|
87
|
-
cesium: ({ ionAccessToken, normal }) =>
|
|
88
|
-
CesiumTerrainProvider.fromUrl(
|
|
89
|
-
IonResource.fromAssetId(1, {
|
|
90
|
-
accessToken: ionAccessToken,
|
|
91
|
-
}),
|
|
92
|
-
{
|
|
93
|
-
requestVertexNormals: normal,
|
|
94
|
-
requestWaterMask: false,
|
|
95
|
-
},
|
|
96
|
-
),
|
|
97
|
-
arcgis: () =>
|
|
98
|
-
ArcGISTiledElevationTerrainProvider.fromUrl(
|
|
99
|
-
"https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer",
|
|
100
|
-
),
|
|
101
|
-
cesiumion: ({ ionAccessToken, ionAsset, ionUrl, normal }) =>
|
|
102
|
-
ionAsset
|
|
103
|
-
? CesiumTerrainProvider.fromUrl(
|
|
104
|
-
ionUrl ||
|
|
105
|
-
IonResource.fromAssetId(parseInt(ionAsset, 10), {
|
|
106
|
-
accessToken: ionAccessToken,
|
|
107
|
-
}),
|
|
108
|
-
{
|
|
109
|
-
requestVertexNormals: normal,
|
|
110
|
-
},
|
|
111
|
-
)
|
|
112
|
-
: null,
|
|
113
|
-
};
|