@3driseai/3drise-viewer 0.1.6 → 0.1.8

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.
Files changed (277) hide show
  1. package/dist/components/Clouds.d.ts.map +1 -1
  2. package/dist/components/Clouds.js +0 -1
  3. package/dist/components/CloudsGenerator.d.ts +32 -0
  4. package/dist/components/CloudsGenerator.d.ts.map +1 -0
  5. package/dist/components/CloudsGenerator.js +58 -0
  6. package/dist/components/CustomPrimitive.js +1 -1
  7. package/dist/components/EnvironmentManager.d.ts +47 -5
  8. package/dist/components/EnvironmentManager.d.ts.map +1 -1
  9. package/dist/components/EnvironmentManager.js +35 -66
  10. package/dist/components/GeometryShape.d.ts.map +1 -1
  11. package/dist/components/GeometryShape.js +19 -3
  12. package/dist/components/HdrEnvironment.d.ts +20 -0
  13. package/dist/components/HdrEnvironment.d.ts.map +1 -0
  14. package/dist/components/HdrEnvironment.js +44 -0
  15. package/dist/components/LandscapeBuilder.d.ts +23 -0
  16. package/dist/components/LandscapeBuilder.d.ts.map +1 -0
  17. package/dist/components/LandscapeBuilder.js +25 -0
  18. package/dist/components/LandscapeObject.d.ts +24 -0
  19. package/dist/components/LandscapeObject.d.ts.map +1 -0
  20. package/dist/components/LandscapeObject.js +27 -0
  21. package/dist/components/ObjectNode.d.ts.map +1 -1
  22. package/dist/components/ObjectNode.js +11 -9
  23. package/dist/components/OceanBuilder.d.ts +35 -0
  24. package/dist/components/OceanBuilder.d.ts.map +1 -0
  25. package/dist/components/OceanBuilder.js +53 -0
  26. package/dist/components/ParticlesR3f.d.ts.map +1 -1
  27. package/dist/components/ParticlesR3f.js +63 -12
  28. package/dist/components/PointCloud.d.ts.map +1 -1
  29. package/dist/components/PointCloud.js +50 -10
  30. package/dist/components/SceneBuilder.d.ts.map +1 -1
  31. package/dist/components/SkySystem.d.ts +27 -6
  32. package/dist/components/SkySystem.d.ts.map +1 -1
  33. package/dist/components/SkySystem.js +6 -5
  34. package/dist/components/SunLight.d.ts.map +1 -1
  35. package/dist/components/SunLight.js +4 -1
  36. package/dist/components/TerrainBuilder.d.ts +30 -0
  37. package/dist/components/TerrainBuilder.d.ts.map +1 -0
  38. package/dist/components/TerrainBuilder.js +44 -0
  39. package/dist/components/index.d.ts +17 -1
  40. package/dist/components/index.d.ts.map +1 -1
  41. package/dist/components/index.js +10 -0
  42. package/dist/components/landscape/LandscapeMesh.d.ts +18 -0
  43. package/dist/components/landscape/LandscapeMesh.d.ts.map +1 -0
  44. package/dist/components/landscape/LandscapeMesh.js +278 -0
  45. package/dist/components/landscape/index.d.ts +3 -0
  46. package/dist/components/landscape/index.d.ts.map +1 -0
  47. package/dist/components/landscape/index.js +1 -0
  48. package/dist/components/landscape/types.d.ts +13 -0
  49. package/dist/components/landscape/types.d.ts.map +1 -0
  50. package/dist/components/landscape/types.js +1 -0
  51. package/dist/components/terrain/Canyon.d.ts +23 -0
  52. package/dist/components/terrain/Canyon.d.ts.map +1 -0
  53. package/dist/components/terrain/Canyon.js +29 -0
  54. package/dist/components/terrain/Dunes.d.ts +22 -0
  55. package/dist/components/terrain/Dunes.d.ts.map +1 -0
  56. package/dist/components/terrain/Dunes.js +25 -0
  57. package/dist/components/terrain/Hills.d.ts +17 -0
  58. package/dist/components/terrain/Hills.d.ts.map +1 -0
  59. package/dist/components/terrain/Hills.js +20 -0
  60. package/dist/components/terrain/Mountains.d.ts +19 -0
  61. package/dist/components/terrain/Mountains.d.ts.map +1 -0
  62. package/dist/components/terrain/Mountains.js +22 -0
  63. package/dist/components/terrain/TerrainSurface.d.ts +22 -0
  64. package/dist/components/terrain/TerrainSurface.d.ts.map +1 -0
  65. package/dist/components/terrain/TerrainSurface.js +94 -0
  66. package/dist/components/terrain/index.d.ts +7 -0
  67. package/dist/components/terrain/index.d.ts.map +1 -0
  68. package/dist/components/terrain/index.js +7 -0
  69. package/dist/components/terrain/types.d.ts +17 -0
  70. package/dist/components/terrain/types.d.ts.map +1 -0
  71. package/dist/components/terrain/types.js +1 -0
  72. package/dist/components/volumetricClouds/Cirrus.d.ts +14 -0
  73. package/dist/components/volumetricClouds/Cirrus.d.ts.map +1 -0
  74. package/dist/components/volumetricClouds/Cirrus.js +13 -0
  75. package/dist/components/volumetricClouds/Cumulonimbus.d.ts +17 -0
  76. package/dist/components/volumetricClouds/Cumulonimbus.d.ts.map +1 -0
  77. package/dist/components/volumetricClouds/Cumulonimbus.js +20 -0
  78. package/dist/components/volumetricClouds/Cumulus.d.ts +14 -0
  79. package/dist/components/volumetricClouds/Cumulus.d.ts.map +1 -0
  80. package/dist/components/volumetricClouds/Cumulus.js +17 -0
  81. package/dist/components/volumetricClouds/Stratocumulus.d.ts +12 -0
  82. package/dist/components/volumetricClouds/Stratocumulus.d.ts.map +1 -0
  83. package/dist/components/volumetricClouds/Stratocumulus.js +16 -0
  84. package/dist/components/volumetricClouds/VolumetricCloudsPass.d.ts +42 -0
  85. package/dist/components/volumetricClouds/VolumetricCloudsPass.d.ts.map +1 -0
  86. package/dist/components/volumetricClouds/VolumetricCloudsPass.js +298 -0
  87. package/dist/components/volumetricClouds/index.d.ts +8 -0
  88. package/dist/components/volumetricClouds/index.d.ts.map +1 -0
  89. package/dist/components/volumetricClouds/index.js +7 -0
  90. package/dist/components/volumetricClouds/types.d.ts +17 -0
  91. package/dist/components/volumetricClouds/types.d.ts.map +1 -0
  92. package/dist/components/volumetricClouds/types.js +1 -0
  93. package/dist/components/water/Host.d.ts +12 -0
  94. package/dist/components/water/Host.d.ts.map +1 -0
  95. package/dist/components/water/Host.js +12 -0
  96. package/dist/components/water/Lake.d.ts +18 -0
  97. package/dist/components/water/Lake.d.ts.map +1 -0
  98. package/dist/components/water/Lake.js +21 -0
  99. package/dist/components/water/OceanSurface.d.ts +27 -0
  100. package/dist/components/water/OceanSurface.d.ts.map +1 -0
  101. package/dist/components/water/OceanSurface.js +60 -0
  102. package/dist/components/water/Sea.d.ts +18 -0
  103. package/dist/components/water/Sea.d.ts.map +1 -0
  104. package/dist/components/water/Sea.js +17 -0
  105. package/dist/components/water/Shore.d.ts +16 -0
  106. package/dist/components/water/Shore.d.ts.map +1 -0
  107. package/dist/components/water/Shore.js +15 -0
  108. package/dist/components/water/Storm.d.ts +14 -0
  109. package/dist/components/water/Storm.d.ts.map +1 -0
  110. package/dist/components/water/Storm.js +13 -0
  111. package/dist/components/water/WaterBody.d.ts +31 -0
  112. package/dist/components/water/WaterBody.d.ts.map +1 -0
  113. package/dist/components/water/WaterBody.js +76 -0
  114. package/dist/components/water/index.d.ts +9 -0
  115. package/dist/components/water/index.d.ts.map +1 -0
  116. package/dist/components/water/index.js +11 -0
  117. package/dist/components/water/types.d.ts +20 -0
  118. package/dist/components/water/types.d.ts.map +1 -0
  119. package/dist/components/water/types.js +1 -0
  120. package/dist/constants.d.ts +1 -0
  121. package/dist/constants.d.ts.map +1 -1
  122. package/dist/constants.js +15 -0
  123. package/dist/hooks/index.d.ts +24 -1
  124. package/dist/hooks/index.d.ts.map +1 -1
  125. package/dist/hooks/index.js +12 -0
  126. package/dist/hooks/useClipmap.d.ts +71 -0
  127. package/dist/hooks/useClipmap.d.ts.map +1 -0
  128. package/dist/hooks/useClipmap.js +81 -0
  129. package/dist/hooks/useCloudLive.d.ts +29 -0
  130. package/dist/hooks/useCloudLive.d.ts.map +1 -0
  131. package/dist/hooks/useCloudLive.js +43 -0
  132. package/dist/hooks/useCloudNoise.d.ts +28 -0
  133. package/dist/hooks/useCloudNoise.d.ts.map +1 -0
  134. package/dist/hooks/useCloudNoise.js +128 -0
  135. package/dist/hooks/useCloudSun.d.ts +49 -0
  136. package/dist/hooks/useCloudSun.d.ts.map +1 -0
  137. package/dist/hooks/useCloudSun.js +84 -0
  138. package/dist/hooks/useCubeCamera.d.ts +27 -9
  139. package/dist/hooks/useCubeCamera.d.ts.map +1 -1
  140. package/dist/hooks/useCubeCamera.js +28 -70
  141. package/dist/hooks/useEnvironmentProbe.d.ts +32 -0
  142. package/dist/hooks/useEnvironmentProbe.d.ts.map +1 -0
  143. package/dist/hooks/useEnvironmentProbe.js +35 -0
  144. package/dist/hooks/useFrameRenderer.d.ts +15 -0
  145. package/dist/hooks/useFrameRenderer.d.ts.map +1 -0
  146. package/dist/hooks/useFrameRenderer.js +23 -0
  147. package/dist/hooks/useLandscapeLive.d.ts +29 -0
  148. package/dist/hooks/useLandscapeLive.d.ts.map +1 -0
  149. package/dist/hooks/useLandscapeLive.js +41 -0
  150. package/dist/hooks/useLandscapeMaps.d.ts +32 -0
  151. package/dist/hooks/useLandscapeMaps.d.ts.map +1 -0
  152. package/dist/hooks/useLandscapeMaps.js +138 -0
  153. package/dist/hooks/useMaterialApplication.d.ts.map +1 -1
  154. package/dist/hooks/useMaterialApplication.js +2 -3
  155. package/dist/hooks/useMaterialOptions.d.ts +2 -2
  156. package/dist/hooks/useMaterialOptions.d.ts.map +1 -1
  157. package/dist/hooks/useMaterialOptions.js +13 -31
  158. package/dist/hooks/useObjectEdges.d.ts.map +1 -1
  159. package/dist/hooks/useObjectEdges.js +3 -49
  160. package/dist/hooks/useOceanLive.d.ts +29 -0
  161. package/dist/hooks/useOceanLive.d.ts.map +1 -0
  162. package/dist/hooks/useOceanLive.js +38 -0
  163. package/dist/hooks/useOceanMaterial.d.ts +39 -0
  164. package/dist/hooks/useOceanMaterial.d.ts.map +1 -0
  165. package/dist/hooks/useOceanMaterial.js +65 -0
  166. package/dist/hooks/useTerrainClipmap.d.ts +12 -0
  167. package/dist/hooks/useTerrainClipmap.d.ts.map +1 -0
  168. package/dist/hooks/useTerrainClipmap.js +10 -0
  169. package/dist/hooks/useTerrainLive.d.ts +34 -0
  170. package/dist/hooks/useTerrainLive.d.ts.map +1 -0
  171. package/dist/hooks/useTerrainLive.js +45 -0
  172. package/dist/index.d.ts +26 -0
  173. package/dist/index.d.ts.map +1 -1
  174. package/dist/index.js +16 -0
  175. package/dist/presets/landscapePresets.d.ts +60 -0
  176. package/dist/presets/landscapePresets.d.ts.map +1 -0
  177. package/dist/presets/landscapePresets.js +194 -0
  178. package/dist/presets/landscapeTypes.d.ts +195 -0
  179. package/dist/presets/landscapeTypes.d.ts.map +1 -0
  180. package/dist/presets/landscapeTypes.js +315 -0
  181. package/dist/presets/oceanSurfacePresets.d.ts +33 -0
  182. package/dist/presets/oceanSurfacePresets.d.ts.map +1 -0
  183. package/dist/presets/oceanSurfacePresets.js +245 -0
  184. package/dist/presets/terrainPresets.d.ts +28 -0
  185. package/dist/presets/terrainPresets.d.ts.map +1 -0
  186. package/dist/presets/terrainPresets.js +293 -0
  187. package/dist/presets/volumetricCloudPresets.d.ts +38 -0
  188. package/dist/presets/volumetricCloudPresets.d.ts.map +1 -0
  189. package/dist/presets/volumetricCloudPresets.js +480 -0
  190. package/dist/shaders/clouds/CirrusMaterial.d.ts +84 -0
  191. package/dist/shaders/clouds/CirrusMaterial.d.ts.map +1 -0
  192. package/dist/shaders/clouds/CirrusMaterial.js +167 -0
  193. package/dist/shaders/clouds/CloudCompositeMaterial.d.ts +20 -0
  194. package/dist/shaders/clouds/CloudCompositeMaterial.d.ts.map +1 -0
  195. package/dist/shaders/clouds/CloudCompositeMaterial.js +82 -0
  196. package/dist/shaders/clouds/CloudResolveMaterial.d.ts +22 -0
  197. package/dist/shaders/clouds/CloudResolveMaterial.d.ts.map +1 -0
  198. package/dist/shaders/clouds/CloudResolveMaterial.js +77 -0
  199. package/dist/shaders/clouds/CloudVolumeMaterial.d.ts +143 -0
  200. package/dist/shaders/clouds/CloudVolumeMaterial.d.ts.map +1 -0
  201. package/dist/shaders/clouds/CloudVolumeMaterial.js +249 -0
  202. package/dist/shaders/clouds/SkyBackgroundMaterial.d.ts +21 -0
  203. package/dist/shaders/clouds/SkyBackgroundMaterial.d.ts.map +1 -0
  204. package/dist/shaders/clouds/SkyBackgroundMaterial.js +42 -0
  205. package/dist/shaders/glsl/cloudCore.glsl.d.ts +24 -0
  206. package/dist/shaders/glsl/cloudCore.glsl.d.ts.map +1 -0
  207. package/dist/shaders/glsl/cloudCore.glsl.js +348 -0
  208. package/dist/shaders/glsl/landscapeCore.glsl.d.ts +49 -0
  209. package/dist/shaders/glsl/landscapeCore.glsl.d.ts.map +1 -0
  210. package/dist/shaders/glsl/landscapeCore.glsl.js +518 -0
  211. package/dist/shaders/glsl/noiseBake.glsl.d.ts +30 -0
  212. package/dist/shaders/glsl/noiseBake.glsl.d.ts.map +1 -0
  213. package/dist/shaders/glsl/noiseBake.glsl.js +164 -0
  214. package/dist/shaders/glsl/oceanCore.glsl.d.ts +52 -0
  215. package/dist/shaders/glsl/oceanCore.glsl.d.ts.map +1 -0
  216. package/dist/shaders/glsl/oceanCore.glsl.js +421 -0
  217. package/dist/shaders/glsl/terrainCore.glsl.d.ts +78 -0
  218. package/dist/shaders/glsl/terrainCore.glsl.d.ts.map +1 -0
  219. package/dist/shaders/glsl/terrainCore.glsl.js +625 -0
  220. package/dist/shaders/landscape/LandscapeMaterial.d.ts +73 -0
  221. package/dist/shaders/landscape/LandscapeMaterial.d.ts.map +1 -0
  222. package/dist/shaders/landscape/LandscapeMaterial.js +136 -0
  223. package/dist/shaders/ocean/OceanSurfaceMaterial.d.ts +57 -0
  224. package/dist/shaders/ocean/OceanSurfaceMaterial.d.ts.map +1 -0
  225. package/dist/shaders/ocean/OceanSurfaceMaterial.js +268 -0
  226. package/dist/shaders/terrain/TerrainMaterial.d.ts +80 -0
  227. package/dist/shaders/terrain/TerrainMaterial.d.ts.map +1 -0
  228. package/dist/shaders/terrain/TerrainMaterial.js +291 -0
  229. package/dist/types/cloudConfigs.d.ts +244 -0
  230. package/dist/types/cloudConfigs.d.ts.map +1 -0
  231. package/dist/types/cloudConfigs.js +282 -0
  232. package/dist/types/index.d.ts +8 -0
  233. package/dist/types/index.d.ts.map +1 -1
  234. package/dist/types/index.js +4 -1
  235. package/dist/types/landscapeConfigs.d.ts +218 -0
  236. package/dist/types/landscapeConfigs.d.ts.map +1 -0
  237. package/dist/types/landscapeConfigs.js +256 -0
  238. package/dist/types/oceanConfigs.d.ts +290 -0
  239. package/dist/types/oceanConfigs.d.ts.map +1 -0
  240. package/dist/types/oceanConfigs.js +380 -0
  241. package/dist/types/terrainConfigs.d.ts +251 -0
  242. package/dist/types/terrainConfigs.d.ts.map +1 -0
  243. package/dist/types/terrainConfigs.js +292 -0
  244. package/dist/utils/cloudUniforms.d.ts +14 -0
  245. package/dist/utils/cloudUniforms.d.ts.map +1 -0
  246. package/dist/utils/cloudUniforms.js +122 -0
  247. package/dist/utils/frameRenderer.d.ts +33 -0
  248. package/dist/utils/frameRenderer.d.ts.map +1 -0
  249. package/dist/utils/frameRenderer.js +24 -0
  250. package/dist/utils/handleCloudsAnimations.d.ts +16 -0
  251. package/dist/utils/handleCloudsAnimations.d.ts.map +1 -0
  252. package/dist/utils/handleCloudsAnimations.js +64 -0
  253. package/dist/utils/landscapeGeometry.d.ts +61 -0
  254. package/dist/utils/landscapeGeometry.d.ts.map +1 -0
  255. package/dist/utils/landscapeGeometry.js +126 -0
  256. package/dist/utils/landscapeHeight.d.ts +44 -0
  257. package/dist/utils/landscapeHeight.d.ts.map +1 -0
  258. package/dist/utils/landscapeHeight.js +65 -0
  259. package/dist/utils/landscapeTextures.d.ts +94 -0
  260. package/dist/utils/landscapeTextures.d.ts.map +1 -0
  261. package/dist/utils/landscapeTextures.js +290 -0
  262. package/dist/utils/landscapeUniforms.d.ts +20 -0
  263. package/dist/utils/landscapeUniforms.d.ts.map +1 -0
  264. package/dist/utils/landscapeUniforms.js +61 -0
  265. package/dist/utils/oceanUniforms.d.ts +47 -0
  266. package/dist/utils/oceanUniforms.d.ts.map +1 -0
  267. package/dist/utils/oceanUniforms.js +216 -0
  268. package/dist/utils/pointsMaterialOwnership.d.ts +9 -0
  269. package/dist/utils/pointsMaterialOwnership.d.ts.map +1 -0
  270. package/dist/utils/pointsMaterialOwnership.js +14 -0
  271. package/dist/utils/rtin.d.ts +63 -0
  272. package/dist/utils/rtin.d.ts.map +1 -0
  273. package/dist/utils/rtin.js +202 -0
  274. package/dist/utils/terrainUniforms.d.ts +14 -0
  275. package/dist/utils/terrainUniforms.d.ts.map +1 -0
  276. package/dist/utils/terrainUniforms.js +196 -0
  277. package/package.json +2 -2
