![]() |
Delphi-Version: XE6
Unit System.Math.Vectors
Hallo,
kennt ihr die Unit System.Math.Vectors? Ich weiß nicht, in welcher Delphi-Version sie dazugekommen ist, aber ich habe sie erst vor kurzem entdeckt. Die Unit enthält eine nette kleine Sammlung von Records mit Methoden für 2D und 3D Vektoren, Matrizen und Quaternionen. Ich wollte mich schon länger mal in die Grundlagen von 3D-Grafik einarbeiten, da kam diese Unit gerade richtig. Allerdings glaube ich ein paar Fehler in der Unit gefunden zu haben! Ich würde deshalb gerne dazu die Meinung von Leuten hören, die sich mit der Materie auskennen. Zunächst mal: Die Unit scheint sich an Microsoft DirectX / .NET zu orientieren. Zu OpenGL gibt es da kleine Unterschiede. Erster Punkt: TMatrix3D.CreateOrthoLH sowie die rechtshändige Version CreateOrthoRH haben mit ziemlicher Sicherheit einen Bug.
Delphi-Quellcode:
Im letzten Befehl wird das Matrixelement m42 befüllt, aber es müsste meiner Meinung nach m43 sein.
class function TMatrix3D.CreateOrthoLH(const AWidth, AHeight, AZNear, AZFar: Single): TMatrix3D;
begin Result := TMatrix3D.Identity; Result.m11 := 2 / AWidth; Result.m22 := 2 / AHeight; Result.m33 := 1 / (AZFar - AZNear); Result.m42 := AZNear / (AZNear - AZFar); end; ![]()
Delphi-Quellcode:
class function TMatrix3D.CreateOrthoOffCenterLH(const ALeft, ATop, ARight, ABottom, AZNear, AZFar: Single): TMatrix3D;
begin Result := TMatrix3D.Identity; Result.m11 := 2 / (ARight - ALeft); Result.m22 := 2 / (ATop - ABottom); Result.m33 := 1 / (AZFar - AZNear); Result.m41 := (ALeft + ARight) / (ALeft - ARight); Result.m42 := (ATop + ABottom) / (ABottom - ATop); Result.m43 := AZNear / (AZNear - AZFar); end; Zweiter Punkt: TMatrix3D.CreateRotationYawPitchRoll Rotationen sind etwas kompliziert, die Reihenfolge, in welcher um die drei Achsen rotiert wird, macht einen Unterschied (Matrixmultiplikation ist nicht kommutativ). ![]()
TMatrix3D.CreateRotationYawPitchRoll(Yaw, Pitch, Roll) = TMatrix3D.CreateRotationZ(Roll) * TMatrix3D.CreateRotationX(Pitch) * TMatrix3D.CreateRotationY(Yaw) oder wenn von "rechts nach links" multipliziert wird: TMatrix3D.CreateRotationYawPitchRoll(Yaw, Pitch, Roll) = TMatrix3D.CreateRotationY(Yaw) * TMatrix3D.CreateRotationX(Pitch) * TMatrix3D.CreateRotationZ(Roll) Dem ist aber nicht so! Stattdessen bekomme ich: TMatrix3D.CreateRotationYawPitchRoll(Yaw, Pitch, Roll) = TMatrix3D.CreateRotationY(Roll) * TMatrix3D.CreateRotationX(Pitch) * TMatrix3D.CreateRotationZ(-Yaw) Was ist da denn los? Die Reihenfolge stimmt (YXZ Konvention). Aber Yaw und Roll sind den falschen Achsen zugewiesen! Oder hat jemand eine andere Erklärung dafür? Testcode:
Delphi-Quellcode:
uses
System.Math.Vectors; function MatrixEqual(const M1, M2: TMatrix3D): Boolean; var i: Integer; begin Result := True; // Leider ist kein TMatrix3D.Equal Operator definiert. Also reduziere das Problem auf // TVector3D.Equal und vergleiche die Komponentenvektoren beider Matrizen for i := Low(M1.M) to High(M1.M) do Result := Result and (M1.M[i] = M2.M[i]); end; procedure RotTest; const B2S: array [Boolean] of string = ('false', 'TRUE!'); var M1, M2, M3, M4: TMatrix3D; Yaw, Pitch, Roll: Single; s: string; begin Yaw := 1.0; Pitch := 2.0; Roll := 3.0; M1 := TMatrix3D.CreateRotationYawPitchRoll(Yaw, Pitch, Roll); M2 := TMatrix3D.CreateRotationZ(Roll) * TMatrix3D.CreateRotationX(Pitch) * TMatrix3D.CreateRotationY(Yaw); M3 := TMatrix3D.CreateRotationY(Yaw) * TMatrix3D.CreateRotationX(Pitch) * TMatrix3D.CreateRotationZ(Roll); M4 := TMatrix3D.CreateRotationY(Roll) * TMatrix3D.CreateRotationX(Pitch) * TMatrix3D.CreateRotationZ(-Yaw); s := ''; s := s + 'M1 (YPR) = M2 (RzPxYy): ' + B2S[MatrixEqual(M1, M2)] + sLineBreak; s := s + 'M1 (YPR) = M3 (YyPxRz): ' + B2S[MatrixEqual(M1, M3)] + sLineBreak; s := s + 'M1 (YPR) = M4 (RyPx-Yz): ' + B2S[MatrixEqual(M1, M4)] + sLineBreak; ShowMessage(s); // Ausgabe: // M1 (YPR) = M2 (RzPxYy): false // M1 (YPR) = M3 (YyPxRz): false // M1 (YPR) = M4 (RyPx-Yz): TRUE! end; |
AW: Unit System.Math.Vectors
Zitat:
Mit meinem Wechsel zu xe7 von xe2 habe ich diese Unit auch entdeckt. Für mich ist diese Art von Vektoren und Matrizen ein guter Ansatz, aber für eine praktische Verwendung sind sie einfach nicht umfangreich genug. Das Problem ist einfach, dass es records sind und man sie nicht ableiten kann. Ich habe deshalb auf diesem Ansatz meinen eigenen Record-Vektor überarbeitet und bin sehr zufrieden damit. Wenn man Opengl oder Direct3d machen will, benötigt man aus meiner Sicht eine umfangreichere Lib wie z.B. die Vectorgeometry.pas aus dem GLScene-Projekt. Diese ist aber von der Anlage sehr veraltet. Ich habe deshalb für die Zukunft (wann immer die auch ist) in meiner Grafikengine einen Umbau auf etwas Modereres geplant. Dazu wollte ich eigentlich wieder den Ansatz von Emba übernehmen und Stück für Stück auf der Basis von der Vectorgeometry erweitern. Wenn Du nach Fehlern suchst, könntest Du Dir vielleicht die Vectorgeometry als Referenz nehmen. Die ist nach meiner Meinung gut ausgetestet. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:11 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz