import { useMemo, useRef } from "react"; import * as THREE from "three"; import { useFrame, useThree } from "@react-three/fiber"; import { FOG_CONFIG } from "@/data/world/fogConfig"; import { getWindVector } from "@/data/world/windConfig"; import { WATER_SHADER_CONFIG } from "@/data/world/waterConfig"; import type { WaterSurfaceConfig } from "@/data/world/waterConfig"; import { useWind } from "@/hooks/world/useWind"; import { WATER_FRAGMENT_SHADER, WATER_VERTEX_SHADER, } from "@/world/water/waterShaders"; export function WaterSurface({ position, renderOrder, rotation, size, }: WaterSurfaceConfig): React.JSX.Element { const scene = useThree((state) => state.scene); const materialRef = useRef(null); const wind = useWind(); const uniforms = useMemo( () => ({ uTime: { value: 0 }, uScale: { value: WATER_SHADER_CONFIG.scale }, uSmoothness: { value: WATER_SHADER_CONFIG.smoothness }, uEdgeThreshold: { value: WATER_SHADER_CONFIG.edgeThreshold }, uEdgeSoftness: { value: WATER_SHADER_CONFIG.edgeSoftness }, uFlowX: { value: WATER_SHADER_CONFIG.flowX }, uFlowZ: { value: WATER_SHADER_CONFIG.flowZ }, uCellSpeed: { value: WATER_SHADER_CONFIG.cellSpeed }, uNoiseScale: { value: WATER_SHADER_CONFIG.noiseScale }, uNoiseFlowSpeed: { value: WATER_SHADER_CONFIG.noiseFlowSpeed }, uDistortAmount: { value: WATER_SHADER_CONFIG.distortAmount }, uBorderRadius: { value: WATER_SHADER_CONFIG.borderRadius }, uBorderSoftness: { value: WATER_SHADER_CONFIG.borderSoftness }, uDeepColor: { value: new THREE.Color(WATER_SHADER_CONFIG.deepColor) }, uMidColor: { value: new THREE.Color(WATER_SHADER_CONFIG.midColor) }, uMidPos: { value: WATER_SHADER_CONFIG.midPos }, uHighlight: { value: new THREE.Color(WATER_SHADER_CONFIG.highlightColor), }, uOpacity: { value: WATER_SHADER_CONFIG.opacity }, uDeepOpacity: { value: WATER_SHADER_CONFIG.deepOpacity }, uFogEnabled: { value: 0 }, uFogMode: { value: 0 }, uFogNear: { value: FOG_CONFIG.near }, uFogFar: { value: FOG_CONFIG.far }, uFogDensity: { value: FOG_CONFIG.density }, uFogColor: { value: new THREE.Color(FOG_CONFIG.color) }, }), [], ); useFrame(({ clock }) => { const material = materialRef.current; if (!material) return; const windVector = getWindVector(wind); const { uFlowX, uFlowZ, uFogColor, uFogDensity, uFogEnabled, uFogFar, uFogMode, uFogNear, uNoiseScale, uTime, } = material.uniforms; if (uTime) uTime.value = clock.getElapsedTime(); if (uFlowX) uFlowX.value = WATER_SHADER_CONFIG.flowX + windVector.x; if (uFlowZ) uFlowZ.value = WATER_SHADER_CONFIG.flowZ + windVector.z; if (uNoiseScale) { uNoiseScale.value = WATER_SHADER_CONFIG.noiseScale * wind.noiseScale; } if (scene.fog instanceof THREE.Fog) { if (uFogEnabled) uFogEnabled.value = 1; if (uFogMode) uFogMode.value = 0; if (uFogNear) uFogNear.value = scene.fog.near; if (uFogFar) uFogFar.value = scene.fog.far; if (uFogColor) uFogColor.value.copy(scene.fog.color); } else if (scene.fog instanceof THREE.FogExp2) { if (uFogEnabled) uFogEnabled.value = 1; if (uFogMode) uFogMode.value = 1; if (uFogDensity) uFogDensity.value = scene.fog.density; if (uFogColor) uFogColor.value.copy(scene.fog.color); } else if (uFogEnabled) { uFogEnabled.value = 0; } }); return ( ); }