Skip to content

Commit

Permalink
Water improvements (FAForever#5654)
Browse files Browse the repository at this point in the history
  • Loading branch information
BlackYps authored Nov 9, 2023
1 parent 4d38082 commit bad19d9
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 21 deletions.
18 changes: 10 additions & 8 deletions effects/mesh.fx
Original file line number Diff line number Diff line change
Expand Up @@ -601,24 +601,26 @@ float3 ComputeNormal( sampler2D source, float2 uv, float3x3 rotationMatrix)
float3 ApplyWaterColor(float depth, float3 viewDirection, float3 color, float3 emission = float3(0, 0, 0)) {
// disable the whole thing on land-only maps
if (surfaceElevation > 0) {
float4 waterColor = tex1D(WaterRampSampler, -depth / (surfaceElevation - abyssElevation));
// we need this switch to make it consistent with the terrain shader coloration
if (IsExperimentalShader()) {
float scaledDepth = (-depth / (surfaceElevation - abyssElevation));
float3 up = float3(0,1,0);
// To simplify, we assume that the light enters vertically into the water,
// this is the length that the light travels underwater back to the camera
float oneOverCosV = 1 / max(dot(up, normalize(viewDirection)), 0.0001);
// light gets absorbed exponentially
float waterAbsorption = saturate(exp(-waterColor.w * (1 + oneOverCosV)));
// Light gets absorbed exponentially.
// To simplify, we assume that the light enters vertically into the water.
float waterAbsorption = 1 - saturate(exp(-scaledDepth * (1 + oneOverCosV)));
// when the mesh emits light, then the path from the surface to the mesh doesn't apply
float emissionAbsorption = saturate(exp(-waterColor.w * oneOverCosV));
float emissionTransmitted = saturate(exp(-scaledDepth * oneOverCosV));
// darken the color first to simulate the light absorption on the way in and out
color *= waterAbsorption;
color *= 1 - waterAbsorption;
// lerp in the watercolor to simulate the scattered light from the dirty water
color = lerp(waterColor.rgb, color, waterAbsorption);
float4 waterColor = tex1D(WaterRampSampler, waterAbsorption);
color = lerp(color, waterColor.rgb, waterAbsorption);
// similarly tune down the emission light
color += emission * emissionAbsorption;
color += emission * emissionTransmitted;
} else {
float4 waterColor = tex1D(WaterRampSampler, -depth / (surfaceElevation - abyssElevation));
color = lerp(color, waterColor.rgb, waterColor.w);
color += emission;
}
Expand Down
10 changes: 5 additions & 5 deletions effects/terrain.fx
Original file line number Diff line number Diff line change
Expand Up @@ -405,16 +405,16 @@ float3 ApplyWaterColorExponentially(float3 viewDirection, float terrainHeight, f
{
if (waterDepth > 0) {
float opacity = saturate(smoothstep(10, 200, CameraPosition.y - WaterElevation) + step(terrainHeight, WaterElevation));
float4 waterColor = tex1D(WaterRampSampler, waterDepth);
float3 up = float3(0,1,0);
// To simplify, we assume that the light enters vertically into the water,
// this is the length that the light travels underwater back to the camera
float oneOverCosV = 1 / max(abs(dot(up, normalize(viewDirection))), 0.0001);
// light gets absorbed exponentially
float waterAbsorption = 1 - saturate(exp(-waterColor.w * (1 + oneOverCosV)));
float oneOverCosV = 1 / max(dot(up, normalize(viewDirection)), 0.0001);
// Light gets absorbed exponentially,
// to simplify, we assume that the light enters vertically into the water.
float waterAbsorption = 1 - saturate(exp(-waterDepth * (1 + oneOverCosV)));
// darken the color first to simulate the light absorption on the way in and out
color *= 1 - waterAbsorption * opacity;
// lerp in the watercolor to simulate the scattered light from the dirty water
float4 waterColor = tex1D(WaterRampSampler, waterAbsorption);
color = lerp(color, waterColor.rgb, waterAbsorption * opacity);
}
return color;
Expand Down
14 changes: 6 additions & 8 deletions effects/water2.fx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ float3 waveCrestColor = float3( 1, 1, 1);
float4x4 WorldToView;
float4x4 Projection;

// red: wave normal strength
// green: water depth
// blue: ???
// red: originally wave normal strength, now used for shadow
// green: water depth (autogenerated by the engine)
// blue: shoreline (autogenerated by the engine)
// alpha: foam reduction
texture UtilityTextureC;

Expand Down Expand Up @@ -350,10 +350,6 @@ float4 HighFidelityPS( VS_OUTPUT inV,
// scale, bias and normalize
float3 N = 2.0 * sum.xyz - 4.0;
N = normalize(N.xzy);

// flatness
float3 up = float3(0,1,0);
N = lerp(up, N, waterTexture.r);

float3 R = reflect(-viewVector, N);

Expand Down Expand Up @@ -396,10 +392,12 @@ float4 HighFidelityPS( VS_OUTPUT inV,
sunReflection = sunReflection * fresnel;
// the sun shouldn't be visible where a unit reflection is
sunReflection *= (1 - saturate(reflectedPixels.a * 2));
// we can control this value to have terrain cast a shadow on the water surface
sunReflection *= waterTexture.r;
refractedPixels.xyz += sunReflection;

// Lerp in the wave crests
refractedPixels.xyz = lerp(refractedPixels.xyz, waveCrestColor, (1 - waterTexture.a) * waveCrest);
refractedPixels.xyz = lerp(refractedPixels.xyz, waveCrestColor, (1 - waterTexture.a) * (1 - waterTexture.b) * waveCrest);

// return the pixels masked out by the water mask
float4 returnPixels = refractedPixels;
Expand Down

0 comments on commit bad19d9

Please sign in to comment.