Texture artifacts after texture switch.

6532e3e5e09db6f966770fdf86c03345
0
hellhound_01 104 Nov 07, 2012 at 08:05 opengl

I’ve written a sprite batcher, which uses a VBO to render multiple sprites in multiple batch calls. This batcher is designed to batch different sprites based on differend texture resources. If I add a Sprite with a new texture, different to the actual texture which is related by actually geometry values in VBO, I render the actual VBO with the actual texture. When rendering is complete I remove the old, batched geometry and replace the actual texture with the new one. Until next texture switch or final render call the batching restarts.

This works fine with different sprites if I render only one sprite for each texture. But if I try to render multiple sprites referencing the same texture, any additional batched sprite has texture artifacts. In the alpha area of those sprites content of the other textures is rendered:

http://s7.directuplo…bdmiwxo_jpg.htm

As you can see I render three different sprites (shelf, knight, barrel). Anything is fine. If a add a second barrel sprite, this sprite texture (and also for any additional barrel) has render artifacts. If I add next an additional shelf texture, only this additional shelf sprite shows the render artifacts, the barrels are rendered correctly.

This is strange and I have no idea what could be wrong.

First I thought there could be a problem with the zBuffer. By this reason I’ve set glDepthMask to false and also set glDisable(GL_DEPTH_TEST) before rendering those sprites. But this takes no effekt.

Any idea what could be wrong?

9 Replies

Please log in or register to post a reply.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Nov 07, 2012 at 18:34

Can you post your code for building the VBOs and rendering the sprites?

B5262118b588a5a420230bfbef4a2cdf
0
Stainless 151 Nov 07, 2012 at 19:25

without looking at the code … we are guessing.

some things to think about.

1) what does your code do if you render this sequence
sprite 1 on texture 1
sprite 1 on texture 2
sprite 2 on texture 1
sprite 2 on texture 2

From your description, I think you are expecting the code to
batch sprite 1 texture 1
draw batch
batch sprite 1 texture 2
draw batch
batch sprite 2 texture 1
draw batch
batch sprite 2 texture 2
draw batch

if that is the case, write out the number of tris it is rendering at each stage. my guess is that the number of tris is wrong.

My reason for thinking that is if the number of tris is wrong at all times, your vbo starts off with

/valid tri/valid tri/garbage/garbage/

On the screen the garbage is more than likely off screen, so you just see one sprite drawn correctly

Then you do a batch with two sprites and in the vbo you have

/valid tri/valid tri/valid tri/valid tri/garbage/garbage/garbage/garbage/

So you see two sprites drawn correctly

Then you draw a batch with one sprite, since you are using the same vbo, you end up with

/valid tri/valid tri/valid tri/valid tri/

So you see the bug as the duff tri’s now have valid screen coords

6532e3e5e09db6f966770fdf86c03345
0
hellhound_01 104 Nov 07, 2012 at 20:10

Sorry guys but I haven’t access to my sources when I’ve opened this thread on coffee break at work. Here is the missing code,
This is my draw call for a single sprite, no magic:

void brSpriteRenderer::draw(boost::shared_ptr<brGraphics::brTexture> texture,
                            const std::vector<VERTEX_2D>& vertices)
{
  if(m_activeTexture!=texture){
      this->switchTexture(texture);
  }

  for(unsigned int i=0; i<vertices.size(); i++){
    m_data.push_back(vertices[i]);
  }
}

On texture switch I first call the render procedure for already batched geometry data,
then I store the texture reference for upcomming draw calls:

void brSpriteRenderer::switchTexture(boost::shared_ptr<brGraphics::brTexture> texture)
{                             
    /* If we have an actual texture active, first render all
       actual batched data which references this texture */                   
    if(m_activeTexture!=0 && m_data.size()>0){
         this->render();  
    }

    // finally switch texture  
    m_activeTexture = texture;
}

And this is my simple render call:

//flush data to GPU
m_buffer->bind();
m_buffer->writeData(0, m_data.size()*sizeof(VERTEX_2D), &m_data[0]);

// perform rendering
m_activeTexture->bind(0);
m_buffer->render(brGraphics::TYPE_TRIANGLES);
m_activeTexture->unbind(0);
m_buffer->unbind();

// clear obsolete batched data
m_data.clear();

Behind my bind/unbind calls there is also no magic:

glActiveTexture(GL_TEXTURE0+unit);
glBindTexture(GL_TEXTURE_2D, m_textureID);
glEnable(GL_TEXTURE_2D);

and accordingly
glDisable(GL_TEXTURE_2D);

@Stainless
The Idea with garbage is not bad, I will check this out. With your assumption you are nearby the
real render sequence:

      /* draw single sprites regarding z-Order from back to front to avoid
          issues with overlapping sprites */
      shelf.draw(spriteBatch);         // Using obstacle atlas texture (1)
      knight.draw(spriteBatch);      // Using Knight atlas texutre (2)
      barrel.draw(spriteBatch);      // Using Barrel atlas texture (3)
      barrel2.draw(spriteBatch);       // Using Barrel atlas texture (3)
6532e3e5e09db6f966770fdf86c03345
0
hellhound_01 104 Nov 07, 2012 at 20:27

Additional Info: Stainless I think you are on the right path. I’ve modified my render call to recreate the VBO
on each render call. Now the artifact part is blinking… I’ve to check out why and when …

B5262118b588a5a420230bfbef4a2cdf
0
Stainless 151 Nov 07, 2012 at 21:47

My guess is that you have done the classic in the render code.

Usually you supply the number of primitives to draw, my guess is you have used the number of points or something like that.

6532e3e5e09db6f966770fdf86c03345
0
hellhound_01 104 Nov 07, 2012 at 22:10

? Sorry but I can not understand what you mean.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Nov 07, 2012 at 22:14

Inside your m_buffer->render() call can you double-check that you’re passing the correct number of vertices to render? And not the number of bytes of data, or some such other number?

6837d514b487de395be51432d9cdd078
0
TheNut 179 Nov 08, 2012 at 04:16

Heh, using Reiner’s tilesets eh? :)
@hellhound_01

I’ve modified my render call to recreate the VBO on each render call.

Depending on your situation, you may improve performance by precreating a VBO large enough to render the maximum number of elements you want. If you need to control how many sprites are rendered, you can pass in the correct number of polygons or vertices into the API.

glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, 0);
// or
glDrawArrays(GL_TRIANGLES, 0, numVerts);

Where numIndices = number of polygons * 3 (triangle = 3 points per polygon)
or numVerts = number of vertices * 3 (for 3D coordinates)

As Stain and Reed mentioned, make sure you’re not passing in something outside of this range, otherwise the video card can do some odd things.

6532e3e5e09db6f966770fdf86c03345
0
hellhound_01 104 Nov 08, 2012 at 08:47

That is it! Thanks Guys you are my heroes! In my vertex buffer implementation I’ve used the allocated amount of vertices by mistake instead of the actual data length. So I’ve rendered (since 2 Years or longer) the complete buffer instead of the actual amount of vertices! This kind of thing has never before attracted attention while I’ve rendered static buffer values until yet.

Again thanks a lot!

Heh, using Reiner’s tilesets eh?

Yes, they are verry impressive. B)