VBO Type - korrektur nötig?

Übersicht BlitzMax, BlitzMax NG Allgemein

Neue Antwort erstellen

 

PhillipK

Betreff: VBO Type - korrektur nötig?

BeitragSo, Jan 13, 2013 15:13
Antworten mit Zitat
Benutzer-Profile anzeigen
Huhu!

Ich habe mich endlich mal wieder mit VBOs auseinandergesetzt.
Vor Urzeiten hatte ich bereits einmal überlegt, ein kleines Tutorial zu schreiben.
Doch bevor es dazu kam, hatte ich mal wieder alles verhaun und kein VBO mehr zustande bekommen. Ergo: Ich war doch zu blöde.

Gestern habe ich mir ein kleines VBO type zusammengebaut, um endlich mal ohne langes probieren ein VBO in gang zu kriegen. Hier ist das ergebnis.

Ich frage mich allerdings, ob ich alles richtig durchdacht habe.

Grobe vorgehensweise:
1) Man erstellt eine instanz des Types.
2) Man erstellt alle Arrays die man benötigt. Es werden VertexArray, TextureArray, NormalArray und Colorarray unterstützt. Man kann diese mit VBO.AddXYZ( arr:float[] ) hinzufügen.
3) Das Type prüft automatisch, welche array hinzugefügt wurden und bestimmt für später zum Rendern den entsprechenden modus.
4) durch die Methode Build() wird das VBO fertig gestellt. Durch die angaben, die mit -3)- gewonnen werden, werden die einzelnen Arrays zu einem größeren zusammengepappt und in den Grafikspeicher geschoben.

Beispielcode zum erstellen eins vbo und rendern folgt unten, erstmal das type:

TYPE TVertexBufferObject
BlitzMax: [AUSKLAPPEN]
Const VBO_VERTICES:Int = 1
Const VBO_TEXCOORDS:Int = 2
Const VBO_NORMAL:Int = 4
Const VBO_COLOR:Int = 8

Type TVertexBufferObject

Field vbo:Int[]

Field buildingArray:Float[][]
Field vertCount:Int = 0

Field currentMode:Int
Field _glMode:Int = GL_v3f

Field vboSize:Int = 0
Field _stride:Int = 0

Field cleared:Int = 0

Field _isCol4:Int = False

Method New()
buildingArray = buildingArray[..4]
vbo = New Int[2] '-> Ja, 2 array einträge. Im moment noch overkill, kriegt aber evtl seine berechtigung für Triangles VS Quads, falls ich keine routine finde, um die Quads in den GL_TRIANGLES modus zu übersetzen. Bin halt faul^^
End Method

Method Create:TVertexBufferObject(approxSize:Int)


Return Self
End Method

Method AddVertexArray(vertices:Float[])
buildingArray[0] = vertices

vertCount = Len(vertices) / 3
If Len(vertices) Mod 3 > 0 Then RuntimeError("Unable to create VBO: Vertice count is not correct.")

currentMode:+VBO_VERTICES
End Method
Method AddTextureArray(texcoords:Float[])
If Len(texcoords) / 2 <> vertCount Then RuntimeError("Lenght of Texcoord array doesnt match with vertex count")

buildingArray[1] = texcoords

currentMode:+VBO_TEXCOORDS
End Method
Method AddNormalArray(normals:Float[])
If Len(normals) / 3 <> vertCount Then RuntimeError("Length of Normals array doesnt match with vertex count")

buildingArray[2] = normals

currentMode:+VBO_NORMAL
End Method
Method AddColorArray(colors:Float[])
If Len(colors) / 3 <> vertCount And Len(colors) / 4 <> vertCount Then RuntimeError("Length of Color array doesnt match with vertex count")

buildingArray[3] = colors

If Len(colors) / 3 = vertCount Then
_isCol4 = False
Else
_isCol4 = True
End If

currentMode:+VBO_COLOR
End Method

