仅凭五十余行纯粹紧凑的 GLSL 着色器代码,就能在二维屏幕上渲染出一整座翻滚奔涌的落日云海。全程不加载任何三维模型、体素网格或外部纹理,完全由数学波动方程与 GPU 并行计算 驱动。这是计算机图形学与算法诗意的极致融合。
⚡ 全景视觉前瞻 · 4K 60FPS 渲染流形

▲ 《Sunset Expanded》完整动态成果前瞻(Apple Metal 60.0 CFR 光栅化)
一、50行纯代码:完整 GLSL 着色器源码
以下为作者 @XorDev 在 Fragcoord 发布的完整着色器实现。全篇无任何外部依赖,依托 100 次体积光线步进、8 阶正交正弦置换循环与双曲正切色调映射:
/*
"Sunset" by @XorDev
Expanded and clarified version of my Sunset shader:
https://www.shadertoy.com/view/wXjSRt
Based on my tweet shader:
https://x.com/XorDev/status/1918764164153049480
*/
// Uniform defaults
float u_brightness = 1.0;
float u_color_base = 1.5;
float u_color_speed = 0.5;
vec3 u_rgb = vec3(0.0, 1.0, 2.0);
float u_color_wave = 14.0;
vec3 u_color_dot = vec3(1.0, -1.0, 0.0);
float u_wave_steps = 8.0;
float u_wave_freq = 5.0;
float u_wave_amp = 0.6;
float u_wave_exp = 1.8;
vec3 u_wave_velocity = vec3(0.2, 0.2, 0.2);
float u_passthrough = 0.2;
float u_softness = 0.005;
float u_steps = 100.0;
float u_sky = 10.0;
float u_fov = 1.0;
void main()
{
float z = 0.0;
float d = 0.0;
float s = 0.0;
vec3 dir = normalize(vec3(2.0 * gl_FragCoord.xy - u_resolution.xy, -u_fov * u_resolution.y));
vec3 col = vec3(0);
for (float i = 0.0; i < u_steps; i++)
{
vec3 p = z * dir;
// Turbulence loop
for (float j = 0.0, f = u_wave_freq; j < u_wave_steps; j++, f *= u_wave_exp)
{
p += u_wave_amp * sin(p * f - u_wave_velocity * u_time).yzx / f;
}
// Distance to top and bottom planes
s = 0.3 - abs(p.y);
// Soften and scale inside the clouds
d = u_softness + max(s, -s * u_passthrough) / 4.0;
// Step forward
z += d;
// Coloring with signed distance, position and cycle time
float phase = u_color_wave * s + dot(p, u_color_dot) + u_color_speed * u_time;
// Apply RGB phase shifts, add base brightness and correct for sky
col += (cos(phase - u_rgb) + u_color_base) * exp(s * u_sky) / d;
}
// Tanh tonemapping
col *= u_softness / u_steps * u_brightness;
fragColor = vec4(tanh(col * col), 1.0);
}
二、逐层递进:五阶段数学解构
阶段一:视锥发射与空间平面对称层
着色器首先在虚拟视锥中发射光线,并将三维空间约束在一层水平无限延展的大气介质中(边界为 $y = \pm 0.3$)。为了兼顾效率与精度,引入了自适应步长算法:在稀疏外部大步跳跃,在介质内部细致步进。
核心数学公式

01 视线发射与大气对称层

▲ 阶段一:视线发射与未扰动的大气几何对称平板
// 阶段一:视锥发射与平板自适应步进
vec3 dir = normalize(vec3(2.0 * gl_FragCoord.xy - u_resolution.xy, -u_fov * u_resolution.y));
for (float i = 0.0; i < u_steps; i++) {
vec3 p = z * dir;
s = 0.3 - abs(p.y); // 大气边界层 [-0.3, +0.3]
d = u_softness + max(s, -s * u_passthrough) / 4.0;
z += d;
}
阶段二:八阶正交置换湍流循环
平整的大气板层如何蜕变为千层翻滚的流体积雨云?核心在于这组八阶正交置换循环。算法沿三维空间施加正弦扰动,并将轴向循环位置换为 YZX。这种自反馈撕裂了欧氏平整度,在微观上激发出混沌壮阔的碎形涡流。
核心数学公式

02 涡流扰动 · 多频正交置换湍流

▲ 阶段二:多频正交置换激发出翻滚汹涌的云团形态
// 阶段二:八阶正交置换正弦湍流循环
for (float j = 0.0, f = u_wave_freq; j < u_wave_steps; j++, f *= u_wave_exp) {
// YZX 轴向置换消除平移共线性,构筑分形卷曲
p += u_wave_amp * sin(p * f - u_wave_velocity * u_time).yzx / f;
}
阶段三:指数级光子内散射积分
赋予云海体积感与穿透力的是简化的比尔-朗伯定律光子积分。光线穿透湍流介质时,能量随厚度呈指数级递增。每一束光子在云层缝隙中发生多重散射,让虚无的曲面凝聚出沉甸甸的夕阳光辉与纵深感。
核心数学公式

03 介质透射 · 光子内散射积分

▲ 阶段三:光子累积与介质边缘强散射效应
// 阶段三:比尔-朗伯定律光子内散射近似
float density = exp(s * u_sky) / d;
col += density * u_color_base;
阶段四:空间相位差余弦晚霞调色盘
绝美的晚霞由纯数学波动调制生成。算法在红绿蓝三通道施加弧度相差,结合厚度与空间点积。金色余晖、绯红霞光与暮霭青紫在翻滚的云顶自然交融,色彩完全由波动相位决定,无需任何外部调色贴图。
核心数学公式

04 余弦光谱 · 空间相位差晚霞全谱

▲ 阶段四:全色谱晚霞绚丽铺展
// 阶段四:空间相位差余弦多相晚霞调色盘
float phase = u_color_wave * s + dot(p, u_color_dot) + u_color_speed * u_time;
// RGB 弧度相差 [0, 1, 2],展开金色到青紫的全色谱
col += (cos(phase - u_rgb) + u_color_base) * exp(s * u_sky) / d;
阶段五:双曲正切高动态色调压制
经历百次步进积分后,累积的能量数值已远超屏幕显示极限。算法在终局阶段先对能量进行归一化二次滤波,再送入双曲正切函数 tanh 进行非线性色调映射。强光在高光区域自然平滑饱和,杜绝过曝死白,最终在屏幕上定格为胶片质感的 4K 落日云海。
核心数学公式

05 终局映射 · 双曲正切高动态压缩

▲ 阶段五:高光柔和滚降,定格电影质感夕阳
// 阶段五:二次滤波与非线性双曲正切色调压制
col *= u_softness / u_steps * u_brightness;
// tanh(C²) 压制高光,带来胶片级柔和滚降与暗部对比
fragColor = vec4(tanh(col * col), 1.0);
三、总结与工程启发
- 正交置换的几何威力:简单的
p += sin(p * f).yzx / f 能够在极短代码内打破网格对称性,激发出与纳维-斯托克斯方程近似的视觉流体卷曲。
- 自适应步长的高效性:通过符号距离函数
s = 0.3 - |p_y| 动态调整步进跳跃步长,实现稀疏区域大步推进、密实区域细致采样的极速收敛。
- 解析调色与色调映射:余弦相位偏移与双曲正切组合,构筑了现代体渲染中近乎零显存开销却具备超高动态范围的光影表达范式。这种以 数学模型 替代显式几何的思路,恰恰是着色器编程最迷人的地方——你不需要庞大的资源管线,一段精巧的数学函数就能在 GPU 上铺开一整个动态世界。