What you'll wind up doing David is creating a vertex buffer to hold the different transformation matrices for each instance of grass. You will need a vertex declaration that has your standard 'grass' vertex components( pos, norm, uv...etc ), and in that same declaration 4 additional 4-component floats to hold the 4x4 transformation matrix...the declaration will look like this:
IDirect3DVertexDeclaration9 *pVDInstances = NULL;
// create instance vertex declaration
D3DVERTEXELEMENT9 pElements[] = {
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, // position
{ 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 }, // normal
{ 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, // uv
{ 1, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 }, // 1st row transformation matrix
{ 1, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2 }, // 2nd row transformation matrix
{ 1, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3 }, // 3rd row transformation matrix
{ 1, 48, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 4 }, // 4th row transformation matrix
D3DDECL_END()// add additional data declarations before this line if you require( be sure to change the 'stride' when setting the 2nd stream source below... )
};
hr = pd3dDevice->CreateVertexDeclaration( ( D3DVERTEXELEMENT9* )&pElements, &pVDInstances );
if( FAILED( hr ) )
{
// handle failure
}
Take note of the first parameter of the D3DVERTEXELEMENT9 constructor...it is '0' for the mesh object and '1' for the transformation matrix. This is because you are going to instruct the graphics device to use 2 different vertex buffers. Also take note of the 'offset' parameters...they begin again at 0 for the 2nd vertex buffer.
Before you can render though, you must also set the frequency of transformation matrices per instance...such that for every instance of grass the graphics device will use 1 transformation matrix.
Before the draw call you will instruct the graphics device like this:
if( FAILED( hr = pd3dDevice->SetStreamSourceFreq( 1, ( D3DSTREAMSOURCE_INSTANCEDATA | 1ul ) ) ) )
{
// handle error
}
// the instance buffer holds the transformation matrices for each instance of grass
IDirect3DVertexBuffer9 *pVBInstances = pXGrassModel->GetInstanceBuffer();
// Set up the instance data stream
if( FAILED( hr = pd3dDevice->SetStreamSource( 1, pVBInstances, 0, sizeof( D3DXMATRIX ) ) ) ) // you can change this if your instance buffer holds more than a single transformation matrix
{
// handle error
}
if( FAILED( hr = pd3dDevice->SetVertexDeclaration( pVDInstances ) ) )
{
// handle error
}
// then set materials and textures as usual and draw
Here is a vertex shader for instances:
struct VS_OUTPUT_Inst
{
float4 Position : POSITION0;
float3 Normal : TEXCOORD0;
float2 UV : TEXCOORD1;
};
VS_OUTPUT_Inst InstancesPass_Vertex_Shader( float4 vPos : POSITION,
float3 vNormal : NORMAL,
float2 vUV : TEXCOORD0,
float4 vRowX : TEXCOORD1,
float4 vRowY : TEXCOORD2,
float4 vRowZ : TEXCOORD3,
float4 vRowW : TEXCOORD4 )
{
VS_OUTPUT_Inst Output = ( VS_OUTPUT_Inst )0;
float4x4 mWorld;
mWorld._m00_m01_m02_m03 = vRowX.xyzw;
mWorld._m10_m11_m12_m13 = vRowY.xyzw;
mWorld._m20_m21_m22_m23 = vRowZ.xyzw;
mWorld._m30_m31_m32_m33 = vRowW.xyzw;
float4x4 mWorldView = mul( mView, mWorld );
float4 Pos = mul( vPos, mWorld );
Pos = mul( Pos, mView );
Pos = mul( Pos, mProjection );
Output.Position = Pos;
Output.Normal = normalize( mul( vNormal, ( float3x3 )mWorldView ) );
Output.UV = vUV;
return( Output );
}
Note the Semantics used here can be traced to the semantics used in the vertex declaration above...