Eigenes Matrix Struct multiplizieren
-
ich habe mir eine Matrix Struktur gebastelt.
Ich möche nun, sowas schreiben können;Matrix World = Matrix.CreateScale(new Vector3(1f, 1f, 1f)) * Matrix.CreateTranslation(new Vector3(+250, 0, 300));
oder
Matrix WVP = World * Camera.View * Camera.Projection;
Ich habe es mit typedef probiert, aber bisher funktioniert es nicht.so sieht die Struktur derzeit aus:
struct Matrix { float m11; float m12; float m13; float m14; float m21; float m22; float m23; float m24; float m31; float m32; float m33; float m34; float m41; float m42; float m43; float m44; static Matrix CreateFromQuaternion() { } static Matrix CreateLookAt() { } static Matrix CreatePerspectiveFieldOfView() { } static Matrix CreateScale(float Scale) { Matrix m; m.m11 = Scale; m.m12 = 0; m.m13 = 0; m.m14 = 0; m.m21 = 0; m.m22 = Scale; m.m23 = 0; m.m24 = 0; m.m31 = 0; m.m32 = 0; m.m33 = Scale; m.m34 = 0; m.m41 = 0; m.m42 = 0; m.m43 = 0; m.m44 = Scale; return m; } static Matrix CreateFromAxisAngle() { } static Matrix CreateFromYawPitchRoll() { } };
Danke
-
Eine Klasse schreiben und den *-Operator überladen. Warum verwendest du kein 2-dim. Array?
float matrix[4][4];
-
Autsch. Man sollte das zwar lieber alles mit Templates machen, aber der Einfachheit halber mal hier:
#include <cstddef> class matrix4 { float data_[4][4]; public: float& operator() (std::size_t i, std::size_t j) { return data_[i][j]; } const float& operator() (std::size_t i, std::size_t j) const { return data_[i][j]; } }; matrix4 null_matrix() { static matrix4 m; return m; } matrix4 operator * (const matrix4& m1, const matrix4& m2) { matrix4 r = null_matrix(); for (std::size_t i = 4; i-- != 0; ) for (std::size_t j = 4; j-- != 0; ) for (std::size_t k = 4; k-- != 0; ) r(i, j) += m1(j, k) * m2(k, i); return r; } int main() { matrix4 m1 = null_matrix(), m2 = null_matrix(); m1(2, 3) = 5; // ... matrix4 m3 = m1 * m2; }
-
Dein operator () const sollte besser float zurückgeben.
-
adonis schrieb:
ich habe mir eine Matrix Struktur gebastelt.
Ich möche nun, sowas schreiben können;Matrix World = Matrix.CreateScale(new Vector3(1f, 1f, 1f)) * Matrix.CreateTranslation(new Vector3(+250, 0, 300));
eeeek
Kommst du aus der C#-Ecke? Sieht jedenfalls sehr nach Speicher-Leak aus ...
-
314159265358979 schrieb:
Dein operator () const sollte besser float zurückgeben.
macht er doch, oder was meinst du?
-
314159265358979 schrieb:
Dein operator () const sollte besser float zurückgeben.
Nein, oder du bietest eine data() Methode an. Denn sonst hast du in const Methoden keine Chance mehr vom Speicher zu lesen.
-
Dann lieber .data(), die float (const)* zurückgibt. Es ist herrlich ineffizient, bei jedem Elementzugriff einen Zeiger dereferenzieren zu müssen.
-
314159265358979 schrieb:
Es ist herrlich ineffizient, bei jedem Elementzugriff einen Zeiger dereferenzieren zu müssen.
Hä?
-
matrix4 null_matrix() { static matrix4 m; return m; }
I loled very hard.
Warum static? Premature optimization! Desweiteren weiss ich gerade nicht, wie das Verhalten vom Array bei Kopier- und Initialisierungskonstruktor umgesetzt wird. Frei nach dem Motto: "Don't make me think" haette ich ein std::vector/std::array benutzt.
-
Referenzen sind auch bloß Zeiger.
-
cooky451 schrieb:
314159265358979 schrieb:
Es ist herrlich ineffizient, bei jedem Elementzugriff einen Zeiger dereferenzieren zu müssen.
Hä?
genau meine Worte. Vielleicht spiel er drauf an, dass es fixer ist, eine float-Variable als Wert, als als Referenz zu übergeben. Er begründet das gleich wahrscheinlich damit, dass Referenzen intern als Zeiger implementiert werden(können), vergisst aber dabei, dass es bei einem Array natürlich ist, die Referenz zu betrachten, nicht aber den Wert(derefereziert werden muss so oder so). Und Schlussendlich liegt sein Fehler darin, dass er nicht realisiert, dass die Funktion inline ist und dadurch der Rückgabewert völlig irrelevant wird.
-
knivil schrieb:
I loled very hard.
Warum static?
Ich bin zu faul die Sachen 0 zu setzen, also lass ich den Compiler die Arbeit machen.
knivil schrieb:
Desweiteren weiss ich gerade nicht, wie das Verhalten vom Array bei Kopier- und Initialisierungskonstruktor umgesetzt wird. Frei nach dem Motto: "Don't make me think" haette ich ein std::vector/std::array benutzt.
Du meinst als Member für die Matrix? Na ja, std::array würde gehen, aber das wollte ich da jetzt nicht noch rein bringen. std::vector ist natürlich ein völlig anderes Verhalten, das würde ich nur nutzen wenn man große Matrizen erwartet.
PS: Das verhält sich alles so wie es soll. static nullt, und Kopierkonstruktoren kopieren einfach das ganze struct. Ist so ja schließlich immer noch ein POD-Typ.
-
Static fuehrt ein implizites
if
ein. Kopiert wird sowieso. Anstaendiger Konstruktor und der Compiler kann RVO nutzen.std::vector ist natürlich ein völlig anderes Verhalten
Voellig anders? Es sollte eigentlich das gleiche Verhalten zeigen, bis auf die Art und Weise wie intern der Speicher verwaltet wird.
Ich bevorzuge std::vector gegenueber std::array auch bei einer 4x4-Matrix, weil man automatisch RVO bzw. Move-Semantik geschenkt bekommt. Und dann setzt der Compiler auch die Elemente automatisch auf 0;
-
knivil schrieb:
Static fuehrt ein implizites
if
ein.Das wusste ich nicht. Warum?
knivil schrieb:
Kopiert wird sowieso. Anstaendiger Konstruktor und der Compiler kann RVO nutzen.
?
knivil schrieb:
std::vector ist natürlich ein völlig anderes Verhalten
Voellig anders? Es sollte eigentlich das gleiche Verhalten zeigen, bis auf die Art und Weise wie intern der Speicher verwaltet wird.
Und die Speicherverwaltung ist nicht uninteressant, insbesondere im Hinblick auf Performance. Mit std::vector musst du für jede Matrix speicher reservieren und wieder freigeben. Solange man da keinen eigenen Allocator oder sonstige Scherze nutzt, kann das für viele kleine Matrizen unangenehm werden. (Zudem kann die Matrix-Klasse dann auch Exceptions werfen.) Weiter baust du natürlich eine weitere Indirektion ein. Und es zerstückelt den Speicher, stell dir mal ein Array aus Matrizen vor. Wenn die intern auch Arrays nutzen, liegt der gesamte Speicher hübsch am Stück.
knivil schrieb:
Ich bevorzuge std::vector gegenueber std::array auch bei einer 4x4-Matrix, weil man automatisch RVO bzw. Move-Semantik geschenkt bekommt. Und dann setzt der Compiler auch die Elemente automatisch auf 0;
Ein weiterer Nachteil: Vielleicht möchtest du die Elemente ja gar nicht auf 0 setzen. Mit std::vector hast du keine Wahl.
Move Semantik wäre in der Tat ein Vorteil, aber bei 64 Byte wird das keinen so großen Unterschied machen denke ich. (Auch wenn ich es nicht gemessen habe.) Die anderen Vorteile sollten doch aber deutlich überwiegen. Zumal man auch auf dem Stack auf Optimierungen in diese Richtung hoffen kann, da ist der Compiler ja etwas freier als mit new/delete.
-
cooky451 schrieb:
Das wusste ich nicht. Warum?
void foo() { static int bar; }
->
int foobar; bool foobar_initialized = false; void foo() { if(!foobar_initialized) { foobar = 0; foobar_initialized = true; } }
Und beim GCC wird das Ganze noch zusätzlich durch einen Mutex abgesichert.
-
314159265358979 schrieb:
Und beim GCC wird das Ganze noch zusätzlich durch einen Mutex abgesichert.
Bei PODs mit default Initialisierung von denen nur gelesen werden kann? Zeig mal bitte den ASM Output. VS macht da nämlich das da raus:
matrix4 m1 = null_matrix(), m2 = null_matrix(); 009C137C mov ecx,10h 009C1381 mov esi,9C4478h 009C1386 lea edi,[esp+8] 009C138A rep movs dword ptr es:[edi],dword ptr [esi] 009C138C mov ecx,10h 009C1391 mov esi,9C4478h 009C1396 lea edi,[esp+48h] 009C139A rep movs dword ptr es:[edi],dword ptr [esi]
Ich bin wahrlich kein ASM-Experte, aber ich glaube viel schneller gehts nicht mehr..
-
Und jetzt mal in einer seperaten Kompilierungseinheit ... und dann in einer statischen Bibliothek ... und dann koennen wir gern noch den ASM-Output bei der Konstruktorloesung anschauen ... habe aber kein VS2010 zur Hand.
Vielleicht möchtest du die Elemente ja gar nicht auf 0 setzen. Mit std::vector hast du keine Wahl.
Dann nimmt man eben nicht
std::vector
.
-
ok mal zurück zum Thema, ich will es als struct belassen. Ich habe
folgendes auf der Microsoft-Seite gefunden:// operator_overloading.cpp // compile with: /EHsc #include <iostream> using namespace std; struct Complex { Complex( double r, double i ) : re(r), im(i) {} Complex operator+( Complex &other ); void Display( ) { cout << re << ", " << im << endl; } private: double re, im; }; // Operator overloaded using a member function Complex Complex::operator+( Complex &other ) { return Complex( re + other.re, im + other.im ); } int main() { Complex a = Complex( 1.2, 3.4 ); Complex b = Complex( 5.6, 7.8 ); Complex c = Complex( 0.0, 0.0 ); c = a + b; c.Display(); }
Ich habe versucht mein struc dementsprechend zu gestalten:
struct Matrix { Matrix(); Matrix(float m11, float m12, float m13, float m14, float m21,float m22, float m23, float m24, float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44) :m11(m11),m12(m12),m13(m13),m14(m14),m21(m21),m22(m22),m23(m23),m24(m24),m31(m31),m32(m32),m33(m33),m34(m34),m41(m41),m42(m42),m43(m43),m44(m44){} Matrix operator*(Matrix &other); float m11; float m12; float m13; float m14; float m21; float m22; float m23; float m24; float m31; float m32; float m33; float m34; float m41; float m42; float m43; float m44; static Matrix CreateFromQuaternion() { } static Matrix CreateLookAt() { } static Matrix CreatePerspectiveFieldOfView() { } static Matrix CreateScale(float Scale) { Matrix m; m.m11 = Scale; m.m12 = 0; m.m13 = 0; m.m14 = 0; m.m21 = 0; m.m22 = Scale; m.m23 = 0; m.m24 = 0; m.m31 = 0; m.m32 = 0; m.m33 = Scale; m.m34 = 0; m.m41 = 0; m.m42 = 0; m.m43 = 0; m.m44 = Scale; return m; } static Matrix CreateFromAxisAngle() { } static Matrix CreateFromYawPitchRoll() { } }; Matrix Matrix::operator*(Matrix &other ) { return Matrix(m11 * other.m11 + m12 * other.m21 + m13 * other.m31 + m14 * other.m41, m11 * other.m12 + m12 * other.m22 + m13 * other.m32 + m14 * other.m42, m11 * other.m13 + m12 * other.m23 + m13 * other.m33 + m14 * other.m43, m11 * other.m14 + m12 * other.m24 + m13 * other.m34 + m14 * other.m44, m21 * other.m11 + m12 * other.m21 + m13 * other.m31 + m14 * other.m41, m21 * other.m22, m21 * other.m23, m21 * other.m24, m31 * other.m31, m31 * other.m32, m31 * other.m33, m31 * other.m34, m41 * other.m41, m41 * other.m42, m41 * other.m43, m41 * other.m44); }
wenn ich allerdings das struct dann verwenden möchte bekomme ich:
Fehler 2 error LNK2005: "public: struct Matrix __thiscall Matrix::operator*(struct Matrix &)" (??DMatrix@@QAE?AU0@AAU0@@Z) ist bereits in main.obj definiert.
Fehler 3 error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""public: __thiscall Matrix::Matrix(void)" (??0Matrix@@QAE@XZ)" in Funktion ""long __cdecl InitDevice(void)" (?InitDevice@@YAJXZ)".\Projects\Mein3dTest\Mein3dTest\main.obj Mein3dTest
Fehler 4 error LNK1120: 1 nicht aufgelöste externe Verweise. Mein3dTestwarum? was mache ich falsch?
Das struct befindet sich bei meiner vector.h in der Hauptdatei hab ich sie aber
included, die CreateScale hatte auch schon funktioniert...
-
Die Fehlermeldung bedeutet: der Linker kann die Implementation des von dir deklarierten default constructors nicht finden.
Das stimmt. Du hast den default constructor auch nicht implementiert.