前回StructuredBufferを作ったが、これを利用して今回は複数インスタンスを同時に描画してみる。
同一Bone(CacheVertexBuffer)
今までWorldMatrixは32BitConstBufferで渡していたが、StructuredBufferで複数渡せるようになったので複数インスタンス対応させてみる。
#define DefRS "RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | DENY_HULL_SHADER_ROOT_ACCESS | DENY_DOMAIN_SHADER_ROOT_ACCESS | DENY_GEOMETRY_SHADER_ROOT_ACCESS | DENY_PIXEL_SHADER_ROOT_ACCESS),DescriptorTable( SRV(t0, flags=DATA_STATIC_WHILE_SET_AT_EXECUTE),visibility=SHADER_VISIBILITY_VERTEX),RootConstants( num32BitConstants=16, b0,visibility=SHADER_VISIBILITY_VERTEX)"
StructuredBuffer<float4x4> World : register(t0) ;
struct _Cam
{
float4x4 TransPV ; // offset: 0 Size: 64
} ;
ConstantBuffer<_Cam> Cam : register(b0) ;
struct VSInput
{
float3 Pos : POSITION ;
float3 Normal : NORMAL ;
float2 UV : TEXCOORD ;
uint IID : SV_InstanceID ;
} ;
struct VSOutput
{
float4 Pos : SV_POSITION ;
} ;
[RootSignature(DefRS)]
VSOutput VSMain( VSInput In )
{
VSOutput Out ;
Out.Pos = mul( Cam.TransPV, mul( World[ In.IID ], float4( In.Pos, 1 ))) ;
return Out ;
}
VertexShaderに「uint IID : SV_InstanceID」の引数を追加し、WorldMatrixを「StructuredBuffer<float4x4>」で定義する。
WorldMatrixの参照は「World[ In.IID ]」でインスタンス別に参照位置を変える。
Bone情報はこのShader以前のパスでキャッシュしてあり、固定のMeshと同じShaderで描画できるようになっている。
すべてのキャラクタが同じ動きをしてしまうので、兵士の行進とか特殊な状況でしか使えなさそう。
個別Bone
今度は個別のアニメーションにも対応できるように、Bone自体をインスタンス分保持して描画してみる。
#define DefRS "RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | DENY_HULL_SHADER_ROOT_ACCESS | DENY_DOMAIN_SHADER_ROOT_ACCESS | DENY_GEOMETRY_SHADER_ROOT_ACCESS | DENY_PIXEL_SHADER_ROOT_ACCESS),RootConstants( num32BitConstants=1, b0,visibility=SHADER_VISIBILITY_VERTEX),DescriptorTable( SRV(t0, flags=DATA_STATIC_WHILE_SET_AT_EXECUTE),visibility=SHADER_VISIBILITY_ALL),DescriptorTable( SRV(t1, flags=DATA_STATIC_WHILE_SET_AT_EXECUTE),visibility=SHADER_VISIBILITY_VERTEX),RootConstants( num32BitConstants=16, b1,visibility=SHADER_VISIBILITY_VERTEX)"
struct _Mesh
{
uint BoneCount ;
} ;
ConstantBuffer<_Mesh> Mesh : register(b0) ;
StructuredBuffer<float4x4> Bone : register(t0) ;
StructuredBuffer<float4x4> World : register(t1) ;
struct _Cam
{
float4x4 TransPV ; // offset: 0 Size: 64
} ;
ConstantBuffer<_Cam> Cam : register(b1) ;
struct VSInput
{
float3 Pos : POSITION ;
float3 Normal : NORMAL ;
float2 UV : TEXCOORD ;
uint4 BoneID : BONE ;
float4 Weight : WEIGHT ;
uint IID : SV_InstanceID ;
} ;
struct VSOutput
{
float4 Pos : SV_POSITION ;
} ;
[RootSignature(DefRS)]
VSOutput VSMain( VSInput In )
{
VSOutput Out ;
uint ofs = Mesh.BoneCount * In.IID ;
float4x4 BoneTrans
= Bone[ In.BoneID[0] + ofs ] * In.Weight[0]
+ Bone[ In.BoneID[1] + ofs ] * In.Weight[1]
+ Bone[ In.BoneID[2] + ofs ] * In.Weight[2]
+ Bone[ In.BoneID[3] + ofs ] * In.Weight[3]
;
Out.Pos = mul( Cam.TransPV, mul( World[ In.IID ], mul( BoneTrans, float4( In.Pos, 1.0f )))) ;
return Out ;
}
「StructuredBuffer<float4x4> Bone」と「uint BoneCount」をConstBufferで追加。
Boneを参照する際、「BoneCount * InIID」でインスタンス別に参照位置を変える。
1回のDrawIndexedInstancedだけど、複数インスタンスでそれぞれ違う動きが出来るようになった。
キャッシュされたVertexBufferで1体、個別Boneで1体描画したときの時間は約174usで、それぞれ20体ずつの描画は約196usと殆ど変わらない速度で描画出来るっぽい。
![]() |
| 1体ずつの描画 |
![]() |
| 20体ずつの描画 |


0 件のコメント:
コメントを投稿