2023年2月18日土曜日

DrawInstanced

前回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 件のコメント:

コメントを投稿