title: "ブーリアン演算" description: "SDFのブーリアン演算(和・積・差)とsmooth minを学びます。図形を組み合わせて複雑な形状を作りましょう。" chapter: "04-shapes" order: 5 challenge: description: "月の形を描いてください。大きな円から少しずらした円を引き算(subtraction)して、三日月を作りましょう。" hints:
- "subtraction は max(d1, -d2) で実現できます。"
- "大きな円(半径0.3)と、少し右にずらした円(半径0.3、中心を右に0.15ずらす)を用意します。"
- "float moon = max(d1, -d2); で三日月になります。d1が元の円、d2がくり抜く円です。"
ブーリアン演算
SDFの合成
SDFの最も強力な特徴のひとつは、複数の図形を数学的に合成できることです。min、max といった単純な関数だけで、和(union)、積(intersection)、差(subtraction)が実現できます。
Union(和):min(d1, d2)
2つの図形を合体させるには、SDFの最小値を取ります:
float opUnion(float d1, float d2) {
return min(d1, d2);
}
各点で「より近い方の図形」の距離が選ばれるため、両方の図形が描画されます。
Intersection(積):max(d1, d2)
2つの図形の重なりだけを残すには、最大値を取ります:
float opIntersection(float d1, float d2) {
return max(d1, d2);
}
両方の図形の内側(両方のSDFが負)の領域だけが残ります。
Subtraction(差):max(d1, -d2)
一方の図形からもう一方をくり抜くには:
float opSubtraction(float d1, float d2) {
return max(d1, -d2);
}
-d2 で図形2の内外を反転させ、max を取ることで、図形1から図形2の領域を除外します。
Smooth Min(滑らかな和)
通常の min では合成部分がシャープな角になります。smooth min を使うと、図形同士が滑らかに融合します:
float smin(float a, float b, float k) {
float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);
return mix(b, a, h) - k * h * (1.0 - h);
}
k は融合の滑らかさを制御するパラメータです。k が大きいほど滑らかに融合し、k = 0 に近づくと通常の min と同じ挙動になります。
実践例
右のプレビューでは、2つの円の union が表示されています:
float d1 = sdCircle(p - vec2(-0.15, 0.0), 0.25);
float d2 = sdCircle(p - vec2(0.15, 0.0), 0.25);
float d = min(d1, d2); // union
まとめ
- Union(和):
min(d1, d2)で図形を合体 - Intersection(積):
max(d1, d2)で重なりを抽出 - Subtraction(差):
max(d1, -d2)で図形をくり抜き - Smooth min で滑らかな融合が可能