法線マッピング
ColorMatrixFilterで法線マッピング。
Gears of Warで法線マップに惚れ直しました。
法線マッピングはper-pixel shadingの手法で、テクセルごとに面の法線を保持するテクスチャを用いて、光源と法線の角度に応じて陰影をつけることであたかも凹凸があるかのように見せるものです。
正規化された各法線ベクトルは成分X,Y,ZをそれぞれR,G,Bチャンネルとして法線マップに収められています。法線と光源がどれぐらい同じ向きか(どれぐらい垂直に近いか)はベクトルの内積で得られます。光源ベクトルは各テクセルで変化しませんので、一つの面に対する上記の計算は、一つのColorMatrixFilterで表現できてしまいます。
具体的な計算を考えてみましょう。法線マップをColorMatrixFilterで陰影を表すビットマップに変換します。
法線マップの各チャンネルをR, G, Bとします。取りうる値はそれぞれ0~0x80~0xFFです。
これらが表す法線ベクトルの各成分をX, Y, Zとします。上記の値が-1~0~1に相当します。
(1に相当するのが0x80なのか0x7Fなのか曖昧ですが、面倒なので考えません。以後 0x100 = 0xFF = 2 * 0x80 = 2 * 0x7Fで勘弁してください。)
法線と光源ベクトル(Lx, Ly, Lz - 正規ベクトルです)の内積は-1~0~1です。
陰影ビットマップの各チャンネルをR', G', B'とし、上記の内積に対して0x00~0x00~0xFFを割り当てます。(簡単にするため。サンプルと違い垂直の面が真っ黒になります)
X = R / 0x80 - 1 Y = G / 0x80 - 1 Z = B / 0x80 - 1 R' = G' = B' = (X * Lx + Y * Ly + Z * Lz) * 0xFF
従って
R' = G' = B' = ((R / 0x80 - 1) * Lx + (G / 0x80 - 1) * Ly + (B / 0x80 - 1) * Lz) * 0xFF
= (R / 0x80 * Lx - Lx + G / 0x80 * Ly - Ly + B / 0x80 * Lz - Lz) * 0xFF
= R * 2 * Lx + G * 2 * Ly + B * 2 * Lz + (Lx + Ly + Lz) * -0xFF
ColorMatrixFilterで書くと
new ColorMatrixFilter([
2 * Lx, 2 * Ly, 2 * Lz, 0, (Lx + Ly + Lz) * -0xFF,
2 * Lx, 2 * Ly, 2 * Lz, 0, (Lx + Ly + Lz) * -0xFF,
2 * Lx, 2 * Ly, 2 * Lz, 0, (Lx + Ly + Lz) * -0xFF,
0, 0, 0, 1, 0
]);
これを適用すると陰影を表すビットマップが得られますので、テクスチャに乗算ブレンドして陰影処理終わりです。 ハードライトを使ってハイライトを加えるのも面白いです。