OpenGL: Matrix mit Vektor multiplizieren



  • Hallo zusammen,

    ist es in OGL möglich, einen Vektor mit dem aktuellen Modelview-Matrix-Stack zu multiplizieren und sich dann den Ergebnisvektor zu speichern?

    Ich möchte mir viele Koordinaten zuerst berechnen und dann mit einem einzigen glDrawElements()-Aufruf rendern.

    👍



  • Kommt drauf an. Wie liegt denn der Vektor vor? Bei einem 4x4-Vektor ist es ja noch relativ simpel (Matrix-Element * Matrix-Element). Bei einem Translations-/ Skalierungs-/ Rotationsvektor wird die Sache etwas aufwendiger. Sollte aber auch überhaupt kein Problem sein.

    Schreib dir doch einfach eine Klasse oder Funktion (empfehle Klasse).

    Und nein, soweit ich weiß bietet OpenGL nichts von Haus aus an.



  • Hi Kóya...,

    mein Vektor ist ein Vertex, vier-komponentig.

    wie kann ich denn auf die aktuelle Gesamtmatrix aus dem Modelview-Stapel zugreifen?



  • Du meinst auf die aktuelle Matrix? So:

    float fvViewMatrix[16 ; 
    glGetFloatv( GL_MODELVIEW_MATRIX, fvViewMatrix );
    

    Für die Projektionsmatrix natürlich "GL_PROJECTION_MATRIX" benutzen (;



  • Ahhh sehr gut, das hatte ich nicht gefunden.
    Danke 👍

    Die Multiplikation muß ich dann also selber schreiben!



  • Jop genau. Empfehle dir so eine einfache Klassen-Architektur: (ungetestet!)

    template <typename T>
    class ChangeMatrix
    {
    	public:
    	ChangeMatrix(std::vector<T> &actMatrix, std::vector<T> newMatrix) // Normally 4x4 (16 matrix)
    	{
    		for(std::vector<T>::iterator i, j = actMatrix.begin(); i != actMatrix.end(), j != newMatrix.end(); ++i, ++j)
    		{
    			*i * (*j);
    		}
    	}
    };
    


  • @st: super, post lieber mal getesteten Code, statt Code der nicht funktioniert. 😛

    @curry-king: Wieso willst du das denn tun? Du kannst doch auch untransformierte Vektoren per glDrawElements an GL übergeben. Hinzu kommt noch, dass du die MV-Matrix entsprechend anpassen (=> Identity) musst, wenn du deine Idee umsetzen willst.



  • David_pb schrieb:

    super, post lieber mal getesteten Code, statt Code der nicht funktioniert. 😛

    Pf, habe doch gesagt das er ungetestet ist du Rüpel.^^



  • David_pb schrieb:

    Wieso willst du das denn tun? Du kannst doch auch untransformierte Vektoren per glDrawElements an GL übergeben.

    Vermutlich weil er viele "kleine" Objekte mit jeweils unterschiedlichen Transformationen rendern will.
    Dazu waere es ineffizient jedes Mal eine neue Matrix zu setzen und entsprechend viele Render-Calls zu machen.
    Ob es sinnvoll ist dafuer die Matrix-Operationen von OpenGL zu verwenden sei mal dahingestellt.
    Generell waere es noch sinnvoll, das Problem zur gesuchten Loesung zu nennen.



  • hellihjb schrieb:

    David_pb schrieb:

    Wieso willst du das denn tun? Du kannst doch auch untransformierte Vektoren per glDrawElements an GL übergeben.

    Vermutlich weil er viele "kleine" Objekte mit jeweils unterschiedlichen Transformationen rendern will.

    Ganz genau das will ich machen.

    Konkret geht es um eine Sierpinski-Pyramide.
    Ich rendere also rekursiv viele kleine Tetraeder. Jeder rekursive Aufruf entspricht einem glDrawElements() Aufruf. Das ist ineffizient, da ich bei jedem draw-Aufruf die Vertexdaten vom Client zur HW schicken muß.

    Es sollen jetzt also alle Vertexkoordinaten für eine bestimmte Rekursionstiefe zunächst komplett berechnet und dann ein einziges Vertexarray mit entsprechendem Index-Array gerendert werden.

    Ist es also sinnvoll, meine Matrizen rekursiv zu berechnen, dann die Vertizes zu transformieren und dann in das Vertex-Array zu schreiben?

    Danke für Eure Hilfe 👍



  • Render den ganzen Krempel doch einfach einmal in eine Display-Liste.



  • Sorry, aber ich muß es mit Vertex-Arrays/VBOs machen.
    Sind Display-Listen nicht auch bald deprecated?



  • Eine Display-Liste haette genau das erledigt was Du jetzt manuell machen willst, naemlich alle Primitiven vortransformiert in einem Vertexbuffer zu sammeln.
    Aber wenn die Loesung mit VBOs erfolgen soll musst Du wohl selber ran.
    Die Hinweise zur Deprecation werden sicherlich nicht sonderlich zeitnah greifen weil man zB unter Windows immer erstmal bei OpenGL 1.1 startet...



  • David_pb schrieb:

    Hinzu kommt noch, dass du die MV-Matrix entsprechend anpassen (=> Identity) musst, wenn du deine Idee umsetzen willst.

    Heisst das also, das z. B. ein

    glTranslatef(...);
    glVertex3f(...);
    

    nicht äquivalent ist zu

    glTranslatef(...);
    glGetFloatv(GL_MODELVIEW_MATRIX, fvViewMatrix );
    new_vertex = fvViewMatrix * vertex; //Pseudo
    glDrawElements(new_vertex); //Pseudo
    

    ???



  • Nein, du transformierst ja dann zweimal.



  • wo transformiere ich denn zweimal?

    //edit
    Achso, erst denken, dann schreiben!

    Also muss ich dann vor meinem glDrawElements() die Identity laden?

    glTranslatef(...);
    glGetFloatv(GL_MODELVIEW_MATRIX, fvViewMatrix );
    new_vertex = fvViewMatrix * vertex; //Pseudo
    glLoadIdentity();
    glDrawElements(new_vertex); //Pseudo
    


  • Ja, das wär ganz sinnvoll. Aber wieso stellst du die Matrix nicht einfach selbst auf und lässt bei GL einfach immer die Einheitsmatrix für die Model->View Transformation?



  • Vor meinen eigenen Transformationen werden schon fünf andere gemacht.
    Wäre es denn performanter, wenn ich die vorherige Matrix auslese und dann darauf meine Matrizen multipliziere, also alles ohne glTranslate, glScale und glRotate?

    Danke für Eure Hilfe!



  • curry-king schrieb:

    Vor meinen eigenen Transformationen werden schon fünf andere gemacht.
    Wäre es denn performanter, wenn ich die vorherige Matrix auslese und dann darauf meine Matrizen multipliziere, also alles ohne glTranslate, glScale und glRotate?

    Einfach ausprobieren! 🙂



  • Sooo.

    Leider funktioniert das nicht so ganz wie ich mir das vorgestellt habe.
    Ich vermute, das irgendetwas bei der Erstellung der Vertex-Liste nicht funktioniert.

    Am Code hat sich nicht viel geändert.

    glRotatef(-45.0f, 0.0f, 1.0f, 0.0f);
    glRotatef(10.0f, 1.0f, 0.0f, 0.0f);
    glRotatef(-4.0f, 0.0f, 0.0f, 1.0f);
    glTranslatef(getLength()/2, 0.0f, -getTriangleHeight());
    GLfloat fvViewMatrix[16];
    glGetFloatv(GL_MODELVIEW_MATRIX, fvViewMatrix);
    transform(fvViewMatrix);
    

    Die Methode transform() Multipliziert nun die Matrix mit mehreren Vektoren und speichert die Ergebnisse.

    void TetrahedronOpt::transform(GLfloat *matrix) {
            Vertex *v = getVertices();
    
    	float m_x = v[0].getPosition()[0];
    	float m_y = v[0].getPosition()[1];
    	float m_z = v[0].getPosition()[2];
    	float m_w = v[0].getPosition()[3];
    
    	GLfloat x = matrix[0]*m_x + 
    				matrix[1]*m_y + 
    				matrix[2]*m_z + 
    				matrix[3]*m_w;
    
    	GLfloat y = matrix[4]*m_x + 
    				matrix[5]*m_y + 
    				matrix[6]*m_z + 
    				matrix[7]*m_w;
    
    	GLfloat z = matrix[8]*m_x + 
    				matrix[9]*m_y + 
    				matrix[10]*m_z + 
    				matrix[11]*m_w;
    
    	GLfloat w = matrix[12]*m_x + 
    				matrix[13]*m_y + 
    				matrix[14]*m_z + 
    				matrix[15]*m_w;
    
    	m_vertices_opt[m_counter].setPosition(x, y, z, w);
    	m_vertices_opt[m_counter++].setColor(0.5f, 0.5f, 0.5f, 1.0f);
    }
    

    Darauf folgt der Draw-Call:

    // Anordnen der Vertexdaten		
    	glVertexPointer(4, GL_FLOAT, sizeof(Vertex), &m_vertices_opt[0].getPosition()[0]);
    
    	// Anordnen der Colordaten
    	glColorPointer(4, GL_FLOAT, sizeof(Vertex),  &m_vertices_opt[0].getColor()[0]);	
    
    	glLoadIdentity();
    
    	// DRAW
    	glDrawElements(GL_TRIANGLE_STRIP, m_numIndices, GL_UNSIGNED_BYTE, m_arrayIndices_opt);
    

    Noch ein Hinweis. Wenn ich statt der Matrixmultiplikation etwas schreibe wie

    glRotatef(-45.0f, 0.0f, 1.0f, 0.0f);
    glRotatef(10.0f, 1.0f, 0.0f, 0.0f);
    glRotatef(-4.0f, 0.0f, 0.0f, 1.0f);
    glTranslatef(getLength()/2, 0.0f, -getTriangleHeight());
    
    glBegin(...)
    // objektkoordinaten
    glEnd(...)
    

    , dann wird das Objekt an die richtige Stelle gezeichnet.

    Blickt da jemand durch, was ich falsch mache?

    Vielen Dank für Eure Hilfe!


Log in to reply