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] [EINKLAPPEN] 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] 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
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 Else l:+Len(Self.buildingArray[3]) EndIf Else If Self.currentMode & VBO_COLOR And Self.getMode() <> GL_T2F_C4F_N3F_V3F Then l:+Len(Self.buildingArray[3]) 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 End Select
Return ret End Method Method Build()
glGenBuffersARB(1, Varptr(Self.vbo[0])) glBindBufferARB(GL_ARRAY_BUFFER, Self.vbo[0])
Local _vboPtr:Float[] = Self.generateArray() glBufferData(GL_ARRAY_BUFFER, Self.getLen() * 4, Varptr(_vboPtr[0]), GL_STATIC_DRAW) Self._glMode = Self.getMode() End Method Method Render() 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
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN]
Local vertsWall:Float[] Local vertsGround:Float[]
Local texWall:Float[] Local texGround:Float[]
Local normalsWall:Float[]
Local x:Int, y:Int
Local t:Float[]
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
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()
Self.VBO = [ground, walls]
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()
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.
|