前言
说实话,我感觉这是一个大坑,不知道为什么要设计成这样混乱的形式。
在我用的时候,以row_major
矩阵,并且mul函数以向量左乘矩阵的形式来绘制时的确能够正常显示,并不会有什么感觉。但是也有人会遇到明明传的矩阵没有问题,却怎么样都绘制不出的情况;或者使用列矩阵,在mul函数用向量左乘的形式却又可以绘制出来的疑问。因此本文目的就是要扫清这些障碍。
ps. 本问题由淡一抹夕霞提供。
DirectX11 With Windows SDK完整目录
欢迎加入QQ群: 727623616 可以一起探讨DX11,以及有什么问题也可以在这里汇报。
一些线性代数基础
行主矩阵与列主矩阵
首先要了解的是,行主矩阵是这样的:
在C++传递给HLSL的字节流数据是不会发生变化的,这一点可以通过VS自带的图形调试器可以察看。
但是数据传递给HLSL后,matrix
(float4x4
)的属性决定如何去接受这些数据。
默认情况下,matrix
(float4x4
)是列矩阵,这意味着它会按列主矩阵的形式进行选取,相当于进行了一次转置。
如果想让它按行主矩阵的形式进行选取,则应当在前面加上row_major
修饰符以避免"转置"。
HLSL中的mul函数
微软的官方文档是这么描述mul函数的(微软官方文档链接),这里进行个人翻译:
使用矩阵数学来进行矩阵x左乘矩阵y的运算,要求矩阵x的列数与矩阵y的行数相等。
如果x是一个向量,那么它将被解释为行向量。
如果y是一个向量,那么它将被解释为列向量。
表面上看起来很美满,很智能,但稍有不慎就要在这里踩大坑了。
dp4指令
dp4是一个汇编指令(微软官方文档链接),使用方法如下:
dp4 dst, src0, src1
其中 src0和src1是一个向量,计算它们的点乘并将结果传给dst。
当然这里并不是要教大家怎么写汇编,而是怎么看。
为了了解mul
函数是如何进行向量与矩阵的乘法运算,我们需要探讨一下它的汇编实现。这里我所使用的是row_major
矩阵。首先是向量作为第一个参数的情况:
可以看到这种运算方式实际上却是按照向量右乘矩阵的形式进行的运算。
然后是将向量作为第二个参数的情况(仅单纯的参数交换):
无论是行向量左乘矩阵,还是列向量右乘矩阵,在汇编层面上都是用dp4
的形式进行计算,这是因为对矩阵来说在内存上是以4个行向量的形式存储的,传递一行比传递一列更简单,适合进行与列向量的运算,并且效率会更高。
但是交换两个参数却会导致运算结果/显示结果的不同,这时候就要看看矩阵所存的值了。
先看一段HLSL代码:
struct VertexPosNormalTex
{
float3 PosL : POSITION;
float3 NormalL : NORMAL;
float2 Tex : TEXCOORD;
};