Search code examples
c++directxshaderdirectx-11hlsl

Why is DirectX skipping every second shader call?


I get a bit frustrating trying to figure out why I have to call a DirectX 11 shader twice to see the desired result.

Here's my current state: I have a 3d object built from vertex and index buffer. This object is then instanced several times. Later, there will be a lot more than just one object, but for now, I'm testing it with this one only. In my render routine, I iterate over all instances, change the world matrices (so that all object instances are put together and form "one big, whole object") and call the shader method to render the data to the screen.

Here's the code so far, that doesn't work:

m_pLevel->Simulate(0.1f);
std::list<CLevelElementInstance*>& lst = m_pLevel->GetInstances();
float x = -(*lst.begin())->GetPosition().x, y = -(*lst.begin())->GetPosition().y, z = -(*lst.begin())->GetPosition().z;
int i = 0;
for (std::list<CLevelElementInstance*>::iterator it = lst.begin(); it != lst.end(); it++)
{
    // Extract base element from current instance
    CLevelElement* elem = (*it)->GetBaseElement();

    // Write vertex and index buffer to video memory
    elem->Render(m_pDirect3D->GetDeviceContext());

    // Call shader
    m_pTextureShader->Render(m_pDirect3D->GetDeviceContext(), elem->GetIndexCount(), XMMatrixTranslation(x, y, z + (i * 8)), viewMatrix, projectionMatrix, elem->GetTexture());
    ++i;
}

My std::list consists of 4 3d objects, which are all the same. They only differ in their position in 3d space. All of the objects are 8.0f x 8.0f x 8.0f, so for simplicity I just line them up. (As can be seen on the shader render line, where I just add 8 units to the Z dimension)

The result is the following: I only see two elements rendered on the screen. And between them, there's an empty space the size of an element. At first, I thought I did some errors with the 3d math, but after a lot of time spent debugging my code, I could not find any errors.

And here is now the confusing part: If I change the content of the for-loop and add another call to the shader, I suddenly see all four elements; and they're all on their correct positions in 3d space:

m_pLevel->Simulate(0.1f);
std::list<CLevelElementInstance*>& lst = m_pLevel->GetInstances();
float x = -(*lst.begin())->GetPosition().x, y = -(*lst.begin())->GetPosition().y, z = -(*lst.begin())->GetPosition().z;
int i = 0;
for (std::list<CLevelElementInstance*>::iterator it = lst.begin(); it != lst.end(); it++)
{
    // Extract base element from current instance
    CLevelElement* elem = (*it)->GetBaseElement();

    // Write vertex and index buffer to video memory
    elem->Render(m_pDirect3D->GetDeviceContext());

    // Call shader
    m_pTextureShader->Render(m_pDirect3D->GetDeviceContext(), elem->GetIndexCount(), XMMatrixTranslation(x, y, z + (i * 8)), viewMatrix, projectionMatrix, elem->GetTexture());

    // Call shader a second time - this seems to have no effect but to allow the next iteration to perform it's shader rendering...
    m_pTextureShader->Render(m_pDirect3D->GetDeviceContext(), elem->GetIndexCount(), XMMatrixTranslation(x, y, z + (i * 8)), viewMatrix, projectionMatrix, elem->GetTexture());
    ++i;
}

Does anybody has an idea of what is going on here?

If it helps, here's the code of the shader:

bool CTextureShader::Render(ID3D11DeviceContext* _pDeviceContext, const int _IndexCount, XMMATRIX& _pWorldMatrix, XMMATRIX& _pViewMatrix, XMMATRIX& _pProjectionMatrix, ID3D11ShaderResourceView* _pTexture)
{
    bool result = SetShaderParameters(_pDeviceContext, _pWorldMatrix, _pViewMatrix, _pProjectionMatrix, _pTexture);
    if (!result)
        return false;
    RenderShader(_pDeviceContext, _IndexCount);
    return true;
}

bool CTextureShader::SetShaderParameters(ID3D11DeviceContext* _pDeviceContext, XMMATRIX& _WorldMatrix, XMMATRIX& _ViewMatrix, XMMATRIX& _ProjectionMatrix, ID3D11ShaderResourceView* _pTexture)
{
    HRESULT result;
    D3D11_MAPPED_SUBRESOURCE mappedResource;
    MatrixBufferType* dataPtr;
    unsigned int bufferNumber;

    _WorldMatrix = XMMatrixTranspose(_WorldMatrix);
    _ViewMatrix = XMMatrixTranspose(_ViewMatrix);
    _ProjectionMatrix = XMMatrixTranspose(_ProjectionMatrix);

    result = _pDeviceContext->Map(m_pMatrixBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
    if (FAILED(result))
        return false;
    dataPtr = (MatrixBufferType*)mappedResource.pData;
    dataPtr->world = _WorldMatrix;
    dataPtr->view = _ViewMatrix;
    dataPtr->projection = _ProjectionMatrix;
    _pDeviceContext->Unmap(m_pMatrixBuffer, 0);

    bufferNumber = 0;
    _pDeviceContext->VSSetConstantBuffers(bufferNumber, 1, &m_pMatrixBuffer);
    _pDeviceContext->PSSetShaderResources(0, 1, &_pTexture);

    return true;
}

void CTextureShader::RenderShader(ID3D11DeviceContext* _pDeviceContext, const int _IndexCount)
{
    _pDeviceContext->IASetInputLayout(m_pLayout);

    _pDeviceContext->VSSetShader(m_pVertexShader, NULL, 0);
    _pDeviceContext->PSSetShader(m_pPixelShader, NULL, 0);

    _pDeviceContext->PSSetSamplers(0, 1, &m_pSampleState);

    _pDeviceContext->DrawIndexed(_IndexCount, 0, 0);
}

If it helps, I can also post the code from the shaders here.

Any help would be appreciated - I'm totally stuck here :-(


Solution

  • The problem is that you are transposing your data every frame, so it's only "right" every other frame:

    _WorldMatrix = XMMatrixTranspose(_WorldMatrix);
    _ViewMatrix = XMMatrixTranspose(_ViewMatrix);
    _ProjectionMatrix = XMMatrixTranspose(_ProjectionMatrix);
    

    Instead, you should be doing something like:

    XMMATRIX worldMatrix = XMMatrixTranspose(_WorldMatrix);
    XMMATRIX viewMatrix = XMMatrixTranspose(_ViewMatrix);
    XMMATRIX projectionMatrix = XMMatrixTranspose(_ProjectionMatrix);
    
    result = _pDeviceContext->Map(m_pMatrixBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
    if (FAILED(result))
        return false;
    dataPtr = (MatrixBufferType*)mappedResource.pData;
    dataPtr->world = worldMatrix;
    dataPtr->view = viewMatrix;
    dataPtr->projection = projectionMatrix;
    _pDeviceContext->Unmap(m_pMatrixBuffer, 0);