@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.
- package/dist/components/Clouds.d.ts.map +1 -1
- package/dist/components/Clouds.js +0 -1
- package/dist/components/CloudsGenerator.d.ts +32 -0
- package/dist/components/CloudsGenerator.d.ts.map +1 -0
- package/dist/components/CloudsGenerator.js +58 -0
- package/dist/components/EnvironmentManager.d.ts +47 -5
- package/dist/components/EnvironmentManager.d.ts.map +1 -1
- package/dist/components/EnvironmentManager.js +35 -66
- package/dist/components/HdrEnvironment.d.ts +20 -0
- package/dist/components/HdrEnvironment.d.ts.map +1 -0
- package/dist/components/HdrEnvironment.js +44 -0
- package/dist/components/LandscapeBuilder.d.ts +23 -0
- package/dist/components/LandscapeBuilder.d.ts.map +1 -0
- package/dist/components/LandscapeBuilder.js +25 -0
- package/dist/components/LandscapeObject.d.ts +24 -0
- package/dist/components/LandscapeObject.d.ts.map +1 -0
- package/dist/components/LandscapeObject.js +27 -0
- package/dist/components/ObjectNode.d.ts.map +1 -1
- package/dist/components/ObjectNode.js +10 -0
- package/dist/components/OceanBuilder.d.ts +35 -0
- package/dist/components/OceanBuilder.d.ts.map +1 -0
- package/dist/components/OceanBuilder.js +53 -0
- package/dist/components/SceneBuilder.d.ts.map +1 -1
- package/dist/components/SkySystem.d.ts +27 -6
- package/dist/components/SkySystem.d.ts.map +1 -1
- package/dist/components/SkySystem.js +6 -5
- package/dist/components/SunLight.d.ts.map +1 -1
- package/dist/components/SunLight.js +4 -1
- package/dist/components/TerrainBuilder.d.ts +30 -0
- package/dist/components/TerrainBuilder.d.ts.map +1 -0
- package/dist/components/TerrainBuilder.js +44 -0
- package/dist/components/index.d.ts +17 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +10 -0
- package/dist/components/landscape/LandscapeMesh.d.ts +18 -0
- package/dist/components/landscape/LandscapeMesh.d.ts.map +1 -0
- package/dist/components/landscape/LandscapeMesh.js +278 -0
- package/dist/components/landscape/index.d.ts +3 -0
- package/dist/components/landscape/index.d.ts.map +1 -0
- package/dist/components/landscape/index.js +1 -0
- package/dist/components/landscape/types.d.ts +13 -0
- package/dist/components/landscape/types.d.ts.map +1 -0
- package/dist/components/landscape/types.js +1 -0
- package/dist/components/terrain/Canyon.d.ts +23 -0
- package/dist/components/terrain/Canyon.d.ts.map +1 -0
- package/dist/components/terrain/Canyon.js +29 -0
- package/dist/components/terrain/Dunes.d.ts +22 -0
- package/dist/components/terrain/Dunes.d.ts.map +1 -0
- package/dist/components/terrain/Dunes.js +25 -0
- package/dist/components/terrain/Hills.d.ts +17 -0
- package/dist/components/terrain/Hills.d.ts.map +1 -0
- package/dist/components/terrain/Hills.js +20 -0
- package/dist/components/terrain/Mountains.d.ts +19 -0
- package/dist/components/terrain/Mountains.d.ts.map +1 -0
- package/dist/components/terrain/Mountains.js +22 -0
- package/dist/components/terrain/TerrainSurface.d.ts +22 -0
- package/dist/components/terrain/TerrainSurface.d.ts.map +1 -0
- package/dist/components/terrain/TerrainSurface.js +94 -0
- package/dist/components/terrain/index.d.ts +7 -0
- package/dist/components/terrain/index.d.ts.map +1 -0
- package/dist/components/terrain/index.js +7 -0
- package/dist/components/terrain/types.d.ts +17 -0
- package/dist/components/terrain/types.d.ts.map +1 -0
- package/dist/components/terrain/types.js +1 -0
- package/dist/components/volumetricClouds/Cirrus.d.ts +14 -0
- package/dist/components/volumetricClouds/Cirrus.d.ts.map +1 -0
- package/dist/components/volumetricClouds/Cirrus.js +13 -0
- package/dist/components/volumetricClouds/Cumulonimbus.d.ts +17 -0
- package/dist/components/volumetricClouds/Cumulonimbus.d.ts.map +1 -0
- package/dist/components/volumetricClouds/Cumulonimbus.js +20 -0
- package/dist/components/volumetricClouds/Cumulus.d.ts +14 -0
- package/dist/components/volumetricClouds/Cumulus.d.ts.map +1 -0
- package/dist/components/volumetricClouds/Cumulus.js +17 -0
- package/dist/components/volumetricClouds/Stratocumulus.d.ts +12 -0
- package/dist/components/volumetricClouds/Stratocumulus.d.ts.map +1 -0
- package/dist/components/volumetricClouds/Stratocumulus.js +16 -0
- package/dist/components/volumetricClouds/VolumetricCloudsPass.d.ts +42 -0
- package/dist/components/volumetricClouds/VolumetricCloudsPass.d.ts.map +1 -0
- package/dist/components/volumetricClouds/VolumetricCloudsPass.js +298 -0
- package/dist/components/volumetricClouds/index.d.ts +8 -0
- package/dist/components/volumetricClouds/index.d.ts.map +1 -0
- package/dist/components/volumetricClouds/index.js +7 -0
- package/dist/components/volumetricClouds/types.d.ts +17 -0
- package/dist/components/volumetricClouds/types.d.ts.map +1 -0
- package/dist/components/volumetricClouds/types.js +1 -0
- package/dist/components/water/Host.d.ts +12 -0
- package/dist/components/water/Host.d.ts.map +1 -0
- package/dist/components/water/Host.js +12 -0
- package/dist/components/water/Lake.d.ts +18 -0
- package/dist/components/water/Lake.d.ts.map +1 -0
- package/dist/components/water/Lake.js +21 -0
- package/dist/components/water/OceanSurface.d.ts +27 -0
- package/dist/components/water/OceanSurface.d.ts.map +1 -0
- package/dist/components/water/OceanSurface.js +60 -0
- package/dist/components/water/Sea.d.ts +18 -0
- package/dist/components/water/Sea.d.ts.map +1 -0
- package/dist/components/water/Sea.js +17 -0
- package/dist/components/water/Shore.d.ts +16 -0
- package/dist/components/water/Shore.d.ts.map +1 -0
- package/dist/components/water/Shore.js +15 -0
- package/dist/components/water/Storm.d.ts +14 -0
- package/dist/components/water/Storm.d.ts.map +1 -0
- package/dist/components/water/Storm.js +13 -0
- package/dist/components/water/WaterBody.d.ts +31 -0
- package/dist/components/water/WaterBody.d.ts.map +1 -0
- package/dist/components/water/WaterBody.js +76 -0
- package/dist/components/water/index.d.ts +9 -0
- package/dist/components/water/index.d.ts.map +1 -0
- package/dist/components/water/index.js +11 -0
- package/dist/components/water/types.d.ts +20 -0
- package/dist/components/water/types.d.ts.map +1 -0
- package/dist/components/water/types.js +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +9 -0
- package/dist/hooks/index.d.ts +24 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +12 -0
- package/dist/hooks/useClipmap.d.ts +71 -0
- package/dist/hooks/useClipmap.d.ts.map +1 -0
- package/dist/hooks/useClipmap.js +81 -0
- package/dist/hooks/useCloudLive.d.ts +29 -0
- package/dist/hooks/useCloudLive.d.ts.map +1 -0
- package/dist/hooks/useCloudLive.js +43 -0
- package/dist/hooks/useCloudNoise.d.ts +28 -0
- package/dist/hooks/useCloudNoise.d.ts.map +1 -0
- package/dist/hooks/useCloudNoise.js +128 -0
- package/dist/hooks/useCloudSun.d.ts +49 -0
- package/dist/hooks/useCloudSun.d.ts.map +1 -0
- package/dist/hooks/useCloudSun.js +84 -0
- package/dist/hooks/useCubeCamera.d.ts +27 -9
- package/dist/hooks/useCubeCamera.d.ts.map +1 -1
- package/dist/hooks/useCubeCamera.js +28 -70
- package/dist/hooks/useEnvironmentProbe.d.ts +32 -0
- package/dist/hooks/useEnvironmentProbe.d.ts.map +1 -0
- package/dist/hooks/useEnvironmentProbe.js +35 -0
- package/dist/hooks/useFrameRenderer.d.ts +15 -0
- package/dist/hooks/useFrameRenderer.d.ts.map +1 -0
- package/dist/hooks/useFrameRenderer.js +23 -0
- package/dist/hooks/useLandscapeLive.d.ts +29 -0
- package/dist/hooks/useLandscapeLive.d.ts.map +1 -0
- package/dist/hooks/useLandscapeLive.js +41 -0
- package/dist/hooks/useLandscapeMaps.d.ts +32 -0
- package/dist/hooks/useLandscapeMaps.d.ts.map +1 -0
- package/dist/hooks/useLandscapeMaps.js +138 -0
- package/dist/hooks/useOceanLive.d.ts +29 -0
- package/dist/hooks/useOceanLive.d.ts.map +1 -0
- package/dist/hooks/useOceanLive.js +38 -0
- package/dist/hooks/useOceanMaterial.d.ts +39 -0
- package/dist/hooks/useOceanMaterial.d.ts.map +1 -0
- package/dist/hooks/useOceanMaterial.js +65 -0
- package/dist/hooks/useTerrainClipmap.d.ts +12 -0
- package/dist/hooks/useTerrainClipmap.d.ts.map +1 -0
- package/dist/hooks/useTerrainClipmap.js +10 -0
- package/dist/hooks/useTerrainLive.d.ts +34 -0
- package/dist/hooks/useTerrainLive.d.ts.map +1 -0
- package/dist/hooks/useTerrainLive.js +45 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -0
- package/dist/presets/landscapePresets.d.ts +60 -0
- package/dist/presets/landscapePresets.d.ts.map +1 -0
- package/dist/presets/landscapePresets.js +194 -0
- package/dist/presets/landscapeTypes.d.ts +195 -0
- package/dist/presets/landscapeTypes.d.ts.map +1 -0
- package/dist/presets/landscapeTypes.js +315 -0
- package/dist/presets/oceanSurfacePresets.d.ts +33 -0
- package/dist/presets/oceanSurfacePresets.d.ts.map +1 -0
- package/dist/presets/oceanSurfacePresets.js +245 -0
- package/dist/presets/terrainPresets.d.ts +28 -0
- package/dist/presets/terrainPresets.d.ts.map +1 -0
- package/dist/presets/terrainPresets.js +293 -0
- package/dist/presets/volumetricCloudPresets.d.ts +38 -0
- package/dist/presets/volumetricCloudPresets.d.ts.map +1 -0
- package/dist/presets/volumetricCloudPresets.js +480 -0
- package/dist/shaders/clouds/CirrusMaterial.d.ts +84 -0
- package/dist/shaders/clouds/CirrusMaterial.d.ts.map +1 -0
- package/dist/shaders/clouds/CirrusMaterial.js +167 -0
- package/dist/shaders/clouds/CloudCompositeMaterial.d.ts +20 -0
- package/dist/shaders/clouds/CloudCompositeMaterial.d.ts.map +1 -0
- package/dist/shaders/clouds/CloudCompositeMaterial.js +82 -0
- package/dist/shaders/clouds/CloudResolveMaterial.d.ts +22 -0
- package/dist/shaders/clouds/CloudResolveMaterial.d.ts.map +1 -0
- package/dist/shaders/clouds/CloudResolveMaterial.js +77 -0
- package/dist/shaders/clouds/CloudVolumeMaterial.d.ts +143 -0
- package/dist/shaders/clouds/CloudVolumeMaterial.d.ts.map +1 -0
- package/dist/shaders/clouds/CloudVolumeMaterial.js +249 -0
- package/dist/shaders/clouds/SkyBackgroundMaterial.d.ts +21 -0
- package/dist/shaders/clouds/SkyBackgroundMaterial.d.ts.map +1 -0
- package/dist/shaders/clouds/SkyBackgroundMaterial.js +42 -0
- package/dist/shaders/glsl/cloudCore.glsl.d.ts +24 -0
- package/dist/shaders/glsl/cloudCore.glsl.d.ts.map +1 -0
- package/dist/shaders/glsl/cloudCore.glsl.js +348 -0
- package/dist/shaders/glsl/landscapeCore.glsl.d.ts +49 -0
- package/dist/shaders/glsl/landscapeCore.glsl.d.ts.map +1 -0
- package/dist/shaders/glsl/landscapeCore.glsl.js +518 -0
- package/dist/shaders/glsl/noiseBake.glsl.d.ts +30 -0
- package/dist/shaders/glsl/noiseBake.glsl.d.ts.map +1 -0
- package/dist/shaders/glsl/noiseBake.glsl.js +164 -0
- package/dist/shaders/glsl/oceanCore.glsl.d.ts +52 -0
- package/dist/shaders/glsl/oceanCore.glsl.d.ts.map +1 -0
- package/dist/shaders/glsl/oceanCore.glsl.js +421 -0
- package/dist/shaders/glsl/terrainCore.glsl.d.ts +78 -0
- package/dist/shaders/glsl/terrainCore.glsl.d.ts.map +1 -0
- package/dist/shaders/glsl/terrainCore.glsl.js +625 -0
- package/dist/shaders/landscape/LandscapeMaterial.d.ts +73 -0
- package/dist/shaders/landscape/LandscapeMaterial.d.ts.map +1 -0
- package/dist/shaders/landscape/LandscapeMaterial.js +136 -0
- package/dist/shaders/ocean/OceanSurfaceMaterial.d.ts +57 -0
- package/dist/shaders/ocean/OceanSurfaceMaterial.d.ts.map +1 -0
- package/dist/shaders/ocean/OceanSurfaceMaterial.js +268 -0
- package/dist/shaders/terrain/TerrainMaterial.d.ts +80 -0
- package/dist/shaders/terrain/TerrainMaterial.d.ts.map +1 -0
- package/dist/shaders/terrain/TerrainMaterial.js +291 -0
- package/dist/types/cloudConfigs.d.ts +244 -0
- package/dist/types/cloudConfigs.d.ts.map +1 -0
- package/dist/types/cloudConfigs.js +282 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +4 -1
- package/dist/types/landscapeConfigs.d.ts +218 -0
- package/dist/types/landscapeConfigs.d.ts.map +1 -0
- package/dist/types/landscapeConfigs.js +256 -0
- package/dist/types/oceanConfigs.d.ts +290 -0
- package/dist/types/oceanConfigs.d.ts.map +1 -0
- package/dist/types/oceanConfigs.js +380 -0
- package/dist/types/terrainConfigs.d.ts +251 -0
- package/dist/types/terrainConfigs.d.ts.map +1 -0
- package/dist/types/terrainConfigs.js +292 -0
- package/dist/utils/cloudUniforms.d.ts +14 -0
- package/dist/utils/cloudUniforms.d.ts.map +1 -0
- package/dist/utils/cloudUniforms.js +122 -0
- package/dist/utils/frameRenderer.d.ts +33 -0
- package/dist/utils/frameRenderer.d.ts.map +1 -0
- package/dist/utils/frameRenderer.js +24 -0
- package/dist/utils/handleCloudsAnimations.d.ts +16 -0
- package/dist/utils/handleCloudsAnimations.d.ts.map +1 -0
- package/dist/utils/handleCloudsAnimations.js +64 -0
- package/dist/utils/landscapeGeometry.d.ts +61 -0
- package/dist/utils/landscapeGeometry.d.ts.map +1 -0
- package/dist/utils/landscapeGeometry.js +126 -0
- package/dist/utils/landscapeHeight.d.ts +44 -0
- package/dist/utils/landscapeHeight.d.ts.map +1 -0
- package/dist/utils/landscapeHeight.js +65 -0
- package/dist/utils/landscapeTextures.d.ts +94 -0
- package/dist/utils/landscapeTextures.d.ts.map +1 -0
- package/dist/utils/landscapeTextures.js +290 -0
- package/dist/utils/landscapeUniforms.d.ts +20 -0
- package/dist/utils/landscapeUniforms.d.ts.map +1 -0
- package/dist/utils/landscapeUniforms.js +61 -0
- package/dist/utils/oceanUniforms.d.ts +47 -0
- package/dist/utils/oceanUniforms.d.ts.map +1 -0
- package/dist/utils/oceanUniforms.js +216 -0
- package/dist/utils/rtin.d.ts +63 -0
- package/dist/utils/rtin.d.ts.map +1 -0
- package/dist/utils/rtin.js +202 -0
- package/dist/utils/terrainUniforms.d.ts +14 -0
- package/dist/utils/terrainUniforms.d.ts.map +1 -0
- package/dist/utils/terrainUniforms.js +196 -0
- 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;
|