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
Roadmap: docs/PERFORMANCE_ROADMAP.md — Batch 5, Issue 4C-2
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:
Target Effects
1. Fresnel Reflection/Refraction
F0for water ≈ 0.02 (dielectric)2. Animated Normal Maps
Two approaches (pick one):
Option A: Scrolling normal maps
Option B: Gerstner waves (procedural)
Recommendation: Option A for now (simpler, proven), with Option B as a future enhancement.
3. Depth-Based Color Absorption
4. Specular Highlights
Implementation Plan
Step 1: Fresnel effect
Step 2: Animated normals
normal = normalize(layer1 + layer2)Step 3: Depth absorption
Step 4: Specular
Step 5: Settings integration
Files to Modify
assets/shaders/vulkan/water.frag— all shader effectsassets/shaders/vulkan/water.vert— pass time, wave parameterssrc/engine/graphics/vulkan/water_system.zig— normal map texture, time uniformsrc/engine/graphics/texture_atlas.zig— add water normal map slotsrc/game/settings/data.zig— water quality settingTesting
Roadmap:
docs/PERFORMANCE_ROADMAP.md— Batch 5, Issue 4C-2