Sign in to follow this  

Odd spritebatch rendering order

This topic is 400 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi everyone,

 

I wrote a 2D spritebatch and I'm having trouble understanding whether the spritebatch behavior is normal or not.

 

So my spritebatch has a single vertex buffer. I have a submit function that takes a "sprite" which is basically a quad and it maps that into the vertex buffer. When you first submit a sprite the "FindTexture" function will check if the sprite exist in a list. If it does it returns an index number that will be sent to the shader in order to tell the shader which texture to render. If it doesn't find the sprite it will push it back and return the last index in the list.

 

All sprites submitted have a Z value of 0.0f and my depth test is disabled.

 

My problem is that when I submit sprite1 and sprite2, sprite2 will be rendered behind sprite1. That makes no sense. What I expect to happen is that sprite2 should be rendered in front of sprite1. since sprite1 is placed first in the vertex buffer and sprite2 is placed second in the buffer.

Of course if I submit sprite2 first then sprite1, then sprite1 will be drawn behind sprite2. which is the behavior I expect when I submit sprite1 then sprite2.

 

 

YprecET.png

 

 

Here is how I call and sumbit sprites to my spritebatch

spriteRenderer->Begin();
              //Submit(Sprite    (Texture, Position,                      Color));
spriteRenderer->Submit(new Sprite(sprite1, Vector3(500.0f, 200.0f, 0.0f), Vector4(1.0f, 1.0f, 1.0f, 1.0f)));
spriteRenderer->Submit(new Sprite(sprite2, Vector3(500.0f, 200.0f, 0.0f), Vector4(1.0f, 1.0f, 1.0f, 1.0f)));
spriteRenderer->End();
spriteRenderer->Draw();

and here is my implementation of the spritebatch

void SpriteRenderer::Begin()
{
     spriteBuffer = (SpriteBuffer*)vertexBuffer->Map();
}

void SpriteRenderer::Submit(Sprite* sprite)
{
	unsigned int textureID = FindTexture(sprite->texture2D);
	sprite->texture2D->Bind("textures", textureID);

	Vector2 topLeftUV, topRightUV, bottomRightUV, bottomLeftUV;
	CalculateUV(sprite, &topLeftUV, &topRightUV, &bottomRightUV, &bottomLeftUV);

	//Top Left
	spriteBuffer->position	= Vector3(sprite->position.x + sprite->rectangle.x, sprite->position.y + sprite->rectangle.y, 0.0f);
	spriteBuffer->color	= sprite->color;
	spriteBuffer->UV	= topLeftUV;
	spriteBuffer->textureID = textureID;
	spriteBuffer++;

	//Top Right
	spriteBuffer->position	= Vector3(sprite->position.x + sprite->rectangle.x + sprite->rectangle.width, sprite->position.y + sprite->rectangle.y, 0.0f);
	spriteBuffer->color	= sprite->color;
	spriteBuffer->UV	= topRightUV;
	spriteBuffer->textureID = textureID;
	spriteBuffer++;

	//Bottom Right
	spriteBuffer->position	= Vector3(sprite->position.x + sprite->rectangle.x + sprite->rectangle.width, sprite->position.y + sprite->rectangle.y + sprite->rectangle.height, 0.0f);
	spriteBuffer->color	= sprite->color;
	spriteBuffer->UV	= bottomRightUV;
	spriteBuffer->textureID = textureID;
	spriteBuffer++;

	//Bottom Left
        spriteBuffer->position	= Vector3(sprite->position.x + sprite->rectangle.x, sprite->position.y + sprite->rectangle.y + sprite->rectangle.height, 0.0f);
	spriteBuffer->color	= sprite->color;
	spriteBuffer->UV	= bottomLeftUV;
	spriteBuffer->textureID = textureID;
	spriteBuffer++;

         indexCount += 6;
}

void SpriteRenderer::End()
{
	vertexBuffer->Unmap();
}

void SpriteRenderer::Draw()
{	
        vertexBuffer->Bind();
	indexBuffer->Bind();
        context->Draw(indexCount);
	indexBuffer->Unbind();
	vertexBuffer->Unbind();

	for (unsigned int i = 0; i < textures.size(); i++)
		textures[i]->Unbind();

	textures.clear();
        indexCount = 0;
}

unsigned int SpriteRenderer::FindTexture(API::Texture2D* texture)
{
        //textures is a list of texture2D pointers.
	for (unsigned int i = 0; i < textures.size(); i++)
	{
		if (textures[i] == texture)
		      return i;
	}

	textures.push_back(texture);
	return (unsigned int)(textures.size() - 1);
}

and here is my pixel shader

#version 450 core

in vec4 fragmentColor;
in vec2 UV;
flat in int textureID;
out vec4 color;

uniform sampler2D textures[5];

void main() 
{
	color = fragmentColor * texture(textures[textureID], UV);
}
Edited by FantasyVII

Share this post


Link to post
Share on other sites

Double check if depth test is disabled, and if sprites are put into buffer in exactly expected order (i.e. sprite1, sprite2).

GPUs are free to render polys in parallel, but output must be exactly the same as if polys were rendered sequentially.

If sprite2 gets under sprite1 - then either the sprites order was wrong, or depth test was enabled.

Share this post


Link to post
Share on other sites

I'm such a dummy :P

 

so in my pixel shader I have my samplers setup as an array

uniform sampler2D textures[5]

and the way I was passing the each texture is by doing this

sprite->texture2D->Bind("textures", textureID);

//this function is equal to this 

glActiveTexture(GL_TEXTURE0 + textureID);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(glGetUniformLocation(glshader->GetProgramID(), "textures"), textureID);

which is totally wrong because this will basically fill the entire array with the last textureID.

 

The correct way of doing this is

if(textureID == 0.0f)
	sprite->texture2D->Bind("textures[0]", textureID);
else if (textureID == 1.0f)
	sprite->texture2D->Bind("textures[1]", textureID);

ofc I can do some string manipulation and get ride of the if statement so effectively it will look something like  this

sprite->texture2D->Bind("textures[" + textureID + "]", textureID);

Share this post


Link to post
Share on other sites

This topic is 400 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this