Blobs サンプル
このサンプルは、ピクセル シェーダーを使用して画面スペースでメタボール効果を模倣します。本当のメタボール テクニックは、押し込み修飾子または引っ張り修飾子に従ってサーフェスを変形します。通常は、水滴の結合などの液体効果をモデル化するために使用されます。メタボール効果は、多大な計算負荷を発生させます。ただし、このサンプルではピクセル シェーダーを使用して 2D 画像空間で 3D メタボール効果を実装します。
Path
ソース : | (SDK ルート)\Samples\C++\Direct3D\Blobs |
実行可能ファイル : | (SDK ルート)\Samples\C++\Direct3D\Bin\x86 or x64\Blobs.exe |
サンプルの概要
メタボール (このテクニックを考案した James Blinn の名前をとって Blinn ブロブとも呼ばれる) は、複数の "ブロブ" を 1 つに結合することで滑らかなサーフェスを簡単に作成する手段として、ほとんどのモデリング ソフトウェアに含まれています。ブロブの間に自然な流れが生じるので、液体をモデル化するパーティクル システムに特に適したテクニックです。
基本テクニックは、アイソサーフェス、つまり閉じたボリュームを定義する 3D 式に基づきます。たとえば、x2 + y2 + z2 = 1 は、原点を中心とする半径 1 の球体を表します。この考え方を任意の 3D 関数に広げます。つまり、連続関数の場合、その関数に沿う形で、任意の定数に等しいすべての点によってアイソサーフェスが表されます。個々のメタボールは、多くの場合にガウス分布によって定義された球体として実装されます。この方法では、最大値が球体の中心に存在し、任意のしきい値を超えるすべての値が球体の内部に含まれるように定義されます。このしきい値をガウスの高さから引くと、サーフィスの高さはブロブの縁でゼロとなります。サーフィスは、このしきい値に従って完全に定義されるので、重なり合う球体の値を加算して新しい球体を作成できます。図 1 は、2 つのガウス曲線を合わせた結果生成される滑らかな曲線を示しています。
図 1:ガウス曲線を合わせると滑らかなブレンディングが生成される
本当のメタボール効果では、これらの計算は 3D 空間で行われます。このサンプルでは、計算を 2D スクリーン空間で実行します。この方法を使うと、優れた視覚効果をごくわずかな計算負荷で生成できます。ただし、精度が失われることに注意してください。その理由は、背景にあるブロブとカメラに近いブロブが同じビュー ベクトルに沿って並んでいる場合、それらが結合されるからです。
サンプルが動作するしくみ
個々のブロブは、ワールド空間の座標、サイズ、およびカラーに従って記述されます。各フレームをレンダリングする前に、ブロブの位置が FrameMove で、次に FillBlobVB プロジェクトで各ブロブの画面スペースでアニメーション表示されます。それらに対応するビルボード四角形で頂点バッファーを塗りつぶします。これらのビルボードの頂点フォーマットは次のとおりです。
struct VS_OUTPUT
{
float4 vPosition : POSITION; // Screen-space position of the vertex
float2 tCurr : TEXCOORD0; // Texture coordinates for Gaussian sample
float2 tBack : TEXCOORD1; // Texture coordinates of vertex position on render target
float2 sInfo : TEXCOORD2; // Z-offset and blob size
float3 vColor : TEXCOORD3; // Blob color
};
tCurr に格納された座標は、球体を定義する 2D ガウス テクスチャーをサンプリングするために使用されます。tBack に格納された座標は、前にレンダリングしたブロブからデータをサンプリングするためと、背景テクスチャーとのブレンディングを行うために使用されます。これらの変換前の頂点は、BlobBlenderPS ピクセル シェーダーに直接渡されます。
PS_OUTPUT BlobBlenderPS( VS_OUTPUT Input )
{
PS_OUTPUT Output;
float4 weight;
// Get the new blob weight
DoLerp( Input.tCurr, weight );
// Get the old data
float4 oldsurfdata = tex2D( SurfaceBufferSampler, Input.tBack );
float4 oldmatdata = tex2D( MatrixBufferSampler, Input.tBack );
// Generate new surface data
float4 newsurfdata = float4((Input.tCurr.x-0.5) * Input.sInfo.y,
(Input.tCurr.y-0.5) * Input.sInfo.y,
0,
1);
newsurfdata *= weight.r;
// Generate new material properties
float4 newmatdata = float4(Input.vColor.r,
Input.vColor.g,
Input.vColor.b,
0);
newmatdata *= weight.r;
// Additive blending
Output.vColor[0] = newsurfdata + oldsurfdata;
Output.vColor[1] = newmatdata + oldmatdata;
return Output;
}
DoLerp ヘルパー関数は、テクスチャー フィルター処理サンプリングを実行します。浮動小数点テクスチャーのバイリニア フィルターリングは、通常グラフィック ドライバーでは実装されていません。各ブロブ ビルボードは、1 組の一時テクスチャーにレンダリングされます。蓄積されたカラー データが 1 つのテクスチャーに格納され、蓄積されたサーフェス法線データが別のテクスチャーに格納されます。
図 2:サーフェス法線バッファー 図 3:カラー バッファー
ブレンディングされた法線とカラー データは、平均サーフェス法線を基にして環境マップにサンプリングする最終的なライティング パスのために BlobLightPS ピクセル シェーダーで使用されます。
float4 BlobLightPS( VS_OUTPUT Input ) : COLOR
{
static const float aaval = THRESHOLD * 0.07f;
float4 blobdata = tex2D( SourceBlobSampler, Input.tCurr);
float4 color = tex2D( MatrixBufferSampler, Input.tCurr);
color /= blobdata.w;
float3 surfacept = float3(blobdata.x/blobdata.w,
blobdata.y/blobdata.w,
blobdata.w-THRESHOLD);
float3 thenorm = normalize(-surfacept);
thenorm.z = -thenorm.z;
float4 Output;
Output.rgb = color.rgb + texCUBE( EnvMapSampler, thenorm );
Output.rgb *= saturate ((blobdata.a - THRESHOLD)/aaval);
Output.a=1;
return Output;
}
その結果、次のイメージが最終的に合成されます。