@@ -0,0 +1,71 @@
1
+ import * as THREE from 'three';
2
+ /**
3
+ * Geometry clipmap rings. Shared by the terrain and the ocean.
4
+ *
5
+ * A surface that reaches the horizon cannot be one grid: at 4 m cells, 25 km is
6
+ * 39 million quads. A clipmap spends its vertices where they are visible instead
7
+ * — level 0 is a dense square centred on the camera, and every level above it is
8
+ * a hollow ring of the SAME vertex count at twice the cell size, so each ring
9
+ * covers four times the area for the same cost. Seven levels of 96 segments at
10
+ * 4 m reach roughly 24 km for about 65k vertices.
11
+ *
12
+ * This hook knows nothing about what displaces it. It was written for terrain
13
+ * (`useTerrainClipmap`, now a shim over this) and the ocean uses it unchanged;
14
+ * the height field, the LOD rule and the material are the caller's business.
15
+ *
16
+ * Two details make it work, and both are baked into the attributes here rather
17
+ * than solved at runtime:
18
+ *
19
+ * **`aMorph`** ramps 0 to 1 across the outer band of every ring. In the vertex
20
+ * shader it slides odd-indexed vertices onto their even neighbours, so by the
21
+ * ring's outer edge the polyline is exactly the next ring's coarser polyline.
22
+ * That closes the T-junction cracks between levels — and because it is a
23
+ * continuous slide rather than a swap, it also removes the pop.
24
+ *
25
+ * **`aCoarse`** is the offset to that even neighbour, and it is zero on even
26
+ * indices. The ring boundaries are all at even indices (which is why `segments`
27
+ * must be a multiple of 8), so a boundary vertex only ever moves ALONG the
28
+ * boundary, never off it. A morph that displaced the edge inward would trade the
29
+ * crack for a gap.
30
+ *
31
+ * **`aCell`** is the ring's world cell size, so one material can serve every
32
+ * ring. Both consumers pair it with the same morph rule —
33
+ * `cellLod = aCell * (1.0 + aMorph)` — which makes a ring's outer edge sample the
34
+ * field at exactly the next ring's cell size. Terrain uses it to drop octaves;
35
+ * the ocean uses it to fade out waves shorter than the cell can carry. In both
36
+ * cases the two sides of a seam then agree on the surface, which the geomorph
37
+ * alone does not guarantee.
38
+ *
39
+ * And one thing that is NOT here, because getting it wrong is the classic way to
40
+ * open the seams: every ring shares ONE snapped origin, exposed as `sharedSnap`.
41
+ * Snapping each ring to its own cell grid — which is what a clipmap tutorial will
42
+ * tell you to do — puts neighbouring rings on origins up to a cell apart, and the
43
+ * boundaries that line up perfectly in local space then miss each other in world
44
+ * space by that offset. The published fix for that is Asirvatham & Hoppe's
45
+ * L-shaped trim piece in four rotations; sharing the origin avoids needing one.
46
+ * The price is that coarse rings re-tessellate in sub-cell steps as the camera
47
+ * moves rather than snapping cleanly, and at their cell sizes the octave cut-off
48
+ * has already smoothed away everything that would show it.
49
+ */
50
+ export interface ClipmapLevel {
51
+ geometry: THREE.BufferGeometry;
52
+ /** World size of one cell at this level. */
53
+ cell: number;
54
+ level: number;
55
+ }
56
+ export interface Clipmap {
57
+ levels: ClipmapLevel[];
58
+ /** The grid every ring is snapped to: twice the finest cell. Twice, so index
59
+ * parity — and with it the geomorph — never flips as the camera crosses a
60
+ * cell boundary. Snapping to one cell inverts the morph every step and the
61
+ * whole surface shimmers. */
62
+ sharedSnap: number;
63
+ }
64
+ /**
65
+ * `segments` is rounded to a multiple of 8: the ring boundaries sit at
66
+ * `segments/4` and `segments/2`, and both must land on even indices or the morph
67
+ * pulls boundary vertices off their own edge.
68
+ */
69
+ export declare function useClipmap(levels: number, segments: number, cellSize: number): Clipmap;
70
+ export default useClipmap;
71
+ //# sourceMappingURL=useClipmap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useClipmap.d.ts","sourceRoot":"","sources":["../../src/hooks/useClipmap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH,MAAM,WAAW,YAAY;IACzB,QAAQ,EAAE,KAAK,CAAC,cAAc,CAAC;IAC/B,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,OAAO;IACpB,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB;;;kCAG8B;IAC9B,UAAU,EAAE,MAAM,CAAC;CACtB;AA4ED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAgBtF;AAED,eAAe,UAAU,CAAC"}
@@ -0,0 +1,81 @@
1
+ import * as THREE from 'three';
2
+ import { useEffect, useMemo } from 'react';
3
+ /** Fraction of the ring's half-extent over which the morph runs. */
4
+ const MORPH_BAND = 0.25;
5
+ function buildLevel(segments, cell, hollow, level) {
6
+ const side = segments + 1;
7
+ const half = segments / 2;
8
+ const count = side * side;
9
+ const positions = new Float32Array(count * 3);
10
+ const aCell = new Float32Array(count);
11
+ const aMorph = new Float32Array(count);
12
+ const aCoarse = new Float32Array(count * 2);
13
+ for (let j = 0; j < side; j++) {
14
+ for (let i = 0; i < side; i++) {
15
+ const v = j * side + i;
16
+ const x = (i - half) * cell;
17
+ const z = (j - half) * cell;
18
+ positions[v * 3] = x;
19
+ positions[v * 3 + 1] = 0;
20
+ positions[v * 3 + 2] = z;
21
+ aCell[v] = cell;
22
+ // Chebyshev distance from the centre, normalised to the half-extent.
23
+ // Square rings need a square metric, or the morph band bulges at the
24
+ // corners and the seam opens there.
25
+ const u = Math.max(Math.abs(i - half), Math.abs(j - half)) / half;
26
+ const t = (u - (1 - MORPH_BAND)) / MORPH_BAND;
27
+ aMorph[v] = Math.min(Math.max(t, 0), 1);
28
+ aCoarse[v * 2] = -(i % 2) * cell;
29
+ aCoarse[v * 2 + 1] = -(j % 2) * cell;
30
+ }
31
+ }
32
+ // The hole spans the middle half in each axis, which is exactly the extent of
33
+ // the level below — the two meet edge to edge with nothing between them.
34
+ const holeLo = segments / 4;
35
+ const holeHi = segments - segments / 4;
36
+ const indices = [];
37
+ for (let j = 0; j < segments; j++) {
38
+ for (let i = 0; i < segments; i++) {
39
+ if (hollow && i >= holeLo && i < holeHi && j >= holeLo && j < holeHi)
40
+ continue;
41
+ const a = j * side + i;
42
+ const b = a + 1;
43
+ const c = a + side;
44
+ const d = c + 1;
45
+ indices.push(a, c, b, b, c, d);
46
+ }
47
+ }
48
+ const geometry = new THREE.BufferGeometry();
49
+ geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
50
+ geometry.setAttribute('aCell', new THREE.BufferAttribute(aCell, 1));
51
+ geometry.setAttribute('aMorph', new THREE.BufferAttribute(aMorph, 1));
52
+ geometry.setAttribute('aCoarse', new THREE.BufferAttribute(aCoarse, 2));
53
+ geometry.setIndex(indices);
54
+ // The mesh is flat in object space and displaced in the vertex shader, so a
55
+ // computed bounding volume describes a plane and the ring is frustum-culled
56
+ // the moment the camera looks up. Infinite sphere, culling handled by the
57
+ // clipmap itself: it only ever exists around the camera.
58
+ geometry.boundingSphere = new THREE.Sphere(new THREE.Vector3(), Infinity);
59
+ geometry.boundingBox = new THREE.Box3(new THREE.Vector3(-Infinity, -Infinity, -Infinity), new THREE.Vector3(Infinity, Infinity, Infinity));
60
+ return { geometry, cell, level };
61
+ }
62
+ /**
63
+ * `segments` is rounded to a multiple of 8: the ring boundaries sit at
64
+ * `segments/4` and `segments/2`, and both must land on even indices or the morph
65
+ * pulls boundary vertices off their own edge.
66
+ */
67
+ export function useClipmap(levels, segments, cellSize) {
68
+ const safeLevels = Math.max(1, Math.min(Math.round(levels), 14));
69
+ const safeSegments = Math.max(16, Math.round(segments / 8) * 8);
70
+ const safeCell = Math.max(0.05, cellSize);
71
+ const clipmap = useMemo(() => {
72
+ const out = [];
73
+ for (let l = 0; l < safeLevels; l++) {
74
+ out.push(buildLevel(safeSegments, safeCell * Math.pow(2, l), l > 0, l));
75
+ }
76
+ return { levels: out, sharedSnap: safeCell * 2 };
77
+ }, [safeLevels, safeSegments, safeCell]);
78
+ useEffect(() => () => { clipmap.levels.forEach((r) => r.geometry.dispose()); }, [clipmap]);
79
+ return clipmap;
80
+ }
81
+ export default useClipmap;
@@ -0,0 +1,29 @@
1
+ import type { Object3D } from 'three';
2
+ /**
3
+ * Live cloud editing, the counterpart to useMaterialUniforms.
4
+ *
5
+ * A slider drag fires on every pointer-move. Routing that through Redux would
6
+ * dispatch and re-render the tree sixty times a second, and — because the cloud
7
+ * pass keys its temporal history off the config — would also restart the
8
+ * accumulation on every one of those frames, so the deck would boil while you tune
9
+ * it. Instead the controller finds the layer with findById(id) and writes straight
10
+ * into the renderer here; Redux only hears about it on slider end.
11
+ *
12
+ * const live = useCloudLive(settings.id);
13
+ * <BaseControllerUi onLiveChange={live.deck} onSettingsChange={dispatchToRedux} ... />
14
+ */
15
+ /** Where VolumetricCloudsPass stashes its handle on the root object's userData. */
16
+ export declare const CLOUD_LIVE_KEY = "__cloudLive";
17
+ export interface CloudLiveHandle {
18
+ deck(key: string, value: number | boolean): void;
19
+ cirrus(key: string, value: number | boolean): void;
20
+ quality(key: string, value: number | boolean): void;
21
+ }
22
+ /**
23
+ * Safe before the layer mounts and after it unmounts: the handle is resolved at call
24
+ * time, not at hook time, so a controller opened before the scene is ready still works
25
+ * once it is — and a stale object reference degrades to a no-op instead of throwing.
26
+ */
27
+ export declare function useCloudLive(target?: Object3D | string | null): CloudLiveHandle;
28
+ export default useCloudLive;
29
+ //# sourceMappingURL=useCloudLive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCloudLive.d.ts","sourceRoot":"","sources":["../../src/hooks/useCloudLive.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAGtC;;;;;;;;;;;;GAYG;AAEH,mFAAmF;AACnF,eAAO,MAAM,cAAc,gBAAgB,CAAC;AAE5C,MAAM,WAAW,eAAe;IAC5B,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACjD,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACnD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;CACvD;AAID;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,GAAG,eAAe,CAkB/E;AAED,eAAe,YAAY,CAAC"}
@@ -0,0 +1,43 @@
1
+ import { useMemo } from 'react';
2
+ import { findById } from '../utils/sceneQuery.js';
3
+ /**
4
+ * Live cloud editing, the counterpart to useMaterialUniforms.
5
+ *
6
+ * A slider drag fires on every pointer-move. Routing that through Redux would
7
+ * dispatch and re-render the tree sixty times a second, and — because the cloud
8
+ * pass keys its temporal history off the config — would also restart the
9
+ * accumulation on every one of those frames, so the deck would boil while you tune
10
+ * it. Instead the controller finds the layer with findById(id) and writes straight
11
+ * into the renderer here; Redux only hears about it on slider end.
12
+ *
13
+ * const live = useCloudLive(settings.id);
14
+ * <BaseControllerUi onLiveChange={live.deck} onSettingsChange={dispatchToRedux} ... />
15
+ */
16
+ /** Where VolumetricCloudsPass stashes its handle on the root object's userData. */
17
+ export const CLOUD_LIVE_KEY = '__cloudLive';
18
+ const NOOP = { deck: () => { }, cirrus: () => { }, quality: () => { } };
19
+ /**
20
+ * Safe before the layer mounts and after it unmounts: the handle is resolved at call
21
+ * time, not at hook time, so a controller opened before the scene is ready still works
22
+ * once it is — and a stale object reference degrades to a no-op instead of throwing.
23
+ */
24
+ export function useCloudLive(target) {
25
+ return useMemo(() => {
26
+ const resolve = () => {
27
+ // Resolved per call, never cached. A findById() memoised in the
28
+ // controller resolves once — and if the layer is not mounted yet, which
29
+ // it is not while the layer is switched off, it resolves to null and
30
+ // stays null until the controller remounts. Every slider then silently
31
+ // does nothing.
32
+ const object = typeof target === 'string' ? findById(target) : target;
33
+ const handle = object?.userData?.[CLOUD_LIVE_KEY];
34
+ return handle ?? NOOP;
35
+ };
36
+ return {
37
+ deck: (key, value) => resolve().deck(key, value),
38
+ cirrus: (key, value) => resolve().cirrus(key, value),
39
+ quality: (key, value) => resolve().quality(key, value),
40
+ };
41
+ }, [target]);
42
+ }
43
+ export default useCloudLive;
@@ -0,0 +1,28 @@
1
+ import * as THREE from 'three';
2
+ /**
3
+ * Bakes the four cloud noise textures once and shares them across the scene.
4
+ *
5
+ * A hook rather than a provider: the cache is keyed on the renderer, so every
6
+ * caller in a Canvas gets the same volumes with no wrapper component to remember.
7
+ * Two decks and four placed clouds should not mean six 128-cubed volumes — the
8
+ * base texture alone is 8 MB, and the field is identical for all of them. What
9
+ * differs per cloud is how it samples it.
10
+ *
11
+ * The bake is a handful of GPU draws plus one readback, a few hundred ms on
12
+ * integrated graphics, paid once per renderer for the life of the page.
13
+ */
14
+ export interface CloudNoise {
15
+ base: THREE.Data3DTexture;
16
+ detail: THREE.Data3DTexture;
17
+ weather: THREE.Texture;
18
+ curl: THREE.Texture;
19
+ dispose(): void;
20
+ }
21
+ export declare function bakeCloudNoise(gl: THREE.WebGLRenderer): CloudNoise | null;
22
+ /**
23
+ * Null when the context cannot support the volumes. Callers should render nothing
24
+ * rather than treat that as an error.
25
+ */
26
+ export declare function useCloudNoise(): CloudNoise | null;
27
+ export default useCloudNoise;
28
+ //# sourceMappingURL=useCloudNoise.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCloudNoise.d.ts","sourceRoot":"","sources":["../../src/hooks/useCloudNoise.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,KAAK,CAAC,aAAa,CAAC;IAC1B,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC;IACvB,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC;IACpB,OAAO,IAAI,IAAI,CAAC;CACnB;AAoGD,wBAAgB,cAAc,CAAC,EAAE,EAAE,KAAK,CAAC,aAAa,GAAG,UAAU,GAAG,IAAI,CAwBzE;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAKjD;AAED,eAAe,aAAa,CAAC"}
@@ -0,0 +1,128 @@
1
+ import * as THREE from 'three';
2
+ import { useMemo } from 'react';
3
+ import { useThree } from '@react-three/fiber';
4
+ import { bakeVertex, bakeBaseFrag, bakeDetailFrag, bakeWeatherFrag, bakeCurlFrag, } from '../shaders/glsl/noiseBake.glsl.js';
5
+ /** Some three builds still export the pre-r137 name. */
6
+ const Texture3D = THREE.Data3DTexture ?? THREE.DataTexture3D;
7
+ const quad = new THREE.PlaneGeometry(2, 2);
8
+ const bakeCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
9
+ function runBake(gl, fragmentShader, width, height, tiles, res) {
10
+ const target = new THREE.WebGLRenderTarget(width, height, {
11
+ minFilter: THREE.NearestFilter,
12
+ magFilter: THREE.NearestFilter,
13
+ format: THREE.RGBAFormat,
14
+ type: THREE.UnsignedByteType,
15
+ depthBuffer: false,
16
+ stencilBuffer: false,
17
+ });
18
+ const material = new THREE.ShaderMaterial({
19
+ uniforms: {
20
+ u_atlas: { value: new THREE.Vector2(width, height) },
21
+ u_tiles: { value: tiles },
22
+ u_res: { value: res },
23
+ },
24
+ vertexShader: bakeVertex,
25
+ fragmentShader,
26
+ glslVersion: THREE.GLSL3,
27
+ depthTest: false,
28
+ depthWrite: false,
29
+ });
30
+ const scene = new THREE.Scene();
31
+ scene.add(new THREE.Mesh(quad, material));
32
+ const prevTarget = gl.getRenderTarget();
33
+ const prevAutoClear = gl.autoClear;
34
+ gl.autoClear = true;
35
+ gl.setRenderTarget(target);
36
+ gl.render(scene, bakeCamera);
37
+ const buffer = new Uint8Array(new ArrayBuffer(width * height * 4));
38
+ gl.readRenderTargetPixels(target, 0, 0, width, height, buffer);
39
+ gl.setRenderTarget(prevTarget);
40
+ gl.autoClear = prevAutoClear;
41
+ target.dispose();
42
+ material.dispose();
43
+ return buffer;
44
+ }
45
+ /** Atlas of z-slices to a real 3D texture, so sampling gets hardware trilinear filtering. */
46
+ function bakeVolume(gl, frag, res, tiles) {
47
+ const width = res * tiles;
48
+ const height = res * Math.ceil(res / tiles);
49
+ const atlas = runBake(gl, frag, width, height, tiles, res);
50
+ const data = new Uint8Array(new ArrayBuffer(res * res * res * 4));
51
+ for (let py = 0; py < height; py++) {
52
+ const ty = Math.floor(py / res);
53
+ const y = py - ty * res;
54
+ for (let px = 0; px < width; px++) {
55
+ const tx = Math.floor(px / res);
56
+ const x = px - tx * res;
57
+ const z = ty * tiles + tx;
58
+ if (z >= res)
59
+ continue;
60
+ const si = (py * width + px) * 4;
61
+ const di = ((z * res + y) * res + x) * 4;
62
+ data[di] = atlas[si];
63
+ data[di + 1] = atlas[si + 1];
64
+ data[di + 2] = atlas[si + 2];
65
+ data[di + 3] = atlas[si + 3];
66
+ }
67
+ }
68
+ const tex = new Texture3D(data, res, res, res);
69
+ tex.format = THREE.RGBAFormat;
70
+ tex.type = THREE.UnsignedByteType;
71
+ tex.minFilter = THREE.LinearFilter;
72
+ tex.magFilter = THREE.LinearFilter;
73
+ tex.wrapS = THREE.RepeatWrapping;
74
+ tex.wrapT = THREE.RepeatWrapping;
75
+ tex.wrapR = THREE.RepeatWrapping;
76
+ tex.unpackAlignment = 1;
77
+ tex.needsUpdate = true;
78
+ return tex;
79
+ }
80
+ function bakePlane(gl, frag, res) {
81
+ const buffer = runBake(gl, frag, res, res, 1, res);
82
+ const tex = new THREE.DataTexture(buffer, res, res, THREE.RGBAFormat, THREE.UnsignedByteType);
83
+ tex.minFilter = THREE.LinearFilter;
84
+ tex.magFilter = THREE.LinearFilter;
85
+ tex.wrapS = THREE.RepeatWrapping;
86
+ tex.wrapT = THREE.RepeatWrapping;
87
+ tex.unpackAlignment = 1;
88
+ tex.needsUpdate = true;
89
+ return tex;
90
+ }
91
+ const cache = new WeakMap();
92
+ export function bakeCloudNoise(gl) {
93
+ const hit = cache.get(gl);
94
+ if (hit)
95
+ return hit;
96
+ // 3D textures are WebGL2 only. Returning null rather than throwing lets the
97
+ // renderer skip clouds on an unsupported context instead of killing the scene.
98
+ if (!gl.capabilities.isWebGL2) {
99
+ console.warn('[clouds] Volumetric clouds need WebGL2 (3D textures). Skipping.');
100
+ return null;
101
+ }
102
+ const noise = {
103
+ base: bakeVolume(gl, bakeBaseFrag, 128, 16),
104
+ detail: bakeVolume(gl, bakeDetailFrag, 64, 8),
105
+ weather: bakePlane(gl, bakeWeatherFrag, 512),
106
+ curl: bakePlane(gl, bakeCurlFrag, 128),
107
+ dispose() {
108
+ this.base.dispose();
109
+ this.detail.dispose();
110
+ this.weather.dispose();
111
+ this.curl.dispose();
112
+ cache.delete(gl);
113
+ },
114
+ };
115
+ cache.set(gl, noise);
116
+ return noise;
117
+ }
118
+ /**
119
+ * Null when the context cannot support the volumes. Callers should render nothing
120
+ * rather than treat that as an error.
121
+ */
122
+ export function useCloudNoise() {
123
+ const gl = useThree((s) => s.gl);
124
+ // Not disposed on unmount: the cache is per-renderer, and a remount would
125
+ // otherwise pay the bake again. Call noise.dispose() when tearing a scene down.
126
+ return useMemo(() => bakeCloudNoise(gl), [gl]);
127
+ }
128
+ export default useCloudNoise;
@@ -0,0 +1,49 @@
1
+ import * as THREE from 'three';
2
+ import type { SkySettings, TimeSettings } from '@3driseai/3drise-core';
3
+ /**
4
+ * The one place the cloud renderer decides where the sun is and what colour it is.
5
+ *
6
+ * Direction comes from whatever the scene already uses, in this order:
7
+ * 1. skySystemManager, when time-of-day is enabled — the same source SunLight,
8
+ * Skybox and Lensflare read, so a time slider moves everything together.
9
+ * 2. SkySettings.elevation / azimuth, the static sun.
10
+ * 3. A fixed mid-morning direction, so a scene with no sky still lights.
11
+ *
12
+ * Colour comes from Kasten-Young air mass through the SAME four Preetham
13
+ * parameters SkyController draws with. That is what keeps the clouds inside the
14
+ * sky rather than pasted onto it: at low sun the beam reddens for the clouds and
15
+ * the background by the same optical depth, because it is the same number.
16
+ */
17
+ export interface CloudSunState {
18
+ direction: THREE.Vector3;
19
+ color: THREE.Color;
20
+ /** Hemispheric fill from above — Rayleigh blue, scaled by how high the sun is. */
21
+ skyAmbient: THREE.Color;
22
+ /** Bounce from below, tinted by the reddened beam. */
23
+ groundAmbient: THREE.Color;
24
+ turbidity: number;
25
+ rayleigh: number;
26
+ mieCoefficient: number;
27
+ mieG: number;
28
+ }
29
+ /**
30
+ * Fill `out` from the sun direction and the sky parameters. Exported so a surface
31
+ * material that wants cloud shadows can agree with the clouds on the sun.
32
+ */
33
+ export declare function computeCloudSun(direction: THREE.Vector3, sky: Partial<SkySettings> | undefined, out: CloudSunState): CloudSunState;
34
+ export interface UseCloudSunOptions {
35
+ skySettings?: SkySettings;
36
+ timeSettings?: TimeSettings;
37
+ /** Override everything — a direction the caller already has. */
38
+ direction?: THREE.Vector3;
39
+ }
40
+ /**
41
+ * Returns a stable object mutated in place. Read it inside useFrame; do not put it
42
+ * in a dependency array — the whole point is that it changes without re-rendering.
43
+ */
44
+ export declare function useCloudSun(options?: UseCloudSunOptions): {
45
+ state: CloudSunState;
46
+ update(): CloudSunState;
47
+ };
48
+ export default useCloudSun;
49
+ //# sourceMappingURL=useCloudSun.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCloudSun.d.ts","sourceRoot":"","sources":["../../src/hooks/useCloudSun.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAEvE;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,aAAa;IAC1B,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC;IACzB,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;IACnB,kFAAkF;IAClF,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC;IACxB,sDAAsD;IACtD,aAAa,EAAE,KAAK,CAAC,KAAK,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CAChB;AAaD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,SAAS,EAAE,GAAG,EAAE,aAAa,GAAG,aAAa,CA2BlI;AAED,MAAM,WAAW,kBAAkB;IAC/B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,gEAAgE;IAChE,SAAS,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,MAAM,IAAI,aAAa,CAAA;CAAE,CA2C/G;AAED,eAAe,WAAW,CAAC"}
@@ -0,0 +1,84 @@
1
+ import * as THREE from 'three';
2
+ import { useMemo, useRef } from 'react';
3
+ import { skySystemManager } from '@3driseai/3drise-core';
4
+ const RAYLEIGH_BASE = [0.0487, 0.113, 0.278];
5
+ const DEFAULT_DIRECTION = new THREE.Vector3(0.35, 0.42, 0.84).normalize();
6
+ /** Kasten-Young relative air mass, clamped where the formula stops behaving. */
7
+ function airMass(cosZenith) {
8
+ const cy = Math.max(cosZenith, -0.02);
9
+ const zenithDeg = (Math.acos(THREE.MathUtils.clamp(cy, -1, 1)) * 180) / Math.PI;
10
+ return Math.min(1 / (Math.max(cy, 0) + 0.15 * Math.pow(Math.max(93.885 - zenithDeg, 0.5), -1.253)), 40);
11
+ }
12
+ /**
13
+ * Fill `out` from the sun direction and the sky parameters. Exported so a surface
14
+ * material that wants cloud shadows can agree with the clouds on the sun.
15
+ */
16
+ export function computeCloudSun(direction, sky, out) {
17
+ const turbidity = sky?.turbidity ?? 2;
18
+ const rayleigh = sky?.rayleigh ?? 1;
19
+ const mieCoefficient = sky?.mieCoefficient ?? 0.005;
20
+ const mieG = sky?.mieDirectionalG ?? 0.76;
21
+ out.direction.copy(direction);
22
+ out.turbidity = turbidity;
23
+ out.rayleigh = rayleigh;
24
+ out.mieCoefficient = mieCoefficient;
25
+ out.mieG = mieG;
26
+ const am = airMass(direction.y);
27
+ const mie = mieCoefficient * turbidity * 4.25;
28
+ const r = Math.exp(-(RAYLEIGH_BASE[0] * turbidity * rayleigh + mie) * am);
29
+ const g = Math.exp(-(RAYLEIGH_BASE[1] * turbidity * rayleigh + mie) * am);
30
+ const b = Math.exp(-(RAYLEIGH_BASE[2] * turbidity * rayleigh + mie) * am);
31
+ out.color.setRGB(r, g, b);
32
+ // Ambient is deliberately not a constant: a cloud's shadowed side is lit by the
33
+ // sky, and the sky goes dark and warm as the sun sets. Freezing it is what makes
34
+ // night clouds glow blue.
35
+ const day = THREE.MathUtils.clamp(direction.y * 2.2, 0.02, 1);
36
+ const k = (0.55 + 0.45 * day) * 1.85;
37
+ out.skyAmbient.setRGB(0.3 * day + 0.02, 0.46 * day + 0.02, 0.86 * day + 0.035).multiplyScalar(k);
38
+ out.groundAmbient.setRGB(0.26 * r, 0.24 * g, 0.21 * b).multiplyScalar(k);
39
+ return out;
40
+ }
41
+ /**
42
+ * Returns a stable object mutated in place. Read it inside useFrame; do not put it
43
+ * in a dependency array — the whole point is that it changes without re-rendering.
44
+ */
45
+ export function useCloudSun(options = {}) {
46
+ const optionsRef = useRef(options);
47
+ optionsRef.current = options;
48
+ const state = useMemo(() => ({
49
+ direction: new THREE.Vector3().copy(DEFAULT_DIRECTION),
50
+ color: new THREE.Color(1, 1, 1),
51
+ skyAmbient: new THREE.Color(),
52
+ groundAmbient: new THREE.Color(),
53
+ turbidity: 2,
54
+ rayleigh: 1,
55
+ mieCoefficient: 0.005,
56
+ mieG: 0.76,
57
+ }), []);
58
+ const scratch = useMemo(() => new THREE.Vector3(), []);
59
+ const update = useMemo(() => () => {
60
+ const { skySettings, timeSettings, direction } = optionsRef.current;
61
+ let dir;
62
+ if (direction) {
63
+ dir = scratch.copy(direction).normalize();
64
+ }
65
+ else if (timeSettings?.enabled) {
66
+ // Same source SunLight reads, so the two can never disagree.
67
+ const sunDirection = skySystemManager.getState()?.sunDirection;
68
+ dir = sunDirection
69
+ ? scratch.copy(sunDirection).normalize()
70
+ : scratch.copy(DEFAULT_DIRECTION);
71
+ }
72
+ else if (skySettings) {
73
+ const el = THREE.MathUtils.degToRad(skySettings.elevation ?? 25);
74
+ const az = THREE.MathUtils.degToRad(skySettings.azimuth ?? 130);
75
+ dir = scratch.set(Math.cos(el) * Math.sin(az), Math.sin(el), Math.cos(el) * Math.cos(az)).normalize();
76
+ }
77
+ else {
78
+ dir = scratch.copy(DEFAULT_DIRECTION);
79
+ }
80
+ return computeCloudSun(dir, skySettings, state);
81
+ }, [scratch, state]);
82
+ return { state, update };
83
+ }
84
+ export default useCloudSun;
@@ -1,18 +1,36 @@
1
1
  import * as THREE from 'three';
