PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : OpenGL-Texturen


shapoc
2009-07-11, 15:41:45
Hallo zusammen,
ich bin neu hier im Forum und habe eine Frage zur Texturverwaltung mit OpenGL. Ich beschreib mal kurz was ich bisher gemacht habe.

Ich programmiere mit Qt und möchte Bilder als Texturen auf Quads darstellen. Dazu habe ich mir bisher jeweils ein eigenes Objekt erstellt, dem eine Position zugewiesen und die Grafik als Textur.
Anschließend bin ich alle Elemente durchgegangen und habe für jedes Element Texturspeicher reserviert.

void GLWidget::setItemList(QList<Item*> list)
{
itemList = list;
texNames = new GLuint[itemList.size()];
}
...
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;
}
}

In meiner Paint-Methode rufe ich dann entsprechend für jedes Element die dazugehörige Textur ab und packe sie auf mein Einheitsquad.

Das funktioniert auch soweit ganz gut, allerdings habe ich ca. 1000 Elemente in meiner Scene, die dann im Moment so ca. 130MB Arbeitsspeicher belegt.

Meine Frage ist nun: 1.) Ist das soweit ok oder hab ich was übersehen?

2.) Ich habe mal irgendwo gelesen, dass man die Bilder auch zu größeren Texturen zusammenfassen kann und später dann für mehrere Objekte jeweils den entsprechenden Ausschnitt aus der größeren Textur ausliest? Weiß jemand wie sowas funktioniert bzw. ob das performanter/ressourcenschonender ist? Hab dazu leider noch keine Beispiele gefunden... :-(

Danke schonmal für Hinweise und Tipps!!!

Gast
2009-07-11, 16:26:56
Das funktioniert auch soweit ganz gut, allerdings habe ich ca. 1000 Elemente in meiner Scene, die dann im Moment so ca. 130MB Arbeitsspeicher belegt.

Kommt halt stark darauf an wie groß deine Textren sind. Wenn die 2k x 2k und du auf jedem Quad eine andere Textur hast geht das schon in den Speicher....

Meine Frage ist nun: 1.) Ist das soweit ok oder hab ich was übersehen?

