0
votes

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.

1
So what values are in the instance buffer on the GPU (check it using PIX)? Also, is the mesh being rendered correctly? You say its being rendered in green and in PIX is black? Can you post some screenshots?Tiago Costa

1 Answers

0
votes

Better late then never I guess, in case someone else stumbles upon this issue. Changing BuildInstanceBuffer 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;

    m_D3DDevice->CreateBuffer(&ibd, NULL, &m_InstanceBuffer);
    D3DXMATRIX* pMatrices = NULL;
    m_InstanceBuffer->Map( D3D10_MAP_WRITE_DISCARD, NULL, ( void** )&pMatrices );
    memcpy( pMatrices, m_instanceData->data(), m_instanceData->size() * sizeof( D3DXMATRIX ) );
    m_InstanceBuffer->Unmap();
}

Basically, piece of cake from there on.