OpenGL immediate mode vs VertexArrays

Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Neue Antwort erstellen

 

PhillipK

Betreff: OpenGL immediate mode vs VertexArrays

BeitragMo, Nov 07, 2011 10:33
Antworten mit Zitat
Benutzer-Profile anzeigen
Heyho!

Ich musste grade mit erschrecken feststellen, das mein immedate mode enorm schneller ist, wie ein VertexArray.
Hierzu hege ich die vermutung, das vertexarrays / vbos sich erst ab einer gewissen anzahl an vertices lohnen. Kann mir da jemand etwas konkreter auf die sprünge helfen?

Hier mal die beiden gemessenen zeiten:

Zirka 1000 Quads:
immediate : 160fps
DrawArray : 100fps

0 Quads:
immediate : 400fps +
DrawArray : 100fps

Es sei angemerkt, das meine immediate version immer dann eintritt, wenn eine änderung stattfand (oder ich den entsprechenden debugknopf drücke), dieser stellt direkt diverse werte ein, baut sogar noch die arrays. Trotzdem, immens schneller.

Habe ich einfach nur irgendwo mist gebaut, oder ist das ein "normales" verhalten, bei so geringen Quad-zahlen?
Ps: die 1000 quads sind auf etwa 10 unterarrays aufgeteilt, die ich einzeln zeichne.

BtbN

BeitragMo, Nov 07, 2011 17:30
Antworten mit Zitat
Benutzer-Profile anzeigen
Auf 100 FPS begrenzt vllt.?
Oder die arrays jeden frame neu erstellt und befüllt?
 

PhillipK

BeitragMo, Nov 07, 2011 18:02
Antworten mit Zitat
Benutzer-Profile anzeigen
Nein, die fps grenze liegt debugmäßig bei 200. Solange ich die annähern kann, ist das map zeichnen in ordnung *g*

Das mit dem neu erstellen und füllen isses ja:

Beim bwegen etc wird ein Array update aufgerufen.
Das ganze kann ich per KEY_SPACE erzwingen, dh folgendes:

Alle kacheln abgehen
Sichtbarkeit überprüfen (2ter array)
Alle sichtbaren kacheln sammeln und zeichnen
---
Alle gesammelten kacheln als array generieren
"update" auf 0 setzen.

-> Wenn update =0, wird der vertex array gezeichnet.
update = 1 oder KEY_SPACE = oben beschriebener vorgang

Update=0 fall: 100fps
Update=1 fall: schwankend, 120 bis 170fps.


Hab testweise das ganze rausgenommen und nur den glBegin-krams drin -> es ist einfach schneller.

Ich verstehe das nicht wirklich - wie kann das sein Very Happy

(nagut, dochnochmal das arrayzeichnen durchforsten - wenn ich da irgendwo waitTimer - warum auch immer - eingebaut habe, begehe ich selbstmord -.-)

edit:

Nein, keinerlei begrenzung.

Hier mal das DrawArray-stückel:

BlitzMax: [AUSKLAPPEN]
	Method RenderArray(map:TLandscape)
If Len(map.array) > 0 And Len(map.texarray) > 0 Then
'If Len(map.array) <> Len(map.texarray) Then RuntimeError("Array längen unterschiedlich")

RecieveGLError("renderstep0")
glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)

RecieveGLError("renderstep1")

Local i:Int, j:Int, col:Float

For i = 0 Until Len(map.array)
col = Float(i + 1) / (SICHTBAREN_EBENEN - 1)
If col < 0.0 Then col = 0.0
If col > 1.0 Then col = 1.0

glColor3f(col, col, col)

For j = 0 Until Len(map.array[i])
Select j
Case 0
glBindTexture(GL_TEXTURE_2D, TBlock_data.Block_Tex)
Case 1
glBindTexture(GL_TEXTURE_2D, TBlock_data.Vegetation_tex)
Case 2
glBindTexture(GL_TEXTURE_2D, TBlock_data.Furniture_tex)
End Select
RecieveGLError("renderstep2")



glVertexPointer(3, GL_FLOAT, 0, map.array[i][j])
glTexCoordPointer(2, GL_FLOAT, 0, map.texarray[i][j])
RecieveGLError("renderstep3")
glDrawArrays(GL_QUADS, 0, Len(map.array[i][j]) / 3)
RecieveGLError("renderstep4")
Next

Next
glDisableClientState(GL_VERTEX_ARRAY)
glDisableClientState(GL_TEXTURE_COORD_ARRAY)
EndIf
End Method


RecieveGLError ist eine kleine debugfunktion, die mir den entsprechenden Error mit zusatz printet, damit ich ewaigte fehler besser nachvollziehen kann.

Alles in allem sind das ingsamt grademal ein tausendenstel der pointerzugriffe auf gleiche arrays etc, wie beim anderen modus. Also muss es in irgendeiner form am glDrawArrays liegen :/

Noobody

BeitragMo, Nov 07, 2011 18:38
Antworten mit Zitat
Benutzer-Profile anzeigen
Nun, du hast bei jedem Quad einen Aufruf an glBindTexture, glVertexPointer, glTexCoordPointer und glDrawArrays drin, d.h. wenn du deine 1000 Quads zeichnest, machst du tatsächlich 1000 Zeichenaufrufe plus State-Changes. Das heisst, dein Array enthält 4 Vertices und du zeichnest 1000 Stück davon.
Kannst du verstehen, warum das langsam ist? Razz

Was du tun solltest, ist, alle deine 1000 Quads in ein VertexArray mit Platz für 4000 Vertices zu schreiben, und mit einem Zeichenaufruf zu zeichnen. Wenn du mehrere Texturen benötigst, machst du für jede Textur ein neues Array mit separatem Zeichenaufruf (oder aber, da wir von einer Tilemap sprechen, packst du die einzelnen kleinen Texturen auf eine grosse und änderst stattdessen die Texturkoordinaten entsprechend).

