Skip to content

Water Shaders

Shaders for realistic water rendering including wave animation, reflections, refractions, caustics, and foam effects.

import {
waterVertexShader,
waterFragmentShader,
advancedWaterVertexShader,
advancedWaterFragmentShader,
causticsShader,
} from '@strata-game-library/shaders';

Simple animated water with Fresnel reflections:

UniformTypeDescription
uTimefloatAnimation time
uWaterColorvec3Base water color
uWaveHeightfloatWave amplitude
uWaveSpeedfloatWave animation speed
uOpacityfloatWater transparency
import { waterVertexShader, waterFragmentShader } from '@strata-game-library/shaders';
const waterMaterial = new THREE.ShaderMaterial({
vertexShader: waterVertexShader,
fragmentShader: waterFragmentShader,
uniforms: {
uTime: { value: 0 },
uWaterColor: { value: new THREE.Color(0x0077be) },
uWaveHeight: { value: 0.5 },
uWaveSpeed: { value: 1.0 },
uOpacity: { value: 0.8 },
},
transparent: true,
});

Full-featured water with Gerstner waves, reflections, refractions, and effects:

UniformTypeDescription
uTimefloatAnimation time
uWaterColorvec3Deep water color
uShallowColorvec3Shallow water color
uReflectionTexturesampler2DReflection render target
uRefractionTexturesampler2DRefraction render target
uNormalMapsampler2DWater normal map
uReflectionStrengthfloatReflection intensity
uRefractionStrengthfloatRefraction distortion
uFresnelPowerfloatFresnel falloff
uFoamTexturesampler2DFoam pattern texture
uFoamThresholdfloatWave height for foam
uCausticsTexturesampler2DCaustics pattern
uCausticsStrengthfloatCaustics intensity
UniformTypeDescription
uWaveAvec4Wave A: (dirX, dirZ, steepness, wavelength)
uWaveBvec4Wave B parameters
uWaveCvec4Wave C parameters
import { advancedWaterVertexShader, advancedWaterFragmentShader } from '@strata-game-library/shaders';
const advancedWaterMaterial = new THREE.ShaderMaterial({
vertexShader: advancedWaterVertexShader,
fragmentShader: advancedWaterFragmentShader,
uniforms: {
uTime: { value: 0 },
uWaterColor: { value: new THREE.Color(0x001e0f) },
uShallowColor: { value: new THREE.Color(0x0088aa) },
// Gerstner waves
uWaveA: { value: new THREE.Vector4(1, 0, 0.5, 30) },
uWaveB: { value: new THREE.Vector4(0.7, 0.7, 0.3, 15) },
uWaveC: { value: new THREE.Vector4(0, 1, 0.2, 8) },
// Reflections
uReflectionTexture: { value: reflectionRT.texture },
uReflectionStrength: { value: 0.5 },
// Refraction
uRefractionTexture: { value: refractionRT.texture },
uRefractionStrength: { value: 0.05 },
// Fresnel
uFresnelPower: { value: 2.0 },
// Foam
uFoamTexture: { value: foamTexture },
uFoamThreshold: { value: 0.7 },
// Caustics
uCausticsTexture: { value: causticsTexture },
uCausticsStrength: { value: 0.3 },
},
transparent: true,
});

Animated caustic patterns for underwater surfaces:

import { causticsShader } from '@strata-game-library/shaders';
const causticsMaterial = new THREE.ShaderMaterial({
vertexShader: causticsShader.vertex,
fragmentShader: causticsShader.fragment,
uniforms: {
uTime: { value: 0 },
uScale: { value: 0.5 },
uSpeed: { value: 0.3 },
uIntensity: { value: 0.4 },
},
transparent: true,
blending: THREE.AdditiveBlending,
});
vec3 gerstnerWave(vec4 wave, vec3 p, inout vec3 tangent, inout vec3 binormal) {
float steepness = wave.z;
float wavelength = wave.w;
float k = 2.0 * PI / wavelength;
float c = sqrt(9.8 / k);
vec2 d = normalize(wave.xy);
float f = k * (dot(d, p.xz) - c * uTime);
float a = steepness / k;
tangent += vec3(
-d.x * d.x * steepness * sin(f),
d.x * steepness * cos(f),
-d.x * d.y * steepness * sin(f)
);
binormal += vec3(
-d.x * d.y * steepness * sin(f),
d.y * steepness * cos(f),
-d.y * d.y * steepness * sin(f)
);
return vec3(
d.x * a * cos(f),
a * sin(f),
d.y * a * cos(f)
);
}
float fresnel(vec3 viewDir, vec3 normal, float power) {
return pow(1.0 - max(dot(viewDir, normal), 0.0), power);
}
float caustics(vec2 uv, float time) {
vec2 p = mod(uv * 6.28318, 6.28318) - 250.0;
float c = 1.0;
float inten = 0.005;
for (int n = 0; n < 4; n++) {
float t = time * (1.0 - (3.5 / float(n + 1)));
vec2 i = p + vec2(cos(t - p.x) + sin(t + p.y), sin(t - p.y) + cos(t + p.x));
c += 1.0 / length(vec2(p.x / (sin(i.x + t) / inten), p.y / (cos(i.y + t) / inten)));
}
c /= 4.0;
c = 1.17 - pow(c, 1.4);
return pow(abs(c), 8.0);
}