日別アーカイブ: 2007年10月9日

Direct3D 10 ShaderModel 4.0 で整数アクセス2、異なる View を活用

前回書いた整数テクスチャの扱いに関して少々追加です。
レンダリングで更新する時は整数処理を行いますが、デバッグなどで
画面に描画する時は RenderTarget の 0.0~1.0 に変換する必要があると
下記エントリで書きました。
Direct3D 10 ShaderModel 4.0 で整数の世界
これを DirectX10(D3D10) の機能を使って自動化できます。

まずリソースの作成を DXGI_FORMAT_R8G8B8A8_UINT ではなく、
DXGI_FORMAT_R8G8B8A8_TYPELESS で宣言しておきます。
初期データの渡し方などは同じです。

D3D10_TEXTURE2D_DESC  t2ddesc;
t2ddesc.Format= DXGI_FORMAT_R8G8B8A8_TYPELESS;
  ~
ID3D10Texture2D*  riTexture2D= NULL;
iDevice->CreateTexture2D( &t2ddesc, &initdata, &riTexture2D );

その後、同じリソースから ShaderResourceView を 2個作成します。
こちらは型を明確にして UINT と UNORM にします。

// ShaderResourceView の作成
D3D10_SHADER_RESOURCE_VIEW_DESC	srvdesc;
srvdesc.Format= DXGI_FORMAT_R8G8B8A8_UINT; // 整数アクセス
srvdesc.ViewDimension= D3D10_SRV_DIMENSION_TEXTURE2D;
srvdesc.Texture2D.MostDetailedMip= 0;
srvdesc.Texture2D.MipLevels= 1;
iDevice->CreateShaderResourceView( riTexture2D, &srvdesc,
	iResourceViewUINT );

srvdesc.Format= DXGI_FORMAT_R8G8B8A8_UNORM; // 固定少数化
srvdesc.ViewDimension= D3D10_SRV_DIMENSION_TEXTURE2D;
iDevice->CreateShaderResourceView( riTexture2D, &srvdesc,
	iResourceViewUNORM );

これでシェーダーからは、iResourceViewUINT 経由でアクセスすると
0~255 の整数値として読み込むことができ、iResourceViewUNORM で
アクセスすると、従来どおり 0~1.0 の少数値で受け取ることが
できるようになります。

例えばシェーダー側では次のように宣言しておきます。

Texture2D	InputTextureUI;
Texture2D	InputTextureF;

エフェクトの変数設定はこんな感じで。

iEffect->GetVariableByName( "InputTextureUI" )->AsShaderResource()->
	SetResource( iTextureBufferUINT );
iEffect->GetVariableByName( "InputTextureF" )->AsShaderResource()->
	SetResource( iTextureBufferUNORM );

受け取るシェーダー側です。

// PixelShader で整数としてアクセスする場合 (0~255)
float4 PS_Update( noperspective float4 Pos : SV_POSITION,
        noperspective float2 UV : TEXCOORD ) : SV_Target
{
    float2  pixsize;
    InputTexture.GetDimensions( pixsize.x, pixsize.y );
    uint2   uvpos= (uint2)( UV.xy * pixsize.xy );
    return  InputTextureUI.Load( uint3(uvpos.xy,0) )* (1.0f/255.0f);
}

// 浮動少数で受け取れるので乗算が不要 (0~1.0)
float4 PS_View( noperspective float4 Pos : SV_POSITION,
        noperspective float2 UV : TEXCOORD ) : SV_Target
{
    float2  pixsize;
    InputTexture.GetDimensions( pixsize.x, pixsize.y );
    uint2   uvpos= (uint2)( UV.xy * pixsize.xy );
    return  InputTextureF.Load( uint3(uvpos.xy,0) );
}

便利です。さすがに良く考えられています。

注意点は、以前のエントリ で書いたように同一のリソースを複数の View
として設定するため、リソースが握られたままになって衝突が
おきやすいことです。
Direct3D 10 HLSL Effect/FX リソース設定のはまり

上記の PixelShader では、UV を 0.0~1.0 に補間した値で受け取って
いるためテクスチャのサイズを乗算する処理が入っています。