假阴影

5 / 17
在简单球体上学习光照项(漫反射/高光/边缘光)。

用一个偏移的椭圆形来模拟球体投射的阴影,不需要任何光线追踪,关键代码是:

下面拆解这个技巧的原理。


什么是假阴影

真实的阴影需要追踪光线、计算遮挡,在片元着色器里代价很高。假阴影(fake shadow)的思路是:阴影在现实中大致是球体在地面的投影,形状近似椭圆。直接在球体下方画一个模糊的深色椭圆,视觉上就能以假乱真。


用 SDF 画椭圆

length(vec2(p.x, p.y+0.28)) - 0.28 是一个圆形的有符号距离场(SDF):

  • p.y + 0.28 把圆心向下移了 0.28 单位(从球心移到球的下方)
  • - 0.28 是圆的半径,让距离场的 0 值落在圆边缘上

把这个距离扔进 smoothstep(0.0, 0.08, d),就得到从圆内部(值 0)到圆外部(值 1)的柔和遮罩。用 1.0 - ... 翻转后,圆内是 1(有阴影),圆外是 0(无阴影)。


控制阴影浓度

原始遮罩最大是 1.0(100% 黑色)。乘以 0.35 把最深阴影压到 35%,让阴影半透明、更自然。

然后用 mix(bg, vec3(0.0), shadow) 把背景色和黑色按阴影强度混合:shadow=0 时显示背景,shadow=0.35 时背景稍微变暗。


试着改一改

改动效果
0.28(偏移量)改为 0.35阴影位置下移,球体感觉悬浮更高
0.08(柔化范围)改为 0.02阴影边缘更锐利
0.35(浓度)改为 0.7阴影更深更明显
把半径 0.28 改为 0.15阴影变小

练习

练习代码中球体已经绘制完成,但 shadow 变量还未计算。补全阴影的 SDF 计算,并将其混合到背景颜色里,让球体下方出现模糊的椭圆阴影。

答案解析

起始代码中背景直接用 bg,没有任何阴影。

length(vec2(p.x, p.y+0.28)) - 0.28 在球心正下方 0.28 处画了一个半径 0.28 的圆形 SDF。smoothstep(0.0, 0.08, d) 将 0 到 0.08 的距离范围平滑映射到 0→1,1.0 - ... 翻转为圆内是 1。乘以 0.35 控制透明度,最后 mix(bg, vec3(0.0), shadow) 把深色叠到背景上。

试着把偏移量 0.28 改成 p.x * 0.2 + 0.28,让阴影随 x 坐标偏移,模拟光从斜上方照射的效果。

GLSL 代码编辑器

正确代码预览

当前代码预览