ブーリアン演算


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の最も強力な特徴のひとつは、複数の図形を数学的に合成できることです。minmax といった単純な関数だけで、和(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 で滑らかな融合が可能