Method getMode:Int()
If Self.currentMode = VBO_VERTICES Then
Return GL_V3F
ElseIf Self.currentMode = VBO_VERTICES + VBO_COLOR Then
Return GL_C3F_V3F
ElseIf Self.currentMode = VBO_VERTICES + VBO_TEXCOORDS Then
Return GL_T2F_V3F
ElseIf Self.currentMode = VBO_VERTICES + VBO_TEXCOORDS + VBO_COLOR Then
Return GL_T2F_C3F_V3F
ElseIf Self.currentMode = VBO_VERTICES + VBO_TEXCOORDS + VBO_NORMAL Then
Return GL_T2F_N3F_V3F
ElseIf Self.currentMode = VBO_VERTICES + VBO_TEXCOORDS + VBO_COLOR + VBO_NORMAL Then
Return GL_T2F_C4F_N3F_V3F
Else
Return - 1
End If
Return - 1
End Method
Method getLen:Int()
Local l:Int = 0

If Self.currentMode & VBO_VERTICES Then
l:+Len(Self.buildingArray[0])
Else
RuntimeError("Unable to create VBO: You need to setup Vertex data to build your VBO!")
EndIf

If Self.currentMode & VBO_TEXCOORDS Then
l:+Len(Self.buildingArray[1])
End If
If Self.currentMode & VBO_NORMAL Then
l:+Len(Self.buildingArray[2])
End If



'Tricky part:
' Falls man alles setzt, dh Normals, Texture, Color und Vertices, ist einzig der C4F modus unterstützt. Heißt: Nur RGBA colors.
' Dh hier muss ich ein wenig abfragen, um überhaupt erstmal rauszukriegen, wieviel Speicher die Farbe im ram benötigt.
If Self.currentMode & VBO_COLOR And Self.getMode() = GL_T2F_C4F_N3F_V3F Then
If Len(Self.buildingArray[3]) / 4 <> vertCount
l:+(Len(Self.buildingArray[3]) / 3) * 4 '-> es sind farben gesetzt, der mode ist zwangsweise C4f, aber es liegt ein RGB array vor.
Else
l:+Len(Self.buildingArray[3]) '-> es liegt ein RGBA array vor.
EndIf
Else If Self.currentMode & VBO_COLOR And Self.getMode() <> GL_T2F_C4F_N3F_V3F Then
l:+Len(Self.buildingArray[3]) ' -> Liegt hoffentlich ein RGB array vor.
End If

Return l
End Method

Method generateArray:Float[] ()
If Self.getMode() = GL_T2F_C4F_N3F_V3F And Self._isCol4 = True And Len(Self.buildingArray[3]) / 4 <> Self.vertCount Then
Local newArr:Float[] = New Float[Len(Self.buildingArray[3]) / 3 * 4]
DebugLog("VBO : GENERATEARRAY: a GL_T2F_C4F_N3F_V3F mode is choosen, but the color array is in RGB format: Fixing array!")
For Local i:Int = 0 Until Self.vertCount
newArr[i * 4 + 0] = Self.buildingArray[3][i * 3 + 0]
newArr[i * 4 + 1] = Self.buildingArray[3][i * 3 + 1]
newArr[i * 4 + 2] = Self.buildingArray[3][i * 3 + 2]
newArr[i * 4 + 3] = 1.0
Next
Self.buildingArray[3] = newArr
End If

Self.vboSize = Self.getLen()
Local ret:Float[] = New Float[Self.vboSize]

Local stride:Int = 0
Select Self.getMode()
Case GL_V3F
For Local i:Int = 0 Until Self.vertCount
ret[i * 3 + 0] = Self.buildingArray[0][i * 3 + 0]
ret[i * 3 + 1] = Self.buildingArray[0][i * 3 + 1]
ret[i * 3 + 2] = Self.buildingArray[0][i * 3 + 2]
Next
Self._stride = 3

Case GL_C3F_V3F
For Local i:Int = 0 Until Self.vertCount
ret[i * 6] = Self.buildingArray[3][i * 3]
ret[i * 6 + 1] = Self.buildingArray[3][i * 2 + 1]
ret[i * 6 + 2] = Self.buildingArray[3][i * 2 + 2]

ret[i * 6 + 3] = Self.buildingArray[0][i * 3 + 0]
ret[i * 6 + 4] = Self.buildingArray[0][i * 3 + 1]
ret[i * 6 + 5] = Self.buildingArray[0][i * 3 + 2]
Next
Self._stride = 6

Case GL_T2F_V3F
For Local i:Int = 0 Until Self.vertCount
ret[i * 5 + 0] = Self.buildingArray[1][i * 2 + 0]
ret[i * 5 + 1] = Self.buildingArray[1][i * 2 + 1]

