入力と出力を定義する

最初に4つの量を分けます。Lは頭部ローカル座標の単位ライト方向ベクトル、φはLから求める符号付き水平ライト角、tはLight StartsからFull Lightまでの制作進行度、u(p)は画素pがLight状態へ切り替わる正規化位置です。

本実験ではtを0~1へ正規化し、7枚のキーをt = 0, 1/6, 2/6, …, 1へ配置します。比較図では便宜上0°~90°の制作目盛りへ換算していますが、Quick SDF Paint 0.9.0のタイムラインは同じtを0~100%で表示します。どちらも物理的なライト角φそのものではありません。

i = 0, …, 6
t_i = i / 6
M_i(p) = 1  (Light)
M_i(p) = 0  (Shadow)

完成するスレッショルドマップの値をu(p)とすると、実行時に必要な基本判定は1つです。次の角括弧は、条件が真なら1、偽なら0を返すアイバーソン括弧(Iverson bracket)を表します。

Light(t, p) = [t ≥ u(p)]

実際のシェーダーでは、頭部ローカルのLから水平ライト角φを求め、設定した開始角と終了角の間を制作進行度tへ写像して比較します。シェーダーによって値や比較方向を反転して保存する場合はありますが、情報の意味は同じです。

uは距離でも物理角でもなく、制作進行度上の切替位置です。SDFが持つ境界付近の距離や勾配は、完成テクスチャには残りません。

Quick SDF Paint 0.9.0のlilToon向け既定出力では、uを反転して16-bitの値へ量子化します。

q_lilToon(p) = round((1 - u(p)) × 65535)

『Hi-Fi RUSH』GDC資料にも、固定角度の二値マスクをDCC上で生成・修正し、1枚のthreshold mapへまとめる制作工程があります。ただし公開資料だけから内部生成式の詳細までは判断できません。本記事の数式と結果は、公開された別実装と本記事の検証コードに基づきます。

比較する4つの方法

1. 最も近いキーを使う

k = round(6t)
Light(t, p) = M_k(p)

作者が描いたキーの形を完全に保ちますが、隣のキーとの中間を越えるまで境界は止まり、差分領域が一度に切り替わります。キーを増やせば段差は細かくなる一方、画像数と修正箇所も増えます。

2. 二値画素を線形補間して0.5で切る

V(p) = (1 - f) M_current(p) + f M_next(p)
Light = [V(p) ≥ 0.5]

M_current = 0、M_next = 1の画素では、結果がLight状態になる条件は常にf ≥ 0.5です。二値結果として評価する限り、変化する全画素が区間中央で同時に反転するため、今回の最近傍キーと同じ結果になりました。

グレーのまま影色を混ぜればフェードになりますが、輪郭が移動する二値影とは別の表現です。

3. 最初にLight状態になるキーを空間方向へぼかす

各画素が最初にLight状態になったキーの制作進行度を段階値として保存し、水平・垂直方向へ半径8 px、カーネル幅17 pxのボックスブラー(box blur)を適用しました。

常時Shadow状態の画素は無効値として計算から除外します。有効な切替値と有効画素の重みを別々にぼかして除算し、正規化した後、常時Shadow状態の画素を元へ戻します。これにより番兵値自体は周囲へ混ざりません。

実装は単純で段差も弱められますが、ぼかし幅は解像度へ依存し、細い領域や近接する輪郭の間で切替値が混ざります。これは一般的なブラー方式すべての代表ではなく、比較用に固定した1つの簡易ベースラインです。

4. SDFの距離比を使う

各二値マスクから、Light状態を正、Shadow状態を負とするSDFを作ります。この正負は本記事と検証コードで採用した符号規約です。逆に定義しても、式全体の符号を一貫して反転すれば結果は変わりません。

距離は、後述する厳密ユークリッド距離変換(exact Euclidean distance transform、exact EDT)で求めます。この実装におけるSDFの絶対値は、最寄りの反対クラスの画素中心までの距離です。隣接キーでShadow状態からLight状態へ変わる画素について、2つの距離から区間内の切替位置を求めます。

SDF距離比は何を計算しているのか

現在のキーではShadow状態、次のキーではLight状態である画素を考えます。現在のSDFはS_current(p) < 0、次のSDFはS_next(p) > 0です。それぞれの絶対距離を次のように定義します。

d_current = -S_current(p)
d_next = S_next(p)

区間内の遷移率r(p)と、制作進行度上の切替位置u(p)は次の比になります。

