Sprite batching for Monkeysheet

I’d like to add sprite batching to MonkeySheet

I guess I should learn to use Vertex Buffers, but I have no clue on where to start. Any advice?
BTW, does this also mean that I can’t use anymore AbstractControls for each sprite?

Looking forward to seeing this

Tried to use the BatchNode?

1 Like

Didn’t help, but from what I see I need to call “batch” every time I add a new sprite; and also this requires sprites to share the same Material, which is currently not the case… each sprite comes with its own Material instance, which includes parameters for spritesheet position.

Pspeed mentioned to check out the wiki about creating custom meshes… I’ll look into it.

I’ve made this sample that uses the BatchNode optimization. If the material color is the same for all quads then I get awesome performances;

public class TestBatch extends SimpleApplication {

    public static void main(String[] args){
        TestBatch app = new TestBatch();
        app.start(); // start the game
    }

    @Override
    public void simpleInitApp() {
        BatchNode bn=new BatchNode();
        for (int i=0;i<10000;i++){
        Quad b = new Quad(.05f, .05f); // create cube shape
        Geometry geom = new Geometry("Box", b);  // create cube geometry from the shape
        Material mat = new Material(assetManager,
          "Common/MatDefs/Misc/Unshaded.j3md");  // create a simple material
        mat.setColor("Color", ColorRGBA.Blue);   // set color of material to blue
        geom.setMaterial(mat);                   // set the cube's material
        geom.move(-5,-5,0);
        int j=i/100;
        int k=i-j*100;
        geom.move(k/10f,j/10f,0);
        bn.attachChild(geom);              // make the cube appear in the scene
        }
        bn.batch();
        rootNode.attachChild(bn);
    }
}

but if I set a random color I get bad performance:

Maybe I’m missing something, but even after reading the mesh tutorial I have no idea on how to put the colors on a vertex buffer in order to optimize the rendering… :confused:

What have you tried?

Setting the color buffer is as easy as setting any other vertex buffer. Then you just have to tell the material that you have vertex colors.

    @Override
    public void simpleInitApp() {
        for (int i=0;i<10000;i++){
        Quad b = new Quad(.05f, .05f); // create cube shape
        Geometry geom = new Geometry("Box", b);  // create cube geometry from the shape
        Material mat = new Material(assetManager,
          "Common/MatDefs/Misc/Unshaded.j3md");  // create a simple material
        mat.setBoolean("VertexColor", true);
        b.setBuffer(VertexBuffer.Type.Color, 4, new byte[]{1,0,0,1});
        geom.setMaterial(mat);                   // set the cube's material
        geom.move(-5,-5,0);
        int j=i/100;
        int k=i-j*100;
        geom.move(k/10f,j/10f,0);
        rootNode.attachChild(geom);              // make the cube appear in the scene
        }
    }

This is what I came up with.

  1. I’ve tried to set a color on the vertex buffer of the mesh. How to set 10000 colors and not just one?
  2. I think I should merge all the quads on the same mesh. Does this mean that I have to declare 10000 arrays with coordinates for each quad?

A color has 4 components.
A box has 8 vertices (or 32 vertices).
Thus, the array should contain 32 values (or 128 values).
I always use FloatBuffer in combination with ColorRGBA.
So, four floats is one vertex (and usually you have 8 vertices).

If it works with what you wrote (4 values instead of 32) this would be really cool.
But this is usually not how it works.
If you actually set the “Color” parameter it’s a shader variable (does not work with batching).
So you have to specify one color per each vertex in the colorbuffer.

And now I see… you use a quad. A quad only has 4 vertices.
You don’t create a cube, it’s actually a square field.

And I wonder … could they actually share a color buffer if they use the same color?
I think it makes a copy in that case, but it would be nice to test this with … 4 … different colors instead of all random.

If I use this buffer

        b.setBuffer(VertexBuffer.Type.Color, 4, new byte[]{1,0,0,1, 0,0,1,1, 0,1,0,1, 1,0,1,1});

I get these instead (zoomed in for clarity)

Still not what I’m aiming. :frowning:

But that’s what you wrote: One corner is red, the next corner is blue, the next is green and the fourth is pink.
EDIT: Seems like it expects [0…1] interval - so you better use float.

