返回

SDF 形状融合

上一个18 / 18
把圆形、矩形和 smooth min 组合起来,构造一个平滑融合的复合形状。

把两个 SDF 形状用 smin 融合,再分别绘制填充层和轮廓层:

下面拆解它。


为什么不直接用 min

min(a, b) 是硬取最小值——两个形状在交界处会突然切换,边缘生硬。

smin(a, b, k) 是平滑最小值:在两个形状接近的区域,距离场被"软化",过渡区域混合了两者,连接处自然圆润,就像两团泥巴捏在一起,而不是两块积木拼在一起。

参数 k 控制融合的柔软程度:k 越大,融合区域越宽、越圆润;k 趋近 0 时退化为硬 min。


形状的位置

两个形状都有偏移:

  • body:p + vec2(0.05, 0.0) 向左偏移,圆角矩形是主体
  • lobe:p - vec2(0.14, 0.02) 向右偏移,圆形是附加突起

偏移让两个形状相互重叠,smin 在重叠区域产生圆润融合,整体看起来像一个有机形状。


填充层和轮廓层

融合后的 SDF 值 d 既能做填充,也能做轮廓:

  • 填充:1.0 - smoothstep(0.0, 0.012, d) → d < 0 的区域(形状内部)亮
  • 轮廓:1.0 - smoothstep(0.018, 0.028, abs(d)) → d ≈ 0 的边界区域(很窄的一圈)亮

轮廓用的是 abs(d)——不管在形状里还是外,靠近 0 都会有响应,形成一条细细的边界线。


试着改一改

改动效果
把 0.16 改成 0.04融合区域变窄,接近硬边
把 lobe 的圆半径从 0.16 改成 0.08突起变小
把 smin 换成 min融合变成硬切,边缘不圆润
把 outlineColor 改成 vec3(1.0, 1.0, 0.2)轮廓变黄

练习

用 smin(body, lobe, 0.16) 融合两个形状的距离场,再用 smoothstep 分别构造填充层 fill 和轮廓层 outline。

答案解析

smin(body, lobe, 0.16) 平滑合并两个距离场,融合宽度约为 0.16。负值区域是形状内部,正值是外部,0 是边界。

fill 使用 smoothstep(0.0, 0.012, d) 在边界处做很窄的柔化,内部(d < 0)几乎全是 1,外部(d > 0.012)几乎全是 0。

outline 使用 abs(d) 对称地检测边界:无论在哪一侧,只要 d 的绝对值小于 0.028,就会有亮度——产生一条宽约 0.01 的发光轮廓线。

练习的起始状态 d = 0.0,fill = 0.0,outline = 0.0,画面只显示背景。补全三行后就能看到完整的融合形状。

试着把 smin 的第三个参数从 0.16 改成 0.3,看看融合区域更大时形状的变化。

GLSL 代码编辑器

正确代码预览

当前代码预览