double-s.t.e.a.l. における リアルタイム cg 表現技法
DESCRIPTION
DOUBLE-S.T.E.A.L. における リアルタイム CG 表現技法. 株式会社ぶんか社ゲーム開発事業部 川瀬 正樹 [email protected]. 本日の発表内容. Xbox の Direct3D マテリアルの表現 水面の表現 被写界深度(DOF)処理 縮小バッファによる高速化 画像フィルタ. Xbox の Direct3D. PC の Direct3D との全体的な違い API 呼び出しオーバヘッドが少ない GPU ネイティブな専用コマンドの追加 よりハードウェアに特化した API - PowerPoint PPT PresentationTRANSCRIPT
本日の発表内容 Xbox の Direct3D マテリアルの表現 水面の表現 被写界深度(DOF)処理 縮小バッファによる高速化 画像フィルタ
Xbox の Direct3D PC の Direct3D との全体的な違い
API 呼び出しオーバヘッドが少ない GPU ネイティブな専用コマンドの追加
よりハードウェアに特化した API GPU コマンドキュー(プッシュバッファ)を直
接生成することも可能 Xbox 拡張機能
GeForce3 の OpenGL 拡張機能とほぼ同じ プログラマブルシェーダの拡張
ピクセルシェーダの拡張 レジスタコンバイナ機能の追加
ベクタ/スカラ毎に各ステージで最大 4入力3出力
ファイナルコンバイナの追加 フォグブレンド etc.
ジェネラルコンバイナ命令(1) xmma d0,d1,d2, s0,s1,s2,s3
d0=s0*s1 d1=s2*s3 d2=s0*s1+s2*s3
xmmc d0,d1,d2, s0,s1,s2,s3 d0=s0*s1 d1=s2*s3 d2= (r0.a>0.5) ? s2*s3 : s0*s1
ジェネラルコンバイナ命令(2) xdd d0,d1, s0,s1,s2,s3
d0=s0 ・ s1 d1=s2 ・ s3
xdm d0,d1, s0,s1,s2,s3 d0=s0 ・ s1 d1=s2*s3
ファイナルコンバイナ命令 xfc s0,s1,s2,s3, s4,s5, s6
最終出力 rgb=s0*s1 + (1-s0)*s2 + s3 最終出力 a=s6 特殊入力レジスタ
PROD = s4*s5 SUM = r0+v1
その他 テクスチャシェーダ(アドレッシング命
令)の追加 texm3x2depth / texbrdf / texm3x3diff etc.
GPU リソースの自由な定義 同一メモリを複数のフォーマットでアクセ
ス ミップマップの動的生成に利用 デプスステンシルバッファを ARGB テクスチャ
として利用
反射/フレネル項 古典的な反射表現
手法 問題点
より物理的な光の挙動 手法
鏡面反射と拡散反射の相関 問題点
古典的な反射表現 拡散反射+鏡面反射(環境マップ)
最近では環境マップも動的に描画される
問題点 フレネル項を反映しにくい
拡散反射と鏡面反射に相関が無いため、エッジ部分の反射光が入射光を超えてしまう
より物理的な光の挙動 拡散反射と鏡面反射の相関
鏡面反射は素材の表面(屈折面)で起こる 拡散反射は素材の表面下で起こる
1.最初に鏡面反射が起こる2.残りの一部が拡散反射を起こす3.残りは透過/吸収される
計算方法は?1. 鏡面反射率 r の計算2. 鏡面反射カラー S を r で重み付け3. 拡散反射カラー D を 1-r で重み付け
フレネルによる反射率計算 真面目な計算など不要 法線と視線の内積から計算例:
s:適当なスケールb:適当なバイアス
光沢の低い素材ではsを小さく 頂点/ピクセルシェーダ内で容易に計算可
能
フレネル効果 (1)フレネル項なし
頂点単位フレネル
ピクセル単位フレネル
フレネル項なし
フレネル効果 (2)
問題点 鏡面反射に環境マップを利用すると、ダイナ
ミックレンジが低過ぎる 現実世界では光は極めて広い強さを持つ 現実では正面での反射率は 10%に満たない素材
が多い
反射率の低い部分ではハイライトが弱くなり、見栄えが良くない 太陽が映りこんでも灰色 etc.
太陽光の反射は 10%でも眩しい 太陽や車のヘッドライトの輝度は、CGでの輝度 1.0 より桁違いに明るい 10%の反射ですら 1.0 より強いことが多
い 太陽ならまだまだ桁違いに強い
反射前の最大輝度が 1.0 では到底再現不可能
ハイダイナミックレンジ(HDR)表現 何らかの方法で 1.0 を超える輝度を表
現したい 反射率の低い部分に合わせて環境マップを作成する(カラーレンジの圧縮)
αチャネルを付加的な輝度情報とする
カラーレンジの圧縮 予めカラーレンジを圧縮しておく
逆に反射率の高いエッジ部分が犠牲に 全体的に反射率の高いマテリアルでは致命的
鏡面や金属素材等⇒RGB 各 8bit の分解能では難しい
DirectX9 以降では改善される ダブル・スティールでは環境マップのみ 0.5倍圧縮(輝度 2.0まで表現可能)
αチャネルを付加的な輝度に 環境マップの αチャネルに輝度情報を追加 どの段階で αチャネルから輝度情報に戻すか
描画時に α値から RGB値を補正する 描画後は既に HDR ではない
⇒グレアフィルタを適用しにくい(輝度抽出が難しい) あまり良好な結果を得られない
ポストプロセスのグレアフィルタと同時に補正する 描画時はマテリアルを考慮して αチャネルへ出力 HDR を利用したより高品質なグレアを生成できる α値でグレアをコントロール可能
⇒反射だけでなく光源も描画できる 残像効果に利用可能
描画ピクセルシェーダサンプルxps.1.1// v0.rgb = diffuse color // v0.a = fresnel reflection ratiotex t0 // .rgb = ベーステクスチャtex t2 // .rgb = 環境マップ // .a = 環境マップの付加輝度tex t3 // shadow map
// v0 = v0 * shadowmap + ambmad v0.rgb, v0, PSR_SHADOW, c[PSC_AMB]
// base.rgb = base * diffuse// env.rgb = env * specularxmma t0.rgb, t2.rgb, r1.rgb, t0, v0, t2, c[PSC_SPEC]
lrp r0.rgb, v0.a, t2, t0+mul r0.a, v0.a, t2.a // αには付加輝度(反射率*環境マップ α)を出力
// さらに光源を加算(適当な調整)mad_x2 r0.rgb, r0.a, t2, r0 // 環境マップ描画時は _x2 は無効
// フォグブレンド後さらに調整xfc FOG.a, r0, FOG.rgb, PROD, t2, r0.a, r0.a
半透明素材は α 値に注意 不透明度としての α値をそのまま出力する
と、意図せず高い輝度になってしまう 半透明素材では αチャネルを書き込み禁止に 半透明でかつ環境マッピングの必要な素材
重要でない場合は αチャネルには書き込まない ⇒HDRをあきらめる
環境マップから計算した α値を別パスで出力 マルチパス描画の負荷とのトレードオフ
グレア 眼やカメラ内部で発生する虚像
レンズ内での光の散乱 光の回折
グレアとなる光は極一部 実質的に強い光でしか確認できない
眩しさを感じる要因の一つ
グレアの生成手法 ジオメトリ情報から生成
遮蔽チェックが必要(かつ確実ではない) 直接光にしか適用できない(反射光を抽出できない) 光源の数に比例して負荷が増大 個々のグレアは高画質
ポストプロセスで生成 アルゴリズムは非常に単純(遮蔽チェック等が不要) 反射光にも適用可能(キラキラ輝く水面/車のボディ) グレアの形状を任意に生成可能 光源数やシーンの複雑さに依存しない
ただし固定の塗りつぶし負荷が極めて高い 元画像のエイリアシングの影響をもろに受ける
ポストプロセスによる生成 画素の輝度に応じた虚像を生成する
RGB値と α値を乗じた値を実際の明るさとみなす(適当)
抽出した輝度を適当な形状に加工 解像度を落とすとエイリアシングが発生 200x150程度が限界?
元のバッファに加算 抽出した輝度は残像として利用
グレア形状の生成 ピクセルシェーダでブラー画像を生成 クロスや六角形のスターを生成
n=1 から任意回数ループ(ピンポンブラー) n回目は n-1回目のレンダリングターゲットをテクスチャに使用 直線上に適当な間隔( 4^n に比例した距離)でサンプリングして加算
1回毎に4テクスチャステージ使用可能 離れる程輝度を低く
例:輝度 = 0.9^(4^n * d)n = 描画パス (0 ~ 任意数 )d = 近い順に 0,1,2,3 (各テクスチャステージに対応)
カラーの変更でスペクトルの分離現象を表現可能⇒1回でサンプリング間隔の 4倍の長さに成長
さらに任意形状にループ( 2 / 4 / 6方向 etc. ) 総計でおよそ 10回以上の描画パスが必要
輝度付きテクスチャ 発光体マテリアルの表現
ベーステクスチャの αチャネルに輝度情報を埋め込む
描画時に αチャネルに出力 α 値が高い程シェーディングの影響を少なくα値が高い=カラーが圧縮されていることを意味するため
⇒グレアフィルタによって自動的に輝く 電球/ネオン/夜のビルの窓/灯り etc. 環境マップにも反映される⇒水面/車のボディに映り込んだネオンが輝く
グレア処理
元画像 元画像 α値
生成したグレア
最終画像 最終画像
元画像+
=
動的環境マップのミップマップ 動的環境マップのミップマップ生成は重要 フレネルによりエッジ部の反射率が高い⇒エイリアシングが目立つ
光沢の低い鏡面反射の近似 ミップマップの最大レベルを制限
D3DTSS_MIPMAPLODBIAS ではなく D3DTSS_MAXMIPLEVEL
多くの場合バイアスよりも良い近似となる
ミップマップ生成 各レベルへのレンダリングで生成
16*16程度まで生成 バイリニアサンプルによるボックスフィ
ルタ エイリアシングが目立ちやすい
特に、光沢の近似として適正レベルより小さいマップが使われている時
本来のミップマップ生成フィルタとしては正しいはずだが…
フィルタを変更
オリジナル環境マップ256*256
ボックスフィルタ16*16エイリアスが目立つ
理想的なブラー16*16
127と 128の座標のピクセルは、最低解像度まで縮小されて初めて相互に影響する
⇒フィルタを変更
複数のテクスチャステージからジッタリングしてサンプリング
水面の表現 水面シミュレーション
メガデモ等で知られる簡易シミュレーションt1(x,y) を時間 t-1 の水面の高さt2(x,y) を時間 t-2 の水面の高さとした時時間 t の水面の高さ t(x,y) は
t(x,y) = ( ( t1(x-1,y) + t1(x+1,y) + t1(x,y-1) + t1(x,y+1) ) * 0.5 – t2(x,y) ) * attn
ハイトフィールド(高低マップ)を更新 (オフセット)バンプ環境マッピング
ハイトフィールドから法線マップを作成 平面反射環境マップから法線に従って uv をオフ
セット いわゆる EMBM による近似
ピクセル単位フレネル項/スペキュラ-を追加
オフセット環境マッピング(1) 反射ベクトルの変化の近似としては雑
近くのオブジェクトの映りこみに対しては有効 ほとんどの人は気付かない 他に有効な(実用的な)手段がない
遠くの背景では誤差が大きい しかし通常の背景ではあまり気にならない 太陽などの強いライトの映りこみ(ハイライト)では誤差が目立つ
キューブ/スフィア環境マップは適正が逆 無限遠を前提とした近似
遠くの背景の映りこみには極めて有効 近くのオブジェクトの映りこみには使いものにならない
⇒全体的にはオフセット環境マップが有効 太陽光のみバンプスペキュラ-を追加
オフセット環境マッピング(2)
オフセット環境マップ
スペキュラ-追加
グレアを切って判りやすくした画像
水面シミュレーション 2パスでハイトフィールドテクスチャを更新
1. w(x,y) = ( ( t1(x-1,y) + t1(x+1,y) + t1(x,y-1) + t1(x,y+1) ) * 0.52. t(x,y) = ( w(x,y) – t2(x,y) ) * 0.98
w(x,y) = ( ( t1(x-1,y) + t1(x+1,y) + t1(x,y-1) + t1(x,y+1) ) * 0.5
// 上下左右の前フレーム高低を加算して半分化xps.1.1
def c0, 0.0f, 0.0f, 0.0f, 0.5f// スケールバイアスdef c1, 0.5f, 0.5f, 0.5f, 0.5f// t0, t1 weightdef c2, 0.5f, 0.5f, 0.5f, 0.5f// t2, t3 weight
tex t0 // 1フレーム前(上)tex t1 // 1フレーム前(下)tex t2 // 1フレーム前(左)tex t3 // 1フレーム前(右)
// 上下左右のフレームを加算して半分化// ただし 0 ~ 1 を -1 ~ 1 に変換してから処理//add_d2 r0, t0_bx2, t1_bx2//add_d2 r1, t2_bx2, t3_bx2xmma DISCARD, DISCARD, r0, t0_bx2, c1, t1_bx2, c1.axmma DISCARD, DISCARD, r1, t2_bx2, c2, t3_bx2, c2.a
// 加算した後にレンジを 0~ 1 に戻すadd r0, r0, r1mad r0, r0, c0.a, c0.a
t(x,y) = ( w(x,y) – t2(x,y) ) * 0.98
// 生成したワークサーフェスと2フレーム前の高低マップを使用xps.1.1
def c0, 0.0f, 0.0f, 0.0f, 0.49f // 減衰 * 0.5fdef c1, 0.0f, 0.0f, 0.0f, 0.5f// スケールバイアス
tex t0 // w(x,y)tex t1 // ht2(x,y) 2フレーム前
// ワークから2フレーム前を減算// ただし 0 ~ 1 を -1 ~ 1 に変換してから処理sub r0, t0_bx2, t1_bx2
// 全体をスケールさせて減衰// その後レンジを 0~ 1 に戻す// r0 = r0 * 減衰 * 0.5f + 0.5fmad r0, r0, c0.a, c1.a
DISCARD は出力の破棄
法線マップの生成 上下左右の高低差から生成
rg ( Nx,Ny)要素から b ( Nz)を計算(正規化を近似) オフセットバンプマップにしか使わず、かつ法線マップを
ミップマップ化しないなら正規化は不要
// (nx, ny, nz) = (r, g, b)xps.1.1
#define R_MASK c0#define G_MASK c1#define B_MASK c2
def c0, 1.0f, 0.0f, 0.0f, 0.0fdef c1, 0.0f, 1.0f, 0.0f, 0.0fdef c2, 0.0f, 0.0f, 1.0f, 0.0f
def c3, 0.5f, 0.5f, 0.5f, 0.5f // スケール/バイアス
tex t0 // 高低マップ上ジッタtex t1 // 高低マップ下ジッタtex t2 // 高低マップ左ジッタtex t3 // 高低マップ右ジッタ
// 上下左右の高低差を取得sub_x2 r0.rgb, t2.a, t3.a // 左-右 nx(r) ソース+sub_x2 r0.a, t0.a, t1.a // 上-下 ny(g) ソース
// 正規化 nz = 1 - sqrt(1 - nx^2 - ny^2) を近似// r1.rgb = r0.rgb ^ 2 + r0.a ^ 2xmma DISCARD.rgb, DISCARD.rgb, r1.rgb, r0.rgb, r0.rgb, r0.a, r0.a
// r1.rgb = 1 – r1.rgb = 1 - (r0.rgb ^ 2 + r0.a ^ 2)mad r1.rgb, -r1, r1, 1-ZERO
// nx, ny, nz を r, g, b にセットxmma DISCARD.rgb, DISCARD.rgb, r0.rgb, r0.rgb, R_MASK, r0.a, G_MASKmad r0.rgb, r1, B_MASK, r0
// スケール/バイアスmad r0.rgb, r0, c3.a, c3.a
ミップマップ化 平面反射環境マップ
視点を水面に対して鏡面反射させてレンダリングした画像 バイリニアによるボックスフィルタでレンダリング
光沢フィルタとして利用しないため単純なボックスフィルタでOK
速度に影響するならミップマップなしでも許容レベル 多少ノイズが発生する
法線マップ(ミップマップは必須) 単純なボックスフィルタでは生成できない 各レベル毎に正規化が必要
1レベル小さくなる毎に隣の法線(テクセル値)との距離が 2倍になることを考慮すべき?
ダブル・スティールでは適当に見栄えのする値で rg(Nx,Ny) をスケーリングした後、正規化(の近似)で b(Nz) を再計算
バンプ環境マッピング 同次射影( q!=1.0 )テクスチャで反射環
境マップをスクリーン座標にマッピング テクスチャ uv を法線マップを元にオフ
セット texbem はテクスチャ座標の同次除算と同時に
利用できない オフセットした uv の置換マップを利用
256*256程度で許容範囲 あまり大きくなるとフィルレートに影響
置換マップ オフセットした uv座標の置換マップを作成
スクリーン系の uv座標にピクセルシェーダでオフセット オフセットしたスクリーン系 uv値を gb に出力
水面レンダリング時 スクリーンにマッピングした同次射影 uv から依存フェッチ
( texreg2gb ) オフセットされた環境マップにアクセス
置換マップの ar 要素が余るので利用 フレネル反射率
置換マップ作成時に、キューブマップで正規化した視線ベクトルと法線マップとの内積から計算して a 要素に出力
スペキュラ用 H・N 置換マップ作成時に、キューブマップで正規化したハーフアング
ルベクトル (L+E)/|L+E|と法線マップ (N) との内積を r 要素に出力 水面レンダリング時に texreg2ar でn乗値に変換
水面描画テクスチャ
最終画像uv 置換マップr: スペキュラ-N・H
a: フレネル反射率
g,b: オフセット済み u,v
ハイトマップ
法線マップr,g,b : N(x,y,z) * 0.5 + 0.5
水面描画ピクセルシェーダ// 水面バンプ平面反射マップシェーダ// αには光源度(反射率*環境マップ α)を出力xps.1.1
tex t0 // base texturetex t1 // .gb = remap GB texture
// .a = Fresnel reflect term// .r = H.N
texreg2gb t2, t1 // remap offset reflect env maptexreg2ar t3, t1 // .rgb = Specular (H.N)^n
// r0.rgb = base.rgb = diffuse// t2.rgb = env.rgb = env * specularxmma r0.rgb, t2.rgb, DISCARD.rgb, t0, v0, t2, c[PSC_SPEC]
// bump specular を加算// t3.rgb = bump specularmad t2.rgb, c[PSC_LIGHT0], t3, t2+mad t2.a, c[PSC_LIGHT0].a, t3.b, t2.a
// reflectionlrp r0.rgb, t1.a, t2, r0+mul r0.a, t1.a, t2.a // αには光源度(反射率*環境マップ α)を出力
// さらに光源を加算mad_x2 r0.rgb, r0.a, t2, r0 // 環境マップ描画時は _x2 は無効
xfc FOG.a, r0, FOG.rgb, PROD, t2, r0.a, r0.a
被写界深度( DOF )処理 マルチサンプリング処理は非現実的
焦点から離れる程ぼやけさせることができれば充分な効果を得られる
デプスバッファを利用 ピクセル単位にデプス値を読み、焦点からの距離を元に、スクリーン上でのぼやけ量を計算
元画像とブラー処理した画像を、ぼやけ量に従ってブレンド
ブラー画像の生成は4テクスチャステージでフィルタリング
ぼやけ量の計算はピクセル毎には少し複雑 焦点距離やカメラの絞り情報から計算
デプス値からテーブル参照 デプス値から直接ぼやけ量をルックアップ 一次元テクスチャを利用
wバッファなら 256段階のテーブルで充分 ニアクリップがある程度遠いならzの方が精度が良
い フレーム毎に 256要素(視点からの距離)のぼや
け量を計算して一次元テクスチャにセット デプスフォーマット D24S8 を A8R8G8B8 とし
てピクセル単位にサンプリング( α部分にデプス値の上位 8ビットがロードされる)
依存フェッチ (texreg2ar) でぼやけ量テーブルから再サンプリング
⇒ぼやけ量(0~1)を取得
ぼやけ量からブレンド (1) 元画像とブラーをかけた画像の 2枚の合
成では、中間部分の画質が劣化する Xbox ではテクスチャを4ステージ利用
可能 デプスバッファ/ルックアップテーブル
で既に2ステージ使用⇒残り2ステージで、ブラー画像を2枚まで利用可能 元画像と合わせて計3枚のブレンド
ぼやけ量からブレンド (2) ブラー画像のサイズはかなり小さめでも問題ない
ダブル・スティールでは 256*192, 160*120 ブラー画像の重みが100%になるとエイリアスが目立つ
⇒どれだけぼやけた状態でも元の画像を少し混ぜておく ぼやけ量からカラー/ブレンド用 αの計算
r=0→ .a = 0.0.rgb = ブラー画像1(結果には影響しない)
r=0.5→ .a = 1.0 より少し小さい値.rgb = ブラー画像1
r=1.0→ .a = 1.0 より微妙に小さい値.rgb = ブラー画像2に画像1を少し合成
r = ぼやけ量( 0.0~ 1.0 )
被写界深度ピクセルシェーダxps.1.1
def c0, 0.0f, 0.0f, 0.0f, 0.15f // (0.9f - 0.75f)def c1, 0.0f, 0.0f, 0.0f, 0.75f
tex t0 // t0.a : wバッファtexreg2ar t1, t0 // t1.a : ブラー量tex t2 // t2 : ブラーテクスチャ1tex t3 // t3 : ブラーテクスチャ2
mad_d2 r0.rgb, t1_bx2.a, c0.a, c1.a+mov r0.a, t1.a
mul r1.rgb, t1_bx2.a, c1.a+xmmc_x2 DISCARD.a, DISCARD.a, r0.a, t1.a, c1.a, 1-ZERO, r0.b
// 出力 αに従って元画像と αブレンディングされるxfc r1.b, t3, t2, ZERO, ZERO, ZERO, r0.a
被写界深度処理情報w値元画像へのブレンド結果
w値 -> ぼやけ量変換テーブル
ブラー画像2 (160*120)
ブラー画像1 (256*192)
元画像
被写界深度処理画像
元画像 被写界深度処理後 ぼやけ量情報
被写界深度処理済み画像 (1)
被写界深度処理済み画像 (2)
縮小バッファ サイズの大きな半透明パーティクルに利用
小さなフレームバッファにレンダリングすることで高速化
何故? 塗りつぶし負荷が大変高くなったため
ポイントスプライト(加算系)が数千から一万個以上 グレア/DOF等の塗りつぶしが10から20回以上 マップ上のオブジェクトでオーバードローが多く発生
加えてサイズの大きな半透明パーティクルが最大数百枚 半透明描画はハードウェアによるzオクルージョンカリン
グが効きにくい
⇒フィルレートが足りない
縮小バッファの実装 半透明パーティクル以外をフレームバッファに描画 フレームバッファを縮小
DOFブラー時の縮小画像を流用できる (160*120) デプスバッファを縮小 ( 同サイズに ) 半透明パーティクルを描画 元のフレームバッファに半透明合成 160*120 ならパーティクル描画自体は約 16倍高速
デプスバッファ縮小と元バッファへの合成が追加コスト パーティクルの塗りつぶし面積が一画面よりも遥かに多い時に意義がある
縮小バッファのカラー/ α 値 フレームバッファへのブレンドは縮小
バッファの各ピクセル単位の α値を使用 パーティクルの濃度によって不透明度を変
化させる パーティクルの薄い部分をフレームバッファに戻すとエイリアスで致命的
濃度の高い部分は少々解像度が低くても気づきにくい
パーティクル描画時にカラー/ α値を適切な値に操作する
パーティクル描画時の操作概要 ポイント
パーティクルの α値が高い程、縮小バッファの α値も高くなる
α値はパーティクルが重なる程高くなる α 値は決して減少しない
⇒縮小バッファの dstα はパーティクル srcα に従って 1.0 に近づくのが理想 それを満たしていれば、正確さはあまり重要
ではない
パーティクル描画のブレンド αブレンドファクタ
D3DRS_SRCBLEND = D3DBLEND_ONED3DRS_DESTBLEND = 3DBLEND_INVSRCALPHA カラーは半透明合成が理想 カラーと αで異なるブレンドファクタは使用できない⇒カラーはピクセルシェーダ内で α 乗算しておく
カラー値はフレームバッファへの合成でさらにαブレンドされる
結果的に元のアルゴリズムよりもパーティクルが薄くなる
⇒縮小バッファ描画時の α 値を変化させておく α=1-(1-α)^2 で近似?
フォグブレンドの問題 ピクセルシェーダ内での α乗算はフォ
グブレンド後に行われるべき フォグが加算されて明るくなってしまう フォグファクタ(濃度)を取得できるのは
ファイナルコンバイナ(最終ステージの後)のみ
フォグブレンド後は乗算を実行できない
⇒フォグファクタを頂点シェーダ内で計算すれば良い
パーティクル描画シェーダxps.1.1
// v0 // diffuse color// v1 // amb/emisive/other ligts color
tex t0 // base texturetexcoord t1 // .a = FOG.atex t3 // shadow/light map
// v0 = v0 * shadow/light map + v1mad v0.rgb, v0, PSR_SHADOW, v1
// r0.rgba = base * diffusemul r0, v0, t0
// α 値のカーブを変化mul r0.a, 1-r0.a, 1-r0.a // α=1-r0.a
// フォグブレンドの後でソース αによる乗算を行う必要がある// r0 = FOG.a * r0 + (1-FOG.a) * FOG.rgblrp r0.rgb, t1.a, r0, FOG.rgb
xfc 1-ZERO, PROD, ZERO, ZERO, r0.rgb, 1-r0.a, 1-r0.a
縮小バッファパーティクル
上のシーンでは、毎フレーム500枚を超える半透明パーティクルと、数千個の加算系の小さなパーティクル(爆発中央部)を描画している
縮小バッファを利用しているのは半透明パーティクルのみ
縮小バッファの評価 カラー値は比較的良好な結果
縮小バッファはマルチタップフィルタでエイリアスを軽減できる
エイリアスはあまり目立たない パーティクルエフェクト程度なら許容範囲
デプスバッファのエイリアスが目立つ ピクセルシェーダで何とかできないか?
他の半透明ポリゴンと干渉すると破綻 奥から手前へ正しい順序で描画できないため
縮小バッファのエラーエッジのエイリアス半透明との干渉による破綻⇒フロントガラスの後ろの煙が描画されていない
ポストプロセス画像フィルタ カメラを通した画像の表現
コントラストの強調(露光オーバー) ジッタリングによるエッジのぼかし
プロジェクタ風 RGB分離
イラスト調 エッジ抽出 淡い色使いの表現
カメラを通した画像の表現 (1)xps.1.1
// c0.rgb : グレアの強さdef c2, 0.5f, 0.5f, 0.5f, 0.0f
// c2.rgb : フェードアウトカラー// c2.a : フェードアウト率def c2, 0.0f, 0.0f, 0.0f, 0.0f
// c3.rgb : カラー変調用def c3, 1.0f, 1.0f, 1.0f, 1.0f// c4.rgb : グレイスケール化係数def c4, 0.30f, 0.59f, 0.11f, 0.0f
def c5, 0.0f, 0.0f, 0.0f, 0.5fdef c6, 0.0f, 0.0f, 0.0f, 0.333333333f
tex t0 // カレントフレームtex t1 // カレントフレームtex t2 // カレントフレームtex t3 // グレアテクスチャ
// カレントフレームを平滑化
lrp r0, c5.a, t1, t2
lrp r0, c6.a, t0, r0
// グレア加算
mad r0, t3, c0, r0
// 輝度取得
dp3 r1, r0, c4
// 輝度強調
mul_x2 v0, r0, r0
// 輝度に従って元絵と合成
lrp r0, r1, r0, v0
// カラー変調
mul_x2 r0, r0, c3
// 変調後フェード処理
xfc c2.a, c2, r0, ZERO, ZERO, ZERO, r0.a
t0~ t2 のテクスチャ座標は左右にジッタリングしている
カメラを通した画像の表現 (2)
プロジェクタ風(RGB分離)
xps.1.1
// c0.rgb : グレアの強さ
// c2.rgb : フェードアウトカラー// c2.a : フェードアウト率def c2, 0.0f, 0.0f, 0.0f, 0.0f
def c5, 1.0f, 0.0f, 0.0f, 0.0f // R マスクdef c6, 0.0f, 1.0f, 0.0f, 0.0f // G マスクdef c7, 0.0f, 0.0f, 1.0f, 0.0f // B マスク
tex t0 // カレントフレーム (R 用ジッタ付き )tex t1 // カレントフレーム (G 用ジッタ付き )tex t2 // カレントフレーム (B 用ジッタ付き )tex t3 // グレアテクスチャ
// RGB マスク付き加算xmma DISCARD.rgb, DISCARD.rgb, r0.rgb, t0, c5, t1, c6mad r0.rgb, t2, c7, r0
// グレアを加算mad r0, t3, c0, r0
// c3 による変調後フェードxfc c2.a, c2, r0, ZERO, r0, c3, r0.a
エッジ抽出 上下左右の輝度差(絶対値)の合計 サンプルではグレイスケール化して
から輝度差を抽出するものが多い 輝度の近い異なる2色の差を抽出できな
い 緑とマゼンタのような補色でも
エッジ抽出が目的ならグレイスケールは不要
もっと単純にRGB全ての差を抽出 RGB差分の内積で近似可能
t0 にジッタリングされた(例えば上下)画像の差分が入っている場合
差の絶対値の合計 = t0.r*t0.r + t0.g*t0.g + t0.b*t0.b
⇒dp3 r0, t0, t0
グレイスケール化
エッジを抽出できない
エッジ抽出/イラスト調
エッジ抽出シェーダxps.1.1
tex t0 // カレントフレーム(上)tex t1 // カレントフレーム(下)tex t2 // カレントフレーム(左)tex t3 // カレントフレーム(右)
// R/G/B 各輝度差を取得sub_x2 r0, t0, t1sub_x2 r1, t2, t3
// それぞれの輝度差を二乗して絶対値の近似を取得// dp3_x4 r0, r0, r0// dp3_x4 r1, r1, r1xdd_x4 r0, r1, r0, r0, r1, r1
// 1 - 全ての輝度差 で白地に黒エッジsub r0, 1-r0, r1 // 1 - r0 - r1
イラスト調xps.1.1
def c2, 0.0f, 0.0f, 0.0f, 0.0fdef c3, 0.0f, 0.0f, 0.0f, 0.5fdef c4, 0.30f, 0.59f, 0.11f, 0.0fdef c7, 0.0f, 0.0f, 0.5f, 0.75f
tex t0 // カレントフレーム(上)tex t1 // カレントフレーム(下)tex t2 // カレントフレーム(左)tex t3 // カレントフレーム(右)
// R/G/B 各輝度差を取得sub_x2 r0, t0, t1sub_x2 r1, t2, t3
// それぞれの輝度差を二乗して絶対値の近似を取得xdd_x4 r0, r1, r0, r0, r1, r1
// 1 - 全ての輝度差 で白地に黒エッジsub r0, 1-r0, r1 // 1 - r0 - r1
// 淡いカラー化dp3_x4 t1, t0, c4lrp t1.a, c7.b, 1-ZERO, t1.alrp t0, c7.a, t0, t1.amul_x2 r0, r0_bx2, t0
xfc c2.a, c2, PROD, ZERO, r0, r0, r0.a
イラスト調元画像のブラーフィルタによって違ったイメージ(タッチ感)に
ご質問は?