@reearth/core 0.0.7-alpha.44 → 0.0.7-alpha.46

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reearth/core",
3
- "version": "0.0.7-alpha.44",
3
+ "version": "0.0.7-alpha.46",
4
4
  "author": "Re:Earth contributors <community@reearth.io>",
5
5
  "license": "Apache-2.0",
6
6
  "description": "A library that abstracts a map engine as one common API.",
@@ -187,6 +187,7 @@ const useFeature = ({
187
187
  onComputedFeatureFetch,
188
188
  shouldUseFeatureIndex,
189
189
  isTilesetReady,
190
+ useExternalStyle,
190
191
  }: {
191
192
  id?: string;
192
193
  tilesetRef: MutableRefObject<Cesium3DTileset | undefined>;
@@ -199,6 +200,7 @@ const useFeature = ({
199
200
  selectedFeatureIdsRef: MutableRefObject<string[]>;
200
201
  shouldUseFeatureIndex?: boolean;
201
202
  isTilesetReady: boolean;
203
+ useExternalStyle?: boolean;
202
204
  }) => {
203
205
  const cachedFeaturesRef = useRef<CachedFeature[]>([]);
204
206
  const cachedCalculatedLayerRef = useRef(layer);
@@ -220,49 +222,51 @@ const useFeature = ({
220
222
 
221
223
  const computedFeature = evalFeature(layer, { ...feature?.feature, properties });
222
224
 
223
- const style = computedFeature?.["3dtiles"];
225
+ if (!useExternalStyle) {
226
+ const style = computedFeature?.["3dtiles"];
224
227
 
225
- COMMON_STYLE_PROPERTIES.forEach(({ name, convert }) => {
226
- const val = convertStyle(style?.[name], convert);
227
-
228
- if (name === "color") {
229
- // Reset color to default so that new style could update all.
230
- raw.color = DEFAULT_FEATURE_COLOR;
228
+ COMMON_STYLE_PROPERTIES.forEach(({ name, convert }) => {
229
+ const val = convertStyle(style?.[name], convert);
231
230
 
232
- // Apply color from style.
233
- if (val !== undefined) {
234
- raw.color = val;
231
+ if (name === "color") {
232
+ // Reset color to default so that new style could update all.
233
+ raw.color = DEFAULT_FEATURE_COLOR;
234
+
235
+ // Apply color from style.
236
+ if (val !== undefined) {
237
+ raw.color = val;
238
+ }
239
+
240
+ // Apply color for selected feature.
241
+ if (isFeatureSelected && typeof layer["3dtiles"]?.selectedFeatureColor === "string") {
242
+ raw.color = toColor(layer["3dtiles"]?.selectedFeatureColor) ?? val;
243
+ }
244
+ } else {
245
+ if (val !== undefined) {
246
+ raw[name] = val;
247
+ }
235
248
  }
249
+ });
236
250
 
237
- // Apply color for selected feature.
238
- if (isFeatureSelected && typeof layer["3dtiles"]?.selectedFeatureColor === "string") {
239
- raw.color = toColor(layer["3dtiles"]?.selectedFeatureColor) ?? val;
240
- }
241
- } else {
242
- if (val !== undefined) {
243
- raw[name] = val;
244
- }
251
+ if (raw instanceof Cesium3DTilePointFeature) {
252
+ POINT_STYLE_PROPERTIES.forEach(({ name, convert }) => {
253
+ const val = convertStyle(style?.[name], convert);
254
+ if (val !== undefined) {
255
+ raw[name] = val;
256
+ }
257
+ });
245
258
  }
246
- });
247
-
248
- if (raw instanceof Cesium3DTilePointFeature) {
249
- POINT_STYLE_PROPERTIES.forEach(({ name, convert }) => {
250
- const val = convertStyle(style?.[name], convert);
251
- if (val !== undefined) {
252
- raw[name] = val;
253
- }
254
- });
255
- }
256
259
 
257
- if ("style" in raw) {
258
- raw.style = new Cesium3DTileStyle(
259
- // TODO: Convert value if it's necessary
260
- MODEL_STYLE_PROPERTIES.reduce((res, { name, convert }) => {
261
- const val = convertStyle(style?.[name as keyof typeof style], convert);
262
- if (val === undefined) return res;
263
- return { ...res, [name]: val };
264
- }, {}),
265
- );
260
+ if ("style" in raw) {
261
+ raw.style = new Cesium3DTileStyle(
262
+ // TODO: Convert value if it's necessary
263
+ MODEL_STYLE_PROPERTIES.reduce((res, { name, convert }) => {
264
+ const val = convertStyle(style?.[name as keyof typeof style], convert);
265
+ if (val === undefined) return res;
266
+ return { ...res, [name]: val };
267
+ }, {}),
268
+ );
269
+ }
266
270
  }
267
271
 
268
272
  attachTag(feature.raw, {
@@ -276,7 +280,7 @@ const useFeature = ({
276
280
  }
277
281
  return;
278
282
  },
279
- [evalFeature, layerId, viewer, shouldUseFeatureIndex, selectedFeatureIdsRef],
283
+ [evalFeature, layerId, viewer, shouldUseFeatureIndex, selectedFeatureIdsRef, useExternalStyle],
280
284
  );
281
285
 
282
286
  const handleTilesetLoad = useCallback(
@@ -615,6 +619,7 @@ export const useHooks = ({
615
619
  selectedFeatureIdsRef,
616
620
  shouldUseFeatureIndex,
617
621
  isTilesetReady,
622
+ useExternalStyle: !!styleUrl,
618
623
  });
619
624
 
620
625
  const [terrainHeightEstimate, setTerrainHeightEstimate] = useState(0);
@@ -730,11 +735,23 @@ export const useHooks = ({
730
735
  }
731
736
  (async () => {
732
737
  const res = await fetch(styleUrl);
733
- if (!res.ok) return;
734
- setStyle(new Cesium3DTileStyle(await res.json()));
738
+ if (!res.ok) {
739
+ console.warn("Failed to fetch style from:", styleUrl);
740
+ return;
741
+ }
742
+ const styleData = await res.json();
743
+ const newStyle = new Cesium3DTileStyle(styleData);
744
+ setStyle(newStyle);
735
745
  })();
736
746
  }, [styleUrl]);
737
747
 
748
+ // Apply style to tileset when both external style and tileset are ready
749
+ useEffect(() => {
750
+ if (style && tilesetRef.current && isTilesetReady) {
751
+ tilesetRef.current.style = style;
752
+ }
753
+ }, [style, isTilesetReady]);
754
+
738
755
  const googleMapPhotorealisticResource = useMemo(() => {
739
756
  if (type !== "google-photorealistic" || !isVisible) return null;
740
757
 
@@ -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
- const globe = cesium.current.cesiumElement.scene.globe as PrivateCesiumGlobe;
264
+ if (applyingRef.current) return;
265
+ applyingRef.current = true;
233
266
 
234
- const surfaceShaderSet = globe._surfaceShaderSet;
235
- if (!surfaceShaderSet) {
236
- if (import.meta.env.DEV) {
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
- const baseFragmentShaderSource = surfaceShaderSet.baseFragmentShaderSource;
271
+ const globe = cesium.current.cesiumElement.scene.globe as PrivateCesiumGlobe;
243
272
 
244
- const GlobeFS = baseFragmentShaderSource?.sources[baseFragmentShaderSource.sources.length - 1];
273
+ // Reset shaders first so we patch the freshest base
274
+ makeGlobeShadersDirty(globe);
245
275
 
246
- if (!GlobeFS || !baseFragmentShaderSource) {
247
- if (import.meta.env.DEV) {
248
- throw new Error("GlobeFS could not find.");
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
- const matchers: StringMatcher[] = [];
254
- const shaders: string[] = [];
255
- if (isIBLEnabled && globe.enableLighting && globe.terrainProvider.hasVertexNormals) {
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
- if (isCustomHeatmapEnabled) {
261
- // This will log the variables needed in the shader below.
262
- // we need the minHeight, maxHeight and logarithmic
263
- matchers.push(shaderForTerrainHeatmap);
264
- shaders.push(HeatmapForTerrainFS);
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
- // This means there is no overridden shader.
268
- if (!matchers.length) return;
295
+ const matchers: StringMatcher[] = [];
296
+ const shaders: string[] = [];
297
+ const terrainHasNormals = !!(globe.terrainProvider as any)?.hasVertexNormals;
269
298
 
270
- needUpdateGlobeRef.current = false;
299
+ if (isIBLEnabled && globe.enableLighting && terrainHasNormals) {
300
+ matchers.push(shaderForIBL);
301
+ shaders.push(IBLFS);
302
+ }
271
303
 
272
- if (!globe?._surface?._tileProvider) {
273
- if (import.meta.env.DEV) {
274
- throw new Error("`globe._surface._tileProvider.materialUniformMap` could not found");
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
- makeGlobeShadersDirty(globe);
311
+ // This means there is no overridden shader.
312
+ if (!matchers.length) return;
280
313
 
281
- const replacedGlobeFS = defaultMatcher.concat(...matchers).execute(GlobeFS);
314
+ needUpdateGlobeRef.current = false;
282
315
 
283
- globe._surface._tileProvider.materialUniformMap = {
284
- ...(globe._surface._tileProvider.materialUniformMap ?? {}),
285
- ...uniformMapForIBL,
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
- surfaceShaderSet.baseFragmentShaderSource = new ShaderSource({
289
- sources: [
290
- ...baseFragmentShaderSource.sources.slice(0, -1),
291
- GlobeFSDefinitions + replacedGlobeFS + shaders.join(""),
292
- ],
293
- defines: baseFragmentShaderSource.defines,
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
- };