Updateperformance bei komplexen 3D Animationen
-
Soweit ich weiß wird dann auf langsamere Register ausgeladert, dann dauerts halt länger. (:
Was man auch machen könnte:
Eine Textur auf die Stellen projezieren und sie mit einer Bumpmap blenden, die vorher mit einer Lightmap (Nach Blickwinkel generiert) multipliziert wird.Dadurch kriegt man Blickwinkelspetifische "3Dimensionale" und sogar Beleuchtete Effekte ohne sonderlich viel CPU und Grafikkarten aufwand.
Das dürfte doch eigentlich recht flott ghen, doer liege ich falsch?
-
makkurona schrieb:
Eine Textur auf die Stellen projezieren und sie mit einer Bumpmap blenden, die vorher mit einer Lightmap (Nach Blickwinkel generiert) multipliziert wird.
???
1. Hat er doch gesagt, dass er keinen Textur-Ansatz will
2. Was soll das bringen? Die Bumpmap ist ja gerade für eine "bessere" Beleuchtung da, wozu also nochmal eine Lightmap?
-
ich würde auf jedem fall mal VBOs versuchen. z.b. könntest du "kacheln" machen, und jede kachel des terrains in einen eigenen VBO packen. diese kacheln kannst du dann einzeln updaten. dadurch müssen nicht so viele vertexdaten zwischen video- und system-ram hin und her geschaufelt werden.
diese kacheln kannst du dann auch gleich für's LOD verwenden - weit entfernte kacheln werden eben nicht mit voller auflösung gezeichnet.
dazu müsstest du dann z.b. für jede kachel "mip-maps" rechnen, also kleinere versionen mit weniger vertices (gröberes mash).
-
this->that schrieb:
makkurona schrieb:
Eine Textur auf die Stellen projezieren und sie mit einer Bumpmap blenden, die vorher mit einer Lightmap (Nach Blickwinkel generiert) multipliziert wird.
???
1. Hat er doch gesagt, dass er keinen Textur-Ansatz will
2. Was soll das bringen? Die Bumpmap ist ja gerade für eine "bessere" Beleuchtung da, wozu also nochmal eine Lightmap?Er sagte, er will sie nicht, weil sie bei verschiedenen Ansichten zu Problemen führen können.
Was die Bumpmaps angeht scheine ich Mist gelabert zu haben. Ich habe mich noch ein zweites mal auf ein paar Seiten kundig gemacht und ja, ich hatte ein falsches Prinzip im Kopf.
Wobei das an sich doch auch mal eine nette Kombination wäre.. unötig, aber nett.^^
-
Was soll das bringen? Die Bumpmap ist ja gerade für eine "bessere" Beleuchtung da, wozu also nochmal eine Lightmap
Bump-Mapping und Light-Mapping sind komplementäre Techniken, können also ohne Weiteres sinnvoll kombiniert werden.
Mit Bump-Mapping kannst du "dellen" auf ein Objekt draufzaubern, also eine gewisse Richtungs- oder Winkelabhängigkeit der Beleuchtung erreichen. Das geht mit Light-Mapping nicht.
Mit Light-Mapping dagegen kannst du gewisse Stellen eines Objektes heller oder dunkler erscheinen lassen ("mehr oder weniger beleuchten"), also eine Positionsabhängigkeit der Beleuchtung erreichen. Das wiederum geht mit Bump-Mapping nicht.
Anders gesagt: beim Bump-Mapping geht es um "Richtungen", beim Light-Mapping dagegen um Positionen.
BTW: heutzutage nimmt man eher Normal-Mapping statt Bump-Mapping, da man mit Normal-Mapping einfach schönere Bilder bekommt ("korrekter" ist es auch, aber das wäre ja relativ egal), und die Grafikkarten mittlerweile halbwegs schnell genug sind.
-
hustbaer schrieb:
Was soll das bringen? Die Bumpmap ist ja gerade für eine "bessere" Beleuchtung da, wozu also nochmal eine Lightmap
Bump-Mapping und Light-Mapping sind komplementäre Techniken, können also ohne Weiteres sinnvoll kombiniert werden.
Nein, normale lightmaps koennen schlecht mit bumpmapping kombiniert werden. aus diesem grund nutzt z.b. HL2 radiosity normalmapping bei dem mehrere lightmaps richtungsabhaengig vorliegen.
Mit Bump-Mapping kannst du "dellen" auf ein Objekt draufzaubern, also eine gewisse Richtungs- oder Winkelabhängigkeit der Beleuchtung erreichen. Das geht mit Light-Mapping nicht.
natuerlich geht das mit lightmaps, mittels bumpmap bekommst du helligkeiten fuer eine normale an einem bestimmten punkt in abhaengikeit von der position+helligkeit der lichtquelle, bei einer lightmap ist diese helligkeit schon abgelegt.
Mit Light-Mapping dagegen kannst du gewisse Stellen eines Objektes heller oder dunkler erscheinen lassen ("mehr oder weniger beleuchten"), also eine Positionsabhängigkeit der Beleuchtung erreichen. Das wiederum geht mit Bump-Mapping nicht.
eine lightmap enthaellt natuerlich auch die helligkeit abhaengig von einem winkel wenn man das moechte und ist von dem lightstrahl zwischen lichtquellen-position und zu pixel im worldspace ausgerechnet.
Anders gesagt: beim Bump-Mapping geht es um "Richtungen", beim Light-Mapping dagegen um Positionen.
Bei bumpmap geht es darum lokale dynamische beleuchtung zu erzeugen. bei lightmaps hat man statische beleuchtung in die man globale ding (wie z.b. radiositaet) einfliessen lassen kann.
BTW: heutzutage nimmt man eher Normal-Mapping statt Bump-Mapping, da man mit Normal-Mapping einfach schönere Bilder bekommt ("korrekter" ist es auch, aber das wäre ja relativ egal), und die Grafikkarten mittlerweile halbwegs schnell genug sind.
normalmaps sind eine art des inputs fuer bumpmapping.
-
So ziemlich genau das was rapso geschrieben hat, wollte ich auch gerade schreiben. Aber seinem Posting ist eigentlich nichts mehr hinzuzufügen. ^^
-
Hm. Ok, wenn rapso das sagt glaube ich es erstmal. Sorry dass ich hier Blödsinn geschrieben habe! Sieht so aus als müsste ich mich mit dem Thema nochmal näher beschäftigen.
-
hustbaer schrieb:
Hm. Ok, wenn rapso das sagt glaube ich es erstmal. Sorry dass ich hier Blödsinn geschrieben habe! Sieht so aus als müsste ich mich mit dem Thema nochmal näher beschäftigen.
da empfehle ich sehr
http://www2.ati.com/developer/gdc/D3DTutorial10_Half-Life2_Shading.pdf
-
Habe nun einige Varianten probiert und möchte Euch die Ergebnisse nicht vorenthalten.
Allerdings bin ich mir nicht sicher, ob ich den erzielten Framerates ohne weiteres glauben darf
Meine Meshdaten liegen erstmal als Punktewolke vor, um die einzelnen Vertices dynamisch ändern zu können.
Getestet wurden 60501 Vertices auf einer Radeon 9250.Die Vertice-Struktur sah so aus:
struct { float nv[3]; float p[3]; char color; } vertice;Das Member "color" ist ein Index auf ein Farbfeld, was zum Testen aber nicht genutzt wurde.
Die Buffer wurden mit glInterleavedArrays definiert, da man sich hiermit einige Aufrufe erspart:glInterleavedArrays(GL_N3F_V3F, sizeof(vertice), 0);glDrawElements ist bei Verwendung von VBOs ab count=42000 gnadenlos in die Knie gegangen, ein Update dauerte dann schlagartig bis zu 5 sec!
40000 dagegen liefen problemlos.
Die Abfrage von GL_MAX_ELEMENTS_INDICES ergab 65535, GL_MAX_ELEMENTS_VERTICES liegt bei 2147483647.
Ohne Verwendung der VBOs gab es überhaupt keine Probleme.
Nach langem Suchen habe ich eben dieses zusätzliche char-Element als Verursacher herausgefunden...
Konnte jedoch nichts konkretes im Web finden, warum die Graka dies nicht mochte.Habe dann das char-Member und sämtliche Dynamik rausgenommen und nur das reine Darstellen der Daten gemessen.
Zum Vergleich habe ich mehrere Varianten erstellt.
Bei der "billigsten" sucht man sich per Pointer jeweils 4 nebeneinanderliegende Vertices und erzeugt einen Quad.
Für glDrawElements wird zusätzlich ein Index-Array erstellt und für glDrawArrays habe ich ein Array erstellt, das die Quads in fortlaufender Reihenfolge enthält.
Der Nachteil von glDrawArrays ist einerseits, dass jedes (innere) Vertice 4x im Array gelistet wird, andererseits geht damit auch die Flexibilität beim Ändern der einzelnen Vertices verloren.Hier nun die Ergebnisse:
glBegin(GL_QUADS)/glEnd: 31 fps
glDrawElements mit Indices-Array: 32 fps
glDrawArrays mit Quad-Array: 41 fps
glDrawArrays mit Quad-Array und VBOs: 41 fps
glDrawElements mit Indices-Array und VBOs: 46 fps
glBegin(GL_QUAD_STRIP)/glEnd: 51 fps
glBegin(GL_QUAD_STRIP)/glEnd, ohne glClear: 59 fps
glDrawElements mit VBOs, ohne glClear: 73 fpsglClear verschlingt somit einiges, da außerhalb der GPU aufgerufen.
Das Bit GL_DEPTH_BUFFER_BIT nimmt 16 Frames, GL_COLOR_BUFFER_BIT weitere 11.
Es machte bei der Menge zudem keinen Unterschied, ob ich die Indices mit einem Standard-Pointer oder mit einem STL-Vector übergab.Sind die Ergebnisse realistisch oder bin ich auf dem Holzweg?
Für die theoretische Videofrequenz von 25 fps würde ja schon die langsamste Methode reichen...
-
versuch triangles statt quads, graphickarten koennen eigentlich keine quads. es wird jedesmal zu dreiecken konvertiert.
wenn du glclear testen willst, mach das clear sofort nach dem swapbuffers und falls du einen stencilbuffer angibst, dann clear den auch.
char color, sowas gibt es hardwaremaessig nicht. und deine struct sollte 16byte alligned sein.
um sagen zu koennen weshalb dein vbo so lange bem update braucht, muesste man sehen was du machst, da laeuft eindeutig etwas schief.wobei ich mir bei einer 9250 auch nicht so sicher bin was die kann, war das nicht nur eine onboard karte?
-
rapso schrieb:
versuch triangles statt quads, graphickarten koennen eigentlich keine quads. es wird jedesmal zu dreiecken konvertiert.
Quads haben einen entscheidenen Vorteil: sie können sich krümmen, was bei korrekten Vertex-Normalen saubere Übergänge schafft.
Ausserdem halbiert es die Anzahl der Objekte, die Indices werden um 1/3 reduziert.
Habe trotzdem mal Triangles probiert.
"glDrawElements mit VBOs, ohne glClear" ging mit Triangles statt Quads von 73 auf 74 fps hoch
rapso schrieb:
wenn du glclear testen willst, mach das clear sofort nach dem swapbuffers und falls du einen stencilbuffer angibst, dann clear den auch.
Stencil nutze ich für den Test noch nicht.
Das glClear hatte ich ja schon rausgenommen, aber danke für den Tip!rapso schrieb:
char color, sowas gibt es hardwaremaessig nicht. und deine struct sollte 16byte alligned sein.
Der Witz ist, dass es bis 40000 Indizes keine Probleme gibt.
Dachte auch, das wäre genau der Sinn von Interleaved Arrays...
Somit sollte es der GPU doch egal sein, oder?rapso schrieb:
um sagen zu koennen weshalb dein vbo so lange bem update braucht, muesste man sehen was du machst, da laeuft eindeutig etwas schief.
Ist eigentlich nix aussergewöhnliches, hier mal eine kurze Zusammenfassung:
struct { float nv[3]; float p[3]; } vertice; // ... // Mesh Vertices extern berechnen // ... // Function Pointer holen glBindBufferARB = (PFNGLBINDBUFFERARBPROC)wglGetProcAddress("glBindBufferARB"); glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffersARB"); glBufferDataARB = (PFNGLBUFFERDATAARBPROC)wglGetProcAddress("glBufferDataARB"); glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)wglGetProcAddress("glDrawRangeElements"); glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) wglGetProcAddress("glDeleteBuffersARB"); // Indices erzeugen indices = new unsigned short[ (mesh.nCountX-1)*(mesh.nCountY-1)*6 ]; int ii=0; for( int x=0; x<(mesh.nCountX-1); x++) { for( int y=0; y<(mesh.nCountY-1); y++) { indices[ii] = x*mesh.nCountY + y; indices[ii+1] = x*mesh.nCountY + y + 1; indices[ii+2] = (x+1)*mesh.nCountY + y + 1; indices[ii+3] = (x+1)*mesh.nCountY + y + 1; indices[ii+4] = (x+1)*mesh.nCountY + y; indices[ii+5] = x*mesh.nCountY + y; ii += 6; } } // VBOs erzeugen und Daten kopieren glGenBuffersARB(1, &vboId); glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboId); glBufferDataARB(GL_ARRAY_BUFFER_ARB, (mesh.nCountX)*(mesh.nCountY)*sizeof(vertice), vertices, GL_STATIC_DRAW_ARB); glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); glGenBuffersARB(1, &eboId); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, eboId); glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, (mesh.nCountX-1)*(mesh.nCountY-1)*6*sizeof(unsigned short), indices, GL_STATIC_DRAW_ARB); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); //später zeichnen glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboId); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, eboId); glInterleavedArrays(GL_N3F_V3F, 0, 0); glDrawElements(GL_TRIANGLES, (mesh.nCountX-1)*(mesh.nCountY-1)*6, GL_UNSIGNED_SHORT, 0); glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);rapso schrieb:
wobei ich mir bei einer 9250 auch nicht so sicher bin was die kann, war das nicht nur eine onboard karte?
Nein, die Radeon 9250 ist eine 128MB AGP Karte mit recht guter 3D Performance.
Bei einer Quadro 3500 lief es ähnlich...Übrigens:
den Performance-Einbruch habe ich auch ohne Licht, also bei folgender Konfig:glDisable(GL_LIGHTING); glPolygonMode( GL_FRONT_AND_BACK, GL_LINE);Mit Licht passiert das nicht:
glEnable(GL_LIGHTING); glPolygonMode( GL_FRONT_AND_BACK, GL_FILL);Tappe hier momentan etwas im Dunkeln

-
rapso schrieb:
mach das clear sofort nach dem swapbuffers.
...
und deine struct sollte 16byte alligned sein.Hi Rapso,
habe beides nochmal explizit ausgetestet.
Hatte mich bislang daran orientiert, Berechnungen direkt nach dem Swappen auszuführen, da ich dies schon öfters gelesen hatte.Die Struktur habe ich jetzt mit
VERTICE __declspec(align(16)) vertice;deklariert, siehe auch http://msdn2.microsoft.com/en-us/library/83ythb65.aspx
Das glClear führe ich nun direkt nach dem Swappen aus.
Beides hat leider nicht die geringste Auswirkung.Mal abgesehen davon, dass die finale FPS mich nicht umhaut, so wundere ich mich immer noch sehr über die drastischen Einbrüche bei Verwendung der VBOs unter den vorher beschriebenen Bedingungen (mehr als 40000 Elemente für glDrawElements und im Wire-Modus).
Gruß,
Modes
-
Vielleicht reicht über der Anzahl von 40000 VBO's die Kapaizität der Grafikkarte nicht mehr und es muss auf festplatte doer andere Speichermedien ausgelagert werden. Schon mit dem RAM wäre es dann wesentlich langsamer als über den Grafikkarten internen Speicher.
Oder ich steh schon wieder auf dem Schlacuh und verwechsel etwas.
-
modestia schrieb:
rapso schrieb:
versuch triangles statt quads, graphickarten koennen eigentlich keine quads. es wird jedesmal zu dreiecken konvertiert.
Quads haben einen entscheidenen Vorteil: sie können sich krümmen, was bei korrekten Vertex-Normalen saubere Übergänge schafft.
eigentlich triangulieren das die graphikkarten nur bzw der treiber, du hast also eigentlich garkeine vorteile davon.
Ausserdem halbiert es die Anzahl der Objekte, die Indices werden um 1/3 reduziert.
Habe trotzdem mal Triangles probiert.
"glDrawElements mit VBOs, ohne glClear" ging mit Triangles statt Quads von 73 auf 74 fps hoch
ich koennte vermuten dass das problem woanders liegt wenn die framerate so ist. 74fps bei 40000 indices? also 60 000 wenn es dreiecke waeren? zufaellig *hehe*
was ist denn der maximale wert deiner 9250? 5Mio/s klingt nicht so gut, meine psp uebertrifft das (ohne licht etc.)rapso schrieb:
wenn du glclear testen willst, mach das clear sofort nach dem swapbuffers und falls du einen stencilbuffer angibst, dann clear den auch.
Stencil nutze ich für den Test noch nicht.
Das glClear hatte ich ja schon rausgenommen, aber danke für den Tip!wenn du einen stencilbuffer setzt, selbst wenn du den nicht benutzt, musst du den beim clear vom zbuffer mit clearen wenn es schnell gehen soll.
rapso schrieb:
char color, sowas gibt es hardwaremaessig nicht. und deine struct sollte 16byte alligned sein.
Der Witz ist, dass es bis 40000 Indizes keine Probleme gibt.
Dachte auch, das wäre genau der Sinn von Interleaved Arrays...
Somit sollte es der GPU doch egal sein, oder?und ab 40 000 indices fuer quads, also 60 000 bei triangles bricht es ein, und das nur wenn das char mit drinnen ist?
rapso schrieb:
um sagen zu koennen weshalb dein vbo so lange bem update braucht, muesste man sehen was du machst, da laeuft eindeutig etwas schief.
Ist eigentlich nix aussergewöhnliches, hier mal eine kurze Zusammenfassung:
...glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, (mesh.nCountX-1)*(mesh.nCountY-1)*6*sizeof(unsigned short), indices, GL_STATIC_DRAW_ARB); ...ich glaube zum updaten sollte man GL_DYNAMIC_DRAW benutzen
Übrigens:
den Performance-Einbruch habe ich auch ohne Licht, also bei folgender Konfig:glDisable(GL_LIGHTING); glPolygonMode( GL_FRONT_AND_BACK, GL_LINE);Mit Licht passiert das nicht:
glEnable(GL_LIGHTING); glPolygonMode( GL_FRONT_AND_BACK, GL_FILL);Tappe hier momentan etwas im Dunkeln

