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'm having a tremendous time getting the second (or additional) sprites in my game engine to render properly. The first one always works great: it is positioned and sized properly in screen coords, and its texture is mapped properly. When I add a second sprite to the world, its texture does not get mapped properly. If I reverse the two sprites render orders, the sprite that was rendered second previously (and had corrupt texture mapping) is now correct, and the other sprite is now corrupt.

I think it has to do with something in my shader not getting cleared out properly before it is used again. I have to admit, I'm fairly new to shaders. Interestingly, I'm building this engine to support both ES1.1 and ES2.0, and the same code works great in ES1.1 for multiple sprites.

I'll attempt to provide relevant code snippets below. Any suggestions would be great - I've browsed dozens of good forums and Stack Exchange. Is there perhaps a call I should be making between primitive renders to clean out the shaders?

Here's the snippet for rendering in ES2.0

void Sprite::Render(GLuint shaderProgram, UniformHandles* uniforms, AttributeHandles* attributes)
{
// Use the shader we were sent
glUseProgram(shaderProgram);

// Enable transparent blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

// Performance: could pull this out and only recalculate when moved
PVRTVec2 bottomLeftPos = PVRTVec2((m_viewDims.x - m_position.x) / m_viewDims.x,
                                      ((m_viewDims.y - (m_position.y - m_drawDims.y)) / m_viewDims.y));

PVRTVec2 topRightPos = PVRTVec2((m_viewDims.x - (m_position.x + m_drawDims.x)) / m_viewDims.x,
                                    (m_viewDims.y - m_position.y) / m_viewDims.y);

// Draw the quad for ES2 (positioning is not based on these values: do not change)
DrawQuad((bottomLeftPos.x * 2.0f) - 1.0f, (bottomLeftPos.y * 2.0f) - 1.0f, (topRightPos.x * 2.0f) - 1.0f, (topRightPos.y * 2.0f) - 1.0f, m_textureResource->texture, uniforms, attributes);

// Turn off blending
glDisable(GL_BLEND);

}

And here's the snippet for DrawQuad()

void Sprite::DrawQuad(float x1, float y1, float x2, float y2, GLuint texture,
                  UniformHandles* uniforms, AttributeHandles* attributes)
{

    // Set the uniforms for rectangle position and width
    // Landscape
    glUniform2f(uniforms->LowerLeft, -y1, x1);
    float scaleMatrix[4] = { 0, x2 - x1, y1 - y2, 0 };
    glUniformMatrix2fv(uniforms->ScaleMatrix, 1, GL_FALSE, scaleMatrix);

    // Use the given texture
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);

    // Bind the vertex buffer object
    glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
    glEnableVertexAttribArray(attributes->in2DVertex);
    glEnableVertexAttribArray(attributes->inSpriteTexCoord);
    glVertexAttribPointer(attributes->in2DVertex, 2, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 4, 0);
    glVertexAttribPointer(attributes->inSpriteTexCoord, 2, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 4, (unsigned char*) (sizeof(GL_FLOAT) * 2));

    // Draws a short triangle strip
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    glDisableVertexAttribArray(attributes->in2DVertex);
    glDisableVertexAttribArray(attributes->inSpriteTexCoord);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

And finally the vertex shader and fragment shader for 2D sprites:

Vertex Shader attribute highp vec2 in2DVertex; attribute highp vec2 inSpriteTexCoord;

uniform highp vec2      LowerLeft;
uniform highp mat2      ScaleMatrix; // Width/height and screen rotation

varying mediump vec2    TexCoord;

void main()
{
   gl_Position = vec4(ScaleMatrix * in2DVertex + LowerLeft, 0, 1);
   TexCoord = inSpriteTexCoord; // formerly in2DVertex
}

Fragment Shader uniform sampler2D sTexture;

varying mediump vec2    TexCoord;

void main()
{
    gl_FragColor = texture2D(sTexture, TexCoord);
}
share|improve this question
add comment

1 Answer

up vote 0 down vote accepted

Although I don't have a solution to the problem I was encountering, I did find a workaround and I am posting it if anyone else ever sees something similar.

For reference, the rendering code I was basing the above snippets on (esp the shaders) came from PowerVR's OpenGLES2.0 SDK (I think the Alpha Blending demo). I mostly understand the coordinate system it is using to render sprites, but I think it's pretty funky. At least, I sure don't think that way when I consider graphics!

SO, I switched it over from that system to a much more "3D"-oriented shader. Here's the new vertex shader:

attribute highp vec4    inSpriteVertex;
attribute highp vec2    inSpriteTexCoord;

uniform highp mat4      OrthoProjectionMatrix;
uniform highp mat4      ModelviewSpriteMatrix;

varying mediump vec2    TexCoord;

void main()
{
    gl_Position = OrthoProjectionMatrix * ModelviewSpriteMatrix * inSpriteVertex;
    //gl_Position = vec4(ScaleMatrix * in2DVertex + LowerLeft, 0, 1);
    TexCoord = inSpriteTexCoord; // formerly in2DVertex
}

Notice I'm still using a 2D texture coordinate but have now upgraded to a 4D position vector for the given vertex and a including two matrices for transformation: an orthographic view matrix and a model view matrix that contains the scale/rotation/translation transforms that have been applied to this sprite.

Again, I wish I knew what I was doing wrong in the original snippets, but this approach seems much more sensible. Probably not as fast at render time, but I think it is reasonable. Hope this helps someone!

share|improve this answer
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.