@takram/three-clouds 0.2.2 → 0.4.0
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 +37 -0
- package/README.md +25 -17
- package/build/index.cjs +9 -9
- package/build/index.cjs.map +1 -1
- package/build/index.js +70 -77
- package/build/index.js.map +1 -1
- package/build/r3f.cjs +1 -1
- package/build/r3f.cjs.map +1 -1
- package/build/r3f.js +180 -186
- package/build/r3f.js.map +1 -1
- package/build/shared.cjs +102 -74
- package/build/shared.cjs.map +1 -1
- package/build/shared.js +443 -380
- package/build/shared.js.map +1 -1
- package/package.json +3 -3
- package/src/CloudLayers.ts +2 -2
- package/src/CloudsEffect.ts +52 -29
- package/src/CloudsMaterial.ts +53 -30
- package/src/CloudsPass.ts +5 -6
- package/src/PassBase.ts +1 -1
- package/src/Procedural3DTexture.ts +2 -4
- package/src/ProceduralTexture.ts +1 -3
- package/src/ShaderArrayPass.ts +5 -5
- package/src/ShadowMaterial.ts +4 -4
- package/src/ShadowPass.ts +5 -6
- package/src/constants.ts +1 -0
- package/src/helpers/setArrayRenderTargetLayers.ts +3 -6
- package/src/qualityPresets.ts +5 -5
- package/src/r3f/CloudLayer.tsx +65 -63
- package/src/r3f/Clouds.tsx +170 -188
- package/src/shaders/clouds.frag +64 -50
- package/src/shaders/clouds.glsl +1 -1
- package/src/shaders/clouds.vert +18 -5
- package/src/shaders/parameters.glsl +3 -2
- package/src/shaders/shadowResolve.frag +2 -2
- package/src/shaders/types.glsl +1 -1
- package/src/shaders/varianceClipping.glsl +2 -2
- package/src/uniforms.ts +3 -3
- package/types/CloudsEffect.d.ts +19 -9
- package/types/CloudsMaterial.d.ts +10 -5
- package/types/qualityPresets.d.ts +1 -1
- package/types/r3f/CloudLayer.d.ts +3 -1
- package/types/r3f/Clouds.d.ts +2 -1
package/src/r3f/CloudLayer.tsx
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
import {
|
2
|
-
forwardRef,
|
3
2
|
useContext,
|
4
3
|
useEffect,
|
5
4
|
useLayoutEffect,
|
6
|
-
useState
|
5
|
+
useState,
|
6
|
+
type FC,
|
7
|
+
type Ref
|
7
8
|
} from 'react'
|
8
9
|
|
9
|
-
import {
|
10
|
+
import type { ExpandNestedProps } from '@takram/three-geospatial/r3f'
|
10
11
|
|
11
12
|
import {
|
12
13
|
CloudLayer as CloudLayerImpl,
|
@@ -18,78 +19,79 @@ import { CloudLayersContext } from './CloudLayers'
|
|
18
19
|
export interface CloudLayerProps
|
19
20
|
extends CloudLayerLike,
|
20
21
|
ExpandNestedProps<CloudLayerLike, 'densityProfile'> {
|
22
|
+
ref?: Ref<CloudLayerImpl>
|
21
23
|
index?: number
|
22
24
|
}
|
23
25
|
|
24
|
-
export const CloudLayer
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
26
|
+
export const CloudLayer: FC<CloudLayerProps> = ({
|
27
|
+
ref: forwardedRef,
|
28
|
+
index: indexProp,
|
29
|
+
...props
|
30
|
+
}) => {
|
31
|
+
const context = useContext(CloudLayersContext)
|
32
|
+
if (context == null) {
|
33
|
+
throw new Error('CloudLayer can only be used within the Clouds component!')
|
34
|
+
}
|
32
35
|
|
33
|
-
|
34
|
-
|
36
|
+
const { layers, indexPool, disableDefault } = context
|
37
|
+
const [index, setIndex] = useState<number>()
|
35
38
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
}
|
39
|
+
useLayoutEffect(() => {
|
40
|
+
if (indexProp != null) {
|
41
|
+
const poolIndex = indexPool.indexOf(indexProp)
|
42
|
+
if (poolIndex !== -1) {
|
43
|
+
indexPool.splice(poolIndex, 1)
|
44
|
+
setIndex(indexProp)
|
45
|
+
return () => {
|
46
|
+
indexPool.push(indexProp)
|
47
|
+
setIndex(undefined)
|
46
48
|
}
|
47
|
-
} else {
|
48
|
-
// Sorting is just for predictability. Layer order is still not defined,
|
49
|
-
// but it doesn't matter.
|
50
|
-
const index = indexPool.sort((a, b) => a - b).shift()
|
51
|
-
if (index != null) {
|
52
|
-
setIndex(index)
|
53
|
-
return () => {
|
54
|
-
indexPool.push(index)
|
55
|
-
setIndex(undefined)
|
56
|
-
}
|
57
|
-
}
|
58
|
-
}
|
59
|
-
}, [indexProp, layers, indexPool])
|
60
|
-
|
61
|
-
useLayoutEffect(() => {
|
62
|
-
if (index == null) {
|
63
|
-
return
|
64
|
-
}
|
65
|
-
const layer = layers[index]
|
66
|
-
return () => {
|
67
|
-
layer.copy(
|
68
|
-
disableDefault ? CloudLayerImpl.DEFAULT : CloudLayers.DEFAULT[index]
|
69
|
-
)
|
70
|
-
}
|
71
|
-
}, [layers, index, disableDefault])
|
72
|
-
|
73
|
-
useEffect(() => {
|
74
|
-
if (index == null) {
|
75
|
-
return
|
76
49
|
}
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
50
|
+
} else {
|
51
|
+
// Sorting is just for predictability. Layer order is still not defined,
|
52
|
+
// but it doesn't matter.
|
53
|
+
const index = indexPool.sort((a, b) => a - b).shift()
|
54
|
+
if (index != null) {
|
55
|
+
setIndex(index)
|
56
|
+
return () => {
|
57
|
+
indexPool.push(index)
|
58
|
+
setIndex(undefined)
|
59
|
+
}
|
81
60
|
}
|
82
|
-
}
|
61
|
+
}
|
62
|
+
}, [indexProp, layers, indexPool])
|
83
63
|
|
84
|
-
|
85
|
-
if (index
|
86
|
-
|
64
|
+
useLayoutEffect(() => {
|
65
|
+
if (index == null) {
|
66
|
+
return
|
67
|
+
}
|
68
|
+
const layer = layers[index]
|
69
|
+
return () => {
|
87
70
|
layer.copy(
|
88
71
|
disableDefault ? CloudLayerImpl.DEFAULT : CloudLayers.DEFAULT[index]
|
89
72
|
)
|
90
|
-
layer.set(props)
|
91
73
|
}
|
74
|
+
}, [layers, index, disableDefault])
|
75
|
+
|
76
|
+
useEffect(() => {
|
77
|
+
if (index == null) {
|
78
|
+
return
|
79
|
+
}
|
80
|
+
if (typeof forwardedRef === 'function') {
|
81
|
+
forwardedRef(layers[index])
|
82
|
+
} else if (forwardedRef != null) {
|
83
|
+
forwardedRef.current = layers[index]
|
84
|
+
}
|
85
|
+
}, [forwardedRef, layers, index])
|
92
86
|
|
93
|
-
|
87
|
+
// Surely this resets any modifications made via forwarded ref.
|
88
|
+
if (index != null) {
|
89
|
+
const layer = layers[index]
|
90
|
+
layer.copy(
|
91
|
+
disableDefault ? CloudLayerImpl.DEFAULT : CloudLayers.DEFAULT[index]
|
92
|
+
)
|
93
|
+
layer.set(props)
|
94
94
|
}
|
95
|
-
|
95
|
+
|
96
|
+
return null
|
97
|
+
}
|
package/src/r3f/Clouds.tsx
CHANGED
@@ -1,33 +1,26 @@
|
|
1
1
|
import { useFrame, useThree, type ElementProps } from '@react-three/fiber'
|
2
2
|
import { EffectComposerContext } from '@react-three/postprocessing'
|
3
|
+
import { useCallback, useContext, useEffect, useMemo, type FC } from 'react'
|
3
4
|
import {
|
4
|
-
|
5
|
-
useCallback,
|
6
|
-
useContext,
|
7
|
-
useEffect,
|
8
|
-
useMemo,
|
9
|
-
useState
|
10
|
-
} from 'react'
|
11
|
-
import {
|
5
|
+
Data3DTexture,
|
12
6
|
LinearFilter,
|
13
7
|
LinearMipMapLinearFilter,
|
14
8
|
NoColorSpace,
|
15
9
|
RedFormat,
|
16
10
|
RepeatWrapping,
|
17
11
|
TextureLoader,
|
18
|
-
type Data3DTexture,
|
19
12
|
type Texture,
|
20
13
|
type WebGLRenderer
|
21
14
|
} from 'three'
|
22
15
|
|
23
16
|
import { AtmosphereContext, separateProps } from '@takram/three-atmosphere/r3f'
|
24
17
|
import {
|
25
|
-
|
18
|
+
DataTextureLoader,
|
26
19
|
DEFAULT_STBN_URL,
|
27
20
|
parseUint8Array,
|
28
21
|
STBNLoader
|
29
22
|
} from '@takram/three-geospatial'
|
30
|
-
import {
|
23
|
+
import type { ExpandNestedProps } from '@takram/three-geospatial/r3f'
|
31
24
|
|
32
25
|
import {
|
33
26
|
CloudsEffect,
|
@@ -42,94 +35,86 @@ import {
|
|
42
35
|
DEFAULT_SHAPE_URL,
|
43
36
|
DEFAULT_TURBULENCE_URL
|
44
37
|
} from '../constants'
|
45
|
-
import {
|
46
|
-
import {
|
38
|
+
import type { Procedural3DTexture } from '../Procedural3DTexture'
|
39
|
+
import type { ProceduralTexture } from '../ProceduralTexture'
|
47
40
|
import { CloudLayers } from './CloudLayers'
|
48
41
|
|
49
|
-
function
|
42
|
+
function useLoadTexture(
|
50
43
|
input: string | Texture | ProceduralTexture,
|
51
44
|
gl: WebGLRenderer
|
52
45
|
): Texture | ProceduralTexture | null {
|
53
|
-
const
|
46
|
+
const loadedTexture = useMemo(
|
47
|
+
() =>
|
48
|
+
typeof input === 'string'
|
49
|
+
? new TextureLoader().load(input, texture => {
|
50
|
+
texture.minFilter = LinearMipMapLinearFilter
|
51
|
+
texture.magFilter = LinearFilter
|
52
|
+
texture.wrapS = RepeatWrapping
|
53
|
+
texture.wrapT = RepeatWrapping
|
54
|
+
texture.colorSpace = NoColorSpace
|
55
|
+
texture.needsUpdate = true
|
56
|
+
})
|
57
|
+
: undefined,
|
58
|
+
[input]
|
59
|
+
)
|
54
60
|
useEffect(() => {
|
55
|
-
if (
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
texture.minFilter = LinearMipMapLinearFilter
|
60
|
-
texture.magFilter = LinearFilter
|
61
|
-
texture.wrapS = RepeatWrapping
|
62
|
-
texture.wrapT = RepeatWrapping
|
63
|
-
texture.colorSpace = NoColorSpace
|
64
|
-
texture.needsUpdate = true
|
65
|
-
|
66
|
-
// WORKAROUND: The color space resets to sRGB for unknown reason, unless
|
67
|
-
// the texture is initialized here.
|
68
|
-
gl.initTexture(texture)
|
69
|
-
|
70
|
-
setData(texture)
|
71
|
-
})().catch(error => {
|
72
|
-
console.error(error)
|
73
|
-
})
|
74
|
-
} else {
|
75
|
-
setData(input)
|
61
|
+
if (loadedTexture != null) {
|
62
|
+
return () => {
|
63
|
+
loadedTexture.dispose()
|
64
|
+
}
|
76
65
|
}
|
77
|
-
}, [
|
78
|
-
|
79
|
-
return data
|
66
|
+
}, [loadedTexture])
|
67
|
+
return (typeof input === 'string' ? loadedTexture : input) ?? null
|
80
68
|
}
|
81
69
|
|
82
|
-
function
|
70
|
+
function useLoad3DTexture(
|
83
71
|
input: string | Data3DTexture | Procedural3DTexture,
|
84
72
|
size: number
|
85
73
|
): Data3DTexture | Procedural3DTexture | null {
|
86
|
-
const
|
74
|
+
const loadedTexture = useMemo(
|
75
|
+
() =>
|
76
|
+
typeof input === 'string'
|
77
|
+
? new DataTextureLoader(Data3DTexture, parseUint8Array, {
|
78
|
+
width: size,
|
79
|
+
height: size,
|
80
|
+
depth: size,
|
81
|
+
format: RedFormat,
|
82
|
+
minFilter: LinearFilter,
|
83
|
+
magFilter: LinearFilter,
|
84
|
+
wrapS: RepeatWrapping,
|
85
|
+
wrapT: RepeatWrapping,
|
86
|
+
wrapR: RepeatWrapping,
|
87
|
+
colorSpace: NoColorSpace
|
88
|
+
}).load(input)
|
89
|
+
: undefined,
|
90
|
+
[input, size]
|
91
|
+
)
|
87
92
|
useEffect(() => {
|
88
|
-
if (
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
depth: size,
|
93
|
-
format: RedFormat,
|
94
|
-
minFilter: LinearFilter,
|
95
|
-
magFilter: LinearFilter,
|
96
|
-
wrapS: RepeatWrapping,
|
97
|
-
wrapT: RepeatWrapping,
|
98
|
-
wrapR: RepeatWrapping,
|
99
|
-
colorSpace: NoColorSpace
|
100
|
-
})
|
101
|
-
const loader = new Loader()
|
102
|
-
;(async () => {
|
103
|
-
setData(await loader.loadAsync(input))
|
104
|
-
})().catch(error => {
|
105
|
-
console.error(error)
|
106
|
-
})
|
107
|
-
} else {
|
108
|
-
setData(input)
|
93
|
+
if (loadedTexture != null) {
|
94
|
+
return () => {
|
95
|
+
loadedTexture.dispose()
|
96
|
+
}
|
109
97
|
}
|
110
|
-
}, [
|
111
|
-
|
112
|
-
return data
|
98
|
+
}, [loadedTexture])
|
99
|
+
return (typeof input === 'string' ? loadedTexture : input) ?? null
|
113
100
|
}
|
114
101
|
|
115
|
-
function
|
102
|
+
function useLoadSTBNTexture(
|
116
103
|
input: string | Data3DTexture
|
117
104
|
): Data3DTexture | null {
|
118
|
-
const
|
105
|
+
const loadedTexture = useMemo(
|
106
|
+
() =>
|
107
|
+
typeof input === 'string' ? new STBNLoader().load(input) : undefined,
|
108
|
+
[input]
|
109
|
+
)
|
119
110
|
useEffect(() => {
|
120
|
-
if (
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
})().catch(error => {
|
125
|
-
console.error(error)
|
126
|
-
})
|
127
|
-
} else {
|
128
|
-
setData(input)
|
111
|
+
if (loadedTexture != null) {
|
112
|
+
return () => {
|
113
|
+
loadedTexture.dispose()
|
114
|
+
}
|
129
115
|
}
|
130
|
-
}, [
|
131
|
-
|
132
|
-
return data
|
116
|
+
}, [loadedTexture])
|
117
|
+
return (typeof input === 'string' ? loadedTexture : input) ?? null
|
133
118
|
}
|
134
119
|
|
135
120
|
export interface CloudsProps
|
@@ -154,119 +139,116 @@ export interface CloudsProps
|
|
154
139
|
stbnTexture?: Data3DTexture | string
|
155
140
|
}
|
156
141
|
|
157
|
-
export const Clouds
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
142
|
+
export const Clouds: FC<CloudsProps> = ({
|
143
|
+
ref: forwardedRef,
|
144
|
+
disableDefaultLayers = false,
|
145
|
+
localWeatherTexture: localWeatherTextureProp = DEFAULT_LOCAL_WEATHER_URL,
|
146
|
+
shapeTexture: shapeTextureProp = DEFAULT_SHAPE_URL,
|
147
|
+
shapeDetailTexture: shapeDetailTextureProp = DEFAULT_SHAPE_DETAIL_URL,
|
148
|
+
turbulenceTexture: turbulenceTextureProp = DEFAULT_TURBULENCE_URL,
|
149
|
+
stbnTexture: stbnTextureProp = DEFAULT_STBN_URL,
|
150
|
+
children,
|
151
|
+
...props
|
152
|
+
}) => {
|
153
|
+
const { textures, transientStates, ...contextProps } =
|
154
|
+
useContext(AtmosphereContext)
|
155
|
+
|
156
|
+
const [atmosphereParameters, others] = separateProps({
|
157
|
+
...cloudsPassOptionsDefaults,
|
158
|
+
...contextProps,
|
159
|
+
...textures,
|
160
|
+
...props
|
161
|
+
})
|
162
|
+
|
163
|
+
const effect = useMemo(() => new CloudsEffect(), [])
|
164
|
+
useEffect(() => {
|
165
|
+
return () => {
|
166
|
+
effect.dispose()
|
167
|
+
}
|
168
|
+
}, [effect])
|
173
169
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
}
|
170
|
+
useFrame(() => {
|
171
|
+
if (transientStates != null) {
|
172
|
+
effect.sunDirection.copy(transientStates.sunDirection)
|
173
|
+
effect.ellipsoidCenter.copy(transientStates.ellipsoidCenter)
|
174
|
+
effect.ellipsoidMatrix.copy(transientStates.ellipsoidMatrix)
|
175
|
+
}
|
176
|
+
})
|
180
177
|
|
181
|
-
|
182
|
-
|
178
|
+
useEffect(() => {
|
179
|
+
if (transientStates != null) {
|
180
|
+
transientStates.overlay = effect.atmosphereOverlay
|
181
|
+
transientStates.shadow = effect.atmosphereShadow
|
182
|
+
transientStates.shadowLength = effect.atmosphereShadowLength
|
183
183
|
return () => {
|
184
|
-
|
184
|
+
transientStates.overlay = null
|
185
|
+
transientStates.shadow = null
|
186
|
+
transientStates.shadowLength = null
|
185
187
|
}
|
186
|
-
}
|
187
|
-
|
188
|
-
useFrame(() => {
|
189
|
-
if (transientStates != null) {
|
190
|
-
effect.sunDirection.copy(transientStates.sunDirection)
|
191
|
-
effect.ellipsoidCenter.copy(transientStates.ellipsoidCenter)
|
192
|
-
effect.ellipsoidMatrix.copy(transientStates.ellipsoidMatrix)
|
193
|
-
}
|
194
|
-
})
|
188
|
+
}
|
189
|
+
}, [effect, transientStates])
|
195
190
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
transientStates.shadowLength = effect.atmosphereShadowLength
|
201
|
-
return () => {
|
202
|
-
transientStates.overlay = null
|
203
|
-
transientStates.shadow = null
|
204
|
-
transientStates.shadowLength = null
|
205
|
-
}
|
191
|
+
const handleChange = useCallback(
|
192
|
+
(event: CloudsEffectChangeEvent) => {
|
193
|
+
if (transientStates == null) {
|
194
|
+
return
|
206
195
|
}
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
case 'atmosphereShadow':
|
219
|
-
transientStates.shadow = effect.atmosphereShadow
|
220
|
-
break
|
221
|
-
case 'atmosphereShadowLength':
|
222
|
-
transientStates.shadowLength = effect.atmosphereShadowLength
|
223
|
-
break
|
224
|
-
}
|
225
|
-
},
|
226
|
-
[effect, transientStates]
|
227
|
-
)
|
228
|
-
useEffect(() => {
|
229
|
-
effect.events.addEventListener('change', handleChange)
|
230
|
-
return () => {
|
231
|
-
effect.events.removeEventListener('change', handleChange)
|
196
|
+
switch (event.property) {
|
197
|
+
case 'atmosphereOverlay':
|
198
|
+
transientStates.overlay = effect.atmosphereOverlay
|
199
|
+
break
|
200
|
+
case 'atmosphereShadow':
|
201
|
+
transientStates.shadow = effect.atmosphereShadow
|
202
|
+
break
|
203
|
+
case 'atmosphereShadowLength':
|
204
|
+
transientStates.shadowLength = effect.atmosphereShadowLength
|
205
|
+
break
|
206
|
+
default:
|
232
207
|
}
|
233
|
-
},
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
208
|
+
},
|
209
|
+
[effect, transientStates]
|
210
|
+
)
|
211
|
+
useEffect(() => {
|
212
|
+
effect.events.addEventListener('change', handleChange)
|
213
|
+
return () => {
|
214
|
+
effect.events.removeEventListener('change', handleChange)
|
215
|
+
}
|
216
|
+
}, [effect, handleChange])
|
217
|
+
|
218
|
+
const renderer = useThree(({ gl }) => gl)
|
219
|
+
const localWeatherTexture = useLoadTexture(localWeatherTextureProp, renderer)
|
220
|
+
const shapeTexture = useLoad3DTexture(
|
221
|
+
shapeTextureProp,
|
222
|
+
CLOUD_SHAPE_TEXTURE_SIZE
|
223
|
+
)
|
224
|
+
const shapeDetailTexture = useLoad3DTexture(
|
225
|
+
shapeDetailTextureProp,
|
226
|
+
CLOUD_SHAPE_DETAIL_TEXTURE_SIZE
|
227
|
+
)
|
228
|
+
const turbulenceTexture = useLoadTexture(turbulenceTextureProp, renderer)
|
229
|
+
const stbnTexture = useLoadSTBNTexture(stbnTextureProp)
|
230
|
+
|
231
|
+
const { camera } = useContext(EffectComposerContext)
|
232
|
+
return (
|
233
|
+
<>
|
234
|
+
<primitive
|
235
|
+
ref={forwardedRef}
|
236
|
+
object={effect}
|
237
|
+
mainCamera={camera}
|
238
|
+
{...atmosphereParameters}
|
239
|
+
localWeatherTexture={localWeatherTexture}
|
240
|
+
shapeTexture={shapeTexture}
|
241
|
+
shapeDetailTexture={shapeDetailTexture}
|
242
|
+
turbulenceTexture={turbulenceTexture}
|
243
|
+
stbnTexture={stbnTexture}
|
244
|
+
{...others}
|
245
|
+
/>
|
246
|
+
<CloudLayers
|
247
|
+
layers={effect.cloudLayers}
|
248
|
+
disableDefault={disableDefaultLayers}
|
249
|
+
>
|
250
|
+
{children}
|
251
|
+
</CloudLayers>
|
252
|
+
</>
|
253
|
+
)
|
254
|
+
}
|