vielleicht bist du ja auch nicht von den vertices her limitiert. zum benchmarken von vertices solltest du das objekt so klein wie moeglich auf dem screen haben. des weiteren lohnen sich garkeine benchmarks wenn du im window mode bist, vor allem clear ist dannn vermutlich viel langsammer.
zudem solltest du checken ob du nicht mit VSync testest, denn wenn dein monitor nur 75hz darstellst, wirst du nie ueber diese fps kommen.
-
modestia schrieb:
rapso schrieb:
mach das clear sofort nach dem swapbuffers.
...
und deine struct sollte 16byte alligned sein.Hi Rapso,
habe beides nochmal explizit ausgetestet.
Hatte mich bislang daran orientiert, Berechnungen direkt nach dem Swappen auszuführen, da ich dies schon öfters gelesen hatte.welche berechnungen?
gut ist
logic zeichnen zwap clear logic zeichnen swap clear ...viele neigen zu
logic clear zeichnen swap ..zudem, wie gesagt, in fullscreen testen ;).
desweiteren, color cleart wohl kein spiel. man ueberzeichnet eh alles, und fuer den z+stencilbuffer gibtb es meist einen 'zero cycle clear', also quasi umsonst.Die Struktur habe ich jetzt mit
VERTICE __declspec(align(16)) vertice;deklariert, siehe auch http://msdn2.microsoft.com/en-us/library/83ythb65.aspx
Das glClear führe ich nun direkt nach dem Swappen aus.
Beides hat leider nicht die geringste Auswirkung.nein, darum geht es nicht

