# 【3D矩阵】

很多意义都与2d矩阵一致,只是比2d矩阵多一个z轴。

内存里数据结构如图所示:

Markdown 图片

# 创建Matrix4x4

public Matrix4x4(Vector4 column0, Vector4 column1, Vector4 column2, Vector4 column3)
{
    this.m00 = column0.x; this.m01 = column1.x; this.m02 = column2.x; this.m03 = column3.x;
    this.m10 = column0.y; this.m11 = column1.y; this.m12 = column2.y; this.m13 = column3.y;
    this.m20 = column0.z; this.m21 = column1.z; this.m22 = column2.z; this.m23 = column3.z;
    this.m30 = column0.w; this.m31 = column1.w; this.m32 = column2.w; this.m33 = column3.w;
}

传参参考下图:

Markdown 图片

# Matrix4x4 相乘

这个操作可以进行多个矩阵的合并。

public static Matrix4x4 operator*(Matrix4x4 lhs, Matrix4x4 rhs)
{
    Matrix4x4 res;
    res.m00 = lhs.m00 * rhs.m00 + lhs.m01 * rhs.m10 + lhs.m02 * rhs.m20 + lhs.m03 * rhs.m30;
    res.m01 = lhs.m00 * rhs.m01 + lhs.m01 * rhs.m11 + lhs.m02 * rhs.m21 + lhs.m03 * rhs.m31;
    res.m02 = lhs.m00 * rhs.m02 + lhs.m01 * rhs.m12 + lhs.m02 * rhs.m22 + lhs.m03 * rhs.m32;
    res.m03 = lhs.m00 * rhs.m03 + lhs.m01 * rhs.m13 + lhs.m02 * rhs.m23 + lhs.m03 * rhs.m33;

    res.m10 = lhs.m10 * rhs.m00 + lhs.m11 * rhs.m10 + lhs.m12 * rhs.m20 + lhs.m13 * rhs.m30;
    res.m11 = lhs.m10 * rhs.m01 + lhs.m11 * rhs.m11 + lhs.m12 * rhs.m21 + lhs.m13 * rhs.m31;
    res.m12 = lhs.m10 * rhs.m02 + lhs.m11 * rhs.m12 + lhs.m12 * rhs.m22 + lhs.m13 * rhs.m32;
    res.m13 = lhs.m10 * rhs.m03 + lhs.m11 * rhs.m13 + lhs.m12 * rhs.m23 + lhs.m13 * rhs.m33;

    res.m20 = lhs.m20 * rhs.m00 + lhs.m21 * rhs.m10 + lhs.m22 * rhs.m20 + lhs.m23 * rhs.m30;
    res.m21 = lhs.m20 * rhs.m01 + lhs.m21 * rhs.m11 + lhs.m22 * rhs.m21 + lhs.m23 * rhs.m31;
    res.m22 = lhs.m20 * rhs.m02 + lhs.m21 * rhs.m12 + lhs.m22 * rhs.m22 + lhs.m23 * rhs.m32;
    res.m23 = lhs.m20 * rhs.m03 + lhs.m21 * rhs.m13 + lhs.m22 * rhs.m23 + lhs.m23 * rhs.m33;

    res.m30 = lhs.m30 * rhs.m00 + lhs.m31 * rhs.m10 + lhs.m32 * rhs.m20 + lhs.m33 * rhs.m30;
    res.m31 = lhs.m30 * rhs.m01 + lhs.m31 * rhs.m11 + lhs.m32 * rhs.m21 + lhs.m33 * rhs.m31;
    res.m32 = lhs.m30 * rhs.m02 + lhs.m31 * rhs.m12 + lhs.m32 * rhs.m22 + lhs.m33 * rhs.m32;
    res.m33 = lhs.m30 * rhs.m03 + lhs.m31 * rhs.m13 + lhs.m32 * rhs.m23 + lhs.m33 * rhs.m33;

    return res;
}

# Vector4 进行 Matrix4x4 变换

对一个Vector4进行矩阵变换操作。

public static Vector4 operator*(Matrix4x4 lhs, Vector4 vector)
{
    Vector4 res;
    res.x = lhs.m00 * vector.x + lhs.m01 * vector.y + lhs.m02 * vector.z + lhs.m03 * vector.w;
    res.y = lhs.m10 * vector.x + lhs.m11 * vector.y + lhs.m12 * vector.z + lhs.m13 * vector.w;
    res.z = lhs.m20 * vector.x + lhs.m21 * vector.y + lhs.m22 * vector.z + lhs.m23 * vector.w;
    res.w = lhs.m30 * vector.x + lhs.m31 * vector.y + lhs.m32 * vector.z + lhs.m33 * vector.w;
    return res;
}

缩放和平移如图所示:

Markdown 图片

旋转矩阵如图所示:

Markdown 图片

# 使用4x4矩阵转换坐标系示例

炮塔发射一条射线射中物体后,在物体击中位置的法线方向放置一组盒子形状的顶点。

public void testFunction()
{
    if(Physics.Raycast(headPos,transform.forward,out RaycastHit hit))
    {
        Vector3 hitPos = hit.point;
        Vector3 up = hit.normal;
        Vector3 right = Vector3.Cross(up,lookDir).normalized;
        Vector3 forward = Vector3.Cross(right,up);

        Quaternion turretRot = Quaternion.LookRotation(forward,up);
        Matrix4x4 turretToWorld = Matrix4x4.TRS(hitPos,turretRot,Vector3.one);
        Matrix4x4 worldToTurret = turretToWorld.inverse;//逆矩阵

        // 测试用盒子形状顶点数据
        Vector3[] pts = new Vector3[] {
            new Vector3(1,0,1),
            new Vector3(-1,0,1),
            new Vector3(-1,0,-1),
            new Vector3(1,0,-1),
            new Vector3(1,2,1),
            new Vector3(-1,2,1),
            new Vector3(-1,2,-1),
            new Vector3(1,2,-1)
        }
        
        Gizmos.color = Color.red;
        for(int i = 0; i < pts.Length;i++)
        {
            // 把顶点局部坐标转换成基于击中位置的世界坐标
            Vector3 worldPt = turretToWorld.MultiplyPoint3x4(pts[i]);
            Gizmos.DrawSphere(worldPt,0.075f);
        }
    }
}