OpenGL-Texturen: verwalten und optimieren



  • Hallo zusammen,
    ich bin neu hier im Forum und habe ein paar Fragen zur Verwaltung von Texturen in OpenGL.
    Ich programmiere mit Qt und möchte dort in meiner Szene viele Elemente (Quads, ca. 1.000) darstellen, die jweils eine Grafik als Textur haben.

    Das funktioniert soweit im Moment. Ich habe es so gelöst, dass ich zuerst alle Grafiken/Bilder einlese und dann für jede Texturspeicher reserviere.

    texNames = new GLuint[itemList.size()];
    

    Anschließend gehe ich beim Initialisieren die Items durch und erzeuge die Texturen aus der jeweiligen Grafik und weise sie zu:

    void GLWidget::bindTextures()
    {
    	unsigned short int counter = 0;
    	QList<Item*>::const_iterator i;
    	for (i = itemList.constBegin(); i != itemList.constEnd(); ++i)
    	{
    		QPixmap* pixmap = (*i)->getTexture();
    		texNames[counter] = bindTexture(*(pixmap), GL_TEXTURE_2D);
    		++counter;
    	}
    }
    

    Meine Frage ist nun, ob das überhaupt der richtige Weg ist, mit vielen Texturen umzugehen. Ich habe letztes mal was gehört, dass man eine Textur auch aus mehreren Grafiken erzeugen kann und dann später einfach den Quads den entsprechenden Ausschnitt aus der großen Textur zuweist. Allerdings weiß ich ehrlich gesagt nicht, wie ich das am besten lösen könnte... 😞

    Wäre für Tipps und Hinweise sehr dankbar!



  • Meine Frage ist nun, ob das überhaupt der richtige Weg ist, mit vielen Texturen umzugehen. Ich habe letztes mal was gehört, dass man eine Textur auch aus mehreren Grafiken erzeugen kann und dann später einfach den Quads den entsprechenden Ausschnitt aus der großen Textur zuweist. Allerdings weiß ich ehrlich gesagt nicht, wie ich das am besten lösen könnte... 😞

    Naja, ob das in deinem Falle das Beste ist, wage ich anzuzweifeln...
    Ansonsten kann ich dir nur raten, dass du einen Tetxurmanager schreiben solltest. Du gibst jedem Texturnamen eine ID-Nummer und checkst vor dem laden der Textur, ob die Textur schon geladen wurde. Was du dir auf jeden Fall ansehen solltest sind VBO's, denn damit bekommst du schoneinmal einen ordentlichen Schub.



  • Hey,
    danke für die Antwort. Das redbook liegt neben mir und ich beschäftige mich mit VBO. Allerdings habe ich da noch ein Verständnisproblem, bei dem du mir vielleicht helfen könntest:

    Ich rufe meine bindTextures ja nur einmal beim Initialisieren auf, von daher werden die Texturen auch nur einmal geladen und zur Grafikkarte geschaufelt, oder?!

    Ich habe auch grad mal ein Beispiel mit VertexArrays und VBOs gemacht, allerdings das Standard-Bsp. Bei mir würde dann ja noch dazukommen, dass ich die Texturen darüber auch verwalten muss, oder? Da ich ja bisher meine Quads manuell rendere mit:

    // schleife über alle items
    // ...
    glBindTexture(GL_TEXTURE_2D, texNames[counter]);
    glBegin(GL_QUADS);
      glTexCoord2d(0, 1); glVertex3d(0, 1, 0);
      glTexCoord2d(0, 0); glVertex3d(0, 1, 0);
      glTexCoord2d(1, 0); glVertex3d(1, 0, 0);
      glTexCoord2d(1, 1); glVertex3d(1, 1, 0);
    glEnd();
    // ende schleife
    

    Würde mir bei VBOs das Setzen der Texturkoordinaten fehlen.

    Meine Frage also: Wie würde man dann die Texturen in diesem Konzept unterbringen?

    Update:
    Vielleicht noch als Info:
    Alle meine Items speichern ihre Position, die ich in der Schleife vorher mit glTranslate...() setze. Deshalb brauch ich in glBegin/glEnd auch nur relative Koordinaten für Textur und Vertex so wie im Beispiel.



  • Ich rufe meine bindTextures ja nur einmal beim Initialisieren auf, von daher werden die Texturen auch nur einmal geladen und zur Grafikkarte geschaufelt, oder?!

    Ja, kommt natürlich darauf an, was du unter "laden" verstehst...

    Meine Frage also: Wie würde man dann die Texturen in diesem Konzept unterbringen?

    ich bin gerade etwas verwirrt, Texturen oder Texturkoordinaten?



  • Unter laden würde ich folgendes verstehen:

    ich rufe in meiner initializeGL Methode meines OpenGL Widgets folgendes auf:

    glGenTextures(itemList.size(), texNames);
    bindTextures();
    

    In der bind-Methode wie schon geschrieben weise ich dann die Texturen aus den Grafiken zu.
    Da ich davon ausgehe, dass die initialize nur einmalig aufgerufen wird und glGenTextures den Speicher für die Texturen auf der Graka reserviert, denke ich dass die Texturen so nur einmalig geladen und vorhanden sind.

    Bitte berichtigt mich, falls ich da was falsch habe!!!

    Zur zweiten Frage:
    Für die Textur-Koordinaten müsste ich analog zu den VBOs ebenfalls den Buffer für Texturkoordinaten nutzen, um meine bisherige Vorgehensweise (Texel zuweisen, Vertex zuweisen) zu ersetzen?! Korrekt?!



  • Jetz muss ich doch nochmal nachfragen, weil ich mit den VBOs nich weiterkomme 😞

    Habe das redbook als getreuen gefährten neben mir und wollte das entsprechende Beispiel zu VBOs umsetzen, leider ohne Erfolg. Beim kompilieren meldet er mir schon einen Fehler beim Aufruf von glGenBuffers():

    GLuint buffers[2];
     glGenBuffers(2, buffers);
    

    Meldung: error: `glGenBuffers' was not declared in this scope

    Also hab ich mal weiter gegooglet, aber durch einige Tipps bin ich eher verwirrt. Ich dachte, VBOs werden ab OpenGL1 1.5 stanadardmäßig unterstützt. Muss ich trotzdem noch was extra einbinden?

    Ich entwickle mit Eclipse und MinGW unter Windows XP.

    Hier mal meine init-Methode:

    void init (void)
    {
        glClearColor (0.0, 0.0, 0.0, 0.0);
    
    /*  initialize viewing values  */
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
    
        GLuint buffers[1];
        glGenBuffers(1, buffers);
        glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
        glVertexPointer(2, GL_FLOAT, 0, BUFFER_OFFSET(0));
        glEnableClientState(GL_VERTEX_ARRAY);
    }
    

    Leider schweigt sich das redbook dazu aus 😞 !



  • Fuer 1000 Quads ist es relativ Wurscht ob man VBOs nimmt oder nicht, vor allem wenn sich deren Positionen staendig aendern.
    Relevant waere dass Du nicht fuer jedes Quad blind glBindTexture aufrufst, sondern irgendwie sortierst.



  • Danke für den Hinweis. Meine Texturen sind "sortiert". Ich lege sie einmal in der Reihenfolge meiner Items an, diese ändert sich nicht mehr.
    Beim zeichnen gehe ich in der selben Reihenfolge vor. Ich ändere lediglich die Positionen der Items in der Szene, aber nicht in der Liste.

    So wie es aussieht ist da also nich mehr viel zu optimieren oder hat jemand noch nen Vorschlag?

    P.S.: Unabhängig davon würde ich trotzdem gerne wissen, wie ich das mit den VBOs hinbekomme...



  • error: `glGenBuffers' was not declared in this scope

    Die OpenGL-Header im Platform-SDK sind von 1996 und repraesentieren V1.1.
    Du musst Dir also alle darueber hinausgehenden Funktionen per Extensions laden:

    PFNGLGENBUFFERSARBPROC glGenBuffers= (PFNGLGENBUFFERSARBPROC) wglGetProcAddress("glGenBuffersARB");
    

    Die notwendigen Deklarationen findest Du hier (bzw systemspezifische Erweiterungen hier).
    Alternativen sind glew oder glee.



  • Ich habs jetz hinbekommen mit den VBOs. Aber nur unter Benutzung der GLee - Library! Damit aber sehr einfach, nur die .h einbinden und mit der lib linken und schon funktionierts.



  • Hab nochmal ne Frage zum VBO. Und zwar funktioniert es ja nun, in meinem Beispielprogramm hab ich nur ein Quad.

    Wenn ich jetz da ne Textur drauflegen möchte, funktioniert das nich. Das Quad wird nur einfarbig gemalt... Ich habe natürlich die Textur geladen und wenn ich nur Vertex Arrays benutze, funktionierts sofort, aber das wär ja dann nicht im graka-speicher, oder?!

    Kann ich eine Textur überhaupt gleichzeitig benutzen, wenn ich die Vertices als VBOs habe?

    Mein Versuch war:

    GLdouble textures[] = { 0, 1, 0, 0, 1, 0, 1, 1};
    
    ...
    
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
     glTexCoordPointer(2, GL_DOUBLE, 0, textures);
    


  • Du musst fuer das Texture_Coord_Array auch ein VBO binden.
    Das kann entweder ein separater Buffer sein wo dann pro Vertex eben (u,v) abgelegt ist,
    oder, wenn Du eine interleaved Struktur hast, der gleiche wie beim Vertex-Array; dann musst Du die Groesse und den Offset innerhalb der Struktur angeben.

    Meines Wissens nach kann keine Grafikkarte nativ Doubles verarbeiten.



  • hey, das hatte ich eigentlich probiert und einen weiteren buffer angelegt. Allerdings wusste ich da nich, wie ich den aufbaue (GL_ARRAY_BUFFER) und dann mit dem texture-pointer verbinde???

    2. Heisst das ich sollte floats als Datentyp benutzen? Für die Vertices benutze ich auch doubles, da funktionierts auf jeden fall...



  • Für die Vertices benutze ich auch doubles, da funktionierts auf jeden fall...

    Geht auch, wird nach dem Schreiben in den VBO aber nochmal unsinnig konvertiert.

    wie ich den aufbaue (GL_ARRAY_BUFFER) und dann mit dem texture-pointer verbinde?

    Guckst Du hier.



  • YEAH! Funktioniert:

    glBindBuffer( GL_ARRAY_BUFFER, buffers[2] );
    	glBufferData(GL_ARRAY_BUFFER, sizeof(textures), textures, GL_STATIC_DRAW);
    
    	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    	glTexCoordPointer( 2, GL_FLOAT, 0, 0 );
    

    Ich glaub, es lag wirklich am GL_DOUBLE, denn nun habe ich das array und den Aufurf in glTexCoordPointer auf GL_FLOAT geändert und nun läuft es!

    Besten Dank!!



  • Und machen VBOs hier einen signifikanten Geschwindigkeitsunterschied?


Anmelden zum Antworten