Transcript CEDEC2002.

DOUBLE-S.T.E.A.L.における
リアルタイムCG表現技法
株式会社ぶんか社ゲーム開発事業部
川瀬 正樹
[email protected]
本日の発表内容






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.
2.
3.
鏡面反射率 r の計算
鏡面反射カラー S を r で重み付け
拡散反射カラー 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
tex t0
tex t2
tex t3
//
//
//
//
v0.a = fresnel reflection ratio
.rgb = ベーステクスチャ
.rgb = 環境マップ
// .a = 環境マップの付加輝度
shadow map
// v0 = v0 * shadowmap + amb
mad v0.rgb, v0, PSR_SHADOW, c[PSC_AMB]
// base.rgb = base * diffuse
// env.rgb = env * specular
xmma 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.5
2. 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
t(x,y) = ( w(x,y) – t2(x,y) ) * 0.98
// 上下左右の前フレーム高低を加算して半分化
xps.1.1
// 生成したワークサーフェスと2フレーム前の高低マップを使用
xps.1.1
def c0, 0.0f, 0.0f, 0.0f, 0.5f
def c1, 0.5f, 0.5f, 0.5f, 0.5f
def c2, 0.5f, 0.5f, 0.5f, 0.5f
def c0, 0.0f, 0.0f, 0.0f, 0.49f
def c1, 0.0f, 0.0f, 0.0f, 0.5f
tex
tex
tex
tex
t0
t1
t2
t3
// スケールバイアス
// t0, t1 weight
// t2, t3 weight
// 1フレーム前(上)
// 1フレーム前(下)
// 1フレーム前(左)
// 1フレーム前(右)
// 上下左右のフレームを加算して半分化
// ただし 0 ~ 1 を -1 ~ 1 に変換してから処理
//add_d2 r0, t0_bx2, t1_bx2
//add_d2 r1, t2_bx2, t3_bx2
xmma DISCARD, DISCARD, r0, t0_bx2, c1, t1_bx2, c1.a
xmma DISCARD, DISCARD, r1, t2_bx2, c2, t3_bx2, c2.a
// 加算した後にレンジを 0~1 に戻す
add r0, r0, r1
mad r0, r0, c0.a, c0.a
// 減衰 * 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.5f
mad r0, r0, c0.a, c1.a
DISCARD は出力の破棄

法線マップの生成
上下左右の高低差から生成



rg(Nx,Ny)要素からb(Nz)を計算(正規化を近似)
オフセットバンプマップにしか使わず、かつ法線マップをミッ
プマップ化しないなら正規化は不要
// (nx, ny, nz) = (r, g, b)
xps.1.1
#define R_MASK
#define G_MASK
#define B_MASK
c0
c1
c2
def c0, 1.0f, 0.0f, 0.0f, 0.0f
def c1, 0.0f, 1.0f, 0.0f, 0.0f
def c2, 0.0f, 0.0f, 1.0f, 0.0f
def c3, 0.5f, 0.5f, 0.5f, 0.5f // スケール/バイアス
tex
tex
tex
tex
t0
t1
t2
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 ^ 2
xmma 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_MASK
mad 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
tex t1
//
//
//
//
texreg2gb t2, t1 //
texreg2ar t3, t1 //
base texture
.gb = remap GB texture
.a = Fresnel reflect term
.r = H.N
remap offset reflect env map
.rgb = Specular (H.N)^n
// r0.rgb = base.rgb = diffuse
// t2.rgb = env.rgb = env * specular
xmma r0.rgb, t2.rgb, DISCARD.rgb, t0, v0, t2, c[PSC_SPEC]
// bump specular を加算
// t3.rgb = bump specular
mad t2.rgb, c[PSC_LIGHT0], t3, t2
+mad t2.a, c[PSC_LIGHT0].a, t3.b, t2.a
// reflection
lrp 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%になるとエイリアスが目立つ
⇒どれだけぼやけた状態でも元の画像を少し混ぜておく


ぼやけ量からカラー/ブレンド用αの計算
.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)

r=0→
被写界深度ピクセルシェーダ
xps.1.1
def c0, 0.0f, 0.0f, 0.0f, 0.15f
def c1, 0.0f, 0.0f, 0.0f, 0.75f
// (0.9f - 0.75f)
tex t0
texreg2ar t1, t0
tex t2
tex t3
//
//
//
//
t0.a : wバッファ
t1.a : ブラー量
t2 : ブラーテクスチャ1
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値->ぼやけ量変換テーブル
ブラー画像1(256*192)
ブラー画像2
(160*120)
被写界深度処理画像
元画像
被写界深度処理後
ぼやけ量情報
被写界深度処理済み画像(1)
被写界深度処理済み画像(2)
縮小バッファ

サイズの大きな半透明パーティクルに利用


小さなフレームバッファにレンダリングすることで高速化
何故?

塗りつぶし負荷が大変高くなったため




ポイントスプライト(加算系)が数千から一万個以上
グレア/DOF等の塗りつぶしが10から20回以上
マップ上のオブジェクトでオーバードローが多く発生
加えてサイズの大きな半透明パーティクルが最大数百枚

半透明描画はハードウェアによるzオクルージョンカリングが
効きにくい
⇒フィルレートが足りない
縮小バッファの実装


半透明パーティクル以外をフレームバッファに描画
フレームバッファを縮小





DOFブラー時の縮小画像を流用できる(160*120)
デプスバッファを縮小(同サイズに)
半透明パーティクルを描画
元のフレームバッファに半透明合成
160*120ならパーティクル描画自体は約16倍高速


デプスバッファ縮小と元バッファへの合成が追加コスト
パーティクルの塗りつぶし面積が一画面よりも遥かに多
い時に意義がある
縮小バッファのカラー/α値

