【问题标题】:Why is DirectX skipping every second shader call?为什么 DirectX 每隔一秒就会跳过一次着色器调用?
【发布时间】:2015-10-12 06:37:33
【问题描述】:

试图弄清楚为什么我必须调用 DirectX 11 着色器两次才能看到所需的结果时,我感到有些沮丧。

这是我目前的状态: 我有一个从顶点和索引缓冲区构建的 3d 对象。然后这个对象会被实例化几次。以后,会有更多的东西,而不仅仅是一个对象,但现在,我只用这个对象来测试它。在我的渲染例程中,我遍历所有实例,更改世界矩阵(以便将所有对象实例放在一起并形成“一个大而完整的对象”)并调用着色器方法将数据渲染到屏幕上。

这是到目前为止的代码,但不起作用:

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;
}

我的std::list 由 4 个 3d 对象组成,它们都是一样的。它们仅在 3d 空间中的位置不同。所有对象都是 8.0f x 8.0f x 8.0f,所以为了简单起见,我只是将它们排列起来。 (可以在着色器渲染线上看到,我只是在 Z 维度上添加了 8 个单位)

结果如下:我只看到屏幕上呈现了两个元素。在它们之间,有一个元素大小的空白空间。 起初,我以为我在 3d 数学上犯了一些错误,但花了很多时间调试我的代码后,我找不到任何错误。

现在是令人困惑的部分: 如果我更改 for 循环的内容并添加另一个着色器调用,我会突然看到所有四个元素;并且它们都在 3d 空间中的正确位置:

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;
}

有人知道这里发生了什么吗?

如果有帮助,这里是着色器的代码:

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);
}

如果有帮助,我也可以在此处发布着色器中的代码。

任何帮助将不胜感激 - 我完全被困在这里:-(

【问题讨论】:

    标签: c++ directx shader directx-11 hlsl


    【解决方案1】:

    问题是您每帧都在转置数据,因此每隔一帧它只是“正确”:

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

    相反,您应该这样做:

    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);
    

    【讨论】:

    • 查克,你是对的!非常感谢!!起初,我不明白为什么这突然有帮助。我认为在 Shader 方法的每次调用中对世界矩阵使用 XMMatrixTranslation(...) 会创建一个新的矩阵对象。但是视图和投影矩阵也发生了变化。我完全忘记了这两个;-)
    【解决方案2】:

    我想知道问题是否在于调用 XMMatrixTranslation(x, y, z + (i * 8)) 所创建的临时对象是通过引用传递给一个函数,然后通过引用传递给另一个函数已修改。

    我对 c++ 规范的了解不足以让我判断这是否是未定义的行为(但我知道这方面有一些棘手的规则 - 不支持将临时分配给非 const 临时,例如)。无论如何,这已经足够让人怀疑了,即使它是定义良好的 c++,它仍然可能是一个尘土飞扬的角落,可能会绊倒不兼容的编译器。

    要排除这种可能性,请尝试这样做:

    XMMatrix worldMatrix = XMMatrixTranslation(x, y, z + (i * 8));
    m_pTextureShader->Render(m_pDirect3D->GetDeviceContext(), elem->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix, elem->GetTexture());
    

    【讨论】:

      猜你喜欢
      • 2020-02-20
      • 2017-12-10
      • 2017-06-20
      • 1970-01-01
      • 1970-01-01
      • 2012-02-17
      • 1970-01-01
      • 2020-04-01
      • 1970-01-01
      相关资源
      最近更新 更多