@3driseai/3drise-viewer 0.1.7 → 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 (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,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"}
@@ -1,73 +1,31 @@
1
- import { useRef, useCallback, useEffect } from 'react';
2
- import { useThree, useFrame } from '@react-three/fiber';
3
- import * as THREE from 'three';
4
- import { createCubeCamera, updateCubeCamera, disposeCubeCamera, setSceneEnvironment, clearSceneEnvironment, } from '@3driseai/3drise-core';
5
- export const useCubeCamera = (options) => {
6
- const { hdrSettings, skyVisible, sunSystemVisible, timeSettings, resolution = 512, position = new THREE.Vector3(0, 50, 0), onEnvironmentUpdate } = options;
1
+ import { useEffect, useMemo } from 'react';
2
+ import { useThree } from '@react-three/fiber';
3
+ import { CubeCameraManager } from '@3driseai/3drise-core';
4
+ export const useCubeCamera = (options = {}) => {
7
5
  const { scene, gl: renderer } = useThree();
8
- const cubeCameraRef = useRef(null);
9
- const isUpdatingRef = useRef(false);
10
- const hdrActive = hdrSettings.visible && (hdrSettings.name || (hdrSettings.urls && hdrSettings.urls.length > 0)) ? true : false;
11
- const initializeCubeCamera = useCallback(() => {
12
- if (!renderer || !scene)
13
- return null;
14
- if (cubeCameraRef.current)
15
- disposeCubeCamera(cubeCameraRef.current, scene);
16
- cubeCameraRef.current = createCubeCamera(scene, resolution, position);
17
- return cubeCameraRef.current;
18
- }, [scene, renderer, resolution, position]);
19
- const updateEnvironment = useCallback(() => {
20
- if (!cubeCameraRef.current || !renderer || !scene)
21
- return null;
22
- if (isUpdatingRef.current)
23
- return null;
24
- try {
25
- isUpdatingRef.current = true;
26
- const texture = updateCubeCamera(cubeCameraRef.current, renderer, scene);
27
- setSceneEnvironment(scene, texture);
28
- onEnvironmentUpdate?.(texture);
29
- return texture;
30
- }
31
- catch {
32
- return null;
33
- }
34
- finally {
35
- isUpdatingRef.current = false;
36
- }
37
- }, [scene, renderer, onEnvironmentUpdate]);
38
- const dispose = useCallback(() => {
39
- if (cubeCameraRef.current && scene) {
40
- disposeCubeCamera(cubeCameraRef.current, scene);
41
- cubeCameraRef.current = null;
42
- }
43
- }, [scene]);
44
- // Create or dispose cube camera based on active sky / HDR state
6
+ const manager = CubeCameraManager.getInstance();
7
+ const { resolution = 512, position, onEnvironmentUpdate } = options;
45
8
  useEffect(() => {
46
- if (hdrActive) {
47
- dispose();
48
- return;
49
- }
50
- if (skyVisible || sunSystemVisible) {
51
- initializeCubeCamera();
52
- updateEnvironment();
53
- }
54
- else {
55
- dispose();
56
- clearSceneEnvironment(scene);
57
- }
58
- }, [hdrActive, skyVisible, sunSystemVisible]);
59
- // Live update when auto-animating (sky moves, environment changes)
60
- const UPDATE_INTERVAL_MS = 300;
61
- useFrame((state) => {
62
- if (hdrActive || !(skyVisible || sunSystemVisible))
63
- return;
64
- if (!timeSettings.autoAnimate)
65
- return;
66
- if (state.clock.getElapsedTime() * 1000 > UPDATE_INTERVAL_MS) {
67
- updateEnvironment();
68
- }
69
- });
70
- // Cleanup on unmount
71
- useEffect(() => () => dispose(), [dispose]);
72
- return { cubeCamera: cubeCameraRef.current, updateEnvironment, initializeCubeCamera, dispose };
9
+ manager.attach(scene, renderer);
10
+ return () => {
11
+ manager.detach();
12
+ };
13
+ }, [manager, scene, renderer]);
14
+ useEffect(() => {
15
+ manager.setOnUpdate(onEnvironmentUpdate ?? null);
16
+ return () => {
17
+ manager.setOnUpdate(null);
18
+ };
19
+ }, [manager, onEnvironmentUpdate]);
20
+ return useMemo(() => ({
21
+ manager,
22
+ get cubeCamera() {
23
+ return manager.getCubeCamera();
24
+ },
25
+ initializeCubeCamera: () => manager.initCubeCamera(resolution, position),
26
+ updateEnvironment: () => manager.updateEnvironment(),
27
+ clear: () => manager.clear(),
28
+ dispose: () => manager.dispose(),
29
+ }), [manager, resolution, position]);
73
30
  };
