Explorar o código

修改水效果

BAI hai 3 semanas
pai
achega
d477cf29ec

BIN=BIN
src/assets/texture/Water_1_Normal.PNG


BIN=BIN
src/assets/texture/Water_2_Normal.PNG


BIN=BIN
src/assets/texture/Water_3_Normal.PNG


+ 7 - 4
src/config/sceneConfig.ts

@@ -19,6 +19,7 @@ export interface WaterMaterialParams {
   flowSpeed: number
   flowDirectionX: number
   flowDirectionY: number
+  normalRotation: number
   waveHeight: number
   foamIntensity: number
   specIntensity: number
@@ -140,8 +141,9 @@ export const defaultWaterParams: WaterMaterialParams = {
   waterColor: '#566a6c',
   deepColor: '#0a2a4a',
   flowSpeed: 3.0,
-  flowDirectionX: -2.1,
-  flowDirectionY: -1.0,
+  flowDirectionX: -1,
+  flowDirectionY: -1.50,
+  normalRotation: 35,
   waveHeight: 0.6,
   foamIntensity: 0.25,
   specIntensity: 2.0,
@@ -149,8 +151,8 @@ export const defaultWaterParams: WaterMaterialParams = {
   fresnelPower: 2.5,
   fresnelIntensity: 1.0,
   depthRange: 44.0,
-  waterNormalStrength: 2.0,
-  waterNormalTiling: 0.26,
+  waterNormalStrength: 1.0,
+  waterNormalTiling: 0.46,
   collisionFoamThreshold: 0.10,
   collisionFoamStrength: 0.5,
 }
@@ -163,6 +165,7 @@ export const defaultCscwaterParams: CscwaterMaterialParams = {
   flowSpeed: 0,
   flowDirectionX: 1.0,
   flowDirectionY: 1.0,
+  normalRotation: 0,
   waveHeight: 0.6,
   foamIntensity: 0.30,
   specIntensity: 2.2,

+ 31 - 12
src/materials/waterNew.ts

@@ -66,7 +66,10 @@ uniform float depthRange;
 uniform vec3 cameraPos;
 uniform vec3 sunDirection;
 uniform vec2 flowDirection;
-uniform sampler2D waterNormalMap;
+uniform float normalRotation;
+uniform sampler2D waterNormalMap1;
+uniform sampler2D waterNormalMap2;
+uniform sampler2D waterNormalMap3;
 uniform float waterNormalStrength;
 uniform float waterNormalTiling;
 uniform float collisionFoamThreshold;
@@ -199,10 +202,19 @@ void main() {
     vec2 waveDisp;
     computeWaveData(wavePos, time, waveHeight * 0.2, 1.0, waveH, waveDisp);
 
+    float rotRad = normalRotation * 3.14159265 / 180.0;
+    float cosA = cos(rotRad);
+    float sinA = sin(rotRad);
     vec2 waterUV = vWorldUV * waterNormalTiling + iTime * flowDir * flowSpeed * 0.10;
-    vec3 waterMap = texture2D(waterNormalMap, waterUV).rgb;
-    waterMap = waterMap * 2.0 - 1.0;
-    vec3 finalNormal = normalize(vec3(waterMap.x * waterNormalStrength, 1.0, waterMap.y * waterNormalStrength));
+    vec3 n1 = texture2D(waterNormalMap1, waterUV).rgb * 2.0 - 1.0;
+    vec3 n2 = texture2D(waterNormalMap2, waterUV * 1.3 + 0.5).rgb * 2.0 - 1.0;
+    vec3 n3 = texture2D(waterNormalMap3, waterUV * 0.7 + 1.0).rgb * 2.0 - 1.0;
+    vec3 waterMap = normalize(n1 + n2 + n3);
+    vec3 finalNormal = normalize(vec3(
+        (waterMap.x * cosA - waterMap.y * sinA) * waterNormalStrength,
+        1.0,
+        (waterMap.x * sinA + waterMap.y * cosA) * waterNormalStrength
+    ));
 
     vec3 viewDir = normalize(cameraPos - vWorldPosition);
     vec3 halfVec = normalize(viewDir + sunDirection);
@@ -224,8 +236,7 @@ void main() {
     float foamShore = smoothstep(0.3, 1.5, waterDepth);
     float foam = (1.0 - foamShore) * foamNoise * foamIntensity * 1.5;
 
-    float wavePeakFoam = smoothstep(0.6, 1.0, abs(waveH) / max(waveHeight * 0.1, 0.01));
-    foam += wavePeakFoam * foamNoise * foamIntensity * 0.3;
+    float wavePeakFoam = 0.0;
 
     foam = clamp(foam, 0.0, 1.0);
 
@@ -269,11 +280,16 @@ void main() {
 
 const textureLoader = new THREE.TextureLoader();
 
-const waterNormalTexture = textureLoader.load(
-  new URL('../assets/waternormals.jpg', import.meta.url).href
-);
-waterNormalTexture.wrapS = THREE.RepeatWrapping;
-waterNormalTexture.wrapT = THREE.RepeatWrapping;
+function loadRepeatTexture(url: string): THREE.Texture {
+  const tex = textureLoader.load(new URL(url, import.meta.url).href)
+  tex.wrapS = THREE.RepeatWrapping
+  tex.wrapT = THREE.RepeatWrapping
+  return tex
+}
+
+const waterNormalTex1 = loadRepeatTexture('../assets/texture/Water_1_Normal.PNG')
+const waterNormalTex2 = loadRepeatTexture('../assets/texture/Water_2_Normal.PNG')
+const waterNormalTex3 = loadRepeatTexture('../assets/texture/Water_3_Normal.PNG')
 
 export const StylizedWaterMaterial = new THREE.ShaderMaterial({
     transparent: true,
@@ -300,7 +316,10 @@ export const StylizedWaterMaterial = new THREE.ShaderMaterial({
         cameraPos: { value: new THREE.Vector3(0, 0, 0) },
         sunDirection: { value: new THREE.Vector3(0.5, 0.8, 0.3).normalize() },
         flowDirection: { value: new THREE.Vector2(1.0, 0.0) },
-        waterNormalMap: { value: waterNormalTexture },
+        normalRotation: { value: 0 },
+        waterNormalMap1: { value: waterNormalTex1 },
+        waterNormalMap2: { value: waterNormalTex2 },
+        waterNormalMap3: { value: waterNormalTex3 },
         waterNormalStrength: { value: 2.0 },
         waterNormalTiling: { value: 0.26 },
         collisionFoamThreshold: { value: 0.10 },

+ 16 - 8
src/scenes/Scene3D.vue

@@ -152,6 +152,7 @@ function syncCscwaterParams() {
   cscwaterMaterial.uniforms.alpha.value = p.alpha
   cscwaterMaterial.uniforms.flowSpeed.value = p.flowSpeed
   cscwaterMaterial.uniforms.flowDirection.value.set(p.flowDirectionX, p.flowDirectionY)
+  cscwaterMaterial.uniforms.normalRotation.value = p.normalRotation
   cscwaterMaterial.uniforms.waveHeight.value = p.waveHeight
   cscwaterMaterial.uniforms.shallowColor.value.set(p.waterColor)
   cscwaterMaterial.uniforms.deepColor.value.set(p.deepColor)
@@ -167,8 +168,6 @@ function syncCscwaterParams() {
   cscwaterMaterial.uniforms.collisionFoamStrength.value = p.collisionFoamStrength
 }
 
-loadFlowDefaults()
-
 const FOAM_DEFAULTS_KEY = 'foamMatParams_defaults'
 
 function loadFoamDefaults() {
@@ -188,8 +187,6 @@ function saveFoamDefaults() {
   showToast('泡沫材质默认值已保存')
 }
 
-loadFoamDefaults()
-
 const WATER_DEFAULTS_KEY = 'waterParams_defaults'
 
 function loadWaterDefaults() {
@@ -209,8 +206,6 @@ function saveWaterDefaults() {
   showToast('水面材质默认值已保存')
 }
 
-loadWaterDefaults()
-
 const CSCWATER_DEFAULTS_KEY = 'cscwaterParams_defaults'
 
 function loadCscwaterDefaults() {
@@ -230,8 +225,6 @@ function saveCscwaterDefaults() {
   showToast('CSCwater 材质默认值已保存')
 }
 
-loadCscwaterDefaults()
-
 const MODEL_DEFAULTS_KEY = 'modelTransform_defaults'
 
 function saveModelDefaults() {
@@ -948,6 +941,7 @@ function syncWaterParams() {
   StylizedWaterMaterial.uniforms.alpha.value = p.alpha
   StylizedWaterMaterial.uniforms.flowSpeed.value = p.flowSpeed
   StylizedWaterMaterial.uniforms.flowDirection.value.set(p.flowDirectionX, p.flowDirectionY)
+  StylizedWaterMaterial.uniforms.normalRotation.value = p.normalRotation
   StylizedWaterMaterial.uniforms.waveHeight.value = p.waveHeight
   StylizedWaterMaterial.uniforms.shallowColor.value.set(p.waterColor)
   StylizedWaterMaterial.uniforms.deepColor.value.set(p.deepColor)
@@ -1281,6 +1275,13 @@ defineExpose({
           <span class="slider-value">{{ waterParams.flowDirectionY.toFixed(1) }}</span>
         </div>
       </div>
+      <div class="material-section">
+        <div class="section-label">法线旋转</div>
+        <div class="slider-item">
+          <input type="range" v-model.number="waterParams.normalRotation" min="-180" max="180" step="1" />
+          <span class="slider-value">{{ waterParams.normalRotation.toFixed(0) }}°</span>
+        </div>
+      </div>
       <div class="material-section">
         <div class="section-label">浅水颜色</div>
         <div class="color-item">
@@ -1621,6 +1622,13 @@ defineExpose({
           <span class="slider-value">{{ cscwaterParams.flowDirectionY.toFixed(1) }}</span>
         </div>
       </div>
+      <div class="material-section">
+        <div class="section-label">法线旋转</div>
+        <div class="slider-item">
+          <input type="range" v-model.number="cscwaterParams.normalRotation" min="-180" max="180" step="1" />
+          <span class="slider-value">{{ cscwaterParams.normalRotation.toFixed(0) }}°</span>
+        </div>
+      </div>
       <div class="material-section">
         <div class="section-label">浅水颜色</div>
         <div class="color-item">