r(p) = d_current / (d_current + d_next)
u(p) = t_current + (t_next - t_current) r(p)

同じ値は、2つのSDFを線形補間したときのゼロ交差からも導けます。

(1 - f) S_current(p) + f S_next(p) = 0
f = S_current(p) / (S_current(p) - S_next(p))

実行時に2枚のSDFを読む代わりに、ゼロを横切る制作進行度だけを1枚のスレッショルドマップへ保存している、と捉えられます。SDFはこの生成が終われば不要です。

30°のマスク、そのSDF、45°のマスク、画素ごとの切替値を並べた生成段階
左から、30°の二値マスク、そのSDF、45°の二値マスク、7キーから生成した切替値。距離場は中間計算で、右端が最終的に必要な制作進行度上の切替データ。

比較実験の条件

手描き画像を選ぶと、特定の方式に都合のよい形を採用する余地があります。そこで制作進行度tに対して連続する正解形状を数式で定義し、0°、15°、30°、45°、60°、75°、90°の制作目盛りに対応する7枚だけを取り出しました。各方式にはこの7枚だけを渡し、元の連続式は与えません。

この7キー構成は、比較条件を等間隔に揃えるための実験用です。Quick SDF Paint 0.9.0の新規プロジェクトが作る既定9キーとは異なり、製品のキー数を推奨するための実験ではありません。

  • 解像度:512 × 512 px
  • 中間評価:1°~89°の89点を1°刻み
  • 形状:直線、非線形な曲線、凹形状、成分の出現と結合、画像端、細線と分岐
  • 距離変換:最寄りの反対クラスの画素中心まで測るexact EDT
  • 評価:全画素不一致率、IoU、1°ごとの変化量、切替位置u(p)の制作目盛り換算MAE
  • 補正:結果を見た後のパラメーター調整なし

円や単一点だけに限定せず、SDFが苦手とする形状の分離・結合と凹部も含めています。全白・全黒のキーから新しい成分が現れる区間では、距離比を定義できないため区間中央をフォールバックとしました。この選択も結果へ含まれます。

実測結果

次の画像は、凹形状を3つの評価位置で比較したものです。列は左から、正解、最近傍、画素線形、正規化ボックスブラー、SDF距離比です。最近傍と画素線形は一致し、ボックスブラーは形全体を太らせ、SDFはキー間で境界を進めています。

凹形状の正解と、最近傍、画素線形、正規化ボックスブラー、SDF距離比の4方式を3つの評価位置で比較した画像
行は22.5°、37.5°、52.5°。白=数式上の正解、橙=最近傍と画素線形、青=正規化ボックスブラー、緑=SDF距離比。

集計値は次のとおりです。進行度変化の標準偏差と最大1°変化量は、小さいほど隣接する評価点間の変化量が均等で、急な切替が少ないことを示します。ただし、まったく変化しない誤った結果でも小さくなるため、画素誤差やIoUと併せて評価します。

切替位置の平均絶対誤差(MAE)は、正解のu(p)が0~1に収まる画素を対象に、各方式が推定した切替位置との差を0°~90°の制作目盛りへ換算した値です。物理的なライト角φの誤差ではありません。

6形状・89評価点を集計した4方式の比較
方式平均画素誤差平均IoU進行度変化の標準偏差最大1°変化量切替位置MAE(制作目盛り換算、°)
最近傍キー3.09%0.8543.20%21.60%3.764°
画素線形+二値化3.09%0.8543.20%21.60%3.764°
初回Lightキー+正規化ボックスブラー6.16%0.7231.92%18.46%7.357°
SDF距離比(exact EDT)0.38%0.9600.31%4.17%0.469°

下表は6形状について、1°~89°の全画像で測った平均画素不一致率です。小さいほど、数式から直接作った正解画像に近いことを示します。

6種類の形状における平均画素不一致率
検証形状最近傍キー画素線形+二値化初回Lightキー+正規化ボックスブラーSDF距離比(exact EDT)
一定速度の直線3.36%3.36%6.73%0.06%
速度が変わる曲線3.95%3.95%8.27%0.71%
凹形状3.83%3.83%7.78%0.96%
成分の出現と結合2.90%2.90%5.51%0.18%
画像端を横切る形状3.27%3.27%6.39%0.07%
細線と分岐1.25%1.25%2.31%0.29%
6形状の平均3.09%3.09%6.16%0.38%

この実験ではSDF距離比が全体として最も低い平均誤差と高いIoUになりました。一方、結果は「SDFなら真の形状変化を復元できる」という証明ではありません。7枚の境界間を距離だけから推定した結果であり、形の意味的な対応は与えていません。

