0
\$\begingroup\$

I was wondering what is the best way to draw textures (for performance). Using the sourceRectange in the spriteBatch.Draw() call and just draw the whole spriteSheet, or crop out every texture on the spritesheet and store them in there own Texture2D object? Like this :

    public static Texture2D Crop(Texture2D spriteSheet, Rectangle source)
    {
        Texture2D croppedTexture2d = new Texture2D(spriteSheet.GraphicsDevice, source.Width, source.Height);
        Color[] imageData = new Color[spriteSheet.Width * spriteSheet.Height];
        Color[] croppedImageData = new Color[source.Width * source.Height];

        spriteSheet.GetData<Color> (imageData);

        int index = 0;

        for (int y = source.Y; y < source.Y + source.Height; y++)
        {
            for (int x = source.X; x < source.X + source.Width; x++)
            {
                croppedImageData [index] = imageData [y * spriteSheet.Width + x];
                index++;
            }
        }

        croppedTexture2d.SetData<Color> (croppedImageData);
        return croppedTexture2d;
    }

And just call that method in the LoadContent() method?

\$\endgroup\$
4
\$\begingroup\$

The sourceRect is much better for this.

Watch this if like a funny video explaining why:

https://www.codeandweb.com/what-is-a-sprite-sheet-performance

The more technical explanation:

I am using pseudo code - the exact number of commands required might vary - but you should see what I am talking about.

If you use isolated sprites the game engine has to perform the following actions on OpenGL (pseudo-code)

foreach sprite as s do
    gl->setTexture(s)
    gl->setSpriteCoordinates(s)
    gl->setDestinationCoordinates(s)
    gl->draw()
end

So you end up with approx. 4*number_of_sprites OpenGL calls. These commands are usually asynchronous - but depending on the exact calls you are using this might even trigger a synchronization between OpenGL and your code. That means: Your code waits until the draw operation is finished. Just wasting the CPU cycles during the refresh.

Using a sprite sheet and a sprite batch changes this completely:

foreach sprite as s do
    sourceCoordinates[] = s->sourceCoordinates()
    destinationCoordinates[] = s->destinationCoordinates()
end
gl->setTexture()
gl->setSpriteCoordinateList(sourceCorrdinates)
gl->setDestinationCoordinateList(desintationCoordinates)
gl->draw()

As you see only 4 OpenGL calls are required. It's simply setting the coordinate lists which have been pre-processed.

The drawing process runs now asynchronously without interruption and the CPU is free for other tasks.

The plain drawing process might take more or less the same time - but you've reduced the overhead for the communication - and the CPU is available.

\$\endgroup\$
  • 1
    \$\begingroup\$ I've never seen it explained like this. Very nice answer. \$\endgroup\$ – craftworkgames Feb 16 '16 at 10:13
0
\$\begingroup\$

Using the sourcerect is better performance wise.

The GPU benefits from as little texture changes as possible. With a textureatlas one texture is sent to the GPU and all sprites can be batched without a texture change.

In reality sprites are actually quads with each vertex points to a coordinate in the texture based on the source rectangle. All vertices inside the same batch are then drawn as one drawcall. This is the reason sprite atlasses are used.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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