在学习D3D11的时候遇到一个问题,事情是这样的:
D3D11引入了常量缓存(const buffer)用来实现数据的高速传输,这块儿buffer是CPU Only Write,GPU Only Read这样的特点,其他还是D3D9的惯例。在我调用完g_pD3DImmediateContext->Map的时候,出现了没有任何图像的问题,后经过改造后,显示终于正常了,先上代码:
// 传入shader前,确保矩阵转置,这是D3D11的要求
pMatrix->m_mxWorld = XMMatrixTranspose(pMatrix->m_mxWorld);
pMatrix->m_mxPorjection = XMMatrixTranspose(pMatrix->m_mxPorjection);
pMatrix->m_mxView = XMMatrixTranspose(pMatrix->m_mxView);
//把基本的3个3D变换矩阵放进显存去,当然对于GPU来说它是只读的,而CPU是只写的
D3D11_MAPPED_SUBRESOURCE MappedResource = {};
// 将矩阵缓冲的显存映射进来,设置矩阵数据先
HRESULT hr = g_pD3DImmediateContext->Map(g_pMatrixBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource);
CopyMemory(MappedResource.pData,pMatrix,sizeof(ST_MATRIXBUFFER));
g_pD3DImmediateContext->Unmap(g_pMatrixBuffer, 0);
g_pD3DImmediateContext->VSSetConstantBuffers(0, 1, &g_pMatrixBuffer);
可以看到,pMatrix->m_mxWorld ,pMatrix->m_mxPorjection ,pMatrix->m_mxView 三个矩阵都是在进行了转置之后才传入常量缓存的,之后画面显示正常了。为何要转置呢?经过一番打探原来事情是这个样子的:
首先我们要知道,矩阵分为行主序和列主序两种矩阵,比如:内存中使用一个二维数组m存储矩阵,第i行第j列的表示方法分别为:
行主序:m[i][j]
列主序:m[j][i]
线性代数意义的同一个矩阵,在D3D 和OpenGL 中的存储顺序:
线代:a11,a12,a13,a14
a21,a22,a23,a24
a31,a32,a33,a34
a41,a42,a43,a44
D3D : a11,a12,a13,a14
a21,a22,a23,a24
a31,a32,a33,a34
a41,a42,a43,a44
OpenGL: a11,a21,a31,a41
a12,a22,a32,a42
a13,a23,a33,a43
a14,a24,a34,a44
D3D是左手定则,OpenGL是右手定则,另外提一句,OGRE用的也是列主序,我们发现只要把行主序和列主序的行列对调就可以了,也就是转置一下就一样了,也就是说D3D和OpenGL如果想转换的话只需要转置一下就ok,那D3D11这里为什么要转置呢,因为D3D11的constant buffer里面shader读取是列主序的读取,所以想在const buffer使用的话还是要转换成列主序,或者也可以编译shader的时候调用D3D10_SHADER_PACK_MATRIX_ROW_MAJOR这个来编译,其实效果是一样的,只不过转换做在了内部,其实早在D3D11之前GPU也是一直读取列主序的矩阵的,只不过转换在D3D驱动内部进行了而已。
或者还有一种方法就是声明这个矩阵的时候直接声明为列主序的矩阵:row_major。
还有一个方法就是在shader里面mul矩阵的时候用矩阵在前,向量在后的方法也可以:
float4 transformedPosition = somePosition * someMatrix;
float4 transformedPosition = someMatrix * somePosition;
另外还要注意const buffer的desc权限 是 cpu only write &gpu only read。