2
- import type { TimeSettings, HdrSettings } from '@3driseai/3drise-core';
2
+ import { CubeCameraManager } from '@3driseai/3drise-core';
3
+ /**
4
+ * Imperative handle onto the scene's single cube camera.
5
+ *
6
+ * The hook deliberately holds **no policy**. It attaches the shared
7
+ * CubeCameraManager to this Canvas's scene and renderer and hands back the four
8
+ * verbs; deciding *when* a cube camera should exist and how often it should
9
+ * refresh belongs to whoever knows about HDR backgrounds and sky visibility —
10
+ * that is EnvironmentManager, not this file.
11
+ *
12
+ * That split matters because the state the policy reads (hdr.visible, the sky
13
+ * toggles, timeSettings.autoAnimate) lives in the host app. A hook that took
14
+ * those as options would force every host to hand them over just to get a cube
15
+ * camera, which is how this ended up implemented twice in the first place.
16
+ *
17
+ * The manager is a singleton: one cube camera per app, whatever mounts this.
18
+ */
3
19
  export interface UseCubeCameraOptions {
4
- hdrSettings: HdrSettings;
5
- skyVisible: boolean;
6
- sunSystemVisible: boolean;
7
- timeSettings: TimeSettings;
20
+ /** Face size of the cube render target. 512 is the default everywhere. */
8
21
  resolution?: number;
22
+ /** Where the probe sits. Defaults to the manager's own (0, 50, 0). */
9
23
  position?: THREE.Vector3;
10
24
  onEnvironmentUpdate?: (texture: THREE.Texture) => void;
11
25
  }