Es ist wahr, dass VertexArrays erst ab einer gewissen Anzahl Vertices einen Geschwindigkeitsvorteil haben, und mit 4 Vertices auf ein paar tausend Zeichenaufrufe ist halt der Overhead grösser.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun
 

PhillipK

BeitragMo, Nov 07, 2011 19:13
Antworten mit Zitat
Benutzer-Profile anzeigen
Hm ne nicht ganz so einfach Very Happy

Meine map ist momentan unterteilt:

Pro Y ebene ein unterarray, pro Textur ein unterarray.
Im normalfall fallen da pro y ebene etwa 150 quads pro ebene an, welche sich auf blöcke beziehen, und ein paar (vllt 15 quads) für andere Texturen.

Momentchen, es war dumm einfach den code zu pasten. Ich kommentiere mal ein wenig :/

BlitzMax: [AUSKLAPPEN]
	Method RenderArray(map:TLandscape)
If Len(map.array) > 0 And Len(map.texarray) > 0 Then

glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)

Local i:Int, j:Int, col:Float

'Anzahl der ebenen durchgehen - 0 bist erste dimension-länge.
For i = 0 Until Len(map.array)

'Farbe setzen (abdunkeln der tieferen ebenen)
col = Float(i + 1) / (SICHTBAREN_EBENEN - 1)
If col < 0.0 Then col = 0.0
If col > 1.0 Then col = 1.0

glColor3f(col, col, col)

'Textur schritte.
'unterteilt in ingesamt 3 texturen: Möbel, Blöcke und Grünzeug.
For j = 0 Until Len(map.array[i])
Select j
Case 0
glBindTexture(GL_TEXTURE_2D, TBlock_data.Block_Tex)
Case 1
glBindTexture(GL_TEXTURE_2D, TBlock_data.Vegetation_tex)
Case 2
glBindTexture(GL_TEXTURE_2D, TBlock_data.Furniture_tex)
End Select

'Wir haben nun ebene Y, Zeichenzeugs X (blöcke, möbel, grünzeug)...

glVertexPointer(3, GL_FLOAT, 0, map.array[i][j])
glTexCoordPointer(2, GL_FLOAT, 0, map.texarray[i][j])
'...und haben die pointer gesetzt.

'Zeichnen:
glDrawArrays(GL_QUADS, 0, Len(map.array[i][j]) / 3)
'Es wurde nun einer von 3 arrays pro höhenstufe gezeichnet.
Next

'Es wurden alle drei arrays der höhenstufe gezeichnet.
Next
glDisableClientState(GL_VERTEX_ARRAY)
glDisableClientState(GL_TEXTURE_COORD_ARRAY)
EndIf
End Method


Hierzu nocheinmal das array erstellen, damit du mir glaubst Very Happy (auszug aus Type TLandscape)
BlitzMax: [AUSKLAPPEN]
	Method buildArray(blocks:TDRawTest[][][])
array = array[..SICHTBAREN_EBENEN]
texarray = texarray[..SICHTBAREN_EBENEN]
Local i:Int, j:Int
For i = 0 Until SICHTBAREN_EBENEN
array[i] = array[i][..3]
texarray[i] = texarray[i][..3]
For j = 0 Until 3
array[i][j] = New Float[12 * 2000]
texarray[i][j] = New Float[8 * 2000]
Next
Next


i = 0
Local indices:Int[][][]
indices = indices[..SICHTBAREN_EBENEN]
For j:Int = 0 Until SICHTBAREN_EBENEN
indices[j] = indices[j][..3]

For Local a:Int = 0 Until 3
indices[j][a] = New Int[2]
Next
Next

' blocks[_y2][block_sorte][indices[_y2]]
Local y:Int = 0
Local block_sorte:Int = 0
Local tile:TDrawTest

' von 0 bis sichtbare ebenen: Ist auf 10 *glaub* eingestellt.
'ausserdem ist "blocks" array vorsortiert, nur etwa sichtbare kacheln sind da überhaupt reingekommen.
For y = 0 Until SICHTBAREN_EBENEN

'Hier etwas besser namentlich verdeutlicht: Block_sorte kann möbel, grünzeug oder Block darstellen.

For block_sorte = 0 Until 3

For i = 0 Until Len(blocks[y][block_sorte])
tile = blocks[y][block_sorte][i]

If tile Then
tile.tile.GetArray(tile.x, tile.y, tile.z, array[y][block_sorte], texarray[y][block_sorte], indices[y][block_sorte])
indices[y][block_sorte][0]:+12 'XYZ für 4 vertices: 12 auf den index drauf.
indices[y][block_sorte][1]:+8 'UV für 4 vertices: 8 auf den index drauf.
EndIf
Next

Next

Next
End Method


Nungut, entweder bin ich nun völlig bescheuert, oder noo hat sich zum ersten mal geirrt! *feier* (aber das ist leider meine schuld, weil der code schwer zu lesen ist (i, j, wer weiß schon was das ist? *g*))

Genau sagen, wieviele Vertices pro höhenstufe und Texturzeugs vorhanden sind, kann ich leider nicht. Ich weiß nur vom Direkten zeichnen, das immer etwa 1000 quads gezeichnet werden.

Nun, dann mal eben anders gefragt: wie kann ich bestimmen, wieviel overhead bei was zustande kommt?
Die bedeutung kann ich mir nur vage übersetzen. Allerdings: Ausgehend davon, ab wieviel vertices lohnt ein Vertexarray? Gibts da eine pi*auge zahl oder ist das reine glückssache, vom ganzen krams drumrum?

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group