Libgdx Spritebatch Render to Texture

libgdx SpriteBatch render to texture

This snippet was given to me on the LibGDX forum and it works flawlessly.

private float m_fboScaler = 1.5f;
private boolean m_fboEnabled = true;
private FrameBuffer m_fbo = null;
private TextureRegion m_fboRegion = null;

public void render(SpriteBatch spriteBatch)
{
int width = Gdx.graphics.getWidth();
int height = Gdx.graphics.getHeight();

if(m_fboEnabled) // enable or disable the supersampling
{
if(m_fbo == null)
{
// m_fboScaler increase or decrease the antialiasing quality

m_fbo = new FrameBuffer(Format.RGB565, (int)(width * m_fboScaler), (int)(height * m_fboScaler), false);
m_fboRegion = new TextureRegion(m_fbo.getColorBufferTexture());
m_fboRegion.flip(false, true);
}

m_fbo.begin();
}

// this is the main render function
my_render_impl();

if(m_fbo != null)
{
m_fbo.end();

spriteBatch.begin();
spriteBatch.draw(m_fboRegion, 0, 0, width, height);
spriteBatch.end();
}
}

Need help to optimize texture drawing on LibGDX, SpriteBatch

It is slow to do things that cause the sprite batch to "flush", which means it has to issue a number of OpenGL commands and transfer vertex data, etc. A flush occurs when you call spriteBatch.end() but also occurs if you:

  • Draw something with a different texture instance than the last thing drawn
  • Change the projection or transform matrices
  • Enable/disable blending

So you want to organize so you are not triggering a flush on every object you draw. What is typically done is to begin the batch, and then each sprite is drawn at its particular location with one of the spriteBatch.draw() methods that includes all the parameters you want. Like this:

batch.setProjectionMatrix(camera.combined);
batch.begin();
for (GameObject obj : myGameObjects)
obj.draw();
batch.end();

//And in your game object / sprite class
public void draw() {
if (texture == null)
return;
spriteBatch.setColor(1f, 1f, 1f, getAlpha());
spriteBatch.draw(texture, -size.width / 2, -size.height / 2, size.width, size.height);
}

Note that the above assumes you are referring to the same sprite batch instance in every object.

Now, to make it behave more like SpriteKit (I'm assuming since I haven't used it), your objects each need a transform. But you don't want to be calling setTransformMatrix or you will trigger a flush. Instead you can use the Affine2 class instead of Matrix4. It functions just as well for holding transform data for a 2D object. Then you can use spriteBatch.draw(textureRegion, width, height, affine2Transform) to draw it without triggering a flush.

To avoid triggering flushes from using different texture instances, you should use a TextureAtlas and texture regions. You can read up on that in the LibGDX documentation on their wiki.

As an aside, when using SpriteBatch, you do not need to make OpenGL calls to enable and disable blending. That is handled internally by SpriteBatch. Call spriteBatch.enableBlending() instead.

libgdx - Render two textures side by side using SpriteBatch and use one camera

Sprite is simply a wrapper (to add more functionality) for a single Texture (or TextureRegion).

You just call "new Sprite();" which creates a sprite with no texture (so nothing to draw, no image information, etc), thus you get a null pointer exception when you try to draw the sprite.

Since you want to combine two textures, why not create a single texture (image) with an external tool (like pain.net or gimp,..)?

If you want to draw two textures as a single object, you need to create your own class, for example:

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

public class TestGame extends ApplicationAdapter
{

public class TwoTextures
{
private final Texture tex1, tex2;
private final float pos1X, pos1Y, pos2X;

public TwoTextures(Texture tex1, Texture tex2, float posX, float posY)
{
this.tex1 = tex1;
this.tex2 = tex2;
this.pos1X = posX;
this.pos1Y = posY;

this.pos2X = posX + tex1.getWidth();
}

public void draw(Batch batch)
{
batch.draw(tex1, pos1X, pos1Y);
batch.draw(tex2, pos2X, pos1Y);
}

public void dispose()
{
tex1.dispose();
tex2.dispose();
}
}

OrthographicCamera camera;

Batch batch;

TwoTextures background;

@Override
public void create()
{
batch = new SpriteBatch();
camera = new OrthographicCamera();

background = new TwoTextures(
new Texture("1.jpg"),
new Texture("2.jpg"),
0,
0);
}

@Override
public void render()
{
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

batch.begin();
{
background.draw(batch);
}
batch.end();
}

@Override
public void dispose()
{
batch.dispose();
background.dispose();
}
}

Drawing sprites in libgdx

You never called create() on your Enemy instance, so the texture and sprite in Enemy are never instantiated. Call enemy.create() in your create() method. Or simplify things and move the code in enemy.create() into the Enemy constructor.

Also, in your Enemy constructor, you are instantiating a useless Sprite instance that does not reference a Texture and which will be thrown away once create() is called on the enemy. And the constructor does not even use the Sprite reference that's passed in (although you are currently just passing in null anyway because spriteEnemy in the SpaceShooter class is never instantiated).

Libgdx save SpriteBatch in a texture

You can render to a FrameBufferObject (FBO). See https://github.com/mattdesl/lwjgl-basics/wiki/FrameBufferObjects

An FBO will work if you are okay with making the decision to render to a texture in advance. One side-effect is that the image is not rendered to the screen, but only to the texture. (Its easy enough to render the texture to the screen afterwards, of course).

As the other answer suggested, you can scrape the bytes off the screen buffer, and make a Texture from the resulting Pixmap (you do not need to go all the way to the filesystem). See https://code.google.com/p/libgdx-users/wiki/Screenshots (just use the getScreenshot method to get a Pixmap of the bytes).

Libgdx SpriteBatch draws Actors, but not other Textures

Normally, your code would have caused a RuntimeException, because you're calling begin on the batch before drawing the stage. But since you actually have two sprite batches (one internal to the Stage because you didn't share the original with it), no actual errors occur.

You're missing a call to spriteBatch.end() after drawing your texture(s). And the call to spriteBatch.begin() needs to move after stage.draw().

And you should pass that sprite batch into the Stage constructor, because it is wasteful to have more than one sprite batch. Each sprite batch uses a fair amount of memory and compiles a shader.

Is LibGDX SpriteBatch draw() smart enough not to redraw 100% exactly same sprite at each render() call?

In OpenGL, you typically redraw the whole screen on every frame. It doesn’t make sense to wonder if the batch is smart enough to avoid redrawing the same thing, because it has to redraw it to prevent it from disappearing.

If you want to avoid redrawing anything on the screen for a while to save battery on the device, you can use GDX.graphics.setContinuousRendering(false) but that means your render() method will stop getting called so you must set it back to true using a timer or input callback.

You could alternatively use a Boolean to decide whether to clear the screen with glClear and draw stuff, but under the hood, LibGDX will still be requesting OpenGL to copy the screen buffer data between the back buffer and the screen buffer.

Not that drawing a single sprite is super trivial and probably not worth a second of thought about optimizing it.



Related Topics



Leave a reply



Submit