第 21 章练习:SDF 视觉效果
对应教程:21 SDF 的视觉效果
起始示例:带孔徽牌的距离效果,需要修改时使用示例源码。
练习 1:估算发光衰减
假设点位于徽牌外部,fill≈0,uGlow=0.08,暂时只看示例的指数因子 exp(-d/uGlow)。
**目标:**算出 d=0、0.08、0.16 时的因子;指出增大 uGlow 后同一外部距离处的光晕会怎样变化。
**完成标准:**能说明 uGlow 是指数衰减距离,不是光晕的硬截止半径;知道最终亮度还受颜色与 0.65 强度系数影响。
练习 2:把对称描边改成仅内侧描边
**目标:**新增一个“仅内侧描边”模式。让 uOutline 表示从零边界向形状内部延伸的宽度;外轮廓和圆孔边缘都应有内侧金线。
**要求:**在现有末尾描边分支中增加模式,保留组合预览与原“仅描边”模式的对称线;两条描边边缘都使用已有的 aa 进行抗锯齿。
**完成标准:**金线只覆盖 -uOutline < d < 0 附近,圆孔的外部不会出现另一半描边;改变宽度控件时,金线主要向徽牌实体内侧变宽。
练习 3:比较“带孔阴影”与“实心阴影”
**目标:**在“填充与柔和阴影”模式中,把阴影所用的距离场临时改为外侧圆角矩形,不从阴影里挖圆孔;徽牌本体仍有孔。比较孔附近的颜色。
**要求:**只修改阴影的查询函数,保持本体 d=sdBadge(p)、偏移、软边和合成顺序不变。完成后恢复原式。
**完成标准:**实心阴影会更明显地透过徽牌的圆孔显示;能解释为什么阴影形状与本体形状可以由不同距离场决定,而这仍是二维遮罩效果。
<a id=“reference-answers”></a>
第 21 章练习参考解答
对应练习:SDF 视觉效果。
练习 1:估算发光衰减
外部距离 d |
exp(-d/0.08) |
|---|---|
| 0 | 1 |
| 0.08 | e⁻¹≈0.368 |
| 0.16 | e⁻²≈0.135 |
实际 shader 还乘 (1-fill)、发光颜色和 0.65,所以边界附近像素的最终颜色不直接等于表中数值。增大 uGlow 会让同一正距离处的指数下降得更慢,光晕扩散更远;它没有某个自动变为零的半径。
练习 2:把对称描边改成仅内侧描边
在 HTML 的 #mode 下拉框追加 <option value="6">仅内侧描边</option>。把片元 shader 最后的描边 if 整块替换为:
// 片元阶段;d、uOutline、aa 均为平面高度单位。
if ( uMode == 0 || uMode == 2 || uMode == 6 ) {
float outline;
if ( uMode == 6 ) {
float afterInnerEdge = smoothstep( -uOutline - aa,
-uOutline + aa, d );
float beforeOuterEdge = 1.0 - smoothstep( -aa, aa, d );
outline = afterInnerEdge * beforeOuterEdge;
} else {
outline = 1.0 - smoothstep( -aa, aa,
abs( d ) - 0.5 * uOutline );
}
color = mix( color, vec3( 1.0, 0.70, 0.23 ), outline );
}
模式 6 不满足前面的填充、发光和阴影条件,因此只在背景上画内侧金线。afterInnerEdge 在 d=-uOutline 附近从 0 变 1,beforeOuterEdge 在 d=0 附近从 1 变 0;乘积只留下内侧带。模式 0 和 2 继续使用原对称描边。圆孔周围的 d<0 区域位于徽牌实体内,所以金线会落在孔外侧的实体上。
练习 3:比较“带孔阴影”与“实心阴影”
只替换阴影分支内计算 shadowD 的一行:
// 片元阶段;仍从 p 减去偏移,仅阴影使用外轮廓场。
float shadowD = sdRoundBox( p - uShadowOffset,
vec2( 0.50, 0.28 ), 0.09 );
保留紧接其后的 shadowAa、shadow、颜色混合,以及前面 d=sdBadge(p) 的本体计算。阴影现在是一块实心圆角矩形,本体依然有圆孔,因而孔内可能透出更多暗色阴影。恢复 float shadowD=sdBadge(p-uShadowOffset); 后,阴影自己也有孔,孔附近的暗色分布随偏移而改变。这是为两层二维遮罩选择不同形状;没有新增真实投影几何。