这可能会在过早优化下提交,但由于顶点着色器在每一帧的每个顶点上执行,这似乎是值得做的事情(在进入像素着色器之前我需要乘以很多变量)。
本质上,顶点着色器执行此操作以将向量转换为投影空间,如下所示:
// Transform the vertex position into projected space.
pos = mul(pos, model);
pos = mul(pos, view);
pos = mul(pos, projection);
output.pos = pos;
由于我正在对着色器中的多个向量执行此操作,因此将这些矩阵组合成 CPU 上的累积矩阵然后将其刷新到 GPU 进行计算是有意义的,如下所示:
// VertexShader.hlsl
cbuffer ModelViewProjectionConstantBuffer : register (b0)
{
matrix model;
matrix view;
matrix projection;
matrix cummulative;
float3 eyePosition;
};
...
// Transform the vertex position into projected space.
pos = mul(pos, cummulative);
output.pos = pos;
在 CPU 上:
// Renderer.cpp
// now is also the time to update the cummulative matrix
m_constantMatrixBufferData->cummulative =
m_constantMatrixBufferData->model *
m_constantMatrixBufferData->view *
m_constantMatrixBufferData->projection;
// NOTE: each of the above vars is an XMMATRIX
我的直觉是行优先/列优先存在一些不匹配,但是 XMMATRIX 是一个行优先结构(并且它的所有运算符都这样对待它)并且 mul(...) 将其矩阵参数解释为行-重大的。所以这似乎不是问题,但也许它仍然是我不理解的方式。
我还检查了累积矩阵的内容,它们看起来是正确的,这进一步增加了混乱。
感谢您的阅读,我将非常感谢您能给我的任何提示。
编辑(评论中要求的其他信息):这是我用作矩阵常量缓冲区的结构:
// a constant buffer that contains the 3 matrices needed to
// transform points so that they're rendered correctly
struct ModelViewProjectionConstantBuffer
{
DirectX::XMMATRIX model;
DirectX::XMMATRIX view;
DirectX::XMMATRIX projection;
DirectX::XMMATRIX cummulative;
DirectX::XMFLOAT3 eyePosition;
// and padding to make the size divisible by 16
float padding;
};
我在 CreateDeviceResources(连同我的其他常量缓冲区)中创建矩阵堆栈,如下所示:
void ModelRenderer::CreateDeviceResources()
{
Direct3DBase::CreateDeviceResources();
// Let's take this moment to create some constant buffers
... // creation of other constant buffers
// and lastly, the all mighty matrix buffer
CD3D11_BUFFER_DESC constantMatrixBufferDesc(sizeof(ModelViewProjectionConstantBuffer), D3D11_BIND_CONSTANT_BUFFER);
DX::ThrowIfFailed(
m_d3dDevice->CreateBuffer(
&constantMatrixBufferDesc,
nullptr,
&m_constantMatrixBuffer
)
);
... // and the rest of the initialization (reading in the shaders, loading assets, etc)
}
我在我创建的矩阵堆栈类中写入矩阵缓冲区。类的客户端在完成修改矩阵后调用 Update():
void MatrixStack::Update()
{
// then update the buffers
m_constantMatrixBufferData->model = model.front();
m_constantMatrixBufferData->view = view.front();
m_constantMatrixBufferData->projection = projection.front();
// NOTE: the eye position has no stack, as it's kept updated by the trackball
// now is also the time to update the cummulative matrix
m_constantMatrixBufferData->cummulative =
m_constantMatrixBufferData->model *
m_constantMatrixBufferData->view *
m_constantMatrixBufferData->projection;
// and flush
m_d3dContext->UpdateSubresource(
m_constantMatrixBuffer.Get(),
0,
NULL,
m_constantMatrixBufferData,
0,
0
);
}