最近傍と画素線形の値が完全に同じなのも重要です。二値化を前提にRGBを混ぜても、境界移動にはならないことを数式と実測の両方で確認できます。

SDFが失敗する条件

SDFは「最寄りの反対クラスの画素中心までの距離」は保持していますが、「1枚目のどの部分が2枚目のどこへ移動したか」は保持していません。凹部、分岐、新しい成分の発生や結合では、最短距離がアーティストの意図した対応にならないことがあります。

円形の成分が途中で出現する形状を正解、正規化ボックスブラー、SDF距離比で比較した画像
左から正解、正規化ボックスブラー、SDF距離比。見た目が近い区間でも、キーの一方に成分が存在しなければ距離比は定義できず、この検証では区間中央を使っている。

また、隣接する2枚ずつの補間は各キー位置では同じマスクに一致しますが、区間境界で境界の移動速度まで一致する保証はありません。この制約は公開されているSDF距離比の解説でも指摘されています。

実用上の利点は「必ず正解になること」ではなく、少ないキーから広い範囲の境界移動を自動生成しやすいことです。破綻する区間だけキーを追加し、アーティストが修正できるワークフローと組み合わせる必要があります。

単調性は補間方式より前の条件

1枚のスレッショルドマップは、各画素に1つの切替位置しか保存できません。制作進行度tが増えるほどLight状態が広がる契約なら、すべての画素と隣接キーで次が成立する必要があります。

M_current(p) ≤ M_next(p)

Shadow → Light → Shadowと往復する画素には、2つの切替位置が必要です。1チャンネルの値では表現できません。これはSDFの精度不足ではなく、出力形式の情報量による制約です。

補間器に不正な列を黙って渡すのではなく、逆遷移と複数遷移を先に検出します。修復する場合も、補間とは別工程として元画像を保持し、どの画素を変更したか追跡できる方が安全です。

8-bitと16-bitの違い

正規化値をbビットへ最近傍丸め(round to nearest)で保存した場合、0°~90°の制作目盛りへ換算した理論上の最大量子化誤差は次のとおりです。

maximum error = 90° / (2 × (2^b - 1))
8-bitと16-bitの制作目盛り換算量子化誤差
精度今回の平均誤差最大誤差
8-bit0.084633°0.176471°
16-bit0.000329°0.0006867°

これは量子化だけの誤差です。元マスクの解像度、補間方式、テクスチャフィルタリング、圧縮、色空間変換は含みません。16-bit化は、不正なキー列や形状対応の誤りを直すものではありません。

値は色ではなくデータなので、Non-Colorとして読み込み、意図しないsRGB変換と非可逆圧縮を避けます。

exact EDTの「exact」とは

今回の参照実装は、二次元変換を各軸の一次元変換へ分離するexact EDTを使っています。FelzenszwalbとHuttenlocherの論文は、サンプルされた関数の距離変換を格子点数に対して線形時間で計算する方法を示しています。Maurerらの論文も任意次元のexact EDTを扱います。

ここでのexactは「二値画像の画素中心間のユークリッド距離として正確」という意味です。元の連続輪郭や、画素の間を通る境界を復元できるという意味ではありません。アンチエイリアス画像からサブピクセル境界を扱う距離変換は別の問題です。

exact EDTであっても、別成分の対応、新しい成分の発生、区間をまたぐ速度、解像度未満の細線、UVアイランドをまたいだ距離、上下方向の光や遮蔽は解決しません。

結論

  • 最近傍キーは元画像を保つが、境界が段階的に切り替わる
  • 二値画像の画素線形補間は、0.5で二値化すると最近傍と同じになる
  • 正規化ボックスブラーは段差を弱められるが、解像度依存の調整と形状の膨張・漏れを伴う
  • SDF距離比は少ないキーから境界移動を作りやすいが、形状の意味やトポロジーを理解しない
  • 最終出力はSDFではなく、制作進行度上の切替位置を格納したスレッショルドマップである
  • 1画素につき1値の形式では、制作進行度方向の単調性が必要である

SDF補間は万能な影生成ではなく、角度別マスクを少ない手作業で連続化するための道具です。性質と失敗条件を理解し、破綻する場所だけを人が直すことで、実制作での反復量を減らせます。

この補間をBlender上で確認し、必要な区間だけキーを増やす手順は、Quick SDF Paint 0.9.0で顔影スレッショルドマップを作る:Blenderでの実践手順で説明します。