前回の「因数分解化BRDF」で放物変換を取り扱ったのですが、この方法は、今まで1次元テクスチャでテーブル引きしていて頂点ごとにかくかくしたたものを滑らかな変化に変えることができます。 この表現で一番最初に思いつくのがトゥーンシェーディングで、トゥーンシェーディングは、下手にやるとグーローシェーディングの線形補間によってポリゴンの形が見えてしまうのですが、放物変換を使うと滑らかに変化させることができます。
今回のプログラムは、次のものです。
まぁ、いつものように適当にファイルが入っています。
APP WIZARD から出力されるフレームワークのファイルは紹介を省かせていただきます。
hlsl.fx | シェーダの入ったエフェクトファイル |
main.h | アプリケーションのヘッダ |
main.cpp | アプリケーションのソース |
あと、実行ファイル、プロジェクトファイルが入っています。
今回は、前回より簡単になっています。ほぼ2色に塗り分けられたトゥーンのテクスチャをライトベクトルを放物変換を使って計算したテクスチャ座標を使ったサンプリングによって、デカールの色に陰影をつけます。
color = | * | (Q(L)) |
なお、今回は前回の放物変換をそのまま使いましたが、実際にやってみると白と黒の境界がテクスチャのふちぎりぎりになってしまったので、テクスチャ座標に変換するときの半径(前回の式のpv)をもう少し小さくしたほうが良いかも知れません。
頂点シェーダでは放物変換を使って、ライトベクトルからテクスチャ座標を計算します。
hlsl.fx 0083: // ------------------------------------------------------------- 0084: // 頂点シェーダプログラム 0085: // ------------------------------------------------------------- 0086: VS_OUTPUT VS(VS_INPUT In) 0087: { 0088: VS_OUTPUT Out = (VS_OUTPUT)0; // 出力データ 0089: 0090: // 位置座標 0091: Out.Pos = mul( In.Pos, mWVP ); 0092: 0093: // 表面座標系の基底ベクトルを求める 0094: float3 N = In.Normal; // 法線ベクトル 0095: float3 B = float3(0,1,0); // 従法線ベクトル 0096: float3 T = normalize(cross(N,B)); // 接ベクトル 0097: B = cross(T,N); 0098: 0099: // ベクトルをテクスチャ座標へ変換する 0100: float3 L = normalize(LightPos-In.Pos.xyz);// ライトベクトル 0101: Out.ToonCoord = Q(L, B,T,N); 0102: 0103: // デカールのテクスチャ座標 0104: Out.Tex = In.Tex; 0105: 0106: return Out; 0107: }
ピクセルシェーダでは先ほど求めたテクスチャ座標でトゥーンのテクスチャを読み込んでデカールテクスチャからの色に陰影をつけます。 なお、そのままでは色の変化が急すぎたので、環境光を0.5つけました(同時に読み込んだ陰影も0.5倍に調整しました)。
hlsl.fx 0108: // ------------------------------------------------------------- 0109: // ピクセルシェーダプログラム 0110: // ------------------------------------------------------------- 0111: float4 PS(VS_OUTPUT In) : COLOR 0112: { 0113: float4 decale = tex2D( DecaleSamp, In.Tex ); // デカール 0114: float shade = tex2D( ToonSamp, In.ToonCoord );// ツゥーン 0115: 0116: return (0.5f*shade+0.5f) * decale; 0117: }
逆に放物変換に特有のクセが出てきますね。 まぁ、でも使えるでしょう。。