ret[i * 5 + 2] = Self.buildingArray[0][i * 3 + 0]
ret[i * 5 + 3] = Self.buildingArray[0][i * 3 + 1]
ret[i * 5 + 4] = Self.buildingArray[0][i * 3 + 2]
Next
Self._stride = 5

Case GL_T2F_C3F_V3F
For Local i:Int = 0 Until Self.vertCount
ret[i * 8 + 0] = Self.buildingArray[1][i * 2 + 0]
ret[i * 8 + 1] = Self.buildingArray[1][i * 2 + 1]

ret[i * 8 + 2] = Self.buildingArray[3][i * 3 + 0]
ret[i * 8 + 3] = Self.buildingArray[3][i * 3 + 1]
ret[i * 8 + 4] = Self.buildingArray[3][i * 3 + 2]

ret[i * 8 + 5] = Self.buildingArray[0][i * 3 + 0]
ret[i * 8 + 6] = Self.buildingArray[0][i * 3 + 1]
ret[i * 8 + 7] = Self.buildingArray[0][i * 3 + 2]
Next
Self._stride = 8
Case GL_T2F_N3F_V3F
For Local i:Int = 0 Until Self.vertCount
ret[i * 8 + 0] = Self.buildingArray[1][i * 2 + 0]
ret[i * 8 + 1] = Self.buildingArray[1][i * 2 + 1]

ret[i * 8 + 2] = Self.buildingArray[2][i * 3 + 0]
ret[i * 8 + 3] = Self.buildingArray[2][i * 3 + 1]
ret[i * 8 + 4] = Self.buildingArray[2][i * 3 + 2]

ret[i * 8 + 5] = Self.buildingArray[0][i * 3 + 0]
ret[i * 8 + 6] = Self.buildingArray[0][i * 3 + 1]
ret[i * 8 + 7] = Self.buildingArray[0][i * 3 + 2]
Next
Self._stride = 8

Case GL_T2F_C4F_N3F_V3F
stride = 12
'noch nicht eingebaut. theoretisch einfach das selbe spiel wie vorher, mit dem unterschied das die rechnung immer ret[i * 8 + X] lautet.
End Select


Return ret
End Method

Rem
bbdoc: Build baut den VBO Array erst im Hauptspeicher zusammen und kopiert ihn dann in den Grafikspeicher.
end rem

Method Build()

glGenBuffersARB(1, Varptr(Self.vbo[0])) 'neuen Buffer anlegen

glBindBufferARB(GL_ARRAY_BUFFER, Self.vbo[0]) 'buffer binden um ihn zu nutzen.

Local _vboPtr:Float[] = Self.generateArray() 'VBo array bauen.

glBufferData(GL_ARRAY_BUFFER, Self.getLen() * 4, Varptr(_vboPtr[0]), GL_STATIC_DRAW) 'Buffer in den Grafispeicher kopieren.

Self._glMode = Self.getMode() 'und noch, zum zeichnen, den modus holen.

End Method

Method Render()
Rem
Anmerkungen:
Der Typ wird zusammengebaut. Heißt, wir können hier keinen fixwert für den Modus angeben. Unterstützt werden:
* GL_V3F -> nur Vertexdaten.
* GL_C3F_V3F -> RGB Array + Vertexdaten
* GL_T2F_V3F -> UV Array + Vertexdaten
* GL_T2F_C3F_V3F -> UV Array + RGB Array + Vertexdaten
* GL_T2F_N3F_V3F -> UV Array + Normal Array + Vertexdaten
* GL_T2F_C4F_N3F_V3F -> UV Array + RGBA Array + Normal Array + Vertexdaten
end rem


glBindBufferARB(GL_ARRAY_BUFFER, Self.vbo[0])

glInterleavedArrays(Self._glMode, Self._stride * 4, Null)

glDrawArrays(GL_QUADS, 0, vboSize / Self._stride)

glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0)

End Method
Method clear()
If cleared = 0 Then glDeleteBuffers(1, Varptr(Self.vbo[0]))
cleared = 1
End Method
Method Delete()
clear()
End Method
End Type



