#pragma once #include #include "Logging.h" #include "Mat3.h" #include "Vec3.h" namespace Framework { template //! Eine 4x4 Matrix class Mat4 { public: T elements[4][4]; //! Die Elemente der Matrix //! Kopiert alle Werte einer anderen Matrix //! \param r Die andere Matrix Mat4& operator=(const Mat4& r) { memcpy(elements, r.elements, sizeof(elements)); return *this; } //! Skalliert die Matrix //! \param r der Faktor Mat4& operator*=(const T r) { for (T& e : elements) e *= r; return *this; } //! Multipliziert die MAtrix mit einer anderen //! \param r Die andere Matrix Mat4& operator*=(const Mat4& r) { return *this = *this * r; } //! Skalliert die Matrix ohne sie zu verändern //! \param r der Faktor Mat4 operator*(const T r) const { Mat4 result = *this; return result *= r; } //! Multipliziert zwei Matrizen //! \param r Die andere Matrix Mat4 operator*(const Mat4& r) const { Mat4 result; for (int j = 0; j < 4; j++) { for (int k = 0; k < 4; k++) { T sum = 0; for (int i = 0; i < 4; i++) sum += elements[j][i] * r.elements[i][k]; result.elements[j][k] = sum; } } return result; } //! Multiplziert die Matrix mit einem Vektor //! \param r Der Vektor Vec3 operator*(const Vec3& r) const { Vec3 result; result.x = elements[0][0] * r.x + elements[0][1] * r.y + elements[0][2] * r.z + elements[0][3]; result.y = elements[1][0] * r.x + elements[1][1] * r.y + elements[1][2] * r.z + elements[1][3]; result.z = elements[2][0] * r.x + elements[2][1] * r.y + elements[2][2] * r.z + elements[2][3]; return result; } Vec3 mult0(const Vec3& r) const { Vec3 result; result.x = elements[0][0] * r.x + elements[0][1] * r.y + elements[0][2] * r.z; result.y = elements[1][0] * r.x + elements[1][1] * r.y + elements[1][2] * r.z; result.z = elements[2][0] * r.x + elements[2][1] * r.y + elements[2][2] * r.z; return result; } //! Berechnet die inverse Matrix Mat4 getInverse() const { Mat4 ret; ret.elements[0][0] = elements[1][1] * elements[2][2] * elements[3][3] - elements[1][1] * elements[2][3] * elements[3][2] - elements[2][1] * elements[1][2] * elements[3][3] + elements[2][1] * elements[1][3] * elements[3][2] + elements[3][1] * elements[1][2] * elements[2][3] - elements[3][1] * elements[1][3] * elements[2][2]; ret.elements[1][0] = -elements[1][0] * elements[2][2] * elements[3][3] + elements[1][0] * elements[2][3] * elements[3][2] + elements[2][0] * elements[1][2] * elements[3][3] - elements[2][0] * elements[1][3] * elements[3][2] - elements[3][0] * elements[1][2] * elements[2][3] + elements[3][0] * elements[1][3] * elements[2][2]; ret.elements[2][0] = elements[1][0] * elements[2][1] * elements[3][3] - elements[1][0] * elements[2][3] * elements[3][1] - elements[2][0] * elements[1][1] * elements[3][3] + elements[2][0] * elements[1][3] * elements[3][1] + elements[3][0] * elements[1][1] * elements[2][3] - elements[3][0] * elements[1][3] * elements[2][1]; ret.elements[3][0] = -elements[1][0] * elements[2][1] * elements[3][2] + elements[1][0] * elements[2][2] * elements[3][1] + elements[2][0] * elements[1][1] * elements[3][2] - elements[2][0] * elements[1][2] * elements[3][1] - elements[3][0] * elements[1][1] * elements[2][2] + elements[3][0] * elements[1][2] * elements[2][1]; ret.elements[0][1] = -elements[0][1] * elements[2][2] * elements[3][3] + elements[0][1] * elements[2][3] * elements[3][2] + elements[2][1] * elements[0][2] * elements[3][3] - elements[2][1] * elements[0][3] * elements[3][2] - elements[3][1] * elements[0][2] * elements[2][3] + elements[3][1] * elements[0][3] * elements[2][2]; ret.elements[1][1] = elements[0][0] * elements[2][2] * elements[3][3] - elements[0][0] * elements[2][3] * elements[3][2] - elements[2][0] * elements[0][2] * elements[3][3] + elements[2][0] * elements[0][3] * elements[3][2] + elements[3][0] * elements[0][2] * elements[2][3] - elements[3][0] * elements[0][3] * elements[2][2]; ret.elements[2][1] = -elements[0][0] * elements[2][1] * elements[3][3] + elements[0][0] * elements[2][3] * elements[3][1] + elements[2][0] * elements[0][1] * elements[3][3] - elements[2][0] * elements[0][3] * elements[3][1] - elements[3][0] * elements[0][1] * elements[2][3] + elements[3][0] * elements[0][3] * elements[2][1]; ret.elements[3][1] = elements[0][0] * elements[2][1] * elements[3][2] - elements[0][0] * elements[2][2] * elements[3][1] - elements[2][0] * elements[0][1] * elements[3][2] + elements[2][0] * elements[0][2] * elements[3][1] + elements[3][0] * elements[0][1] * elements[2][2] - elements[3][0] * elements[0][2] * elements[2][1]; ret.elements[0][2] = elements[0][1] * elements[1][2] * elements[3][3] - elements[0][1] * elements[1][3] * elements[3][2] - elements[1][1] * elements[0][2] * elements[3][3] + elements[1][1] * elements[0][3] * elements[3][2] + elements[3][1] * elements[0][2] * elements[1][3] - elements[3][1] * elements[0][3] * elements[1][2]; ret.elements[1][2] = -elements[0][0] * elements[1][2] * elements[3][3] + elements[0][0] * elements[1][3] * elements[3][2] + elements[1][0] * elements[0][2] * elements[3][3] - elements[1][0] * elements[0][3] * elements[3][2] - elements[3][0] * elements[0][2] * elements[1][3] + elements[3][0] * elements[0][3] * elements[1][2]; ret.elements[2][2] = elements[0][0] * elements[1][1] * elements[3][3] - elements[0][0] * elements[1][3] * elements[3][1] - elements[1][0] * elements[0][1] * elements[3][3] + elements[1][0] * elements[0][3] * elements[3][1] + elements[3][0] * elements[0][1] * elements[1][3] - elements[3][0] * elements[0][3] * elements[1][1]; ret.elements[3][2] = -elements[0][0] * elements[1][1] * elements[3][2] + elements[0][0] * elements[1][2] * elements[3][1] + elements[1][0] * elements[0][1] * elements[3][2] - elements[1][0] * elements[0][2] * elements[3][1] - elements[3][0] * elements[0][1] * elements[1][2] + elements[3][0] * elements[0][2] * elements[1][1]; ret.elements[0][3] = -elements[0][1] * elements[1][2] * elements[2][3] + elements[0][1] * elements[1][3] * elements[2][2] + elements[1][1] * elements[0][2] * elements[2][3] - elements[1][1] * elements[0][3] * elements[2][2] - elements[2][1] * elements[0][2] * elements[1][3] + elements[2][1] * elements[0][3] * elements[1][2]; ret.elements[1][3] = elements[0][0] * elements[1][2] * elements[2][3] - elements[0][0] * elements[1][3] * elements[2][2] - elements[1][0] * elements[0][2] * elements[2][3] + elements[1][0] * elements[0][3] * elements[2][2] + elements[2][0] * elements[0][2] * elements[1][3] - elements[2][0] * elements[0][3] * elements[1][2]; ret.elements[2][3] = -elements[0][0] * elements[1][1] * elements[2][3] + elements[0][0] * elements[1][3] * elements[2][1] + elements[1][0] * elements[0][1] * elements[2][3] - elements[1][0] * elements[0][3] * elements[2][1] - elements[2][0] * elements[0][1] * elements[1][3] + elements[2][0] * elements[0][3] * elements[1][1]; ret.elements[3][3] = elements[0][0] * elements[1][1] * elements[2][2] - elements[0][0] * elements[1][2] * elements[2][1] - elements[1][0] * elements[0][1] * elements[2][2] + elements[1][0] * elements[0][2] * elements[2][1] + elements[2][0] * elements[0][1] * elements[1][2] - elements[2][0] * elements[0][2] * elements[1][1]; T det = elements[0][0] * ret.elements[0][0] + elements[0][1] * ret.elements[1][0] + elements[0][2] * ret.elements[2][0] + elements[0][3] * ret.elements[3][0]; if (det == 0) { Logging::error() << "Fehler beim erstellen der Inversen Matrix"; return ret; } det = 1.0f / det; for (int i = 0; i < 16; i++) ret.elements[i / 4][i % 4] = ret.elements[i / 4][i % 4] * det; return ret; } //! Erzeugt eine Matrix, die einen Vektor um die Z Achse dreht, wenn sie //! mit ihm multipliziert wird \param radian Der Winkel in Bogenmas static Mat4 rotationZ(T radian) { const T cosTheta = (T)lowPrecisionCos(radian); const T sinTheta = (T)lowPrecisionSin(radian); Mat4 r = {cosTheta, -sinTheta, 0, 0, sinTheta, cosTheta, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; return r; } //! Erzeugt eine Matrix, die einen Vektor um die X Achse dreht, wenn sie //! mit ihm multipliziert wird \param radian Der Winkel in Bogenmas static Mat4 rotationX(T radian) { const T cosTheta = (T)lowPrecisionCos(radian); const T sinTheta = (T)lowPrecisionSin(radian); Mat4 r = {1, 0, 0, 0, 0, cosTheta, -sinTheta, 0, 0, sinTheta, cosTheta, 0, 0, 0, 0, 1}; return r; } //! Erzeugt eine Matrix, die einen Vektor um die Y Achse dreht, wenn sie //! mit ihm multipliziert wird \param radian Der Winkel in Bogenmas static Mat4 rotationY(T radian) { const T cosTheta = (T)lowPrecisionCos(radian); const T sinTheta = (T)lowPrecisionSin(radian); Mat4 r = {cosTheta, 0, sinTheta, 0, 0, 1, 0, 0, -sinTheta, 0, cosTheta, 0, 0, 0, 0, 1}; return r; } //! Erzeugt eine Matrix, die einen Vektor Skalliert, wenn sie mit ihm //! multipliziert wird \param faktor Der Faktor static Mat4 scaling(T faktor) { Mat4 s = { faktor, 0, 0, 0, 0, faktor, 0, 0, 0, 0, faktor, 0, 0, 0, 0, 1}; return s; } //! Erzeugt eine Matrix, die einen Vektor Skalliert, wenn sie mit ihm //! multipliziert wird \param faktorX Der Faktor für die X Komponente //! des Vektors \param faktorY Der Faktor für die Y Komponente des //! Vektors \param faktorZ Der Faktor für die Z Komponente des Vektors static Mat4 scaling(T faktorX, T faktorY, T faktorZ) { Mat4 s = {faktorX, 0, 0, 0, 0, faktorY, 0, 0, 0, 0, faktorZ, 0, 0, 0, 0, 1}; return s; } //! Erzeugt eine Matrix, die einen Vektor verchiebt, wenn sie mit ihm //! multipliziert wird \param offset Die Koordinaten, um die der Vektor //! verschoben werden soll static Mat4 translation(const Vec3 offset) { Mat4 t = {1, 0, 0, offset.x, 0, 1, 0, offset.y, 0, 0, 1, offset.z, 0, 0, 0, 1}; return t; } //! Erzeugt eine Matrix, die einen Vektor auf den Bildschirm Projeziert //! \param openingAngle Der Öffnungswinkel der Kamera im Bogenmas //! \param bildschirmXY Das Seitenverhältnis des Rechtecks auf dem //! Bildschirm, in dem gezeichnet werden soll. (Breite / Höhe) \param //! minz Der Mindestabstand zur Kamera, ab dem gezeichnet wird \param //! maxZ Der Maximalabstand zur Kamera, ab dem nicht mehr gezeichnet //! wird static Mat4 projektion( float openingAngle, float bildschirmXY, float minZ, float maxZ) { Mat4 p = {(float)(1 / tan(openingAngle / 2)) / bildschirmXY, 0, 0, 0, 0, (float)(1 / tan(openingAngle / 2)), 0, 0, 0, 0, maxZ / (maxZ - minZ), -(minZ * maxZ) / (maxZ - minZ), 0, 0, 1, 0}; return p; } //! Erzeugt eine Matrix, die mit allem Multipliziert werden kann ohne es //! zu ändern static Mat4 identity() { Mat4 i = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; return i; } //! Gibt eine Rotationsmatrix zurück, so dass vector a wenn man ihn //! damit dreht in richtung des vectors b zeigt \param a der vector der //! gedreht werden soll \param b der vector zu dem gedreht werden soll static Mat4 rotationTo(Vec3& a, Vec3& b) { Vec3 aNorm = Vec3(a).normalize(); Vec3 bNorm = Vec3(b).normalize(); Vec3 v = aNorm.crossProduct(bNorm); T s = v.getLengthSq(); T c = aNorm * bNorm; T m = (1 - c) / s; Mat3 cpm({0, -v.z, v.y, v.z, 0, -v.x, -v.y, v.x, 0}); Mat3 cpm2 = cpm * cpm; Mat3 res = Mat3::identity() + cpm + cpm2 * m; return Mat4({res.elements[0][0], res.elements[0][1], res.elements[0][2], 0, res.elements[1][0], res.elements[1][1], res.elements[1][2], 0, res.elements[2][0], res.elements[2][1], res.elements[2][2], 0, 0, 0, 0, 1}); } }; } // namespace Framework