A.R*_*.R. 3 c++ directx directx-11
我是Direct3D 11的新手,我在理解如何基于每个对象更新常量(和其他缓冲区)方面遇到了一些麻烦.我在一些简单的代码,我试图让两个四边形绘制到屏幕,但在不同的位置.这是我用来绘制它们的代码.
// ------------------------------------------------------------------------------------------------------------------------------
void QuadShape::UpdateBuffers(ID3D11DeviceContext* pContext)
{
// We need to know about our verts + set the constant buffers...
// NOTE: We only really need to do this when the buffer data actually changes...
XMMATRIX translate = XMMatrixTranspose(XMMatrixTranslation(X, Y, 0));
XMStoreFloat4x4(&ConstData.World, translate);
D3D11_MAPPED_SUBRESOURCE mappedResource;
ZeroMemory(&mappedResource, sizeof(D3D11_MAPPED_SUBRESOURCE));
pContext->Map(ConstBuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
memcpy(mappedResource.pData, &ConstData, sizeof(ObjectConstBuffer));
pContext->Unmap(ConstBuf, 0);
}
// ------------------------------------------------------------------------------------------------------------------------------
void QuadShape::Draw(ID3D11DeviceContext* pContext)
{
UpdateBuffers(pContext);
pContext->DrawIndexed(_VertCount, _StartVert, 0);
}
Run Code Online (Sandbox Code Playgroud)
您可以看到我正在根据对象的当前X/Y位置计算转换矩阵,并将其映射到对象的常量缓冲区,表示为"ConstBuf".我遇到的问题来自于这样一个事实:即使我已经验证了为每个四元组计算的矩阵确实不同,并且缓冲区确实是动态的,所有四边形结尾都被绘制在同一位置.
我猜测正在发生的事情是,映射的资源只是被最后一个矩阵所覆盖,但我认为MAP_WRITE_DISCARD应该避免这种情况.我很困惑,我怎样才能为每个对象使用不同的常量缓冲区,让它们显示在不同的位置?
您应该按更新频率对常量缓冲区进行分组,因此如果您有一些每个对象更改的数据,请将其放在一个常量缓冲区中.如果您有其他数据 - 如投影矩阵 - 仅在调整窗口大小时才会更改,请将其放在另一个常量缓冲区中.
因此,例如,定义两个这样的缓冲区,如下所示:
struct CBPerObject
{
XMMATRIX mWorld; // world matrix
};
struct CBChangeOnResize
{
XMMATRIX mProjection; // projection matrix
};
Run Code Online (Sandbox Code Playgroud)
然后创建常量缓冲区并在成员变量中保留对它们的引用:
CComPtr<ID3D11Buffer> m_pCBPerObject; // dx11 constant buffer (per object)
CComPtr<ID3D11Buffer> m_pCBChangeOnResize; // dx11 constant buffer (change on resize)
Run Code Online (Sandbox Code Playgroud)
创建代码(为清晰起见,省略了错误处理):
// create the constant buffers
D3D11_BUFFER_DESC pBuffDesc;
ZeroMemory(&pBuffDesc, sizeof(pBuffDesc));
pBuffDesc.Usage = D3D11_USAGE_DEFAULT;
pBuffDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
pBuffDesc.CPUAccessFlags = 0;
// per object changes
pBuffDesc.ByteWidth = sizeof(CBPerObject);
m_pDevice->CreateBuffer(&pBuffDesc, nullptr, &m_pCBPerObject);
// on resize changes
pBuffDesc.ByteWidth = sizeof(CBChangeOnResize);
m_pDevice->CreateBuffer(&pBuffDesc, nullptr, &m_pCBChangeOnResize);
Run Code Online (Sandbox Code Playgroud)
现在你可以在初始化期间将它们绑定一次(假设布局不会改变):
// constant buffers never change in shaders
pContext->VSSetConstantBuffers(0, 1, &m_pCBPerObject.p);
pContext->VSSetConstantBuffers(1, 1, &m_pCBChangeOnResize.p);
Run Code Online (Sandbox Code Playgroud)
您可能还需要绑定到像素着色器,而是使用PSSetConstantBuffers.
现在,您只需要在需要时更新常量缓冲区.例如,调整窗口大小时:
void CMyClass::OnSize()
{
// update projection matrix
CBChangeOnResize cbBuffer;
// calculate the projection matrix - for example:
XMMATRIX mProjection = XMMatrixOrthographicOffCenterLH(fLeft, fRight, fBottom,
fTop, 0.1f, 1000.0f);
cbBuffer.mProjection = XMMatrixTranspose(mProjection);
// update the constant buffer
pContext->UpdateSubresource(m_pCBChangeOnResize, 0, nullptr, &cbBuffer, 0, 0);
}
Run Code Online (Sandbox Code Playgroud)
同样,在绘图时,更新每个对象的世界矩阵:
void CMyClass::DrawScene()
{
// draw the complete scene
CBPerObject cbBuffer;
// ... clear render target etc.
// for each object ...
{
cbBuffer.mWorld = XMLoadFloat4x4(pObject->GetWorld());
// update cb and draw object
pContext->UpdateSubresource(m_pCBPerObject, 0, nullptr, &cbBuffer, 0, 0);
pContext->DrawIndexed(6, 0, 0);
}
// ... etc.
}
Run Code Online (Sandbox Code Playgroud)
因此,除非布局发生更改,否则无需重新绑定常量缓冲区,您可以使用UpdateSubresource而不是上面显示的Map/ Unmap.
在顶点(像素)着色器中,根据它们绑定的槽来定义常量缓冲区:
cbuffer cbPerObject : register (b0)
{
matrix mWorld;
};
cbuffer cbChangeOnResize : register (b1)
{
matrix mProjection;
};
Run Code Online (Sandbox Code Playgroud)
在语法中:register (b0)和register (b1)的b0和b1指供给到第一个参数VSSetConstantBuffers.