Direct3D 11 和 2D:HLSL 中的乘法矩阵向量未给出正确结果

Direct3D 11 and 2D: multiplication matrix-vector in HLSL does not give the correct result

我仍在努力改进我的 Direct3D 11 二维测试程序,没有任何额外的库(参见 )。

现在,我要做的是旋转 window 的内容(客户)区域。 GDI 部分正在工作,但不是 D3D 部分。函数 d3d_resize() 接受一个名为 rot 的参数,根据它的值(0、1、2 或 3),我想旋转客户区。

现在,我关注 rot == 0,即没有旋转。

我使用常量缓冲区来存储旋转矩阵,定义(数学)如下:

|r11 r12 t1|
|r21 r22 t2|

其中子矩阵(r)是旋转部分,子向量(t)是平移

所以对于rot == 0,矩阵基本上就是单位矩阵+没有平移。如果 (x,y) 是我的 2D 向量,我将其扩展为 1 以考虑平移,因此:

|1 0 0|   |x|   |x|
|0 1 0| * |y| = |y|
          |1|

也就是说,如果rot == 0,我想要的。我的旋转C部分是:

typedef struct
{
    float rotation[2][3]; /* rotation + translation */
    float dummy[2]; /* for 16 bytes padding */
} Const_Buffer;

void d3d_resize(D3d *d3d, int rot, UINT width, UINT height)
{
    /* snip */

    switch (rot)
    {
        case 0:
            ((Const_Buffer *)mapped.pData)->rotation[0][0] = 1.0f;
            ((Const_Buffer *)mapped.pData)->rotation[0][1] = 0.0f;
            ((Const_Buffer *)mapped.pData)->rotation[0][2] = 0.0f;
            ((Const_Buffer *)mapped.pData)->rotation[1][0] = 0.0f;
            ((Const_Buffer *)mapped.pData)->rotation[1][1] = 1.0f;
            ((Const_Buffer *)mapped.pData)->rotation[1][2] = 0.0f;
            break;
        case 1:
            ((Const_Buffer *)mapped.pData)->rotation[0][0] = 0.0f;
            ((Const_Buffer *)mapped.pData)->rotation[0][1] = -1.0f;
            ((Const_Buffer *)mapped.pData)->rotation[0][2] = 2.0f;
            ((Const_Buffer *)mapped.pData)->rotation[1][0] = 1.0f;
            ((Const_Buffer *)mapped.pData)->rotation[1][1] = 0.0f;
            ((Const_Buffer *)mapped.pData)->rotation[1][2] = 0.0f;
            break;
        case 2:
            ((Const_Buffer *)mapped.pData)->rotation[0][0] = -1.0f;
            ((Const_Buffer *)mapped.pData)->rotation[0][1] = 0.0f;
            ((Const_Buffer *)mapped.pData)->rotation[0][2] = 0.0f;
            ((Const_Buffer *)mapped.pData)->rotation[1][0] = 0.0f;
            ((Const_Buffer *)mapped.pData)->rotation[1][1] = -1.0f;
            ((Const_Buffer *)mapped.pData)->rotation[1][2] = 0.0f;
            break;
        case 3:
            ((Const_Buffer *)mapped.pData)->rotation[0][0] = 0.0f;
            ((Const_Buffer *)mapped.pData)->rotation[0][1] = 1.0f;
            ((Const_Buffer *)mapped.pData)->rotation[0][2] = 0.0f;
            ((Const_Buffer *)mapped.pData)->rotation[1][0] = -1.0f;
            ((Const_Buffer *)mapped.pData)->rotation[1][1] = 0.0f;
            ((Const_Buffer *)mapped.pData)->rotation[1][2] = 2.0f;
            break;
    }

    /* snip */
}

顶点着色器是:

cbuffer cv_viewport : register(b0)
{
    float2x3 rotation_matrix;
}

struct vs_input
{
    float2 position : POSITION;
    float4 color : COLOR;
};

struct ps_input
{
    float4 position : SV_POSITION;
    float4 color : COLOR;
};

ps_input main_vs(vs_input input )
{
    ps_input output;
    float2 p = input.position;
    p = mul(rotation_matrix, float3(input.position, 1.0f));
    output.position = float4(p, 0.0f, 1.0f);
    output.color = input.color;
    return output;
}

我使用 Visual Studio 图形调试器检查 rot == 0 时的常量缓冲区值,它们看起来是正确的。

但是当 rot == 0 时,黄色三角形和蓝色矩形不显示。如果我在着色器中注释乘法完成的行,它们就会显示。我做错了什么,但我不知道是什么地方。在 link 下面找到完整的 C 代码 + 我的 github 中的着色器代码(它太大而无法内联发布)

C代码:https://github.com/vtorri/d3d_rot/blob/master/d3d_rot.c

着色器代码:https://github.com/vtorri/d3d_rot/blob/master/shader_3.hlsl

没有mul的截图:

屏幕截图与 mul:

所以,实际上,问题是在 C 代码中使用矩阵填充常量缓冲区,并在着色器中为矩阵指定行布局(参见 https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-variable-syntax

解决方案:

C 代码中的常量缓冲区:

float rotation[2][4];

着色器中的常量缓冲区:

row_major float2x3 rotation_matrix;

现在,它正在运行:-)