Skip to content
Andrew Voirol
Monday, August 31, 2026terragemini-build

Blinn-Phong specular ocean glint and raytraced atmospheric scattering

ShadersWebGLVisualization

TerraGemini renders oceanic reflection and planetary atmosphere using a raytraced billboard quad covering the screen-space bounding disc of the planet (u2+v2≤1.0u^2 + v^2 \le 1.0u2+v2≤1.0).

1. Spherical Normal Reconstruction

For any fragment (u,v)∈[−1,1]2(u, v) \in [-1, 1]^2(u,v)∈[−1,1]2, fragments outside r2=u2+v2≤1.0r^2 = u^2 + v^2 \le 1.0r2=u2+v2≤1.0 are discarded. The unit normal N\mathbf{N}N on the sphere surface is derived analytically:

N=(u−v1.0−r2)\mathbf{N} = \begin{pmatrix} u \\ -v \\ \sqrt{1.0 - r^2} \end{pmatrix}N=​u−v1.0−r2​​​

2. Solar Vector & Half-Angle Glint

With solar azimuth θsun\theta_{\text{sun}}θsun​ and constant solar elevation α=0.35 rad\alpha = 0.35\text{ rad}α=0.35 rad, the normalized light vector L\mathbf{L}L is constructed. Blinn-Phong specular intensity is calculated using the half-angle vector H=L+V∥L+V∥\mathbf{H} = \frac{\mathbf{L} + \mathbf{V}}{\|\mathbf{L} + \mathbf{V}\|}H=∥L+V∥L+V​ with an exponent of s=38.0s = 38.0s=38.0:

Ispec=(max⁡(N⋅H,0.0))38⋅step(0.001,N⋅L)I_{\text{spec}} = (\max(\mathbf{N} \cdot \mathbf{H}, 0.0))^{38} \cdot \text{step}(0.001, \mathbf{N} \cdot \mathbf{L})Ispec​=(max(N⋅H,0.0))38⋅step(0.001,N⋅L)

The step function guarantees that the unlit hemisphere receives zero specular highlight.

3. Rayleigh Atmospheric Limb & Composite

Limb scattering Ilimb=(1.0−1.0−r2)2.6I_{\text{limb}} = (1.0 - \sqrt{1.0 - r^2})^{2.6}Ilimb​=(1.0−1.0−r2​)2.6 produces an atmospheric rim halo. The final composited fragment combines diffuse ocean tone, specular glint, and atmospheric scattering in a single pass:

Cfinal=Cocean⋅(0.18+0.82(N⋅L))+Cspecular⋅(1.85⋅Ispec)+Catmos⋅(0.75⋅Ilimb)\mathbf{C}_{\text{final}} = \mathbf{C}_{\text{ocean}} \cdot (0.18 + 0.82(\mathbf{N} \cdot \mathbf{L})) + \mathbf{C}_{\text{specular}} \cdot (1.85 \cdot I_{\text{spec}}) + \mathbf{C}_{\text{atmos}} \cdot (0.75 \cdot I_{\text{limb}})Cfinal​=Cocean​⋅(0.18+0.82(N⋅L))+Cspecular​⋅(1.85⋅Ispec​)+Catmos​⋅(0.75⋅Ilimb​)

← Previous

O(1) GPU vertex slicing: 250,000 points without PCIe memory reallocation

Next →

3x3 Sobel normal gradient convolution for procedural coastlines


Andrew Voirol

Builder, hacker, shipper. Currently leaving localhost.

Navigate

WorkThreadsBuilder's LogAboutContactRSS Feed

Connect

X / TwitterGitHubLinkedIn

© 2026 Andrew Voirol·Back to top ↑
✦Just one prompt away from figuring it all out.