trying to improve draw performance on my c++, OpenGL, SDL game. Back in school we mostly learned immediate mode, so thats how my drawing was originally implemented. When I started reading up online about improving performance I read about VBOs and how they are so much better and use the graphics card memory etc. so i took a couple of nights and converted to them. When i tested the game, it actually ran slower (draw method went from ~7 to ~10 ticks). Did I clearly do something wrong? or are VBOs only more efficient in certain situations?
here's my class for tessellated polygons after adding VBOs (my game draws a lot of flat 2d shapes in a 3d world, sort of papermario-style)
#include "Tesselator.h"
Tesselator::Tesselator(std::vector vertices, Gradient* gradient) {
this->vertices = vertices;
this->gradient = gradient;
tesselator = gluNewTess();
gluTessCallback(tesselator, GLU_TESS_BEGIN_DATA, (void(CALLBACK*)())beginCallback);
gluTessCallback(tesselator, GLU_TESS_VERTEX_DATA, (void(CALLBACK*)())vertexCallback);
gluTessCallback(tesselator, GLU_TESS_END, (void(CALLBACK*)())endCallback);
int vertcount = (int)vertices.size();
GLdouble vertarray[vertcount][3];
for (int i = 0; i < vertices.size(); i++) {
vertarray[i][0] = vertices[i].x;
vertarray[i][1] = vertices[i].y;
vertarray[i][2] = 0;
}
gluTessBeginPolygon(tesselator, this);
gluTessBeginContour(tesselator);
for (int i = 0; i < vertices.size(); i++) {
gluTessVertex(tesselator, vertarray[i], vertarray[i]);
}
gluTessEndContour(tesselator);
gluTessEndPolygon(tesselator);
gluDeleteTess(tesselator);
for (int i = 0; i < triangles.size(); i++) {
triangleVBOs.push_back(new VertexBufferObject(triangles[i]));
}
for (int i = 0; i < trianglefans.size(); i++) {
triangleFanVBOs.push_back(new VertexBufferObject(trianglefans[i]));
}
for (int i = 0; i < trianglestrips.size(); i++) {
triangleStripVBOs.push_back(new VertexBufferObject(trianglestrips[i]));
}
}
Tesselator::~Tesselator() {
for (int i = 0; i < triangleVBOs.size(); i++) {
delete triangleVBOs[i];
}
for (int i = 0; i < triangleFanVBOs.size(); i++) {
delete triangleFanVBOs[i];
}
for (int i = 0; i < triangleStripVBOs.size(); i++) {
delete triangleStripVBOs[i];
}
triangleVBOs.clear();
triangleFanVBOs.clear();
triangleStripVBOs.clear();
}
void Tesselator::draw(float z) {
Drawing::applyZTranslation(z);
for (int i = 0; i < triangleVBOs.size(); i++) {
triangleVBOs[i]->draw(GL_TRIANGLES);
}
for (int i = 0; i < triangleFanVBOs.size(); i++) {
triangleFanVBOs[i]->draw(GL_TRIANGLE_FAN);
}
for (int i = 0; i < triangleStripVBOs.size(); i++) {
triangleStripVBOs[i]->draw(GL_TRIANGLE_STRIP);
}
Drawing::applyZTranslation(-z);
}
void Tesselator::addTriangle() {
std::vector triangleVertices;
triangles.push_back(triangleVertices);
}
void Tesselator::addTriangleFan() {
std::vector triangleFanVertices;
trianglefans.push_back(triangleFanVertices);
}
void Tesselator::addTriangleStrip() {
std::vector triangleStripVertices;
trianglestrips.push_back(triangleStripVertices);
}
void Tesselator::addVertex(b2Vec2 vertex) {
if (currentType == GL_TRIANGLES) {
triangles.back().push_back(b2Vec2(vertex.x, vertex.y));
}
else if (currentType == GL_TRIANGLE_FAN) {
trianglefans.back().push_back(b2Vec2(vertex.x, vertex.y));
}
else if (currentType == GL_TRIANGLE_STRIP) {
trianglestrips.back().push_back(b2Vec2(vertex.x, vertex.y));
}
}
void CALLBACK Tesselator::beginCallback(GLenum type, GLvoid * tessdata) {
Tesselator* tess = (Tesselator*) tessdata;
tess->currentType = type;
if (type == GL_TRIANGLES) {
tess->addTriangle();
}
else if (type == GL_TRIANGLE_FAN) {
tess->addTriangleFan();
}
else if (type == GL_TRIANGLE_STRIP) {
tess->addTriangleStrip();
}
}
void CALLBACK Tesselator::vertexCallback(GLdouble* vertex, GLvoid* tessdata) {
Tesselator* tess = (Tesselator*) tessdata;
tess->addVertex(b2Vec2(*(vertex), *(vertex + 1)));
}
void CALLBACK Tesselator::endCallback() {
}
and here is my vertex buffer object class
#include "VertexBufferObject.h"
VertexBufferObject::VertexBufferObject(std::vector shapeVertices) {
numberOfCoordinateValues = 0;
for (int i = 0; i < shapeVertices.size(); i++) {
numberOfCoordinateValues = numberOfCoordinateValues + 2;
}
float coordinateValues[numberOfCoordinateValues];
int coordinateValueArrayIndex = 0;
for (int i = 0; i < shapeVertices.size(); i++) {
coordinateValues[coordinateValueArrayIndex] = shapeVertices[i].x;
coordinateValueArrayIndex++;
coordinateValues[coordinateValueArrayIndex] = shapeVertices[i].y;
coordinateValueArrayIndex++;
}
glGenBuffers(1, &id);
glBindBuffer(GL_ARRAY_BUFFER, id);
glBufferData(GL_ARRAY_BUFFER, sizeof(coordinateValues), coordinateValues, GL_STATIC_DRAW);
}
VertexBufferObject::~VertexBufferObject() {
glDeleteBuffers(1, &id);
}
void VertexBufferObject::draw(GLenum mode) {
glBindBuffer(GL_ARRAY_BUFFER, id);
glVertexPointer(2, GL_FLOAT, 0, NULL);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(mode, 0, numberOfCoordinateValues/2);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
and heres what the draw method for Tesselator used to look like before adding VBOs
void Tesselator::draw(float z) {
for (int i = 0; i < triangles.size(); i++) {
Drawing::drawTriangles(triangles[i], z, gradient);
}
for (int i = 0; i < trianglefans.size(); i++) {
Drawing::drawTriangleFan(trianglefans[i], z, gradient);
}
for (int i = 0; i < trianglestrips.size(); i++) {
Drawing::drawTriangleStrip(trianglestrips[i], z, gradient);
}
}
and in Drawing.cpp:
void Drawing::drawTriangles(std::vector vertices, float z, Gradient* gradient) {
glBegin(GL_TRIANGLES);
for (int i = 0; i < vertices.size(); i++) {
addVertex(vertices[i].x, vertices[i].y, z, gradient);
}
glEnd();
}
void Drawing::drawTriangleFan(std::vector vertices, float z, Gradient* gradient) {
glBegin(GL_TRIANGLE_FAN);
for (int i = 0; i < vertices.size(); i++) {
addVertex(vertices[i].x, vertices[i].y, z, gradient);
}
glEnd();
}
void Drawing::drawTriangleStrip(std::vector vertices, float z, Gradient* gradient) {
glBegin(GL_TRIANGLE_STRIP);
for (int i = 0; i < vertices.size(); i++) {
addVertex(vertices[i].x, vertices[i].y, z, gradient);
}
glEnd();
}
No comments:
Post a Comment