es geht darum dass in einem array die vertices immer 16byte (oder zumindestens 8byte) alligned sind.
wenn also sizeof(Vertex) 16, 32, 48... ist, gibst du der graphikkarte optimales futter. wenn du einen char einbaust, also dann ganz krumme werte hast bei den addressen der vertices, kommt eine gpu damit absolut nicht klar.
Ist wie SSE bei CPUs, alligned load ist sehr viel schneller als unalligned.Mal abgesehen davon, dass die finale FPS mich nicht umhaut, so wundere ich mich immer noch sehr über die drastischen Einbrüche bei Verwendung der VBOs unter den vorher beschriebenen Bedingungen (mehr als 40000 Elemente für glDrawElements und im Wire-Modus).
wiremodus kann durchaus langsammer als fillmodus sein ;). skalier das objekt einfach ganz klein zum testen. und wie gesagt, vsync aus und fullscreen

-
rapso schrieb:
welche berechnungen?
z.B. die Berechnungen, die das Mesh bzw. einzelne Vertices dynamisch aktualisieren und die beweglichen Objekte neu positionieren.
rapso schrieb:
viele neigen zu
logic clear zeichnen swap ..Ähem...an diesem Gerücht ist bestimmt was dran

rapso schrieb:
zudem, wie gesagt, in fullscreen testen ;).
DAS bringt in der Tat was, bin ohne glClear auf 106 fps gekommen