31
+ export default useCubeCamera;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * When the scene's cube-camera probe should exist, and how often it refreshes.
3
+ *
4
+ * This is the *policy* half of the cube camera; useCubeCamera is the imperative
5
+ * half. It lives in a hook rather than inside EnvironmentManager because two
6
+ * hosts need it — the composed EnvironmentManager used by published scenes, and
7
+ * the editor's HDR connector, which subscribes to Redux and composes the leaf
8
+ * components itself. Duplicating a rule this fiddly is how the two paths drifted
9
+ * apart last time.
10
+ *
11
+ * The rule itself:
12
+ * - An HDR background provides its own IBL, so the probe is disposed.
13
+ * - Otherwise, if there is any sky, the probe exists and captures it.
14
+ * - Otherwise there is nothing to capture, so dispose and clear the environment.
15
+ *
16
+ * The refresh accumulates delta and resets. The obvious-looking
17
+ * `clock.getElapsedTime() * 1000 > interval` is true on *every* frame after the
18
+ * first 0.3 s, which re-renders all six cube faces per frame.
19
+ */
20
+ export interface UseEnvironmentProbeOptions {
21
+ /** An HDR background or playlist is supplying the environment map. */
22
+ hdrActive: boolean;
23
+ /** Analytic sky or the sun rig is visible — something worth capturing. */
24
+ skyActive: boolean;
25
+ /** Time of day is animating, so the capture goes stale and needs refreshing. */
26
+ autoAnimate: boolean;
27
+ resolution?: number;
28
+ intervalMs?: number;
29
+ }
30
+ export declare function useEnvironmentProbe({ hdrActive, skyActive, autoAnimate, resolution, intervalMs, }: UseEnvironmentProbeOptions): void;
31
+ export default useEnvironmentProbe;
32
+ //# sourceMappingURL=useEnvironmentProbe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useEnvironmentProbe.d.ts","sourceRoot":"","sources":["../../src/hooks/useEnvironmentProbe.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,0BAA0B;IACvC,sEAAsE;IACtE,SAAS,EAAE,OAAO,CAAC;IACnB,0EAA0E;IAC1E,SAAS,EAAE,OAAO,CAAC;IACnB,gFAAgF;IAChF,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,mBAAmB,CAAC,EAChC,SAAS,EACT,SAAS,EACT,WAAW,EACX,UAAgB,EAChB,UAAgB,GACnB,EAAE,0BAA0B,GAAG,IAAI,CA6BnC;AAED,eAAe,mBAAmB,CAAC"}
@@ -0,0 +1,35 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import { useFrame } from '@react-three/fiber';
3
+ import { useCubeCamera } from './useCubeCamera.js';
4
+ export function useEnvironmentProbe({ hdrActive, skyActive, autoAnimate, resolution = 512, intervalMs = 300, }) {
5
+ const { manager, initializeCubeCamera, updateEnvironment, dispose, clear } = useCubeCamera({
6
+ resolution,
7
+ });
8
+ useEffect(() => {
9
+ if (hdrActive) {
10
+ dispose();
11
+ return;
12
+ }
13
+ if (skyActive) {
14
+ initializeCubeCamera();
15
+ updateEnvironment();
16
+ }
17
+ else {
18
+ dispose();
19
+ clear();
20
+ }
21
+ }, [hdrActive, skyActive, initializeCubeCamera, updateEnvironment, dispose, clear]);
22
+ const elapsedMsRef = useRef(0);
23
+ useFrame((_, delta) => {
24
+ if (hdrActive || !skyActive || !autoAnimate)
25
+ return;
26
+ if (!manager.hasCubeCamera())
27
+ return;
28
+ elapsedMsRef.current += delta * 1000;
29
+ if (elapsedMsRef.current >= intervalMs) {
30
+ elapsedMsRef.current = 0;
31
+ updateEnvironment();
32
+ }
33
+ });
34
+ }
35
+ export default useEnvironmentProbe;
@@ -0,0 +1,15 @@
1
+ import { type FrameRenderer } from '../utils/frameRenderer';
2
+ /**
3
+ * Declare that this component produces the finished frame.
4
+ *
5
+ * For a full-screen pass that runs at `useFrame(…, 1)` and composites to the canvas
6
+ * itself. Everything that needs a complete image — screenshots, thumbnails — asks
7
+ * through `renderFrame()` rather than calling `gl.render(scene, camera)`, which would
8
+ * draw the scene graph and silently drop whatever the pass adds.
9
+ *
10
+ * Pass a stable callback (a ref-held function or useCallback); it is registered on
11
+ * mount and released on unmount, so plain rendering resumes when the pass goes away.
12
+ */
13
+ export declare function useFrameRenderer(render: FrameRenderer | null | undefined): void;
14
+ export default useFrameRenderer;
15
+ //# sourceMappingURL=useFrameRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFrameRenderer.d.ts","sourceRoot":"","sources":["../../src/hooks/useFrameRenderer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyB,KAAK,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEnF;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAM/E;AAED,eAAe,gBAAgB,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { useEffect } from 'react';
2
+ import { useThree } from '@react-three/fiber';
3
+ import { registerFrameRenderer } from '../utils/frameRenderer.js';
4
+ /**
5
+ * Declare that this component produces the finished frame.
6
+ *
7
+ * For a full-screen pass that runs at `useFrame(…, 1)` and composites to the canvas
8
+ * itself. Everything that needs a complete image — screenshots, thumbnails — asks
9
+ * through `renderFrame()` rather than calling `gl.render(scene, camera)`, which would
10
+ * draw the scene graph and silently drop whatever the pass adds.
11
+ *
12
+ * Pass a stable callback (a ref-held function or useCallback); it is registered on
13
+ * mount and released on unmount, so plain rendering resumes when the pass goes away.
14
+ */
15
+ export function useFrameRenderer(render) {
16
+ const gl = useThree((s) => s.gl);
17
+ useEffect(() => {
18
+ if (!render)
19
+ return;
20
+ return registerFrameRenderer(gl, render);
21
+ }, [gl, render]);
22
+ }
23
+ export default useFrameRenderer;
@@ -0,0 +1,29 @@
1
+ import type { Object3D } from 'three';
2
+ /**
3
+ * Live landscape editing, the counterpart to `useTerrainLive` and `useOceanLive`.
4
+ *
5
+ * The rule is the same — a slider drag writes straight into the renderer and
6
+ * Redux only hears about it on slider end — but the stakes are higher here.
7
+ * `meshError` re-runs RTIN, `chunks` rebuilds every index buffer,
8
+ * `arrayResolution` repacks the texture arrays and `surfaceSamples` recompiles
9
+ * the shader. Those are commit-on-release; everything else is a uniform and goes
10
+ * through this, and the renderer's handle enforces the split from
11
+ * `LANDSCAPE_LIVE_*_KEYS` so a controller cannot half-apply a rebuild key by
12
+ * passing it here.
13
+ *
14
+ * Pass the ID, not a resolved Object3D: the panel is routinely open before the
15
+ * landscape exists, and a findById() memoised in the controller resolves to null
16
+ * exactly once and stays null for the session.
17
+ */
18
+ export declare const LANDSCAPE_LIVE_KEY = "__landscapeLive";
19
+ export interface LandscapeLiveHandle {
20
+ config(key: string, value: number | boolean | string): void;
21
+ quality(key: string, value: number | boolean | string): void;
22
+ /** One field of one surface, by index. The surface list drives this. */
23
+ surface(index: number, key: string, value: number | boolean | string): void;
24
+ /** One field of the generated-splat block. Every one of them is a uniform. */
25
+ autoSplat(key: string, value: number | boolean | string): void;
26
+ }
27
+ export declare function useLandscapeLive(target?: Object3D | string | null): LandscapeLiveHandle;
28
+ export default useLandscapeLive;
29
+ //# sourceMappingURL=useLandscapeLive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLandscapeLive.d.ts","sourceRoot":"","sources":["../../src/hooks/useLandscapeLive.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAGrC;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,kBAAkB,oBAAoB,CAAA;AAEnD,MAAM,WAAW,mBAAmB;IAChC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,CAAA;IAC3D,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,CAAA;IAC5D,wEAAwE;IACxE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,CAAA;IAC3E,8EAA8E;IAC9E,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,CAAA;CACjE;AASD,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,GAAG,mBAAmB,CAcvF;AAED,eAAe,gBAAgB,CAAA"}
@@ -0,0 +1,41 @@
1
+ import { useMemo } from 'react';
2
+ import { findById } from '../utils/sceneQuery.js';
3
+ /**
4
+ * Live landscape editing, the counterpart to `useTerrainLive` and `useOceanLive`.
5
+ *
6
+ * The rule is the same — a slider drag writes straight into the renderer and
7
+ * Redux only hears about it on slider end — but the stakes are higher here.
8
+ * `meshError` re-runs RTIN, `chunks` rebuilds every index buffer,
9
+ * `arrayResolution` repacks the texture arrays and `surfaceSamples` recompiles
10
+ * the shader. Those are commit-on-release; everything else is a uniform and goes
11
+ * through this, and the renderer's handle enforces the split from
12
+ * `LANDSCAPE_LIVE_*_KEYS` so a controller cannot half-apply a rebuild key by
13
+ * passing it here.
14
+ *
15
+ * Pass the ID, not a resolved Object3D: the panel is routinely open before the
16
+ * landscape exists, and a findById() memoised in the controller resolves to null
17
+ * exactly once and stays null for the session.
18
+ */
19
+ export const LANDSCAPE_LIVE_KEY = '__landscapeLive';
20
+ const NOOP = {
21
+ config: () => { },
22
+ quality: () => { },
23
+ surface: () => { },
24
+ autoSplat: () => { },
25
+ };
26
+ export function useLandscapeLive(target) {
27
+ return useMemo(() => {
28
+ const resolve = () => {
29
+ const object = typeof target === 'string' ? findById(target) : target;
30
+ const handle = object?.userData?.[LANDSCAPE_LIVE_KEY];
31
+ return handle ?? NOOP;
32
+ };
33
+ return {
34
+ config: (key, value) => resolve().config(key, value),
35
+ quality: (key, value) => resolve().quality(key, value),
36
+ surface: (index, key, value) => resolve().surface(index, key, value),
37
+ autoSplat: (key, value) => resolve().autoSplat(key, value),
38
+ };
39
+ }, [target]);
40
+ }
41
+ export default useLandscapeLive;
@@ -0,0 +1,32 @@
1
+ import { type DecodedHeightmap } from '../utils/landscapeTextures';
2
+ import type { LandscapeConfig, LandscapeQualityConfig } from '../types/landscapeConfigs';
3
+ import type { LandscapeMapUniforms } from '../utils/landscapeUniforms';
4
+ /**
5
+ * Every image a landscape needs, loaded and packed.
6
+ *
7
+ * The surfaces go into two `DataArrayTexture`s rather than sixteen samplers:
8
+ * one binding, one integer layer index, no branch tree. Every layer must be the
9
+ * same size and user uploads never are, so each image is redrawn at
10
+ * `arrayResolution` on the way in.
11
+ *
12
+ * **The height maps ride in the normal array's alpha channel.** A tangent-space
13
+ * normal map only needs RGB, so the surface's own height — the thing that makes
14
+ * a transition read as material rather than as a cross-fade — costs nothing but
15
+ * the channel that was already there. A third array would have been another
16
+ * 100 MB at 1024.
17
+ *
18
+ * Loading is one effect with a cancellation flag, and the previous set is
19
+ * disposed only after the new one is ready, so a change of preset does not blink
20
+ * the ground away.
21
+ */
22
+ export interface LandscapeMapsState extends LandscapeMapUniforms {
23
+ /** The decoded heightmap, for RTIN and for CPU height queries. */
24
+ heightField: DecodedHeightmap | null;
25
+ ready: boolean;
26
+ error: string | null;
27
+ /** Surfaces that actually contributed a layer, in order. */
28
+ layerCount: number;
29
+ }
30
+ export declare function useLandscapeMaps(config: LandscapeConfig, quality: LandscapeQualityConfig): LandscapeMapsState;
31
+ export default useLandscapeMaps;
32
+ //# sourceMappingURL=useLandscapeMaps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLandscapeMaps.d.ts","sourceRoot":"","sources":["../../src/hooks/useLandscapeMaps.ts"],"names":[],"mappings":"AAEA,OAAO,EAOH,KAAK,gBAAgB,EACxB,MAAM,4BAA4B,CAAA;AACnC,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAA;AACxF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AAEtE;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB;IAC5D,kEAAkE;IAClE,WAAW,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACpC,KAAK,EAAE,OAAO,CAAA;IACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAA;CACrB;AA4CD,wBAAgB,gBAAgB,CAC5B,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,sBAAsB,GAChC,kBAAkB,CAmHpB;AAED,eAAe,gBAAgB,CAAA"}