CGワールドのVol.46に、
ガラクタスタジオさんのラクガキ王国の記事が載っていました。
その中にボツになった記事として、スクリーントーンを張った、トーンシェーダーの記事が載っていましたので、
挑戦してみました。
今回は、ツゥーンシェーダーを施すのと同時に、暗い部分にてんてんのスクリーントーンを張りました。
今回のソースは、次のものです(DirectX8.1用です)。
まぁ、いつものように適当にファイルが入っています。
前回と頂点シェーダプログラムと、draw.cpp が変化しています。
ps.sh | ピクセルシェーダープログラム。今回、ここが複合技。 |
vs.vsh | 頂点シェーダープログラム。 |
draw.cpp | メインの描画部分。 |
draw.h | 描画の各関数の定義。特に意味無いので出番無し。 |
main.h | 基本的な定数など。今回も出番無し。 |
main.cpp | 描画に関係しないシステム的な部分。変更が無いので、出番無し。 |
あと、いつもの様に、モデルと、実行ファイル及び、プロジェクトファイルが入っています。
トーン用のテクスチャーで特別なことは、スクリーン座標を使うことです。
透視変換した後の座標値を(いい感じに見えるように)適当にスケールをかけて、テクスチャー座標に使います。
また、ツゥーンシェーダーした光の強さを計算して、一定の(0.3)以下の光の強さ以下のときにトーンを張るようにピクセルシェーダープログラムを組んでいます。
今回は、ツゥーンシェーダーの時と比較して、
・2つめのテクスチャーをトーン用のテクスチャーにしている
・シェーダープログラムを書き換えた
という違いしかないので、シェーダープログラムだけの解説に絞ります。
頂点シェーダープログラムは、次のようになります。
0001: vs.1.0 0002: 0003: ; c0-3 -- world + ビュー + 透視変換行列 0006: ; c12 -- {0.0, 0.5, 1.0, 2.5} 0007: ; c13 -- ライトのベクトル 0009: ; c15 -- メッシュの色 0010: ; 0011: ; v0 頂点の座標値 0012: ; v3 法線ベクトル 0015: 0016: ;座標変換 0017: dp4 oPos.x, v0, c0 0018: dp4 oPos.y, v0, c1 0019: dp4 oPos.z, v0, c2 0020: dp4 oPos.w, v0, c3 0021: 0022: ; ((l,n)+1)/2 (平行光源のライティングを0~1に範囲変更) 0023: dp3 r0.x, v3, c13 0024: add r0.x, r0, c12.z 0025: mul oT0.x, r0.x, c12.y 0026: 0027: ; スクリーン座標をテクスチャー座標に設定 0028: dp4 r0.x, v0, c0 0029: dp4 r0.y, v0, c1 0030: dp4 r0.w, v0, c3 0031: rcp r0.w, r0.w 0032: mul r0.xy, r0, r0.w 0033: mul oT1.xy, r0, c12.ww 0034: 0035: ; メッシュの色 0036: mov oD0, c15
変わった部分は、2つめのテクスチャー座標 oT1 の設定です。
XY成分と、同次座標の計算用のW成分のスクリーン座標を求めます。
その後、w=1.0fの空間に変換し、適当なスケール c12.w = 2.5f を掛けて座標にしています。
c12.w をいろいろと変えると、スクリーントーンの点の大きさが変わります。
ピクセルシェーダープログラムは、いままでの組み合わせです。
下のソースの黄色の部分ですが、モノトーンフィルターでやった方法で、ツゥーンシェーダーの結果の色 t0 の色の強さを求めます。
次に、c0.w = 0.2 を減算して、トーンを掛ける部分と掛けない部分を切断する色の強さを調整します。
後は、比較命令 cnd を持ちいて、トーンを掛ける部分(明るさが0.3以下)と、掛けない部分(明るさが0.3以上)を決定します。
0004: ps.1.0 0005: 0006: def c0, 0.0f, 0.0f, 0.0f, 0.2f 0007: def c1, 0.299f, 0.587f, 0.114f,1.000f ; v = 0.299*R + 0.587*G + 0.114*G 0008: 0009: ; テクスチャーの色を引っ張ってくる 0010: tex t0 ; ツゥーンテクスチャー 0011: tex t1 ; トーンテクスチャー 0012: 0013: mul r1, t0, v0 ; ツゥーンシェーディング 0014: 0015: dp3 r0.rgba, t0, c1 ; 色の強さを求める 0018: add r0.a, r0, -c0 ; 切断色を調整する 0016: mov r0.rgb, t1 ; トーンテクスチャーを引っ張る 0020: cnd r0, r0.a, c1.aaa, r0 ; (0.5 < 色の強さ-0.2) ? 1 ? トーンテクスチャー 0021: 0022: mul r0, r0, r1 ; 最終色=トーン*ツゥーン*オブジェクトの色
作っていて気が付いたのですが、ドアの部分などで、不自然にスクリーントーンが引き伸ばされる場合があります。
テクスチャーを繰り返しモード(D3DTADDRESS_WRAP)で貼り付けているのですが、その処理が正常になされないようです。
(テクスチャーの値が0~1にクリップされる?)
従って、テクスチャーのサイズを大きくするか、ポリゴンを細かく分割するかの対応が必要そうです。
静止画で見ると、そこそこ見れるのですが、動くと「ブキミ」ですね。
うまくオブジェクトに貼り付けて、ツゥーン処理と絡めれば、そこそこ使えるかと思います。