Demo of a physically-based water shader for a pixel art style.

The water height is generated using 3D simplex noise with domain warping. That texture is sampled from two locations with different X and Y offsets that are added together for the final water height, to get the effect of waves traveling in different directions. The height is used to calculate the water normal at each pixel, which is used to calculate the reflectance of the water with the fresnel equations, as well as the refraction angle based on camera angle parameters. Two different camera angle values can be used for the refraction and reflection calculations for finer control of the final look. The shader is capable of aligning the refraction to the pixel grid, but I found I preferred higher resolution refraction. Light absorbance is calculated based on the estimated path length of light through the water for each pixel. Then the shader blends from from the water color to the color where the refracted ray hits based on the absorbance, and from that to white based on the reflectance. If the water is less than a certain depth, it is colored white for the foam. The final output color is then posterized.

Ideally in the future I'd like to implement some sort of ray tracing or ray marching type of solution to better calculate how the color of the water is applied, calculate where the refracted light hits, and generate realistic caustics. I may also want to add a dithering effect; currently there's a trade off between having the posterization color depth higher to avoid color banding, and lower to help hide the shape of the noise texture used.

Published 3 hours ago
StatusPrototype
PlatformsHTML5
Authorestivalbloom
Made withGodot