Ähnliche Raten bekomme ich (nun logischerweise) auch, wenn ich das Windowsfenster auf ca. 600x400 Pixel setze.
Denke, hier bin ich einfach zu gierig nach Pixeln
rapso schrieb:
desweiteren, color cleart wohl kein spiel. man ueberzeichnet eh alles, und fuer den z+stencilbuffer gibtb es meist einen 'zero cycle clear', also quasi umsonst.
Aha, also lieber einen blauen Himmel als Hintergrund zeichnen als "clearen"?
Beim Stencil bin ich noch nicht, werde ich aber mal testen...rapso schrieb:
nein, darum geht es nicht

es geht darum dass in einem array die vertices immer 16byte (oder zumindestens 8byte) alligned sind.Dachte, genau das soll ja die "align" Methode vorgaukeln.
Hatte aber das CHAR aus dem Struct schon rausgenommen, so dass es hier kein Unterschied mehr machte.Komme jetzt der Sache schon näher, danke schonmal!
-
glFlush() vor dem swappen kann in einigen fällen und treiberabhängig einen großen geschwindigkeitsvorteil bringen

edit: SwapBuffers() impliziert eigentlich glFlush(), nichtsdestotrotz hat es aus irgendeinem mir unerfindlichem grund ein steigerung der framerate eines projektes von mir um 250% gebracht. vielleicht ist der treiber verbuggt :S