2.) Ich habe mal irgendwo gelesen, dass man die Bilder auch zu größeren Texturen zusammenfassen kann und später dann für mehrere Objekte jeweils den entsprechenden Ausschnitt aus der größeren Textur ausliest? Weiß jemand wie sowas funktioniert bzw. ob das performanter/ressourcenschonender ist? Hab dazu leider noch keine Beispiele gefunden... :-(

Danke schonmal für Hinweise und Tipps!!!
Zu 2. kann ich auch nicht viel sagen, ich galube aber nicht dass das einen Geschwindigkeitsunterschied macht. Höchstens dass du dann alles in einem Rutsch auf die Graka laden kannst und dadurch weniger Overhead hast als wenn du es 1000 mal hintereinander machst, aber ob das viel ausmacht....
Vor allem musst du dann ja aufpassen wenn du MIPs erzeugst, da brauchst du dann einen Rahmen zwischen den einzelen Texturen sonst funktioniert das ganze nicht. Hat nicht Half-Life 2 das so gemacht? War aber glaub ich dann auch recht kompliziert...

Markus89
2009-07-11, 17:33:15
Das zusammenfassen von Texturen bedeutet einfach folgendes: deine Bilder sind zum Beispiel alle 64x64 Pixel groß. Dann erstellt man eine 128x128 Pixel große Textur und packt die vier Bilder neben und untereinander dort hinein. Entsprechend muss man beim Zeichnen die Texturkoordinaten anpassen. Dadurch spart man sich Texturwechsel und ein bisschen Speicher.

Ein Texturwechsel verbraucht relativ viel Zeit, aber wenn du nur Quads mit einer Textur drauf zeichnest wird dir das nichts bringen.

shapoc
2009-07-11, 18:52:09
Danke euch erstmal für die schnellen Antworten.

@Markus89: Ich habe zwar Quads, aber jeweils mit einer eigenen Textur, die aus einem Bild kommt.
Macht das dann einen Unterschied?

Markus89
2009-07-11, 19:23:42
Wie groß sind denn die Texturen? Es bringt ja nichts wenn du mehrere Bilder in eine Textur packst und die dann zu groß ist. 1000 Texuren sind schon ne ganze Menge aber selbst ohne Details zu wissen würde ich behaupten dass du beim Zeichnen keine Performancezuwächse bekommen wirst.

shapoc
2009-07-11, 19:35:27
Erstmal relativ klein, zwischen 120 und 200 Pixeln. Später sollen eventuell größere nachgeladen werden, beim heranzoomen zum beispiel.

ScottManDeath
2009-07-11, 19:37:44
http://developer.nvidia.com/object/nv_texture_tools.html

... unter texture atlas tools gibts Tools und Dokumentation um mehrere Texturen in einer groesseren zusammenzufassen, aka texture atlas.

shapoc
2009-07-12, 12:10:20
@ScottManDeath: Danke für den Hinweis. Das scheint bei denen ja ordentlich Performance zu bringen. Bei mir ist nur das Problem, dass ich die Bilder dynamisch erst zur laufzeit habe und deshalb das nicht im voraus erstellen kann.
Aber es gibt doch bestimmt ne Möglichkeit, wie man mit OpenGL direkt sich selbst eine größere Textur zusammenbauen kann, oder?! Kann mir jemand dazu Tipps oder Beispiele geben?

Dann könnte ich mir quasi ausrechnen, wie viele Quads ich habe und diese dann durch eine zweier-Potenz z.b. in 512x512-er Texturen zusammenfassen und müsste mir für jedes Quad die Textur-ID und die Position in der Textur speichern.

instinct
2009-07-12, 14:04:19
Schau dir mal FBOs (Framebuffer Object) an. Damit kannst du eine Szene beispielsweise in eine 2D-Textur rendern.
Du könntest also in orthografischer Projektion deine Texturen einmal auf mehrere direkt nebeneinander liegende Quads (oder auf ein großen Quad) rendern und die Textur speichern.
Auslesen der gerenderten Texture mit glTexSubImage2D (eventuell in Verbindung mit PBOs (Pixel Buffer Object))

shapoc
2009-07-12, 14:58:45
@instinct: Danke für den Tipp. Allerdings möchte ich die Position meiner Quads zur Laufzeit verändern. wenn also beim verschieben der szene ein quad links aus dem fenster rausgeht, soll es rechts wieder reinkommen. also eine art "unendliche" scrollebene...

Ein einziges Quad wird wahrscheinlich auch nicht gehen, weil ich später auch noch die einzelnen Quads per Mouse auswählen möchte.

Markus89
2009-07-12, 16:20:58
glTexSubImage2D schreibt in eine Textur und liest sie nicht. FBOs bringen bei dem Problem meiner Meinung nach nicht viel da man die Textur vorher auch erstellen müsste um sie dann in das FBO zu rendern.

Ich würde das so machen:


glGenTextures(1, &texID); // Textur erstellen
glBindTexture(texID, GL_TEXTURE_2D); // binden
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 512, 512, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); // Format bestimmen

// Einzelne Bilder in die Textur laden
glTexSubImage2D(GL_TEXTURE_2D,
0,
xoffset, yoffset, // Position
width, height // Größe des Bildes
GL_RGB, GL_UNSIGNED_BYTE
data);



Du erstellst eine 512x512 Pixel große Textur und kannst den Platz darin für mehrere Bilder benutzen deren Daten du mit glTexSubImage2D hochlädst.
Dann musst du dir noch die Position der einzelnen Bilder merken um die Texturkoordinaten anzupassen.

instinct
2009-07-13, 10:04:53
Mit glTexSubImage2D kann man sehr wohl Daten auslesen. Ist eine Texture geladen und gebunden kommt man ohne Weiteres nicht mehr an die PixelDaten. Mit glTexSubImage2D kann man sich eine Pointer auf ein GLubyte * holen, wo man die Pixelinformationen wieder abgreifen kann.

Markus89
2009-07-13, 10:38:33
Nein. glTexSubImage2D schreibt die Daten in die Textur. Die einzige Möglichkeit die Daten auszulesen ist glGetTexImage() - und da nur alles auf einmal.