3.0 KiB
3.0 KiB
Camera Effects Detailed Reference
Prerequisites
- Ray marching fundamentals (ray origin, ray direction)
- Multipass buffers (for accumulation-based DoF)
- Hash functions for stochastic sampling
Thin Lens Model Derivation
A real camera lens focuses light from a focal plane onto the sensor. Points not on the focal plane project to a circle of confusion (CoC) on the sensor.
Circle of Confusion Formula
CoC = |S2 - S1| × A × f / (S1 × (S2 - f))
Where:
S1= focal distance (distance to in-focus plane)S2= object distanceA= aperture diameterf= focal length
Simplified for Shaders
CoC ≈ apertureSize × |depth - focalDistance| / depth
Ray-Based Implementation
Instead of computing CoC per pixel, we model the physical process:
- Choose a random point on the aperture disk → new ray origin
- The focal point (where the original ray hits the focal plane) stays fixed
- New ray direction =
normalize(focalPoint - newOrigin) - Average many such samples → natural bokeh with correct occlusion
Aperture Shape
- Circular:
vec2 p = sqrt(r) * vec2(cos(a), sin(a))— uniform disk - Polygonal: reject samples outside polygon for hexagonal/octagonal bokeh
- The
sqrt(r)is critical for uniform distribution (area-preserving)
Poisson Disk Sampling
Pre-computed 16-point Poisson disk for blur kernels:
const vec2 poissonDisk[16] = vec2[](
vec2(-0.94201624, -0.39906216), vec2(0.94558609, -0.76890725),
vec2(-0.09418410, -0.92938870), vec2(0.34495938, 0.29387760),
vec2(-0.91588581, 0.45771432), vec2(-0.81544232, -0.87912464),
vec2(-0.38277543, 0.27676845), vec2(0.97484398, 0.75648379),
vec2(0.44323325, -0.97511554), vec2(0.53742981, -0.47373420),
vec2(-0.26496911, -0.41893023), vec2(0.79197514, 0.19090188),
vec2(-0.24188840, 0.99706507), vec2(-0.81409955, 0.91437590),
vec2(0.19984126, 0.78641367), vec2(0.14383161, -0.14100790)
);
Advantages over regular grid: no structured aliasing patterns, better coverage per sample count.
Motion Blur Approaches
Stochastic Time Sampling (Ray Marching)
For each pixel, pick a random time within the shutter interval:
t_sample = iTime + (rand - 0.5) * shutterDuration
Use t_sample for all scene animation. Accumulate multiple frames for convergence.
Velocity Buffer (Post-Process)
- Render scene + store per-pixel velocity vectors
- For each pixel, sample along the velocity direction
- Weight samples by distance from center (triangle filter)
Hybrid
Use temporal accumulation (TAA-style) with per-frame time jitter — converges over frames with no per-frame cost increase.
Film Grain Characteristics
Real film grain properties:
- Luminance-dependent: More visible in shadows, less in highlights
- Temporally varying: Different pattern each frame (use
fract(iTime)in hash seed) - Spatially uncorrelated: Use pixel coordinates in hash, not UV (grain should be screen-resolution)
- Intensity: 0.02-0.05 for subtle, 0.1+ for stylized/vintage look