I’d like to have a different color for each square, while at the same time batch the render… from your suggestion I thought that setting multiple colors on the vertex buffer was the way to go.

Yes, but given the code from above you set the same four colors for every Quad.

Should be something like this:

float red = FastMath.nextRandomFloat();
float green = FastMath.nextRandomFloat();
float blue = FastMath.nextRandomFloat();
float alpha = 1.0f;
b.setBuffer(VertexBuffer.Type.Color, 4, new float[]{
    red,green,blue,alpha, 
    red,green,blue,alpha, 
    red,green,blue,alpha, 
    red,green,blue,alpha
});

:slight_smile:

As ogli is detailing…

When you have a shape, that shape is made up of vertexes. Each vertex can have different attributes like TexCoord, TexCoord2, Color, Size, etc… if you have four vertexes then you will need four of whatever attribute you are trying to set. There is a one to one mapping. So when you give it four different vertex colors you are giving each vertex its own unique color. “Why do my vertexes all have different colors?” “Because you gave them different colors.”

“How do I get each quad to have its own color?” “Give each quad its own color of vertex.” But obviously, *4 because you have four vertexes in each quad.

While I appreciate your help @Ogli @pspeed , maybe I didn’t explain well.

So far, I got how to change the color of a quad, even the vertices of the quad. You have explained very well how to do this. But all the 10000 quads have the same color (or gradient).

I want to grasp the “secret” of creating a 10000 buffer that contains 10000 different colors for my 10000 quads… which will be the starting point for implementing sprite batching for Monkeysheet, or so I think :stuck_out_tongue:

Create 10000 different quads. Give them 10000 different color buffers with four vertex colors each in them.

You are already doing this. The only issue is that you use the same color in each pass of the loop.

@Override
    public void simpleInitApp() {
        ColorRGBA[] allMyColors = ...10000 different colors in an array or whatever

        for (int i=0;i<10000;i++){
            Quad b = new Quad(.05f, .05f); // create cube shape
            Geometry geom = new Geometry("Box", b);  // create cube geometry from the shape
            Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");  // create a simple material
            mat.setBoolean("VertexColor", true);
            b.setBuffer(VertexBuffer.Type.Color, 4, new float[]{allMyColors[i].r,allMyColors[i].g,allMyColors[i].b,allMyColors[i].a,
allMyColors[i].r,allMyColors[i].g,allMyColors[i].b,allMyColors[i].a,
allMyColors[i].r,allMyColors[i].g,allMyColors[i].b,allMyColors[i].a,
allMyColors[i].r,allMyColors[i].g,allMyColors[i].b,allMyColors[i].a});
            geom.setMaterial(mat);                   // set the cube's material
            geom.move(-5,-5,0);
            int j=i/100;
            int k=i-j*100;
            geom.move(k/10f,j/10f,0);
            rootNode.attachChild(geom);              // make the cube appear in the scene
        }
    }

(Note: I converted your byte[] to float[] just to make the code easier to write.)

I mean, how were you giving the quads different colors before? I assume you were setting something on their material. Now you set the color buffer instead.

I’m trying to understand why this is confusing. Not seeing the gap.

1 Like

Then I suppose the next step would be

        Mesh mesh = new Mesh();
        Vector3f [] vertices = new Vector3f[40000]; //4*10000 triangles

…and I have to manually adjust the position of each vertex of the mesh?

Now you’ve lost me.
You can set the color buffer like you did before.
Just take my or pspeed’s code snippet to give each Quad its own color.

After the batching took place you should have one giant batch with all Quads and each one has its own color.

If you want, you can create your custom mesh right from the start, yes. The wiki article tells you all you need to know in order to achieve this. But it should also be possible in the way you are currently using (see begin of this post).

By the way, it’s “a vertex” and “many vertices”. :slight_smile:

That lighted the lamp :flashlight: and I’m actually going somewhere :
high performance with 10000 different colored quads. :slight_smile:

Ok, now I have the batchnode with all the colors. But I need to call batch() every time I add or remove a quad.

Is it preferable to work like this or is it better to:

have an arraylist of vertices and attach a “proxy-abstractcontrol” that manages them as if they were spatials, and convert the arraylist into a mesh vertex buffer?