TOP

ABOUT

PROGRAM

DIALY







VTFフォグ

 1.はじめに
 西川さんが書かれている3Dゲームファンのための「バーチャファイター5」グラフィックス講座の中に
"Vertex Texture Fetchingを使って,フォグを行うVTFフォグ"っていうのが気になってやってみたのですが…
う〜ん。ちゃんとできているんですかね?
サンプルの方は,SM3.0対応でないと動かないので注意してください。

※2010/06/06追記 やっぱりプログラムがおかしかったので修正しました。



 2.VTFフォグ
 西川さんが書かれている記事によると…
VTFフォグでは,「フォグマップ」と呼ばれる霧の濃淡分布が記録されているテクスチャーを用意します。Vertex Texture Fetchingでフォグマップから取り出した値で高さフォグの処理を頂点単位で実行するそうです。

…とりあえず,あっているかどうかはわかないのですが,実装は次のように行ってみました。
まずは,頂点シェーダ側の処理です。
00075:  //--------------------------------------------------------------------------------------------------
00076:  // Name : VertexShaderFunction()
00077:  // Desc : 頂点シェーダ
00078:  //--------------------------------------------------------------------------------------------------
00079:  VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
00080:  {
00081:  	VertexShaderOutput output = (VertexShaderOutput)0;
00082:  
00083:  	// 座標変換
00084:  	float4 worldPosition = mul(input.Position, World);
00085:  	float4 viewPosition = mul(worldPosition, View);
00086:  	output.Position = mul(viewPosition, Projection);
00087:  
00088:  	// TODO: add your vertex shader code here.
00089:  	output.ObjPosition = input.Position;
00090:  	output.TexCoord = input.TexCoord;
00091:  	output.Normal = input.Normal;
00092:  
00093:  	// テクスチャ座標
00094:  	float2 uv = input.TexCoord + FogTranslate;
00095:  
00096:  	// テクスチャから濃度を取り出す
00097:  	float density = tex2Dlod( FogSmp, float4( uv, 0, 0 ) ).x;
00098:  	output.Density = density * 0.75f + 0.25f;
00099:  	
00100:  	// フォグ係数算出
00101:  	output.Fog = FogCoord.x + input.Position.y * FogCoord.y;
00102:  	
00103:  	return output;
00104:  }
頂点シェーダでやっているのは,いつも通りの座標変換とフォグマップを参照して,濃度を取り出すことです。濃度を取り出したら,高さフォグでinput.Position.yと高さを基にフォグ係数を算出していた所をテクスチャから取り出した値のdensityにしています。tex2Dを使ってテクスチャを参照できればいいんですが,HLSLだとコンパイル時にエラーになるので,今回も回避策としてtex2Dproj()を使っています。
あとは,西川さんの記事に『しかも、このフォグマップをスクロールさせれば、複雑な濃淡の霧が風で流れているように見せられる。』ということが書いてあるので,とりあえずフォグマップを平行移動させるられるように,96行目でテクスチャ座標を算出する際に,FogTranslateによって,サンプルする座標値をずらして,スクロールできるようにしています。

ピクセルシェーダの処理ですが,基本的に普通のフォグとかと変わりません。オブジェクトの色とフォグの色を線形合成するだけです。
00118:  //--------------------------------------------------------------------------------------------------
00119:  // Name : PixelShaderFunction()
00120:  // Desc : ピクセルシェーダ
00121:  //--------------------------------------------------------------------------------------------------
00122:  float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
00123:  {
00124:  	// TODO: add your pixel shader code here.
00125:  	float3 N = normalize( input.Normal );
00126:  	float3 L = normalize( LightPosition - input.ObjPosition.xyz );
00127:  	float3 E = normalize( CameraPosition - input.ObjPosition.xyz );
00128:  	float3 H = normalize( L + E );
00129:  
00130:  	// ライティング
00131:  	float4 output = HalfLambert( N, L, H );
00132:  
00133:  	// テクスチャ
00134:  	output *= tex2D( DecalSmp, input.TexCoord );
00135:  
00136:  	// 濃度を考慮した色を算出
00137:  	float4 fog_color = FogColor * input.Density;
00138:  
00139:  	// フォグ色とオブジェクト色を線形合成
00140:  	output = lerp( fog_color, output, input.Fog );
00141:  
00142:  	return output;
00143:  }
一応,実装はこんな感じでやってみたんですが…。
う〜ん,最終結果が全然あってない気もする…。
今回は,フォグマップを動的に作成することをしていませんが,フォグマップを動的に作成すれば,記事中にもあるように,もやが掻き乱されるような演出など色々と凝ったことができると思います。


 Download
本ソースコードおよびプログラムを使用したことによる如何なる損害も製作者は責任を負いません。
本ソースコードおよびプログラムは自己責任でご使用ください。
プログラムの作成にはMicrosoft Visual Studio 2008 SP1 Professional, XNA Game Studio 3.0を用いています。