@3driseai/3drise-viewer 0.1.7 → 0.1.9

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 (259) 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/EnvironmentManager.d.ts +47 -5
  7. package/dist/components/EnvironmentManager.d.ts.map +1 -1
  8. package/dist/components/EnvironmentManager.js +35 -66
  9. package/dist/components/HdrEnvironment.d.ts +20 -0
  10. package/dist/components/HdrEnvironment.d.ts.map +1 -0
  11. package/dist/components/HdrEnvironment.js +44 -0
  12. package/dist/components/LandscapeBuilder.d.ts +23 -0
  13. package/dist/components/LandscapeBuilder.d.ts.map +1 -0
  14. package/dist/components/LandscapeBuilder.js +25 -0
  15. package/dist/components/LandscapeObject.d.ts +24 -0
  16. package/dist/components/LandscapeObject.d.ts.map +1 -0
  17. package/dist/components/LandscapeObject.js +27 -0
  18. package/dist/components/ObjectNode.d.ts.map +1 -1
  19. package/dist/components/ObjectNode.js +10 -0
  20. package/dist/components/OceanBuilder.d.ts +35 -0
  21. package/dist/components/OceanBuilder.d.ts.map +1 -0
  22. package/dist/components/OceanBuilder.js +53 -0
  23. package/dist/components/SceneBuilder.d.ts.map +1 -1
  24. package/dist/components/SkySystem.d.ts +27 -6
  25. package/dist/components/SkySystem.d.ts.map +1 -1
  26. package/dist/components/SkySystem.js +6 -5
  27. package/dist/components/SunLight.d.ts.map +1 -1
  28. package/dist/components/SunLight.js +4 -1
  29. package/dist/components/TerrainBuilder.d.ts +30 -0
  30. package/dist/components/TerrainBuilder.d.ts.map +1 -0
  31. package/dist/components/TerrainBuilder.js +44 -0
  32. package/dist/components/index.d.ts +17 -1
  33. package/dist/components/index.d.ts.map +1 -1
  34. package/dist/components/index.js +10 -0
  35. package/dist/components/landscape/LandscapeMesh.d.ts +18 -0
  36. package/dist/components/landscape/LandscapeMesh.d.ts.map +1 -0
  37. package/dist/components/landscape/LandscapeMesh.js +278 -0
  38. package/dist/components/landscape/index.d.ts +3 -0
  39. package/dist/components/landscape/index.d.ts.map +1 -0
  40. package/dist/components/landscape/index.js +1 -0
  41. package/dist/components/landscape/types.d.ts +13 -0
  42. package/dist/components/landscape/types.d.ts.map +1 -0
  43. package/dist/components/landscape/types.js +1 -0
  44. package/dist/components/terrain/Canyon.d.ts +23 -0
  45. package/dist/components/terrain/Canyon.d.ts.map +1 -0
  46. package/dist/components/terrain/Canyon.js +29 -0
  47. package/dist/components/terrain/Dunes.d.ts +22 -0
  48. package/dist/components/terrain/Dunes.d.ts.map +1 -0
  49. package/dist/components/terrain/Dunes.js +25 -0
  50. package/dist/components/terrain/Hills.d.ts +17 -0
  51. package/dist/components/terrain/Hills.d.ts.map +1 -0
  52. package/dist/components/terrain/Hills.js +20 -0
  53. package/dist/components/terrain/Mountains.d.ts +19 -0
  54. package/dist/components/terrain/Mountains.d.ts.map +1 -0
  55. package/dist/components/terrain/Mountains.js +22 -0
  56. package/dist/components/terrain/TerrainSurface.d.ts +22 -0
  57. package/dist/components/terrain/TerrainSurface.d.ts.map +1 -0
  58. package/dist/components/terrain/TerrainSurface.js +94 -0
  59. package/dist/components/terrain/index.d.ts +7 -0
  60. package/dist/components/terrain/index.d.ts.map +1 -0
  61. package/dist/components/terrain/index.js +7 -0
  62. package/dist/components/terrain/types.d.ts +17 -0
  63. package/dist/components/terrain/types.d.ts.map +1 -0
  64. package/dist/components/terrain/types.js +1 -0
  65. package/dist/components/volumetricClouds/Cirrus.d.ts +14 -0
  66. package/dist/components/volumetricClouds/Cirrus.d.ts.map +1 -0
  67. package/dist/components/volumetricClouds/Cirrus.js +13 -0
  68. package/dist/components/volumetricClouds/Cumulonimbus.d.ts +17 -0
  69. package/dist/components/volumetricClouds/Cumulonimbus.d.ts.map +1 -0
  70. package/dist/components/volumetricClouds/Cumulonimbus.js +20 -0
  71. package/dist/components/volumetricClouds/Cumulus.d.ts +14 -0
  72. package/dist/components/volumetricClouds/Cumulus.d.ts.map +1 -0
  73. package/dist/components/volumetricClouds/Cumulus.js +17 -0
  74. package/dist/components/volumetricClouds/Stratocumulus.d.ts +12 -0
  75. package/dist/components/volumetricClouds/Stratocumulus.d.ts.map +1 -0
  76. package/dist/components/volumetricClouds/Stratocumulus.js +16 -0
  77. package/dist/components/volumetricClouds/VolumetricCloudsPass.d.ts +42 -0
  78. package/dist/components/volumetricClouds/VolumetricCloudsPass.d.ts.map +1 -0
  79. package/dist/components/volumetricClouds/VolumetricCloudsPass.js +298 -0
  80. package/dist/components/volumetricClouds/index.d.ts +8 -0
  81. package/dist/components/volumetricClouds/index.d.ts.map +1 -0
  82. package/dist/components/volumetricClouds/index.js +7 -0
  83. package/dist/components/volumetricClouds/types.d.ts +17 -0
  84. package/dist/components/volumetricClouds/types.d.ts.map +1 -0
  85. package/dist/components/volumetricClouds/types.js +1 -0
  86. package/dist/components/water/Host.d.ts +12 -0
  87. package/dist/components/water/Host.d.ts.map +1 -0
  88. package/dist/components/water/Host.js +12 -0
  89. package/dist/components/water/Lake.d.ts +18 -0
  90. package/dist/components/water/Lake.d.ts.map +1 -0
  91. package/dist/components/water/Lake.js +21 -0
  92. package/dist/components/water/OceanSurface.d.ts +27 -0
  93. package/dist/components/water/OceanSurface.d.ts.map +1 -0
  94. package/dist/components/water/OceanSurface.js +60 -0
  95. package/dist/components/water/Sea.d.ts +18 -0
  96. package/dist/components/water/Sea.d.ts.map +1 -0
  97. package/dist/components/water/Sea.js +17 -0
  98. package/dist/components/water/Shore.d.ts +16 -0
  99. package/dist/components/water/Shore.d.ts.map +1 -0
  100. package/dist/components/water/Shore.js +15 -0
  101. package/dist/components/water/Storm.d.ts +14 -0
  102. package/dist/components/water/Storm.d.ts.map +1 -0
  103. package/dist/components/water/Storm.js +13 -0
  104. package/dist/components/water/WaterBody.d.ts +31 -0
  105. package/dist/components/water/WaterBody.d.ts.map +1 -0
  106. package/dist/components/water/WaterBody.js +76 -0
  107. package/dist/components/water/index.d.ts +9 -0
  108. package/dist/components/water/index.d.ts.map +1 -0
  109. package/dist/components/water/index.js +11 -0
  110. package/dist/components/water/types.d.ts +20 -0
  111. package/dist/components/water/types.d.ts.map +1 -0
  112. package/dist/components/water/types.js +1 -0
  113. package/dist/constants.d.ts.map +1 -1
  114. package/dist/constants.js +9 -0
  115. package/dist/hooks/index.d.ts +24 -1
  116. package/dist/hooks/index.d.ts.map +1 -1
  117. package/dist/hooks/index.js +12 -0
  118. package/dist/hooks/useClipmap.d.ts +71 -0
  119. package/dist/hooks/useClipmap.d.ts.map +1 -0
  120. package/dist/hooks/useClipmap.js +81 -0
  121. package/dist/hooks/useCloudLive.d.ts +29 -0
  122. package/dist/hooks/useCloudLive.d.ts.map +1 -0
  123. package/dist/hooks/useCloudLive.js +43 -0
  124. package/dist/hooks/useCloudNoise.d.ts +28 -0
  125. package/dist/hooks/useCloudNoise.d.ts.map +1 -0
  126. package/dist/hooks/useCloudNoise.js +128 -0
  127. package/dist/hooks/useCloudSun.d.ts +49 -0
  128. package/dist/hooks/useCloudSun.d.ts.map +1 -0
  129. package/dist/hooks/useCloudSun.js +84 -0
  130. package/dist/hooks/useCubeCamera.d.ts +27 -9
  131. package/dist/hooks/useCubeCamera.d.ts.map +1 -1
  132. package/dist/hooks/useCubeCamera.js +28 -70
  133. package/dist/hooks/useEnvironmentProbe.d.ts +32 -0
  134. package/dist/hooks/useEnvironmentProbe.d.ts.map +1 -0
  135. package/dist/hooks/useEnvironmentProbe.js +35 -0
  136. package/dist/hooks/useFrameRenderer.d.ts +15 -0
  137. package/dist/hooks/useFrameRenderer.d.ts.map +1 -0
  138. package/dist/hooks/useFrameRenderer.js +23 -0
  139. package/dist/hooks/useLandscapeLive.d.ts +29 -0
  140. package/dist/hooks/useLandscapeLive.d.ts.map +1 -0
  141. package/dist/hooks/useLandscapeLive.js +41 -0
  142. package/dist/hooks/useLandscapeMaps.d.ts +32 -0
  143. package/dist/hooks/useLandscapeMaps.d.ts.map +1 -0
  144. package/dist/hooks/useLandscapeMaps.js +138 -0
  145. package/dist/hooks/useOceanLive.d.ts +29 -0
  146. package/dist/hooks/useOceanLive.d.ts.map +1 -0
  147. package/dist/hooks/useOceanLive.js +38 -0
  148. package/dist/hooks/useOceanMaterial.d.ts +39 -0
  149. package/dist/hooks/useOceanMaterial.d.ts.map +1 -0
  150. package/dist/hooks/useOceanMaterial.js +65 -0
  151. package/dist/hooks/useTerrainClipmap.d.ts +12 -0
  152. package/dist/hooks/useTerrainClipmap.d.ts.map +1 -0
  153. package/dist/hooks/useTerrainClipmap.js +10 -0
  154. package/dist/hooks/useTerrainLive.d.ts +34 -0
  155. package/dist/hooks/useTerrainLive.d.ts.map +1 -0
  156. package/dist/hooks/useTerrainLive.js +45 -0
  157. package/dist/index.d.ts +26 -0
  158. package/dist/index.d.ts.map +1 -1
  159. package/dist/index.js +16 -0
  160. package/dist/presets/landscapePresets.d.ts +60 -0
  161. package/dist/presets/landscapePresets.d.ts.map +1 -0
  162. package/dist/presets/landscapePresets.js +194 -0
  163. package/dist/presets/landscapeTypes.d.ts +195 -0
  164. package/dist/presets/landscapeTypes.d.ts.map +1 -0
  165. package/dist/presets/landscapeTypes.js +315 -0
  166. package/dist/presets/oceanSurfacePresets.d.ts +33 -0
  167. package/dist/presets/oceanSurfacePresets.d.ts.map +1 -0
  168. package/dist/presets/oceanSurfacePresets.js +245 -0
  169. package/dist/presets/terrainPresets.d.ts +28 -0
  170. package/dist/presets/terrainPresets.d.ts.map +1 -0
  171. package/dist/presets/terrainPresets.js +293 -0
  172. package/dist/presets/volumetricCloudPresets.d.ts +38 -0
  173. package/dist/presets/volumetricCloudPresets.d.ts.map +1 -0
  174. package/dist/presets/volumetricCloudPresets.js +480 -0
  175. package/dist/shaders/clouds/CirrusMaterial.d.ts +84 -0
  176. package/dist/shaders/clouds/CirrusMaterial.d.ts.map +1 -0
  177. package/dist/shaders/clouds/CirrusMaterial.js +167 -0
  178. package/dist/shaders/clouds/CloudCompositeMaterial.d.ts +20 -0
  179. package/dist/shaders/clouds/CloudCompositeMaterial.d.ts.map +1 -0
  180. package/dist/shaders/clouds/CloudCompositeMaterial.js +82 -0
  181. package/dist/shaders/clouds/CloudResolveMaterial.d.ts +22 -0
  182. package/dist/shaders/clouds/CloudResolveMaterial.d.ts.map +1 -0
  183. package/dist/shaders/clouds/CloudResolveMaterial.js +77 -0
  184. package/dist/shaders/clouds/CloudVolumeMaterial.d.ts +143 -0
  185. package/dist/shaders/clouds/CloudVolumeMaterial.d.ts.map +1 -0
  186. package/dist/shaders/clouds/CloudVolumeMaterial.js +249 -0
  187. package/dist/shaders/clouds/SkyBackgroundMaterial.d.ts +21 -0
  188. package/dist/shaders/clouds/SkyBackgroundMaterial.d.ts.map +1 -0
  189. package/dist/shaders/clouds/SkyBackgroundMaterial.js +42 -0
  190. package/dist/shaders/glsl/cloudCore.glsl.d.ts +24 -0
  191. package/dist/shaders/glsl/cloudCore.glsl.d.ts.map +1 -0
  192. package/dist/shaders/glsl/cloudCore.glsl.js +348 -0
  193. package/dist/shaders/glsl/landscapeCore.glsl.d.ts +49 -0
  194. package/dist/shaders/glsl/landscapeCore.glsl.d.ts.map +1 -0
  195. package/dist/shaders/glsl/landscapeCore.glsl.js +518 -0
  196. package/dist/shaders/glsl/noiseBake.glsl.d.ts +30 -0
  197. package/dist/shaders/glsl/noiseBake.glsl.d.ts.map +1 -0
  198. package/dist/shaders/glsl/noiseBake.glsl.js +164 -0
  199. package/dist/shaders/glsl/oceanCore.glsl.d.ts +52 -0
  200. package/dist/shaders/glsl/oceanCore.glsl.d.ts.map +1 -0
  201. package/dist/shaders/glsl/oceanCore.glsl.js +421 -0
  202. package/dist/shaders/glsl/terrainCore.glsl.d.ts +78 -0
  203. package/dist/shaders/glsl/terrainCore.glsl.d.ts.map +1 -0
  204. package/dist/shaders/glsl/terrainCore.glsl.js +625 -0
  205. package/dist/shaders/landscape/LandscapeMaterial.d.ts +73 -0
  206. package/dist/shaders/landscape/LandscapeMaterial.d.ts.map +1 -0
  207. package/dist/shaders/landscape/LandscapeMaterial.js +136 -0
  208. package/dist/shaders/ocean/OceanSurfaceMaterial.d.ts +57 -0
  209. package/dist/shaders/ocean/OceanSurfaceMaterial.d.ts.map +1 -0
  210. package/dist/shaders/ocean/OceanSurfaceMaterial.js +268 -0
  211. package/dist/shaders/terrain/TerrainMaterial.d.ts +80 -0
  212. package/dist/shaders/terrain/TerrainMaterial.d.ts.map +1 -0
  213. package/dist/shaders/terrain/TerrainMaterial.js +291 -0
  214. package/dist/types/cloudConfigs.d.ts +244 -0
  215. package/dist/types/cloudConfigs.d.ts.map +1 -0
  216. package/dist/types/cloudConfigs.js +282 -0
  217. package/dist/types/index.d.ts +8 -0
  218. package/dist/types/index.d.ts.map +1 -1
  219. package/dist/types/index.js +4 -1
  220. package/dist/types/landscapeConfigs.d.ts +218 -0
  221. package/dist/types/landscapeConfigs.d.ts.map +1 -0
  222. package/dist/types/landscapeConfigs.js +256 -0
  223. package/dist/types/oceanConfigs.d.ts +290 -0
  224. package/dist/types/oceanConfigs.d.ts.map +1 -0
  225. package/dist/types/oceanConfigs.js +380 -0
  226. package/dist/types/terrainConfigs.d.ts +251 -0
  227. package/dist/types/terrainConfigs.d.ts.map +1 -0
  228. package/dist/types/terrainConfigs.js +292 -0
  229. package/dist/utils/cloudUniforms.d.ts +14 -0
  230. package/dist/utils/cloudUniforms.d.ts.map +1 -0
  231. package/dist/utils/cloudUniforms.js +122 -0
  232. package/dist/utils/frameRenderer.d.ts +33 -0
  233. package/dist/utils/frameRenderer.d.ts.map +1 -0
  234. package/dist/utils/frameRenderer.js +24 -0
  235. package/dist/utils/handleCloudsAnimations.d.ts +16 -0
  236. package/dist/utils/handleCloudsAnimations.d.ts.map +1 -0
  237. package/dist/utils/handleCloudsAnimations.js +64 -0
  238. package/dist/utils/landscapeGeometry.d.ts +61 -0
  239. package/dist/utils/landscapeGeometry.d.ts.map +1 -0
  240. package/dist/utils/landscapeGeometry.js +126 -0
  241. package/dist/utils/landscapeHeight.d.ts +44 -0
  242. package/dist/utils/landscapeHeight.d.ts.map +1 -0
  243. package/dist/utils/landscapeHeight.js +65 -0
  244. package/dist/utils/landscapeTextures.d.ts +94 -0
  245. package/dist/utils/landscapeTextures.d.ts.map +1 -0
  246. package/dist/utils/landscapeTextures.js +290 -0
  247. package/dist/utils/landscapeUniforms.d.ts +20 -0
  248. package/dist/utils/landscapeUniforms.d.ts.map +1 -0
  249. package/dist/utils/landscapeUniforms.js +61 -0
  250. package/dist/utils/oceanUniforms.d.ts +47 -0
  251. package/dist/utils/oceanUniforms.d.ts.map +1 -0
  252. package/dist/utils/oceanUniforms.js +216 -0
  253. package/dist/utils/rtin.d.ts +63 -0
  254. package/dist/utils/rtin.d.ts.map +1 -0
  255. package/dist/utils/rtin.js +202 -0
  256. package/dist/utils/terrainUniforms.d.ts +14 -0
  257. package/dist/utils/terrainUniforms.d.ts.map +1 -0
  258. package/dist/utils/terrainUniforms.js +196 -0
  259. package/package.json +2 -2
