Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I've started a game engine for learning purposes. I have successfully gotten an opengl renderer working and I can draw textures of varying sizes to the screen. The way I have done this is by creating a hard coded array of vertices that are just a box.

float Renderer2D::vertices[30] = {
        0.f,  1.f, 0.0f, 0.0f, 0.0f, // Top-left
        0.f, 0.f, 0.0f, 0.0f, 1.0f,  // Bottom-left
        1.f, 1.f, 0.0f, 1.0f, 0.0f, // Top-right
        1.f, 1.f, 0.0f, 1.0f, 0.0f, // Top-right
        0.f, 0.f, 0.0f, 0.0f, 1.0f,  // Bottom-left
        1.f, 0.f, 0.0f, 1.0f, 1.0f // Bottom-right
};

(The first three are xyz - The fourth and fifth floats are texture coords)

I send this to the GPU at the beginning of my program. For every sprite I draw, I create a transformation matrix like this:

void Renderer2D::draw(int x, int y, int w, int h)
{
    float posX = 2.0f * x / m_screenWidth - 1.0f;
    float posY = 1.0f - 2.0f * y / m_screenHeight - 2.0f*h/m_screenHeight;

    glm::mat4 translation, scale;
    translation = glm::translate(glm::mat4(1.0f), glm::vec3(posX, posY, 0));

    scale = glm::scale(glm::mat4(1.0f), glm::vec3(2.0f * w /   m_screenWidth,2.0f*h/m_screenHeight, 1.f));
    transformation = translation * scale;
    glUniformMatrix4fv(m_shaderProgram.getMVPLocation(), 1, GL_FALSE, &transformation[0][0]);
    glUniform1i(m_shaderProgram.getSamplerLocation(), 0);

    m_shaderProgram.enableVertexAttribArray();

    glActiveTexture(GL_TEXTURE0);
    glDrawArrays(GL_TRIANGLES, 0, 6);

    m_shaderProgram.disableVertexAttribArray();
}

I started looking up other questions on here about sprite batches, so I could optimize my draw calls. But in all of these questions it was suggested that a vertex array should be built up, with vertex's for every sprite.

In my code, I send vertices to the gpu once, and call glDrawArrays for every sprite. If I built the vertex array every frame, I'd send the vertices every frame (not every sprite) and call glDrawArrays once per frame. I would still have to calculate the matrices for every sprite.

Is glDrawArrays much more computationally expensive than sending a vertex buffer? Does this definitely need fixing?

If I build a vertex buffer dynamically, how could I allocate the space if I don't know how many sprites are going to be drawn? Do you just put a hard limit on it?

share|improve this question
4  
If it's not broken, you shouldn't fix it. I'd recommend you dedicate more time to making, and finishing your game so it's fun before applying unnecessary optimizations. If you start getting a bottleneck, and after profiling your code you find that you're getting performance problems in the pipeline, that's the moment to start optimizing. –  Panda Pajama Feb 26 '13 at 6:09
    
I'm more interested in making the engine than making a game. I already know how to use unity3D and XNA, so I would go that route if I wanted to. Also, I'm worried I won't be able to draw subsets of images because the uv's are static. –  kfan Feb 26 '13 at 6:46
    
@kfan: There is no engine without a game. When you "just make an engine" you end up wasting oodles of time making a useless hunk of pointless code that maybe does some unimportaant things well and very likely does necessary things poorly or not at all. Make a game, and an engine will fall out. That's where just about every real engine came from. Attempts like Unity3D to make "just an engine" took years by a professional team to build into a barely useful pile of crud that then took several versions and a lot of feedback from devs making real games to make usable. –  Sean Middleditch Feb 26 '13 at 22:26
    
hmm.. I just find all of the things that make a game engine tick very fascinating and I wanted to learn more about them by building one. I've made games from engines in the past, so it's not like I'm going in blind. I have ideas for what I'll use it for when its finished, so that is shaping my design. I'm not trying to make a one-size fits all engine. –  kfan Feb 27 '13 at 1:40
    
premature optimization is never a good idea. Although I don't think (as some of the other commenters seem to) that building an engine for the educational value has no merit. That said, it's likely that you'd learn more by making a game out of your engine. –  Emmett J. Butler Mar 4 '13 at 22:36
add comment

2 Answers 2

up vote 4 down vote accepted

As your sprite count increases, you will notice that glDrawArrays is relatively slow. Luckily, the GPUs happen to have a huge bandwidth. That's why huge amounts can be uploaded on every frame. When creating your vertex buffer you can even give it GL_DYNAMIC_DRAW or GL_STREAM_DRAW as usage parameter to suggest that the data will be updated all the time. This way the GPU will try to have it in the fastest part of the memory (if possible). Uploading a lot on every frame and making as few calls as possible is the way GPUs are designed to work.

If you don't know how many vertices you're going to have, just allocate as much as you think you'll need. If you exceed the cap, you can always create an even bigger one and copy the old data to the new one.

One problem with having all the quads in vertex buffer is the textures. All the textures needed by the quads in one vertex buffer have to be in the same texture atlas. If you can't fit all textures in one texture atlas you have to divide the quad batch into multiple batches.

share|improve this answer
1  
Ok, that seems to make sense. One more question though. If my sprites require different textures, how can I tell the shaders in the middle of a draw to switch textures? One option could be a texture atlas, but then EVERY image I use would have to be in an atlas. –  kfan Feb 26 '13 at 8:18
    
Good point. I updated the answer. –  JohannesA Feb 26 '13 at 8:24
add comment

I'm being picky, but there are some simple math operations which can be optimized by computing them only when they need it. For instance:

float posX = 2.0f * x / m_screenWidth - 1.0f;
float posY = 1.0f - 2.0f * y / m_screenHeight - 2.0f*h/m_screenHeight;

These values are only going to change when sprite moves, rather than each frame, so it makes sense to only compute them at those moments.

You will not see any FPS increases by this specific example, but the general principle is a good one to keep in mind.

share|improve this answer
    
Sounds like premature optimizing. If storing the posX and posY makes the code harder to read, it shouldn't be done unless optimizing is needed and profiling suggests it would help. And we are talking about sprites in games. Most sprites move on every frame. Also, this doesn't answer the question. –  JohannesA Feb 26 '13 at 12:02
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.