Und hier nun ein auszug aus meinem VBO tests.
Wer lust hat, da durchzusteigen, wirds selber sehen.
Für die anderen gilt:
Ich nutze 2 VBO - einmal für wände, einmal für den boden.
Die wände kriegen zusätzlich einen Normal-array verpasst, das VBO erstellt sich trotzdem richtig und zeichnet sich aus individuell.
PS: Im moment habe ich Fix auf GL_QUADS eingestellt! Ist noch ausbaufähig Smile

BlitzMax: [AUSKLAPPEN]

'Auszug aus einer Methode, die meinen Sektoren ihre VBO erstellt.

'Arrays definieren.
Local vertsWall:Float[]
Local vertsGround:Float[]

Local texWall:Float[]
Local texGround:Float[]

Local normalsWall:Float[]

Local x:Int, y:Int

Local t:Float[] '-> tmp Array als zwischenspeicher.
'-> In einer schleife die daten zusammenschustern.
For x = 0 Until SEK_TILES_X
For y = 0 Until SEK_TILES_Y
If walls[x, y] Then
'...
texWall:+walls[x, y].GetTexArray()
vertsWall:+walls[x, y].GetVertexArray(x, y, z)
noramlsWall:+walls[x, y].GetNormalArray()

Else
vertsGround:+img.getVertexcoordArray(x, y, -0.00001)
texGround:+img.getTexcoordArray(tiles[x, y])
End If
Next
Next

'Nun zur hauptattraktion:
'- VBO erstellen
'- Arrays einfügen
'- VBO "bauen"

Local ground:TVertexBufferObject = New TVertexBufferObject
ground.AddVertexArray(vertsGround)
ground.AddTextureArray(texGround)
ground.Build()

Local walls:TVertexBufferObject = New TVertexBufferObject
walls.AddVertexArray(vertsWall)
walls.AddTextureArray(texWall)
walls.AddNormalArray(normalsWall)
walls.Build()

'-> Speichern zum Rendern.
Self.VBO = [ground, walls]



'' Rendern:
' Anmk1: VBO kennt keine Textur. Wollen wir auch nicht. wir legen die Textur selbst fest.
' Anmk2: VBO sollte niemals absolute Positionen kennen. Besser ist, wir nutzen vorher eine Matrixtransformation
glBindTexture(GL_TEXTURE_2D, Self.img.tex)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) ;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) ;

VBO[0].Render() '<--- So einfach kanns gehen.


glBindTexture(GL_TEXTURE_2D, Self.wallTex.tex)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) ;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) ;

VBO[1].Render()


So nun an euch profis:
Habe ich die eigenheiten des anscheinend doch recht simplen VBO bedacht?
Macht euch keine sorgen über den doch recht komplex aussehenden Build krams - Konnte bisher keine Bugs feststellen, dh alles wird so gezeichnet wie es zu erwarten war.

Gibts dennoch feinheiten, was ich ausbessern könnte? Oder kann man das ding so als "allgemein brauchbar" abstempeln, wenn ich noch 2-3 feinheiten ausbesser?


Edit:
Kleine anmerkung noch.
die arrays, die man übergibt, sind ziemlich arg beschränkt, da es mir unmöglich ist, feinheiten rauszufinden, ohne das ganze zu überladen wirken zu lassen.

Vertexarray:
Vertexarray gibt die LÄNGE vor. Ich erwarte immer ein X,Y,Z format. Dh pro Vertex wird der reihe nach X,Y,Z in den array geschrieben.
Die Länge des Vertexarray/3 gibt die erwartete länge an.

TextureCoordArray:
2 Texturkoordinaten sets werden nicht unterstützt. Im moment lediglich U,V. Selbes spiel wie vorher: Pro vertex wird 1x U,V erwartet.
Länge muss (Länge Texture Array) / 2 * 3 = (Länge VertexArray) sein!

NormalCoordArray:
Selbes spiel wie sonst. Die länge des Normalcoord array muss dem des Vertexarrays entsprechen.

Color Array:
Das Problemkind. Für die Colors sind die Modi ziemlich eingeschränkt. Dh man muss Vertex,Texture,Normal UND Color setzen, um ein RGBA format nutzen zu können. Im normalfall sollte es Reichen, RGB array zu verwenden (in diesem fall entspricht die länge des colorarray der des Vertexarray). Sollte man alles setzen, versucht mein Type den RGB array umzuformen indem es als alphawert pro Farbcode 1.0 festsetzt.

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group