Skip to content

[Batch 5] Water shader: Fresnel, animated normals, depth absorption #390

@MichaelFisher1997

Description

@MichaelFisher1997

Summary

Improve the water fragment shader with physically-based rendering: Fresnel reflection/refraction blending, animated normal maps for wave simulation, and depth-based color absorption. This builds on the separate water render pass from #386.

Depends on: #386 (water render pass + reflection texture)

Current State (after #386)

Water has a reflection texture and a basic water fragment shader. The shader samples the reflection texture but lacks:

  • Fresnel effect (reflection stronger at grazing angles)
  • Surface animation (static flat water)
  • Depth-based coloring (uniform blue regardless of depth)

Target Effects

1. Fresnel Reflection/Refraction

float fresnel = schlickFresnel(dot(view_dir, normal), F0);
vec3 color = mix(refraction_color, reflection_color, fresnel);
  • F0 for water ≈ 0.02 (dielectric)
  • Looking straight down → mostly refraction (see through)
  • Looking at grazing angle → mostly reflection (mirror-like)
  • Creates natural-looking water at all viewing angles

2. Animated Normal Maps

Two approaches (pick one):

Option A: Scrolling normal maps

  • Tile a normal map texture across the water surface
  • Scroll UV over time (two layers at different speeds/directions for complexity)
  • Simple and effective, used in most games

Option B: Gerstner waves (procedural)

  • Compute wave normal procedurally from sum of sine waves
  • Parameters: wavelength, amplitude, direction, speed
  • More realistic but more GPU cost
  • Recommended for a tech showcase engine

Recommendation: Option A for now (simpler, proven), with Option B as a future enhancement.

3. Depth-Based Color Absorption

float water_depth = scene_depth - surface_depth;
vec3 shallow_color = vec3(0.1, 0.6, 0.8);  // light blue
vec3 deep_color = vec3(0.02, 0.05, 0.15);  // dark navy
vec3 absorption = mix(shallow_color, deep_color, clamp(water_depth / max_depth, 0, 1));
  • Compare water surface depth with scene depth buffer
  • Shallow water (depth < 1 block): nearly transparent, see through clearly
  • Medium depth (3-5 blocks): blue tint with reduced visibility
  • Deep water (10+ blocks): dark navy, opaque

4. Specular Highlights

vec3 specular = pow(max(dot(half_vec, wave_normal), 0.0), 128) * sun_color * sun_intensity;
  • Sun specular reflection on water surface
  • Sharp highlight using high exponent (128)
  • Only when sun is visible (not behind terrain)

Implementation Plan

Step 1: Fresnel effect

Step 2: Animated normals

  • Add a normal map texture to the texture atlas (or separate texture)
  • Two scrolling layers: normal = normalize(layer1 + layer2)
  • Time uniform from push constants or UBO
  • Scroll speed configurable in settings

Step 3: Depth absorption

  • Read scene depth from G-pass depth buffer (or depth attachment)
  • Compare with interpolated fragment depth
  • Apply exponential absorption curve

Step 4: Specular

  • Sun direction from atmosphere system
  • View direction from camera
  • Wave normal from animated normal map
  • Add specular contribution to final color

Step 5: Settings integration

  • Water quality setting: LOW (flat tint), MEDIUM (reflection only), HIGH (all effects)
  • Animated normals toggle
  • Water color customization (future)

Files to Modify

  • assets/shaders/vulkan/water.frag — all shader effects
  • assets/shaders/vulkan/water.vert — pass time, wave parameters
  • src/engine/graphics/vulkan/water_system.zig — normal map texture, time uniform
  • src/engine/graphics/texture_atlas.zig — add water normal map slot
  • src/game/settings/data.zig — water quality setting

Testing

  • Fresnel effect visible: looking down = clear, looking across = reflective
  • Water surface animates smoothly (no jitter)
  • Shallow water is nearly transparent, deep water is opaque blue
  • Sun creates specular highlight on water surface
  • LOW preset falls back to flat tinted water
  • TAA doesn't cause water flickering
  • No performance regression > 1ms for water pass

Roadmap: docs/PERFORMANCE_ROADMAP.md — Batch 5, Issue 4C-2

Metadata

Metadata

Assignees

No one assigned

    Labels

    batch-5Batch 5: Final PushdocumentationImprovements or additions to documentationenhancementNew feature or requesthotfixquestionFurther information is requestedshaders

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions