====== 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.