VAOs



  • Und zwar möchte ich gerne OpenGL 3.3 Core lernen und habe auch ein kleines Tutorial gefunden.

    Der Aufbau ist in etwa so:

    main() 
    
    lege shader und programm an, nutze dieses 
    lege float array an und erzeuge vao 
    
    while running: 
    clear 
    GLDrawArrays()
    

    Es wird ein Viereck dargestellt. Nun ist meine Frage wie ich ein zweites Viereck zeichnen könnte.

    Was funktioniert hat war:

    main() 
    
    lege shader und programm an, nutze dieses 
    
    while running: 
    clear 
    lege float array an und erzeuge vao 
    GLDrawArrays() 
    lege neues float array an und ninde an die selbe vao-variable 
    GLDrawArrays()
    

    Ich bin mir aber nicht sicher ob das so gut oder erwünscht ist,
    vielleicht sollte ich mir die vielen DrawArrays sparen und einfach neue Punkte anhängen?
    Oder soll ich gar mehrere vao erzeugen?

    Naja ich kenn mich leider nocht nicht so gut aus und fand
    glBegin() und End() schön übersichtlich, aber ich will mal was aktuelleres lernen 🙂

    Wenn ihr Beispielcode habt nehm ich den gerne an, auch grob skizziert wie ich es getan hab ist ok



  • Ist die Frage unzureichend gestellt?

    Falls Beispielcode nötig ist, könnte ich den liefern.



  • Grüsse,
    dein Pseudocode ist extrem komprimiert und ich bin mir nicht sicher ob du bereits verstanden hast was ein VAO ist.

    z.b. folgende Zeile:

    lege float array an und erzeuge vao
    

    Was meinst du hier mit dem float array? Ein einfaches Array mit Vertexattributen? Wo wird das VBO erstellt, gebunden, Daten gesendet, AttribPointer gesetzt, VertexAttrib Array aktiviert etc.?

    Vlt zeigst du doch ein wenig code um nachzuvollziehen ob du soweit erstmal alles richtig machst.

    Angenommen es stimmt bisher alles, so hast du sicherlich die Attribute (Koordinaten, ggf Farbe, Textur-Koordinaten etc.) für 4 Vertices festgelegt und sendest dann den draw-call (glDrawArrays(GL_TRIANGLE_STRIP,....)).

    Du hast verschiedene Möglichkeiten ein zweites Viereck zu zeichnen.

    • weitere Vertices definieren
    • Bisherige Vertices transformieren und nochmal zeichnen
    • instancing nutzen
      ...


  • Ja zunächst mal das Ausgangsprogramm aus einem Tutorial

    lege float array an und erzeuge vao

    void create_vao() 
    { 
        // Create our static triangle strip of 2 triangles = 4 vertices 
        const float quad[8] = { 
            -.5f,  .5f, 
            -.5f, -.5f, 
             .5f,  .5f, 
             .5f, -.5f 
        }; 
    
        // Generate ID for VAO, and bind it as the active VAO 
        glGenVertexArrays(1, &g_vao); 
        glBindVertexArray(g_vao); 
    
        // Generate a VBO to store our vertex list 
        glGenBuffers(1, &g_vbo); 
        glBindBuffer(GL_ARRAY_BUFFER, g_vbo); 
        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*8, quad, GL_STATIC_DRAW); 
        glVertexAttribPointer((GLuint)0, 2, GL_FLOAT, GL_FALSE, 0, 0); 
        glEnableVertexAttribArray(0); 
    }
    

    main:

    int main()
    {
        create_shader()
        create_vao()
    
        while (App.IsOpened()) 
        {
            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 
            App.Display(); 
        } 
        glDeleteBuffers(1, &g_vbo); 
        glDeleteVertexArrays(1, &g_vao); 
    
        return EXIT_SUCCESS; 
    }
    

    Nun wollte ich ein zweites Viereckt haben.
    Folgendes hat geklappt, wenn ich mir auch nicht sicher bin, ob das eine gute Möglichkeit ist:

    Ich führe eine Funktion create_vao2() ein in der der selbe code steht, nur mit anderen Koordinaten und änder die main so:

    int main()
    {
        create_shader()
    
        while (App.IsOpened()) 
        {
            create_vao()
            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
            create_vao2();
            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
            App.Display(); 
        } 
        glDeleteBuffers(1, &g_vbo); 
        glDeleteVertexArrays(1, &g_vao); 
    
        return EXIT_SUCCESS; 
    }
    

    Das ganze funktioniert auf jeden Fall, aber ich gaube dass es sehr unschön ist.
    Ich würde gerne mal einen Minicode sehen, indem das was ich gern hätte (vielleicht auch ein Dreieck und ein Viereck?) mal vorgeführt wird.
    Die OPenGL 3.3 Samplepacks sind doch schon gehobenes Niveau.



  • Prinzipiell stimmt das schon so.
    Da du wohl noch nicht allzuviel Erfahrung hast macht es wohl wenig Sinn dir jetzt Beispiele mit instancing oder transformations zu zeigen.

    Ich vermute mal aufgrund von App.Display(), dass du die SFML benutzt.
    Dazu sei gesagt, dass es mit SFML IMHO nicht möglich ist im core-profile zu arbeiten. Es ist mit Version 1.6 nicht mal möglich die major- und minor-Version anzugeben (soll wohl mit Version 2.0 gehen - aber auch dann keine profile-Unterstützung soweit ich weiss).
    Demzufolge arbeitest du ohnehin im compatibility mode mit einem 2.1 Rendercontext (es wird von der SFML wglCreateContext genutzt).

    Zurück zum Thema.
    Es macht in deinem Beispiel natürlich wenig Sinn bei jedem loop-Durchlauf create_vao() aufzurufen. Das würde man vorher genau einmal tun und innerhalb der loop nur noch die VAOs binden.
    Zwei VAOs anzulegen ist völlig in Ordnung.

    Es würde dann in etwa so aussehen:
    create_vao()

    void create_vao()
    {
        // Create our static triangle strip of 2 triangles = 4 vertices
        const float quad[8] = {
            -.5f,  .5f,
            -.5f, -.5f,
             .5f,  .5f,
             .5f, -.5f
        };
    
        const float triangle[6] = {
            1.0f,  0.0f,
            2.0f,  0.0f,
            1.5f,  1.0f,
        };
    
        glGenVertexArrays(2, g_vao);       // unsigned int g_vao[2];
        glGenBuffers(2, g_vbo);        // unsigned int g_vbo[2];
    
        glBindVertexArray(g_vao[0]);
        glBindBuffer(GL_ARRAY_BUFFER, g_vbo[0]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*8, quad, GL_STATIC_DRAW);
        glVertexAttribPointer((GLuint)0, 2, GL_FLOAT, GL_FALSE, 0, 0);
        glEnableVertexAttribArray(0);
    
        glBindVertexArray(g_vao[1]);
        glBindBuffer(GL_ARRAY_BUFFER, g_vbo[1]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*6, triangle, GL_STATIC_DRAW);
        glVertexAttribPointer((GLuint)0, 2, GL_FLOAT, GL_FALSE, 0, 0);
        glEnableVertexAttribArray(0);
    
        glBindVertexArray(0);
    }
    

    main()

    int main()
    {
        create_shader()
        create_vao()
    
        while (App.IsOpened())
        {
            glBindVertexArray(g_vao[0]);
            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
            glBindVertexArray(g_vao[1]);
            glDrawArrays(GL_TRIANGLE,0,3);
            glBindVertexArray(0);
            App.Display();
        }
        glDeleteBuffers(2, g_vbo);
        glDeleteVertexArrays(2, g_vao);
    
        return EXIT_SUCCESS;
    }
    


  • danke soweit.

    Du hast Recht, ich nutze SFML, aber die Version 2 so dass ich OpenGL 3.3 Core nutzen können sollte. 1.x unterstützt das ganze nicht.
    Auf jeden Fall hat Laurent auf die Frage ob OGL 3.x funktioniert geanwortet, dass das in SFML 2 möglich ist.

    Wenn es ok ist mehrere VAOs anzulegen, ist das ganze ja einfacher als erwartet.
    In irgend einem anderen Tutorial (ich glaub des war ein OGL 2.1 Tutorial)
    hab ich was gesehen, wo alle Punkte in einen Vector geworfen wurden und dann angeben wurde: 1-4 sind ein Viereck, 5-7 ein Dreieck usw...

    Würde sich dann auch eine KLasse anbieten wie Viereck, die ein lokales VAO verwaltet?

    instancing oder transformations?
    Mach mich doch nicht neugierig ^^, werds mal googlen , wenn du aber Lust hast kannst du mir auch davon ein Beispiel geben.

    Danke soweit, des hilft schonmal gewaltig weiter



  • shisha schrieb:

    danke soweit.

    Du hast Recht, ich nutze SFML, aber die Version 2 so dass ich OpenGL 3.3 Core nutzen können sollte. 1.x unterstützt das ganze nicht.
    Auf jeden Fall hat Laurent auf die Frage ob OGL 3.x funktioniert geanwortet, dass das in SFML 2 möglich ist.

    Ja - 3.x wird unterstützt und mann kann die major- und minor-Version ja auch in einem ContextSettings-struct angeben, allerdings wird weiterhin das compatibility-profile genutzt.
    Auszug WglContext.cpp:

    PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = reinterpret_cast<PFNWGLCREATECONTEXTATTRIBSARBPROC>(wglGetProcAddress("wglCreateContextAttribsARB"));
            if (wglCreateContextAttribsARB)
            {
                int attributes[] =
                {
                    WGL_CONTEXT_MAJOR_VERSION_ARB, mySettings.MajorVersion,
                    WGL_CONTEXT_MINOR_VERSION_ARB, mySettings.MinorVersion,
                    WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, //<---- kannst du natürlich ändern
                    0, 0
                };
                myContext = wglCreateContextAttribsARB(myDeviceContext, sharedContext, attributes);
            }
    

    shisha schrieb:

    Würde sich dann auch eine KLasse anbieten wie Viereck, die ein lokales VAO verwaltet?

    Selbstverständlich. Simples Beispiel: Du erstellst eine abstrakte Klasse shape mit einer Funktionsdeklaration draw (pure virtual) und verschiedene konkrete Klassen (Viereck, Dreieck, Kreis ...), die von der abstrakten Klasse erben. Beim erstellen der Objekte werden Vertice-Koordinaten berechnet oder direkt angegeben, VBO und VAO erstellt usw.
    Innerhalb der draw Methode wird dann einfach das VAO gebunden, der drawcall gesetzt und die Bindung wieder gebrochen.
    Nun können Objekte unterschielicher Typen erstellt werden und kannst durch Polymorphismus bequem alle draw-Methoden aufrufen (über Referenzen oder Pointer).

    shisha schrieb:

    instancing oder transformations?
    Mach mich doch nicht neugierig ^^, werds mal googlen , wenn du aber Lust hast kannst du mir auch davon ein Beispiel geben.

    Kleines Beispiel, wo beides genutzt wird (ist natürlich relativ sinnfrei, aber soll ja auch nur als Beispiel dienen) - achja ich nutze hier die GLM-library :
    init():

    bool init() {
    //...
    //schnipp schnapp
        // Vertice Koordinaten
        std::vector<glm::vec2> coord;
    	coord.push_back(glm::vec2(0.0f,0.0f));
    	coord.push_back(glm::vec2(2.0f,0.0f));
    	coord.push_back(glm::vec2(1.0f,2.0f));
    
    	// VBO erstellen
    	glGenBuffers(1,&vboId);
    	glBindBuffer(GL_ARRAY_BUFFER,vboId);
    	glBufferData(GL_ARRAY_BUFFER,coord.size()*sizeof(myVect3),&coord[0],GL_STATIC_DRAW);
    
    	// VAO erstellen
    	glGenVertexArrays(1,&vaoId);
    	glBindVertexArray(vaoId);
    		glBindBuffer(GL_ARRAY_BUFFER,vboId);
    		glVertexAttribPointer(shaderProgram.getAttributLocation("a_mcVertex"),2,GL_FLOAT,GL_FALSE,0,0);
    		glEnableVertexAttribArray(shaderProgram.getAttributLocation("a_mcVertex"));
    	glBindVertexArray(0);
    
        // Uniform setzen - Projektionsmatrix (muss natürlich bei einem resize neu gesetzt werden
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram.getProgramId(),"projmatrix"),1,GL_FALSE,glm::value_ptr(projectionMatrix));
    //...
    //schnipp schnapp
    }
    

    render():

    //...
    //schnipp schnapp
    // transformation-matrix
    	modelviewMatrix = glm::mat4(1.0f);
    	modelviewMatrix = glm::translate(modelviewMatrix,glm::vec3(1.0f,0.0f,-10));
    
    	// set uniforms
    	glUniformMatrix4fv(glGetUniformLocation(shaderProgram.getProgramId(),"mvmatrix"),1,GL_FALSE,glm::value_ptr(modelviewMatrix));
    
    	// draw calls
    	glBindVertexArray(vaoId);
    	glDrawArraysInstanced(GL_TRIANGLES,0,3,5);
    
        // modelview-matrix wird geaendert - Translation - und neu gesetzt
    	modelviewMatrix = glm::translate(modelviewMatrix,glm::vec3(-4.0f,0.0,0.0f));
    	glUniformMatrix4fv(glGetUniformLocation(shaderProgram.getProgramId(),"mvmatrix"),1,GL_FALSE,glm::value_ptr(modelviewMatrix));
    	glDrawArraysInstanced(GL_TRIANGLES,0,3,5);
    	glBindVertexArray(0);
    //...
    //schnipp schnapp
    

    Vertex-Shader:

    #version 330
    
    // -- UNIFORMS --
    uniform mat4 mvmatrix;	
    uniform mat4 projmatrix;	
    
    // -- IN --
    in vec2 a_mcVertex ;			
    
    // -- OUT --
    out float myColor;
    
    void main()
    {
    	vec4 mcVert = vec4(a_mcVertex,0.0,1.0);
    	mcVert.x += gl_InstanceID*0.2;
    
    	myColor = gl_InstanceID*0.2;
    	gl_Position =  projmatrix  * mvmatrix * mcVert;
    }
    

    Kurze Erläuterung zu instancing:
    Wie du siehst heissen die draw-calls jetzt nicht mehr glDrawArrays sondern glDrawArraysInstanced. Es kommt ein zusätzlicher Parameter hinzu, der angibt wieviele Instanzen gerendert werden sollen (in meinem Beispiel 5).
    Im Prinzip wird hier fünf mal glDrawArrays aufgerufen und jedesmal eine ZählVariable inkrementiert. Auf diese Variable hast du im Vertex-Shader mit gl_InstanceID zugriff (es gibt auch gl_VertexID, gl_PrimitiveID, ...).
    Beim ersten call (erstes Dreieck) ist gl_InstanceID gleich 0, beim zweiten 1 usw.
    Im Shadercode siehst du, dass ich die X-Koordinate in Abhängigkeit der InstanceID änder und ebenfalls einen von InstanceID abhängigen Wert an den FragmentShader übergebe (Farbwert soll sich jedesmal ein wenig aendern).

    Kurze Erläuterung zu Transformationen:
    Das Thema ist nicht kurz und bündig zu erklären. Dazu solltest du am besten mal ein wenig googlen oder Bücher lesen. Du solltest dich mit Vektoren, Matrizen etc. auskennen (ausser natürlich du beschränkst dich auf so simple Dinge wie hier im Beispiel).
    Letztendlich werden hier 2 Matrizen erstellt (eine für die Projektion und eine für die Transformationen).
    Im Shader werden die Vertex-Koordinaten nun mit den Matrizen multipliziert.
    Wenn ich in meine ModelviewMatrix nun eine weitere Transformation einfliessen lasse (im Beispiel z.b. eine Translation = Verschiebung um -4.0) so ändern sich auch die endgültigen Koordinaten des Dreiecks.

    Stichwörter nach denen du mal googeln kannst: object-space (viewing space, screen space ...) , modelview matrix, projektion, translation, rotationsmatrix ... und und und 🙂

    Für den Anfang sicherlich nicht unbedingt notwendig das alles zu verstehen und zu wissen, allerdings wirst du nicht drum rum kommen wenn du dich ernsthaft mit OpenGL oder Direct3D auseinandersetzen möchtest.

    Ich hoffe ich konnte dir ein wenig helfen - ansonsten weiter fragen 🙂



  • super das ist verdammt gut sowas zu finden.
    DIe meisten Tutorials für OGL sind einfach nicht einsteigerfreundlich oder noch öfter hoffnungslos veraltet.

    Kennst du eine Lib die OGL 3 core unterstützt? QT hab ich in Erinnerung, werd aber nochmal nachsehen.

    An der Mathematik solls nicht scheitern, eher an OpenGL
    In OGL 1.irgendwas habe ich einen Szenengraphen implementiert, der zwar auch nichts konnte ausser farbige figuren zu zeichnen und zu verschieben/rotieren (nicht mal Texturen), aber immerhin.

    Da es push und pop nicht mehr gibt, müsste ich ohnehin meinen eigenen Matrixstack implementieren...

    Eine gute Quelle zum Lernen wäre auch nett. Die OpenGL Spezifikation durchzulesen ist ein wenig mühselig ... und Tutorials - schwer zu finden.

    Die Superbible geht mir am Anfang zu wenig auf die mitgelieferten Klassen ein und das RedBook ist fast vollständig mit deprecated Sachen zugemüllt.
    (Das Inhaltsverzeichnis ist das beste. This chapter can contain methods that are considered deprecated oder so ähnlich 🙂



  • Ich kann dir leider kein framework empfehlen, da ich selber keines verwende 😃

    Hier ist eine Liste mit GUI Toolkits - vlt. hilft das bei der Recherche.

    Davon, dass es wenige gute aktuelle Tutorials gibt, kann ich ebenfalls ein Lied singen. Meist sind es wirklich nur Anfänger-Tutorials die einem zeigen wie man ein Fenster erstellt und ein Dreieck zeichnet.

    Die von dir angesprochenen Bücher (Bluebook, Redbook) habe ich ebenfalls gelesen und fand sie nicht so dolle. Lediglich das Orangebook ist zu empfehlen (OpenGL Shading Language).

    Mir geht es da ähnlich wie dir - es ist nicht leicht sich die Infos überall zusammenzuklauben.
    Hier im Forum wurden schon einige male Links zu Tutorials gepostet - vielleicht findest du da was bei.
    Ansonsten musst du dir wohl die samplepacks ansehen (da lernt man auf jedenfall einiges) oder auf den Seiten von nvidia und amd mal schauen (developer-sections). Auch da gibts nette Beispiele.


Anmelden zum Antworten