フレームバッファへのブレンドは縮小バッ
ファの各ピクセル単位のα値を使用

パーティクルの濃度によって不透明度を変化
させる



パーティクルの薄い部分をフレームバッファに戻す
とエイリアスで致命的
濃度の高い部分は少々解像度が低くても気づきにく
い
パーティクル描画時にカラー/α値を適切な値
に操作する
パーティクル描画時の操作概要

ポイント


パーティクルのα値が高い程、縮小バッファのα値
も高くなる
α値はパーティクルが重なる程高くなる

α値は決して減少しない
⇒縮小バッファの dstα はパーティクル srcα に
従って1.0に近づくのが理想

それを満たしていれば、正確さはあまり重要では
ない
パーティクル描画のブレンド

αブレンドファクタ
D3DRS_SRCBLEND = D3DBLEND_ONE
D3DRS_DESTBLEND = 3DBLEND_INVSRCALPHA
 カラーは半透明合成が理想
 カラーとαで異なるブレンドファクタは使用できない
⇒カラーはピクセルシェーダ内でα乗算しておく

カラー値はフレームバッファへの合成でさらにαブレ
ンドされる
結果的に元のアルゴリズムよりもパーティクルが薄くなる
⇒縮小バッファ描画時のα値を変化させておく


α=1-(1-α)^2 で近似?
フォグブレンドの問題

ピクセルシェーダ内でのα乗算はフォグブレ
ンド後に行われるべき


フォグが加算されて明るくなってしまう
フォグファクタ(濃度)を取得できるのはファイナ
ルコンバイナ(最終ステージの後)のみ

フォグブレンド後は乗算を実行できない
⇒フォグファクタを頂点シェーダ内で計算すれ
ば良い
パーティクル描画シェーダ
xps.1.1
// v0 // diffuse color
// v1 // amb/emisive/other ligts color
tex t0
texcoord t1
tex t3
// base texture
// .a = FOG.a
// shadow/light map
// v0 = v0 * shadow/light map + v1
mad v0.rgb, v0, PSR_SHADOW, v1
// r0.rgba = base * diffuse
mul r0, v0, t0
// α値のカーブを変化
mul r0.a, 1-r0.a, 1-r0.a
// α=1-r0.a
// フォグブレンドの後でソースαによる乗算を行う必要がある
// r0 = FOG.a * r0 + (1-FOG.a) * FOG.rgb
lrp 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
lrp r0, c5.a, t1, t2
// c0.rgb : グレアの強さ
def c2, 0.5f, 0.5f, 0.5f, 0.0f
lrp r0, c6.a, t0, r0
// グレア加算
// c2.rgb : フェードアウトカラー
// c2.a : フェードアウト率
def c2, 0.0f, 0.0f, 0.0f, 0.0f
mad r0, t3, c0, r0
// c3.rgb : カラー変調用
def c3, 1.0f, 1.0f, 1.0f, 1.0f
// c4.rgb : グレイスケール化係数
def c4, 0.30f, 0.59f, 0.11f, 0.0f
dp3 r1, r0, c4
def c5, 0.0f, 0.0f, 0.0f, 0.5f
def c6, 0.0f, 0.0f, 0.0f, 0.333333333f
tex
tex
tex
tex
t0
t1
t2
t3
// カレントフレーム
// カレントフレーム
// カレントフレーム
// グレアテクスチャ
// 輝度取得
// 輝度強調
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
def c6, 0.0f, 1.0f, 0.0f, 0.0f
def c7, 0.0f, 0.0f, 1.0f, 0.0f
tex
tex
tex
tex
t0
t1
t2
t3
//
//
//
//
// R マスク
// G マスク
// B マスク
カレントフレーム(R 用ジッタ付き)
カレントフレーム(G 用ジッタ付き)
カレントフレーム(B 用ジッタ付き)
グレアテクスチャ
// RGB マスク付き加算
xmma DISCARD.rgb, DISCARD.rgb, r0.rgb, t0, c5, t1, c6
mad 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
xps.1.1
def
def
def
def
c2,
c3,
c4,
c7,
0.0f, 0.0f, 0.0f, 0.0f
0.0f, 0.0f, 0.0f, 0.5f
0.30f, 0.59f, 0.11f, 0.0f
0.0f, 0.0f, 0.5f, 0.75f
tex
tex
tex
tex
t0
t1
t2
t3
// カレントフレーム(上)
// カレントフレーム(下)
// カレントフレーム(左)
// カレントフレーム(右)
tex
tex
tex
tex
t0
t1
t2
t3
//
//
//
//
カレントフレーム(上)
カレントフレーム(下)
カレントフレーム(左)
カレントフレーム(右)
// R/G/B 各輝度差を取得
sub_x2 r0, t0, t1
sub_x2 r1, t2, t3
// それぞれの輝度差を二乗して絶対値の近似を取得
// dp3_x4 r0, r0, r0
// dp3_x4 r1, r1, r1
xdd_x4 r0, r1, r0, r0, r1, r1
// 1 - 全ての輝度差 で白地に黒エッジ
sub r0, 1-r0, r1 // 1 - r0 - r1
// R/G/B 各輝度差を取得
sub_x2 r0, t0, t1
sub_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, c4
lrp t1.a, c7.b, 1-ZERO, t1.a
lrp t0, c7.a, t0, t1.a
mul_x2 r0, r0_bx2, t0
xfc c2.a, c2, PROD, ZERO, r0, r0, r0.a
イラスト調
元画像のブラーフィルタによって
違ったイメージ(タッチ感)に
ご質問は?
?
[email protected]