12
- export declare const useCubeCamera: (options: UseCubeCameraOptions) => {
13
- cubeCamera: THREE.CubeCamera | null;
14
- updateEnvironment: () => THREE.Texture | null;
26
+ export interface UseCubeCameraReturn {
27
+ manager: CubeCameraManager;
28
+ readonly cubeCamera: THREE.CubeCamera | null;
15
29
  initializeCubeCamera: () => THREE.CubeCamera | null;
30
+ updateEnvironment: () => THREE.Texture | null;
31
+ clear: () => void;
16
32
  dispose: () => void;
17
- };
33
+ }
34
+ export declare const useCubeCamera: (options?: UseCubeCameraOptions) => UseCubeCameraReturn;
35
+ export default useCubeCamera;
18
36
  //# sourceMappingURL=useCubeCamera.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useCubeCamera.d.ts","sourceRoot":"","sources":["../../src/hooks/useCubeCamera.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACvE,MAAM,WAAW,oBAAoB;IACjC,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,YAAY,EAAE,YAAY,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC;IACzB,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,KAAK,IAAI,CAAC;CAC1D;AAED,eAAO,MAAM,aAAa,GAAI,SAAS,oBAAoB,KAAG;IACtD,UAAU,EAAE,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;IACpC,iBAAiB,EAAE,MAAM,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;IAC9C,oBAAoB,EAAE,MAAM,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;IACpD,OAAO,EAAE,MAAM,IAAI,CAAC;CAqE3B,CAAC"}
1
+ {"version":3,"file":"useCubeCamera.d.ts","sourceRoot":"","sources":["../../src/hooks/useCubeCamera.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,oBAAoB;IACjC,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC;IACzB,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,KAAK,IAAI,CAAC;CAC1D;AAED,MAAM,WAAW,mBAAmB;IAChC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;IAC7C,oBAAoB,EAAE,MAAM,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;IACpD,iBAAiB,EAAE,MAAM,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;IAC9C,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,eAAO,MAAM,aAAa,GAAI,UAAS,oBAAyB,KAAG,mBAgClE,CAAC;AAEF,eAAe,aAAa,CAAC"}