====== std.matrix — Matrizen und Transformationen ====== ''import std.matrix;'' Feste Matrizen und Vektoren in ''f64'': ''Vec3'', ''Vec4'', ''Mat3'', ''Mat4'' — mit allem, was eine Transformationskette braucht: Verschieben, Drehen, Skalieren, Invertieren, Kameramatrix und Projektion. → [[lyx_-_programmiersprache:units|Zurück zur Unit-Übersicht]] · [[lyx_-_programmiersprache:units:coordinates|std.coordinates]] · [[lyx_-_programmiersprache:units:quat|std.quat]] · [[lyx_-_programmiersprache:units:linalg|std.linalg]] **Quelle:** ''std/matrix.lyx'' ---- ===== 1. Speicherordnung ===== **Row-major.** Das Feld ''mRC'' ist Zeile R, Spalte C — ''m01'' steht also in Zeile 0, Spalte 1. Ein Vektor wird als **Spalte rechts** multipliziert: var v2: Vec4 := Mat4MulVec4(m, v); // v' = M · v **Wer die Matrix an OpenGL weiterreicht, transponiert vorher** (''Mat4Transpose'') oder übergibt sie mit gesetztem ''transpose''-Flag — GL erwartet column-major. Das ist der Fehler, der ein Bild kippt, ohne dass eine Meldung erscheint. Aus derselben Ordnung folgt die Reihenfolge beim Verketten: ''Mat4Mul(A, B)'' wendet **erst B, dann A** an — wie in der Mathematik. ---- ===== 2. Vec3 und Vec4 ===== ^ Bereich ^ Funktionen ^ | Bauen | ''Vec3New'', ''Vec3Zero'', ''Vec3One'', ''Vec3UnitX/Y/Z'', ''Vec4New'', ''Vec4Zero'' | | Rechnen | ''Vec3Add'', ''Vec3Sub'', ''Vec3Neg'', ''Vec3Scale'', ''Vec3MulComp'', ''Vec3Dot'', ''Vec3Cross'' (Vec4 entsprechend) | | Länge | ''Vec3Length'', ''Vec3LengthSq'', ''Vec3Normalize'', ''Vec3Distance'', ''Vec3DistanceSq'' | | Mischen | ''Vec3Lerp'', ''Vec3Reflect'', ''Vec3Equals(a, b, eps)'' | | 3 ↔ 4 | ''Vec4FromPoint'' (w = 1), ''Vec4FromDirection'' (w = 0), ''Vec4XYZ'' | **''Vec4FromPoint'' und ''Vec4FromDirection'' sind nicht dasselbe.** Ein **Punkt** trägt ''w = 1'' und wird von einer Verschiebung mitgenommen; eine **Richtung** trägt ''w = 0'' und bleibt davon unberührt. Wer eine Normale als Punkt transformiert, verschiebt sie mit — und bekommt eine Beleuchtung, die sich mit der Kamera bewegt. Dafür gibt es auch die fertigen Wege ''Mat4MulPoint3'' und ''Mat4MulDir3''. ---- ===== 3. Mat3 ===== ^ Bereich ^ Funktionen ^ | Bauen | ''Mat3New'', ''Mat3Zero'', ''Mat3Identity'', ''Mat3FromRows'', ''Mat3FromCols'' | | Zugriff | ''Mat3Row(m, i)'', ''Mat3Col(m, j)'' | | Rechnen | ''Mat3Add'', ''Mat3Sub'', ''Mat3Scale'', ''Mat3Mul'', ''Mat3MulVec3'', ''Mat3Transpose'', ''Mat3Trace'', ''Mat3Det'' | | Invertieren | ''Mat3Inverse(m): Mat3Inv'' | | 2D-Transformationen | ''Mat3Translate2D'', ''Mat3Scale2D'', ''Mat3Rotate2D'' | Die 2D-Funktionen nutzen ''Mat3'' als **homogene** 3×3-Matrix — der übliche Weg, eine Verschiebung in der Ebene als Matrix zu führen. ---- ===== 4. Mat4 ===== ^ Bereich ^ Funktionen ^ | Bauen | ''Mat4Identity'', ''Mat4Zero'', ''Mat4FromRows'', ''Mat4FromCols'', ''Mat3ToMat4'', ''Mat4ToMat3'' | | Rechnen | ''Mat4Add'', ''Mat4Sub'', ''Mat4ScaleBy'', ''Mat4Mul'', ''Mat4Transpose'', ''Mat4Trace'', ''Mat4Det'' | | Anwenden | ''Mat4MulVec4'', ''Mat4MulPoint3'', ''Mat4MulDir3'', ''Mat4ProjectPoint3'' | | Invertieren | ''Mat4Inverse(m): Mat4Inv'' | | Transformationen | ''Mat4Translate'', ''Mat4ScaleXYZ'', ''Mat4RotateX/Y/Z'', ''Mat4RotateAxis'' | | Kamera und Projektion | ''Mat4LookAt'', ''Mat4Perspective'', ''Mat4Ortho'', ''Mat4Frustum'' | ---- ===== 5. Ergebnisse, die scheitern können ===== pub type Mat4Inv = struct { ok: bool; m: Mat4; } pub type Mat3Inv = struct { ok: bool; m: Mat3; } pub type Vec3Result = struct { ok: bool; v: Vec3; } **Eine singuläre Matrix hat keine Inverse, und eine perspektivische Teilung durch ''w = 0'' kein Ergebnis.** Beides liefert deshalb ein Struct mit ''ok''-Feld statt einer Zahl, die nach Ergebnis aussieht: var inv: Mat4Inv := Mat4Inverse(m); if (inv.ok) { /* inv.m benutzen */ } Betroffen sind ''Mat3Inverse'', ''Mat4Inverse'', ''Vec4PerspectiveDivide'' und ''Mat4ProjectPoint3''. ''MatEpsilon()'' liefert die Schranke, ab der eine Determinante als null gilt — dieselbe, die ''…Equals(a, b, eps)'' als Vorgabe nimmt. ---- ===== 6. Beispiel ===== unit main; import std.matrix; import std.io; import std.string; fn main(): int64 { // erst drehen, dann verschieben var m: Mat4 := Mat4Mul(Mat4Translate(Vec3New(1.0, 2.0, 3.0)), Mat4RotateZ(1.5707963268)); var p: Vec3 := Mat4MulPoint3(m, Vec3New(1.0, 0.0, 0.0)); PrintLn(StrConcat("Punkt: ", StrConcat(FloatToStr(p.x, 3), StrConcat(" ", StrConcat(FloatToStr(p.y, 3), StrConcat(" ", FloatToStr(p.z, 3))))))); var inv: Mat4Inv := Mat4Inverse(m); PrintLn(StrConcat("invertierbar: ", BoolToStr(inv.ok))); return 0; } Punkt: 1.000 3.000 3.000 invertierbar: true ---- ===== 7. Warum der Quelltext umständlich aussieht ===== Die Unit trägt sechzehn **benannte** ''f64''-Felder statt eines Arrays und schreibt ''0.0 - x'' statt ''-x''. Das war kein Stil, sondern Notwehr gegen drei Compilerdefekte: ^ Issue ^ Was nicht ging ^ Stand ^ | [[https://github.com/SEOLizer/LyX-Compiler/issues/1496|#1496]] | negatives Literal als Operand (''x * -2.0'') | **behoben**, nachgemessen mit 1.2.2D | | [[https://github.com/SEOLizer/LyX-Compiler/issues/1499|#1499]] | ''f64''-''con'' als Operand (''x * PI'') | **behoben** | | [[https://github.com/SEOLizer/LyX-Compiler/issues/1498|#1498]] | Strukturfeld ''[N]f64'' rechnete ganzzahlig | **behoben** | Alle drei sind inzwischen erledigt — die Umgehungen im Quelltext sind damit historisch, nicht mehr nötig. Für Anwender ändert sich nichts: die API war davon nie betroffen. ---- ===== 8. Abgrenzung ===== ^ Aufgabe ^ Unit ^ | Feste 3×3/4×4-Matrizen, Grafik-Transformationen | **std.matrix** | | Vektoren ohne Matrizen | [[lyx_-_programmiersprache:units:coordinates:vec3|std.coordinates.vec3]] | | Drehungen ohne Gimbal Lock, Interpolation | [[lyx_-_programmiersprache:units:quat|std.quat]] | | Beliebig große Matrizen, Gleichungssysteme | [[lyx_-_programmiersprache:units:linalg|std.linalg]] | Letzte Aktualisierung: 2026-09-06 — Seite neu angelegt; erhoben aus ''std/matrix.lyx'', Beispiel gegen lyxc 1.2.2D übersetzt und ausgeführt.