So, I'm trying to do hardware instancing in DirectX10 with a simple shader where the vertex struct takes a position, texture coordinate and normal for the vertices and a model matrix for the instances. Problem is creating the input layout that sends data to the model matrix in the shader. Debugging with PIX shows that the matrix only gets nonsense values.
Relevant code:
Input layout
m_Tech = m_Effect->GetTechniqueByName("SimpleTech");
//Position-normal-texture vertex
D3D10_INPUT_ELEMENT_DESC posNormalTexVertexDesc[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"NORMAL", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"mTransform", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 0, D3D10_INPUT_PER_INSTANCE_DATA, 1},
{"mTransform", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_INSTANCE_DATA, 1},
{"mTransform", 2, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_INSTANCE_DATA, 1},
{"mTransform", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, D3D10_APPEND_ALIGNED_ELEMENT, D3D10_INPUT_PER_INSTANCE_DATA, 1}
};
D3D10_PASS_DESC PassDesc;
m_Effect->GetTechniqueByName("SimpleTech")->GetPassByIndex(0)->GetDesc(&PassDesc);
HR(mp_D3DDevice->CreateInputLayout(posNormalTexVertexDesc, 7, PassDesc.pIAInputSignature,
PassDesc.IAInputSignatureSize, &m_InputLayout));
Shader struct
struct VS_IN
{
float4 Pos : POSITION;
float2 TexCoord : TEXCOORD0;
float4 Normal : NORMAL;
row_major float4x4 mTransform : mTransform;
};
Buffers
void Model::BuildVertexBuffer()
{
D3D10_BUFFER_DESC vbd;
vbd.Usage = D3D10_USAGE_DEFAULT;
vbd.ByteWidth = sizeof(MeshVertex) * (UINT)m_Mesh->VertexCount();
vbd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
vbd.CPUAccessFlags = 0;
vbd.MiscFlags = 0;
D3D10_SUBRESOURCE_DATA vinitData;
vinitData.pSysMem = m_Mesh->VertexData();
m_D3DDevice->CreateBuffer(&vbd, &vinitData, &m_VertexBuffer);
}
void Model::BuildInstanceBuffer()
{
D3D10_BUFFER_DESC ibd;
ibd.Usage = D3D10_USAGE_DEFAULT;
ibd.ByteWidth = sizeof(D3DXMATRIX) * (UINT)m_instanceData->size();
ibd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
ibd.CPUAccessFlags = 0;
ibd.MiscFlags = 0;
D3D10_SUBRESOURCE_DATA vinitData;
vinitData.pSysMem = &m_instanceData[0];
m_D3DDevice->CreateBuffer(&ibd, &vinitData, &m_InstanceBuffer);
}
Draw call
void Model::Draw(Camera& camera)
{
UINT strides[2];
UINT offsets[2];
ID3D10Buffer* bufferPointers[2];
//Set buffer strides
strides[0] = sizeof(MeshVertex);
strides[1] = sizeof(D3DXMATRIX);
//Set buffer offsets
offsets[0] = 0;
offsets[1] = 0;
//Set the array of pointers to the vertex and instance buffers
bufferPointers[0] = m_VertexBuffer;
bufferPointers[1] = m_InstanceBuffer;
//Set the vertex and instance buffers to active in the input assembler so it may be rendered
m_D3DDevice->IASetVertexBuffers(0,2,bufferPointers, strides, offsets);
m_D3DDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
//Set input layout
m_D3DDevice->IASetInputLayout(m_Effect->GetLayout());
//Set
m_Effect->SetResources(camera, NULL);
D3D10_TECHNIQUE_DESC techDesc;
ID3D10EffectTechnique* tech = m_Effect->GetTech();
tech->GetDesc( &techDesc );
for(UINT i = 0; i < techDesc.Passes; ++i)
{
ID3D10EffectPass* pass = tech->GetPassByIndex(i);
pass->Apply(0);
m_D3DDevice->DrawInstanced(m_Mesh->VertexCount(), m_instanceData->size(),0,0);
}
}
m_instanceData is a vector that holds a D3DXMATRIX for each instance. Have looked at the example that comes with the SDK and our input layout seems to look the same way yet the matrix is not transferred correctly?
I'm currently just sending an identity matrix as a model matrix for testing purposes but it shows as something entirely different. I have checked so that the data is in the vector for sure once I initialize the instance buffer.
Edit1: Changed the BuildInstanceBuffer() method to
void Model::BuildInstanceBuffer()
{
D3D10_BUFFER_DESC ibd;
ibd.Usage = D3D10_USAGE_DYNAMIC;
ibd.ByteWidth = sizeof(D3DXMATRIX) * (UINT)m_instanceData->size();
ibd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
ibd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
ibd.MiscFlags = 0;
D3D10_SUBRESOURCE_DATA vinitData;
vinitData.pSysMem = &m_instanceData[0];
m_D3DDevice->CreateBuffer(&ibd, &vinitData, &m_InstanceBuffer);
D3DXMATRIX* pMatrices = NULL;
m_InstanceBuffer->Map( D3D10_MAP_WRITE_DISCARD, NULL, ( void** )&pMatrices );
memcpy( pMatrices, m_InstanceBuffer, m_instanceData->size() * sizeof( D3DXMATRIX ) );
m_InstanceBuffer->Unmap();
}
Second edit: Guess that was a bit pre-mature. Seems my model matrix in the shader is being filled "correctly", as each row gets a value at the right point. But that value is still not the one I'm passing in.
This honestly gets stranger by the minute. When I debug the program in visual studio, I get a green mesh. In PIX, it shows up in black. I could really use the help on this one, I have no idea what's going on now.