@@ -0,0 +1,298 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as THREE from 'three';
3
+ import { useCallback, useEffect, useMemo, useRef } from 'react';
4
+ import { useFrame, useThree } from '@react-three/fiber';
5
+ import { useFrameRenderer } from '../../hooks/useFrameRenderer.js';
6
+ import { useObjectReady } from '../../hooks/useObjectReady.js';
7
+ import { CLOUD_LIVE_KEY } from '../../hooks/useCloudLive.js';
8
+ import { useCloudNoise } from '../../hooks/useCloudNoise.js';
9
+ import { useCloudSun } from '../../hooks/useCloudSun.js';
10
+ import { CloudVolumeMaterial } from '../../shaders/clouds/CloudVolumeMaterial.js';
11
+ import { CirrusMaterial } from '../../shaders/clouds/CirrusMaterial.js';
12
+ import { CloudResolveMaterial } from '../../shaders/clouds/CloudResolveMaterial.js';
13
+ import { CloudCompositeMaterial } from '../../shaders/clouds/CloudCompositeMaterial.js';
14
+ import { applyCameraUniforms, applyCirrusUniforms, applyDeckUniforms, applySunUniforms, } from '../../utils/cloudUniforms.js';
15
+ import { applyCloudsKeyframeAnimations, applyCloudsMouseMove, resolveDeckConfig, } from '../../utils/handleCloudsAnimations.js';
16
+ const quad = new THREE.PlaneGeometry(2, 2);
17
+ const orthoCam = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
18
+ function passScene(material) {
19
+ const scene = new THREE.Scene();
20
+ scene.add(new THREE.Mesh(quad, material));
21
+ return scene;
22
+ }
23
+ /** rgb 0, alpha 1 — composites as "nothing here", so a disabled layer costs one texel. */
24
+ function emptyTexture() {
25
+ const tex = new THREE.DataTexture(Uint8Array.from([0, 0, 0, 255]), 1, 1, THREE.RGBAFormat, THREE.UnsignedByteType);
26
+ tex.needsUpdate = true;
27
+ return tex;
28
+ }
29
+ const VolumetricCloudsPass = ({ id = '3drise-clouds', deck, cirrus, quality, skySettings, timeSettings, sunIntensity = 1, animations, mouseMove, onObjectReady, onObjectDispose, }) => {
30
+ const gl = useThree((s) => s.gl);
31
+ const scene = useThree((s) => s.scene);
32
+ const size = useThree((s) => s.size);
33
+ const dpr = useThree((s) => s.viewport.dpr);
34
+ const noise = useCloudNoise();
35
+ const { state: sun, update: updateSun } = useCloudSun({ skySettings, timeSettings });
36
+ const deckOn = !!deck?.enabled;
37
+ const cirrusOn = !!cirrus?.enabled;
38
+ const width = Math.max(2, Math.floor(size.width * dpr));
39
+ const height = Math.max(2, Math.floor(size.height * dpr));
40
+ const lowW = Math.max(2, Math.floor(width * quality.resolutionScale));
41
+ const lowH = Math.max(2, Math.floor(height * quality.resolutionScale));
42
+ const targets = useMemo(() => {
43
+ const makeSceneTarget = () => {
44
+ const depthTexture = new THREE.DepthTexture(width, height);
45
+ depthTexture.type = THREE.UnsignedIntType;
46
+ depthTexture.minFilter = THREE.NearestFilter;
47
+ depthTexture.magFilter = THREE.NearestFilter;
48
+ return new THREE.WebGLRenderTarget(width, height, {
49
+ minFilter: THREE.LinearFilter,
50
+ magFilter: THREE.LinearFilter,
51
+ type: THREE.HalfFloatType,
52
+ depthBuffer: true,
53
+ depthTexture,
54
+ });
55
+ };
56
+ const lowOpts = {
57
+ minFilter: THREE.LinearFilter,
58
+ magFilter: THREE.LinearFilter,
59
+ type: THREE.HalfFloatType,
60
+ depthBuffer: false,
61
+ stencilBuffer: false,
62
+ };
63
+ return {
64
+ // Ping-ponged so nothing ever samples the depth attachment it is writing.
65
+ sceneA: makeSceneTarget(),
66
+ sceneB: makeSceneTarget(),
67
+ deck: new THREE.WebGLRenderTarget(lowW, lowH, lowOpts),
68
+ cirrus: new THREE.WebGLRenderTarget(lowW, lowH, lowOpts),
69
+ histA: new THREE.WebGLRenderTarget(lowW, lowH, lowOpts),
70
+ histB: new THREE.WebGLRenderTarget(lowW, lowH, lowOpts),
71
+ };
72
+ }, [width, height, lowW, lowH]);
73
+ useEffect(() => () => { Object.values(targets).forEach((t) => t.dispose()); }, [targets]);
74
+ const passes = useMemo(() => {
75
+ const deckMat = new CloudVolumeMaterial();
76
+ const cirrusMat = new CirrusMaterial();
77
+ const resolveMat = new CloudResolveMaterial();
78
+ const compositeMat = new CloudCompositeMaterial();
79
+ for (const m of [deckMat, cirrusMat, resolveMat, compositeMat]) {
80
+ m.glslVersion = THREE.GLSL3;
81
+ m.depthTest = false;
82
+ m.depthWrite = false;
83
+ }
84
+ return {
85
+ deckMat, cirrusMat, resolveMat, compositeMat,
86
+ deckScene: passScene(deckMat),
87
+ cirrusScene: passScene(cirrusMat),
88
+ resolveScene: passScene(resolveMat),
89
+ compositeScene: passScene(compositeMat),
90
+ };
91
+ }, []);
92
+ useEffect(() => () => {
93
+ [passes.deckMat, passes.cirrusMat, passes.resolveMat, passes.compositeMat]
94
+ .forEach((m) => m.dispose());
95
+ }, [passes]);
96
+ const empty = useMemo(emptyTexture, []);
97
+ const prevViewProj = useRef(new THREE.Matrix4());
98
+ const jitProj = useRef(new THREE.Matrix4());
99
+ const jitInv = useRef(new THREE.Matrix4());
100
+ const frame = useRef(0);
101
+ const validHistory = useRef(0);
102
+ const time = useRef(0);
103
+ const histFlip = useRef(0);
104
+ const prevCamPos = useRef(new THREE.Vector3());
105
+ const prevCamQuat = useRef(new THREE.Quaternion());
106
+ // Animation scratch. Kept in refs so a keyframed coverage does not re-render the
107
+ // React tree sixty times a second.
108
+ const override = useRef({});
109
+ const startValues = useRef({});
110
+ // Live controller overrides. A slider drag writes here every pointer-move and the
111
+ // frame loop reads it on top of the config, so the deck responds without a Redux
112
+ // dispatch per frame. Cleared when the config identity changes, which is exactly
113
+ // slider-end committing the same value.
114
+ const liveDeck = useRef({});
115
+ const liveCirrus = useRef({});
116
+ const liveQuality = useRef({});
117
+ useEffect(() => { liveDeck.current = {}; }, [deck]);
118
+ useEffect(() => { liveCirrus.current = {}; }, [cirrus]);
119
+ useEffect(() => { liveQuality.current = {}; }, [quality]);
120
+ // The handle a controller reaches through findById(id).userData. Set in an effect,
121
+ // never as a userData JSX prop: R3F replaces the whole userData object on every
122
+ // render, which would drop the handle the moment anything above re-renders.
123
+ const rootRef = useRef(null);
124
+ const liveHandle = useMemo(() => ({
125
+ deck: (key, value) => { liveDeck.current[key] = value; },
126
+ cirrus: (key, value) => { liveCirrus.current[key] = value; },
127
+ quality: (key, value) => { liveQuality.current[key] = value; },
128
+ }), []);
129
+ useEffect(() => {
130
+ const root = rootRef.current;
131
+ if (!root)
132
+ return;
133
+ root.userData.id = id;
134
+ root.userData[CLOUD_LIVE_KEY] = liveHandle;
135
+ return () => {
136
+ delete root.userData[CLOUD_LIVE_KEY];
137
+ };
138
+ }, [id, liveHandle]);
139
+ // ObjectReadySource's union is widened by Record<string, any>, but spelling the
140
+ // cast out keeps the intent: this reports the layer's settings, not a mesh's.
141
+ useObjectReady(rootRef, { id, type: 'clouds', deck, cirrus, quality }, onObjectReady, onObjectDispose);
142
+ // Only a resolution change genuinely invalidates the history — the buffers are
143
+ // reallocated and nothing in them maps to the new grid.
144
+ //
145
+ // Config edits deliberately do NOT reset it. Dragging a slider dispatches a new
146
+ // config object every pointer-move, so resetting here would restart the temporal
147
+ // accumulation on every frame of the drag and the deck would boil while you tune
148
+ // it. The neighbourhood clamp in the resolve is exactly what absorbs a field that
149
+ // changes under the history.
150
+ useEffect(() => { validHistory.current = 0; }, [width, height, lowW, lowH]);
151
+ // The frame body, extracted so it can be driven from two places: the render loop,
152
+ // and an off-loop caller that needs a finished image (see useFrameRenderer). It is
153
+ // held in a ref rather than a useCallback because it closes over a dozen pieces of
154
+ // per-frame state, and a dependency array over all of them would be re-created
155
+ // every render anyway — which would re-register the frame renderer every render.
156
+ const drawFrame = (camera, pointer, delta) => {
157
+ if (!noise)
158
+ return;
159
+ frame.current += 1;
160
+ time.current += Math.min(delta, 0.05);
161
+ updateSun();
162
+ // ---- 1. scene ----
163
+ const sceneRT = (frame.current & 1) ? targets.sceneA : targets.sceneB;
164
+ const prevTarget = gl.getRenderTarget();
165
+ const prevAutoClear = gl.autoClear;
166
+ gl.autoClear = true;
167
+ gl.setRenderTarget(sceneRT);
168
+ // No sky pass. SkyController / Skybox already drew the background into this
169
+ // target; the clouds only borrow the atmosphere function for ambient and
170
+ // aerial perspective, so a second sky would just fight the first.
171
+ gl.render(scene, camera);
172
+ // Sub-pixel rotation, applied ONLY to the cloud ray basis. Jittering
173
+ // camera.projectionMatrix would shimmer the scene pass, which nothing resolves.
174
+ const jx = ((frame.current & 1) ? 0.5 : -0.5) / lowW;
175
+ const jy = ((frame.current & 2) ? 0.5 : -0.5) / lowH;
176
+ jitProj.current.copy(camera.projectionMatrix);
177
+ jitProj.current.elements[8] = jx * 2;
178
+ jitProj.current.elements[9] = jy * 2;
179
+ jitInv.current.copy(jitProj.current).invert();
180
+ const bindShared = (m) => {
181
+ applySunUniforms(m, sun, sunIntensity);
182
+ applyCameraUniforms(m, camera, jitInv.current, lowW, lowH);
183
+ m.uniforms.u_time.value = time.current;
184
+ if (m.uniforms.u_frame)
185
+ m.uniforms.u_frame.value = frame.current;
186
+ m.uniforms.u_depth.value = sceneRT.depthTexture;
187
+ m.uniforms.u_hasDepth.value = 1;
188
+ m.uniforms.u_screenSpace.value = 1;
189
+ };
190
+ // ---- 2 & 3. deck march, then temporal resolve ----
191
+ let deckTex = empty;
192
+ if (deckOn && deck) {
193
+ // Keyframes first, then pointer on top, so the two compose rather than
194
+ // the pointer snapping back to the stored config every frame.
195
+ for (const k in override.current)
196
+ delete override.current[k];
197
+ applyCloudsKeyframeAnimations(animations?.clouds?.animations, startValues.current, deck, override.current, time.current);
198
+ if (mouseMove?.enabled && mouseMove.clouds?.enabled) {
199
+ applyCloudsMouseMove(mouseMove.clouds.properties, deck, override.current, pointer);
200
+ }
201
+ // config -> keyframe/pointer domain -> live controller drag, in that order.
202
+ const animated = resolveDeckConfig(deck, override.current);
203
+ const live = resolveDeckConfig(animated, liveDeck.current);
204
+ const liveQual = { ...quality, ...liveQuality.current };
205
+ const m = passes.deckMat;
206
+ applyDeckUniforms(m, live, liveQual);
207
+ m.uniforms.u_base.value = noise.base;
208
+ m.uniforms.u_detail.value = noise.detail;
209
+ m.uniforms.u_weather.value = noise.weather;
210
+ m.uniforms.u_curl.value = noise.curl;
211
+ m.uniforms.u_host.value = 1;
212
+ bindShared(m);
213
+ gl.setRenderTarget(targets.deck);
214
+ gl.render(passes.deckScene, orthoCam);
215
+ const history = histFlip.current ? targets.histB : targets.histA;
216
+ const destination = histFlip.current ? targets.histA : targets.histB;
217
+ const r = passes.resolveMat.uniforms;
218
+ r.u_current.value = targets.deck.texture;
219
+ r.u_history.value = history.texture;
220
+ r.u_prevViewProj.value.copy(prevViewProj.current);
221
+ // UNJITTERED, deliberately. The march samples along jittered rays, but the
222
+ // reprojection maps pixel CENTRES between frames. Feeding it the jittered
223
+ // inverse offsets every history fetch by the current sub-pixel jitter, and
224
+ // since that cycles through four offsets the resolved image shifts about a
225
+ // full-res pixel every frame even with the camera locked. That reads as jitter.
226
+ r.u_invProj.value.copy(camera.projectionMatrixInverse);
227
+ r.u_camWorld.value.copy(camera.matrixWorld);
228
+ r.u_camPos.value.copy(camera.position);
229
+ r.u_texel.value.set(1 / lowW, 1 / lowH);
230
+ // Reprojection proxy: the deck's mid-height. Cheaper than storing
231
+ // per-pixel cloud depth and, for a layer far relative to per-frame
232
+ // camera motion, indistinguishable.
233
+ r.u_proxyHeight.value = (live.baseAltitude + live.topAltitude) * 0.5;
234
+ r.u_valid.value = validHistory.current > 1 ? 1 : 0;
235
+ // While the camera moves, the proxy-plane reprojection is only approximate
236
+ // and a high history weight smears. Ease off, and restore it once still.
237
+ const moved = camera.position.distanceToSquared(prevCamPos.current) > 1e-8
238
+ || Math.abs(camera.quaternion.dot(prevCamQuat.current)) < 0.9999995;
239
+ r.u_blend.value = moved ? Math.min(quality.temporalBlend, 0.7) : quality.temporalBlend;
240
+ gl.setRenderTarget(destination);
241
+ gl.render(passes.resolveScene, orthoCam);
242
+ histFlip.current ^= 1;
243
+ validHistory.current += 1;
244
+ deckTex = destination.texture;
245
+ }
246
+ else {
247
+ validHistory.current = 0;
248
+ }
249
+ // ---- 4. cirrus ----
250
+ let cirrusTex = empty;
251
+ if (cirrusOn && cirrus) {
252
+ const m = passes.cirrusMat;
253
+ applyCirrusUniforms(m, { ...cirrus, ...liveCirrus.current }, quality);
254
+ m.uniforms.u_weather.value = noise.weather;
255
+ bindShared(m);
256
+ gl.setRenderTarget(targets.cirrus);
257
+ gl.render(passes.cirrusScene, orthoCam);
258
+ cirrusTex = targets.cirrus.texture;
259
+ }
260
+ // ---- 5. composite ----
261
+ const c = passes.compositeMat.uniforms;
262
+ c.u_scene.value = sceneRT.texture;
263
+ c.u_clouds.value = deckTex;
264
+ c.u_cirrus.value = cirrusTex;
265
+ c.u_depth.value = sceneRT.depthTexture;
266
+ c.u_lowTexel.value.set(1 / lowW, 1 / lowH);
267
+ c.u_exposure.value = quality.exposure;
268
+ c.u_tonemap.value = quality.tonemap ? 1 : 0;
269
+ c.u_hasCirrus.value = cirrusOn ? 1 : 0;
270
+ gl.setRenderTarget(prevTarget);
271
+ gl.render(passes.compositeScene, orthoCam);
272
+ gl.autoClear = prevAutoClear;
273
+ prevViewProj.current.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
274
+ prevCamPos.current.copy(camera.position);
275
+ prevCamQuat.current.copy(camera.quaternion);
276
+ };
277
+ // Keep the latest body and pointer reachable from the off-loop path without
278
+ // making either a dependency of the registration.
279
+ const drawRef = useRef(drawFrame);
280
+ drawRef.current = drawFrame;
281
+ const pointerRef = useRef(new THREE.Vector2());
282
+ useFrame((state, delta) => {
283
+ pointerRef.current.copy(state.pointer);
284
+ drawRef.current(state.camera, state.pointer, delta);
285
+ }, 1);
286
+ // This pass composites to the canvas itself, so gl.render(scene, camera) is not a
287
+ // complete frame while it is mounted — it draws the scene graph and drops the
288
+ // clouds, which is what made screenshots come back with everything but the sky.
289
+ // delta 0: an off-loop frame must not advance cloud time or the animation jumps.
290
+ const renderCompleteFrame = useCallback((camera) => {
291
+ drawRef.current(camera, pointerRef.current, 0);
292
+ }, []);
293
+ useFrameRenderer(renderCompleteFrame);
294
+ // An empty group, but a real one: it carries userData.id so findById() can reach
295
+ // this layer, and the live handle so a controller can drive it without Redux.
296
+ return _jsx("group", { ref: rootRef });
297
+ };
298
+ export default VolumetricCloudsPass;
@@ -0,0 +1,8 @@
1
+ export type { CloudLayerProps } from './types';
2
+ export type { VolumetricCloudsPassProps } from './VolumetricCloudsPass';
3
+ export { default as VolumetricCloudsPass } from './VolumetricCloudsPass';
4
+ export { default as Cumulus } from './Cumulus';
5
+ export { default as Stratocumulus } from './Stratocumulus';
6
+ export { default as Cumulonimbus } from './Cumulonimbus';
7
+ export { default as Cirrus } from './Cirrus';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/volumetricClouds/index.ts"],"names":[],"mappings":"AAGA,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,YAAY,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAExE,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,7 @@
1
+ // Volumetric cloud layers. Each renders the shared pipeline with the coercions its
2
+ // type needs; exactly one is mounted at a time, by CloudsGenerator.
3
+ export { default as VolumetricCloudsPass } from './VolumetricCloudsPass.js';
4
+ export { default as Cumulus } from './Cumulus.js';
5
+ export { default as Stratocumulus } from './Stratocumulus.js';
6
+ export { default as Cumulonimbus } from './Cumulonimbus.js';
7
+ export { default as Cirrus } from './Cirrus.js';
@@ -0,0 +1,17 @@
1
+ import type { MouseMoveInteractions, ObjectAnimations, SkySettings, TimeSettings } from '@3driseai/3drise-core';
2
+ import type { ObjectReadyProps } from '../../types/objectReady';
3
+ import type { CirrusLayerConfig, CloudDeckConfig, CloudsQualityConfig } from '../../types/cloudConfigs';
4
+ /** Shared by every layer component. The generator hands all four the same shape. */
5
+ export interface CloudLayerProps extends ObjectReadyProps {
6
+ /** Scene id, so a controller can findById() the layer and drive it live. */
7
+ id?: string;
8
+ deck: CloudDeckConfig;
9
+ cirrus: CirrusLayerConfig | null;
10
+ quality: CloudsQualityConfig;
11
+ skySettings?: SkySettings;
12
+ timeSettings?: TimeSettings;
13
+ sunIntensity?: number;
14
+ animations?: ObjectAnimations;
15
+ mouseMove?: MouseMoveInteractions;
16
+ }
17
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/volumetricClouds/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAExG,oFAAoF;AACpF,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACrD,4EAA4E;IAC5E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACjC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,SAAS,CAAC,EAAE,qBAAqB,CAAC;CACrC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import type { OceanLayerProps } from './types';
3
+ /**
4
+ * Picks the container for a water type.
5
+ *
6
+ * Every type works on both hosts — a pool of storm water is a fair thing to
7
+ * want — so the host switch lives here, once, rather than in each of the four
8
+ * type wrappers.
9
+ */
10
+ declare const Host: React.FC<OceanLayerProps>;
11
+ export default Host;
12
+ //# sourceMappingURL=Host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Host.d.ts","sourceRoot":"","sources":["../../../src/components/water/Host.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;;;;;GAMG;AACH,QAAA,MAAM,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CACuD,CAAC;AAE5F,eAAe,IAAI,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import OceanSurface from './OceanSurface.js';
3
+ import WaterBody from './WaterBody.js';
4
+ /**
5
+ * Picks the container for a water type.
6
+ *
7
+ * Every type works on both hosts — a pool of storm water is a fair thing to
8
+ * want — so the host switch lives here, once, rather than in each of the four
9
+ * type wrappers.
10
+ */
11
+ const Host = (props) => props.config.host === 'object' ? _jsx(WaterBody, { ...props }) : _jsx(OceanSurface, { ...props });
12
+ export default Host;
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import type { OceanLayerProps } from './types';
3
+ /**
4
+ * Inland water.
5
+ *
6
+ * Short fetch does all the work: a lake in a gale has small, short, steep waves,
7
+ * because there is no open water upwind for anything longer to build over. Get
8
+ * that wrong and a lake renders as a shrunken ocean, which is the single most
9
+ * common mistake in water rendering.
10
+ *
11
+ * Swell is clamped, and that one IS a coercion. Swell is energy that has
12
+ * travelled out of the weather that made it, over hundreds of kilometres; a lake
13
+ * cannot have any. Left free, the slider produces long, low, ocean-looking rollers
14
+ * on a pond, which is exactly the failure the type exists to prevent.
15
+ */
16
+ declare const Lake: React.FC<OceanLayerProps>;
17
+ export default Lake;
18
+ //# sourceMappingURL=Lake.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Lake.d.ts","sourceRoot":"","sources":["../../../src/components/water/Lake.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;;;;;;;;;;;GAYG;AACH,QAAA,MAAM,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAGnC,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useMemo } from 'react';
3
+ import Host from './Host.js';
4
+ /**
5
+ * Inland water.
6
+ *
7
+ * Short fetch does all the work: a lake in a gale has small, short, steep waves,
8
+ * because there is no open water upwind for anything longer to build over. Get
9
+ * that wrong and a lake renders as a shrunken ocean, which is the single most
10
+ * common mistake in water rendering.
11
+ *
12
+ * Swell is clamped, and that one IS a coercion. Swell is energy that has
13
+ * travelled out of the weather that made it, over hundreds of kilometres; a lake
14
+ * cannot have any. Left free, the slider produces long, low, ocean-looking rollers
15
+ * on a pond, which is exactly the failure the type exists to prevent.
16
+ */
17
+ const Lake = ({ config, ...rest }) => {
18
+ const resolved = useMemo(() => ({ ...config, swell: Math.min(config.swell, 0.15) }), [config]);
19
+ return _jsx(Host, { config: resolved, ...rest });
20
+ };
21
+ export default Lake;
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+ import type { OceanLayerProps } from './types';
3
+ /**
4
+ * The world ocean: a geometry clipmap that follows the camera, displaced in the
5
+ * vertex shader by the wave field.
6
+ *
7
+ * One clipmap, one material, four water types — they differ by the spectrum the
8
+ * CPU uploads, not by having separate renderers, the same way the four landforms
9
+ * share one height field and three of the four cloud types share one marcher.
10
+ *
11
+ * Like the terrain and unlike the cloud pass, this does NOT take over the render
12
+ * loop. It is an ordinary mesh with an ordinary material, so it depth-sorts
13
+ * against scene objects, receives the sun's shadow map, takes scene fog, and the
14
+ * cloud pass composites over it correctly because it is simply in the scene when
15
+ * that pass renders.
16
+ *
17
+ * ## The clipmap follows the camera in XZ only
18
+ *
19
+ * Y is `config.seaLevel`, which is this body's own and has nothing to do with
20
+ * the terrain's. Sea level and ground level are independent by design: a scene
21
+ * may have water and no terrain, terrain and no water, or a lake at +40 m beside
22
+ * a sea at 0. What connects them is computed — the shoreline is where the ground
23
+ * crosses this surface — never configured.
24
+ */
25
+ declare const OceanSurface: React.FC<OceanLayerProps>;
26
+ export default OceanSurface;
27
+ //# sourceMappingURL=OceanSurface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OceanSurface.d.ts","sourceRoot":"","sources":["../../../src/components/water/OceanSurface.tsx"],"names":[],"mappings":"AACA,OAAO,KAAiB,MAAM,OAAO,CAAC;AAItC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAuD3C,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -0,0 +1,60 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useRef } from 'react';
3
+ import { useObjectReady } from '../../hooks/useObjectReady.js';
4
+ import { useClipmap } from '../../hooks/useClipmap.js';
5
+ import { useOceanMaterial } from '../../hooks/useOceanMaterial.js';
6
+ /**
7
+ * The world ocean: a geometry clipmap that follows the camera, displaced in the
8
+ * vertex shader by the wave field.
9
+ *
10
+ * One clipmap, one material, four water types — they differ by the spectrum the
11
+ * CPU uploads, not by having separate renderers, the same way the four landforms
12
+ * share one height field and three of the four cloud types share one marcher.
13
+ *
14
+ * Like the terrain and unlike the cloud pass, this does NOT take over the render
15
+ * loop. It is an ordinary mesh with an ordinary material, so it depth-sorts
16
+ * against scene objects, receives the sun's shadow map, takes scene fog, and the
17
+ * cloud pass composites over it correctly because it is simply in the scene when
18
+ * that pass renders.
19
+ *
20
+ * ## The clipmap follows the camera in XZ only
21
+ *
22
+ * Y is `config.seaLevel`, which is this body's own and has nothing to do with
23
+ * the terrain's. Sea level and ground level are independent by design: a scene
24
+ * may have water and no terrain, terrain and no water, or a lake at +40 m beside
25
+ * a sea at 0. What connects them is computed — the shoreline is where the ground
26
+ * crosses this surface — never configured.
27
+ */
28
+ const OceanSurface = ({ id = '3drise-water', config, quality, skySettings, timeSettings, sunIntensity = 1, onObjectReady, onObjectDispose, }) => {
29
+ const clipmap = useClipmap(quality.levels, quality.segments, quality.cellSize);
30
+ const meshRefs = useRef([]);
31
+ const { material, rootRef } = useOceanMaterial({
32
+ id,
33
+ config,
34
+ quality,
35
+ skySettings,
36
+ timeSettings,
37
+ sunIntensity,
38
+ onFrame: (cfg, _qual, state) => {
39
+ // ONE origin for the whole pyramid, snapped to twice the finest cell.
40
+ //
41
+ // Snapping each ring to its own cell grid is the textbook clipmap and
42
+ // it is what tears the seams open: neighbouring rings then sit on
43
+ // origins up to a cell apart, and boundaries that match exactly in
44
+ // local space miss each other in the world by that offset.
45
+ const snap = clipmap.sharedSnap;
46
+ const ox = Math.round(state.camera.position.x / snap) * snap;
47
+ const oz = Math.round(state.camera.position.z / snap) * snap;
48
+ for (let i = 0; i < clipmap.levels.length; i++) {
49
+ meshRefs.current[i]?.position.set(ox, cfg.seaLevel, oz);
50
+ }
51
+ },
52
+ });
53
+ useObjectReady(rootRef, { id, type: 'ocean', config, quality }, onObjectReady, onObjectDispose);
54
+ return (_jsx("group", { ref: rootRef, children: clipmap.levels.map((ring, i) => (_jsx("mesh", { ref: (m) => { meshRefs.current[i] = m; }, geometry: ring.geometry, material: material, receiveShadow: quality.receiveShadows,
55
+ // Displacement happens in the vertex shader, so the
56
+ // object-space bounds describe a flat plane. Culling against
57
+ // them hides the water the moment the camera tilts up.
58
+ frustumCulled: false }, ring.level))) }));
59
+ };
60
+ export default OceanSurface;
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import type { OceanLayerProps } from './types';
3
+ /**
4
+ * Open ocean.
5
+ *
6
+ * The reference case for the wave field, because everything in the spectrum is
7
+ * visible at once: long swell running under a shorter wind sea, whitecaps where
8
+ * the two coincide and steepen a crest past folding, and a horizon that only
9
+ * looks right because of the curvature term.
10
+ *
11
+ * Nothing is coerced here. The four types differ in the spectrum the CPU
12
+ * uploads, not in what the shader is allowed to do — unlike the terrain, where
13
+ * canyon-only shaping had to be forced off on the other landforms because the
14
+ * shader branches on the type. Nothing in the water shader branches on it.
15
+ */
16
+ declare const Sea: React.FC<OceanLayerProps>;
17
+ export default Sea;
18
+ //# sourceMappingURL=Sea.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sea.d.ts","sourceRoot":"","sources":["../../../src/components/water/Sea.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;;;;;;;;;;;GAYG;AACH,QAAA,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAAkC,CAAC;AAEtE,eAAe,GAAG,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import Host from './Host.js';
3
+ /**
4
+ * Open ocean.
5
+ *
6
+ * The reference case for the wave field, because everything in the spectrum is
7
+ * visible at once: long swell running under a shorter wind sea, whitecaps where
8
+ * the two coincide and steepen a crest past folding, and a horizon that only
9
+ * looks right because of the curvature term.
10
+ *
11
+ * Nothing is coerced here. The four types differ in the spectrum the CPU
12
+ * uploads, not in what the shader is allowed to do — unlike the terrain, where
13
+ * canyon-only shaping had to be forced off on the other landforms because the
14
+ * shader branches on the type. Nothing in the water shader branches on it.
15
+ */
16
+ const Sea = (props) => _jsx(Host, { ...props });
17
+ export default Sea;
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import type { OceanLayerProps } from './types';
3
+ /**
4
+ * Coastal water.
5
+ *
6
+ * Narrow directional spread, because waves refract into alignment with the beach
7
+ * as they shoal, and a stronger shoreline than the other types: this is the one
8
+ * that is defined by meeting the ground rather than by the wind over it.
9
+ *
10
+ * The shoreline itself — depth-ramped colour, the foam line and the wash — needs
11
+ * the refraction depth grab and the terrain height field, so today this type is
12
+ * a coastal spectrum with the shore parameters standing ready. That is phase 4.
13
+ */
14
+ declare const Shore: React.FC<OceanLayerProps>;
15
+ export default Shore;
16
+ //# sourceMappingURL=Shore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Shore.d.ts","sourceRoot":"","sources":["../../../src/components/water/Shore.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;;;;;;;;;GAUG;AACH,QAAA,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAAkC,CAAC;AAExE,eAAe,KAAK,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import Host from './Host.js';
3
+ /**
4
+ * Coastal water.
5
+ *
6
+ * Narrow directional spread, because waves refract into alignment with the beach
7
+ * as they shoal, and a stronger shoreline than the other types: this is the one
8
+ * that is defined by meeting the ground rather than by the wind over it.
9
+ *
10
+ * The shoreline itself — depth-ramped colour, the foam line and the wash — needs
11
+ * the refraction depth grab and the terrain height field, so today this type is
12
+ * a coastal spectrum with the shore parameters standing ready. That is phase 4.
13
+ */
14
+ const Shore = (props) => _jsx(Host, { ...props });
15
+ export default Shore;
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import type { OceanLayerProps } from './types';
3
+ /**
4
+ * Storm sea.
5
+ *
6
+ * Same model as `Sea` with the wind at the top of its range, which is where the
7
+ * Jacobian foam earns its place: past about 15 m/s the crests fold on their own
8
+ * and the whitecaps appear because the surface is genuinely breaking, not
9
+ * because a threshold was lowered. Turn choppiness down and the storm loses its
10
+ * foam — that is the model being honest, not a bug.
11
+ */
12
+ declare const Storm: React.FC<OceanLayerProps>;
13
+ export default Storm;
14
+ //# sourceMappingURL=Storm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Storm.d.ts","sourceRoot":"","sources":["../../../src/components/water/Storm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;;;;;;;GAQG;AACH,QAAA,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAAkC,CAAC;AAExE,eAAe,KAAK,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import Host from './Host.js';
3
+ /**
4
+ * Storm sea.
5
+ *
6
+ * Same model as `Sea` with the wind at the top of its range, which is where the
7
+ * Jacobian foam earns its place: past about 15 m/s the crests fold on their own
8
+ * and the whitecaps appear because the surface is genuinely breaking, not
9
+ * because a threshold was lowered. Turn choppiness down and the storm loses its
10
+ * foam — that is the model being honest, not a bug.
11
+ */
12
+ const Storm = (props) => _jsx(Host, { ...props });
13
+ export default Storm;