簡體   English   中英

System.Numerics 矩陣乘法的完全錯誤值

[英]Completely wrong value for matrix multiplication with System.Numerics

盡管可通過 NuGet 獲得的System.Numerics.Vectors庫有自己的視圖和投影矩陣函數,但我想自己實現它,只使用向量和矩陣結構。

不幸的是,將目標向量與(正確的)視圖矩陣相乘時,我已經得到了完全錯誤的結果。 我正在使用右手坐標系和以下說明

var cameraVector4 = new Vector4(0, 4, 2, 1);
var focusVector4 = new Vector4(0, 0, 0, 1);
var vMatrix4 = LookAt(cameraVector4, focusVector4, new Vector4(0, 1.0f, 0, 0));
var targetVector4 = new Vector4(1, 0, -1, 1);
var targetViewVector4 = Vector4.Transform(targetVector4, vMatrix4);

具有以下功能

private static Matrix4x4 LookAt(Vector4 cameraVector4, Vector4 focusVector4, Vector4 upVector4) {
    if (cameraVector4 == focusVector4) return Matrix4x4.Identity;
    var z = Vector4.Normalize(cameraVector4 - focusVector4);
    var x = Vector4.Normalize(upVector4.Cross(z));
    var y = Vector4.Normalize(z.Cross(x));

    return new Matrix4x4(
        x.X, x.Y, x.Z, -Vector4.Dot(x, cameraVector4),
        y.X, y.Y, y.Z, -Vector4.Dot(y, cameraVector4),
        z.X, z.Y, z.Z, -Vector4.Dot(z, cameraVector4),
        0, 0, 0, 1);
}

public static class Vector4Extensions {
    public static Vector4 Cross(this Vector4 self, Vector4 vector4) {
        return new Vector4(
            self.Y * vector4.Z - self.Z * vector4.Y,
            self.Z * vector4.X - self.X * vector4.Z,
            self.X * vector4.Y - self.Y * vector4.X,
            0);
    }
}

在我上面的示例中,預期的視圖矩陣是

vMatrix4確實具有相同的值。 然而,將vMatrix4targetVector4相乘應該會產生<1, 0.894427, -4.91935, 1>但 Visual Studio 報告<1, -0.8944272, -0.4472136, 5.472136>

我的問題是,該庫是否存在計算結果的數值問題,是否存在數據類型不匹配,或者是否錯誤地使用Vector4.Transform期望它返回ViewMatrix * TargetVector


編輯

使用以下自定義擴展方法時

public static Vector4 ApplyMatrix(this Vector4 self, Matrix4x4 matrix) {
    return new Vector4(
        matrix.M11 * self.X + matrix.M12 * self.Y + matrix.M13 * self.Z + matrix.M14 * self.W,
        matrix.M21 * self.X + matrix.M22 * self.Y + matrix.M23 * self.Z + matrix.M24 * self.W,
        matrix.M31 * self.X + matrix.M32 * self.Y + matrix.M33 * self.Z + matrix.M34 * self.W,
        matrix.M41 * self.X + matrix.M42 * self.Y + matrix.M43 * self.Z + matrix.M44 * self.W
    );
}

調用targetVector4.ApplyMatrix(targetVector4)產生正確的結果。 這意味着Vector4.Transform在內部似乎做了一些真正出乎意料的事情。

我使用 dotPeek 反編譯了System.Numerics庫並偶然發現了這一點:

public static Vector4 Transform(Vector4 vector, Matrix4x4 matrix) {
    return
        new Vector4(
            (float)
            (vector.X * (double) matrix.M11 +
             vector.Y * (double) matrix.M21 +
             vector.Z * (double) matrix.M31 +
             vector.W * (double) matrix.M41),
            (float)
            (vector.X * (double) matrix.M12 +
             vector.Y * (double) matrix.M22 +
             vector.Z * (double) matrix.M32 +
             vector.W * (double) matrix.M42),
            (float)
            (vector.X * (double) matrix.M13 +
             vector.Y * (double) matrix.M23 +
             vector.Z * (double) matrix.M33 +
             vector.W * (double) matrix.M43),
            (float)
            (vector.X * (double) matrix.M14 +
             vector.Y * (double) matrix.M24 +
             vector.Z * (double) matrix.M34 +
             vector.W * (double) matrix.M44));
}

這種方法意味着庫將向量解釋為行向量並從右側乘以矩陣,而不是將矩陣乘以列向量左側的“通常”方式。 要解決此問題,您有兩個選擇:

  • 編寫一個自定義方法,按照您需要的順序將向量與矩陣相乘。
  • 在應用轉換之前轉置矩陣,這可能是一個輕微的開銷。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM