铸造自定义矩阵浮动*

Casting custom Matrix to float*

本文关键字:自定义      更新时间:2023-10-16

所以我断断续续地编写自己的物理引擎已经有一段时间了,最近我开始设置DirectX渲染,而不是用OpenGL硬编码渲染。现在,在最后,我遇到了一些我无法理解的非常奇怪的行为。

为了将矩阵传递给着色器以绘制内容,可以调用一个使用const float*的函数,而执行此操作的典型方法是将D3DXMATRIX强制转换传递给float*D3DXMATRIX和强制转换运算符声明为:

typedef struct D3DXMATRIX : public D3DMATRIX
{
    ...
    operator FLOAT* ();
    operator CONST FLOAT* () const;
    ....
} D3DXMATRIX, *LPD3DMATRIX;

并且CCD_ 5被声明为:

typedef struct _D3DMATRIX {
    union {
        struct {
            float    __11, _12, _13, _14;
            float    __21, _22, _23, _24;
            float    __31, _32, _33, _34;
            float    __41, _42, _43, _44;
        };
        float m[4][4];
    };
} D3DMATRIX;

在不同的文件(D3DX10math.inl)中,这两个铸造运算符定义为:

D3DX10INLINE
D3DXMATRIX::operator FLOAT* ()
{
    return (FLOAT *) &_11;
}
D3DX10INLINE
D3DXMATRIX::operator CONST FLOAT* () const
{
    return (CONST FLOAT *) &_11;
}

CONSTFLOAT关键字在minwindef.h中定义,D3DX10INLINE在D3DX10.h中定义为:

#ifndef CONST
#define CONST const
#endif
....
typedef float FLOAT;
....
#define D3DX10INLINE __forceline

对我描述的函数的调用很简单:

D3DXMATRIX m;
foo->SetMatrix((float*)&m);

在我的整个引擎中,我一直在使用我自己的Matrix类,当我试图将它传递到上面的函数而不是D3DXMATRIX时,它会发送不正确的数据。我的Matrix类(似乎)以与D3DXMATRIX相同的方式定义,但拒绝以相同的方式工作。这是我的矩阵类(或相关部分):

class Matrix {
    public:
        ....
        operator float* ();
        operator const float* () const;
        ....
    private:
        union {
            struct {
                float _00, _01, _02, _03;
                float _10, _11, _12, _13;
                float _20, _21, _22, _23;
                float _30, _31, _32, _33;
            };
            float m[4][4];
        }
};   

功能定义为:

__forceinline
Matrix::operator float* ()
{
    return (float *) &_00;
}
__forceinline
Matrix::operator const float* () const
{
    return (const float *) &_00;
}

我已经尝试在CPP文件、头文件和类定义中定义运算符,无论是否使用inline__forceinline,但没有什么能使它工作。我想我可以将每个矩阵中的所有数据复制到D3DXMATRIX,但这会浪费大量的时间/操作,应该无关紧要。最大的问题是,我一辈子都无法弄清楚为什么一切都会这样。我不知道为什么。

为了确保数据被传递到DirectX函数中,我设置了一个测试函数,这样我就可以调试它,并查看传递的确切值:

void Test(const float *a, const float *b)
{
    bool result[16] = {false};
    float aa[16], bb[16];
    for(unsigned int i = 0; i < 16; ++i)
    {
        result[i] = a[i] == b[i];
        aa[i] = a[i];
        bb[i] = b[i];
    }
}

例如,如果我传入一个D3DXMATRIX,其中16个浮点中的每个浮点的值为1-16,作为第一个参数,其中一个矩阵的值与b相同,则aa将填充值1-16,但bb将={0.0, 1.875, 0.0, 2.0, 0.0, 2.125, 0.0, 2.5, 0.0, 2.315, 0.0, 2.375, 0.0, 2.4375, 0.0, 2.5}

所以。。。有人知道为什么这个代码会这样做吗?

您实际上使用operator float*不正确。

D3DXMATRIX m;
foo->SetMatrix((float*)&m);

在这里,您可以将m地址转换为float*。这不是调用operator float,它只是一个reinterpret_cast(编译器应该对此发出警告)。但幸运的是,D3DMATRIX不包含任何其他成员,一开始也没有填充,所以一切都正常。

如果Matrix在其_00之前包含其他数据成员,或者不是标准布局,则这种转换可能产生不确定的结果。

所以底线是,你应该做

foo->SetMatrix((float*)m);

或者只是

foo->SetMatrix(m);