読者です 読者をやめる 読者になる 読者になる

GameProgrammar's Night

ゲームプログラム系の覚え書き

DistanceFieldTextureメモ

DistanceFieldTexture DirectX シェーダー

これ→ http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf

 2007年の論文なのですが、今更知りましたとさ。ちょうざっくり言うと

「テキストなどの境界線くっきりしてるものを拡大描画する時でも綺麗な境界線が出るようにしよう! アルファテストだけで」

 というお話。実装簡単なのにびっくりするぐらい綺麗に拡大されて感動。ちょっとだけいじると縮小にもかなり強くすることもできる様子。
 実装はこれからやってみますが、論文を読んでわかったつもりになっていることをメモ書き

  • Distance Field Textureは事前生成
    • 対象なるテキストを高解像度で作成(ベクターグラフィック的に拡縮したいってのがモチベーションなので、イラレなどのベクターツールで作ると良いんじゃないかなー?)
    • 描画する部分を白、描画しない部分を黒にする
    • 作った高解像度画像をbitmapとかpngとかのバイナリフォーマットにする(たぶん、可逆フォーマットが良いと思う)
    • バイナリにした画像を読み込んで、内・外判定(内外は、外は黒、内は白みたく色で表現すると楽)
    • 各ピクセルを走査して一番近い反対色への距離を計算して、0~255の色値(値が大きいほど近い)にして画像にプロットしていく
      • どれぐらいの距離まで考慮にいれるかは、自分で決めるっぽい?
    • プロットしていく時は、DistanceFieldTextrueサイズに合わせた位置に。
      • 「DistanceFieldTextrue.x = 元イメージ.x * 元イメージ幅 / DistanceFieldTextrueサイズ」的な感じで
    • 論文には4096×4096を128×128にした例が載ってます
  • Distance Filed Textureを使ってレンダリング
    • サンプリングにLINER指定をして普通にテクスチャとして読み込む
    • 適当な閾値でアルファテストをONにしておく
    • 距離が0.5未満ピクセルは描画しないように、アルファテスト閾値未満のアルファ値にしてしまう
    • 距離が0.5以上ならば、アルファテストの閾値以上のアルファ値にする


が、基本の流れ。距離をアルファ換算していらんとこをアルファテストで落としてしまおうってのが肝のようです。
 距離によるアルファ値計算をsmoothstepなどを使ってアンチエイリアスを掛ける形にしておくと縮小時にも綺麗に見える。
 また、レンダリング時に距離の値を上手いこと使うことで、縁取りをしたり、縁を光らせたりすることもできる。
 SM2.0の範囲でも色々できるっぽいのも魅力。

 固定機能のみでやるならば、アルファテスト閾値を127、アルファブレンドOFFでやるんじゃないかなと思われます。
 
 わりと、ぐりぐりいじれるデモは、こことか→ https://forum.libcinder.org/topic/signed-distance-field-font-rendering

 実装して実験したら、結果を書きます。