Jump to content


Texture artifacts after texture switch.

opengl

9 replies to this topic

#1 hellhound_01

    New Member

  • Members
  • PipPip
  • 58 posts

Posted 07 November 2012 - 08:05 AM

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?
"There is only one god and his name is death. And there is only one thing we have to say to Death: Not today!" -- Syrio Forel (from Game of Thrones)

#2 Reedbeta

    DevMaster Staff

  • Administrators
  • 5311 posts
  • LocationSanta Clara, CA

Posted 07 November 2012 - 06:34 PM

Can you post your code for building the VBOs and rendering the sprites?
reedbeta.com - developer blog, OpenGL demos, and other projects

#3 Stainless

    Member

  • Members
  • PipPipPipPip
  • 582 posts
  • LocationSouthampton

Posted 07 November 2012 - 07:25 PM

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

#4 hellhound_01

    New Member

  • Members
  • PipPip
  • 58 posts

Posted 07 November 2012 - 08:10 PM

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)

"There is only one god and his name is death. And there is only one thing we have to say to Death: Not today!" -- Syrio Forel (from Game of Thrones)

#5 hellhound_01

    New Member

  • Members
  • PipPip
  • 58 posts

Posted 07 November 2012 - 08:27 PM

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 ...
"There is only one god and his name is death. And there is only one thing we have to say to Death: Not today!" -- Syrio Forel (from Game of Thrones)

#6 Stainless

    Member

  • Members
  • PipPipPipPip
  • 582 posts
  • LocationSouthampton

Posted 07 November 2012 - 09:47 PM

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.

#7 hellhound_01

    New Member

  • Members
  • PipPip
  • 58 posts

Posted 07 November 2012 - 10:10 PM

? Sorry but I can not understand what you mean.
"There is only one god and his name is death. And there is only one thing we have to say to Death: Not today!" -- Syrio Forel (from Game of Thrones)

#8 Reedbeta

    DevMaster Staff

  • Administrators
  • 5311 posts
  • LocationSanta Clara, CA

Posted 07 November 2012 - 10:14 PM

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?
reedbeta.com - developer blog, OpenGL demos, and other projects

#9 TheNut

    Senior Member

  • Moderators
  • 1701 posts
  • LocationCyberspace

Posted 08 November 2012 - 04:16 AM

Heh, using Reiner's tilesets eh? :)

hellhound_01 said:

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.
http://www.nutty.ca - Being a nut has its advantages.

#10 hellhound_01

    New Member

  • Members
  • PipPip
  • 58 posts

Posted 08 November 2012 - 08:47 AM

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!

Quote

Heh, using Reiner's tilesets eh?

Yes, they are verry impressive. B)
"There is only one god and his name is death. And there is only one thing we have to say to Death: Not today!" -- Syrio Forel (from Game of Thrones)





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users