Gradient background

Anything libgdx related goes here!

Gradient background

Postby lijas » Thu May 30, 2013 5:40 pm


How do I make a gradient background in libgdx?
I have read something about making a rectangle and set the vertex colors, but dident really understand.

The background has to be really big so I cant make a .png...

Can someone help?
Posts: 42
Joined: Thu May 30, 2013 5:36 pm

Re: Gradient background

Postby bitiotic » Sun Jun 02, 2013 5:10 am

Using a Mesh to make a gradient background should be very efficient. With a Libgdx Mesh you describe how much data each vertex will have (that's the `VertexAttributes` passed into the Mesh constructor) and then you provide a long list of floats that provide all that data for all vertices in one list.

I think the place to start is with the MeshColorTexture triangle from the now-classic Libgdx tutorial: Get the "Color" example working from that tutorial, so you have a gradient-colored triangle on screen. This example passes two VertexAttribute objects that together say each vertex will have 3 position-related floats (x, y, and z), and will have 1 "packed" float for the color of the vertex. The float array passed into "setVertices" contains 12 totals floats (3 vertices with 4 floats per vertex -- x, y, z, color). The Color float is created from calling Color.toFloatBits() and passing in four values between 0 and 255 (representing red, green, blue, and alpha).

Now change that triangle into a square that fills the screen. Change the "3, 3" to "4, 4" in the Mesh constructor (since you're passing 4 vertices and 4 indices), change around the x,y,z coordinates in the float[] array to be the four corners of the screen (you should have a 16-element float array).

You'll need to fix the indices so they "walk" the verticies in such a way as to create two triangles (as the render() method asks OpenGL to render the Mesh as a list of triangles. So you need to walk the verticies in an "N" or "Z" order (not a "C" or "U" shape). If the indices seem odd and useless, you are correct. They're pretty useless for small examples like this, and are an API hold-over from OpenGL. You'll want to change the render method to ask to render the Mesh as a "GL10.GL_TRIANGLE_STRIP" with 4 vertices.

I'm assuming you're using OpenGL ES 1.x (not 2.0), as otherwise you'll need a shader (which is another way of creating a gradient). The Mesh API is very "close" to the underlying OpenGL APIs, so any tutorials or references you have for OpenGL (e.g., explaining vertices and indices) will help with concepts here, if not actual API calls.
Posts: 81
Joined: Tue Feb 05, 2013 2:59 pm

Re: Gradient background

Postby kalle_h » Sun Jun 02, 2013 8:42 am

If's its just one color to other gradient you can use very small texture(like 2x2) texture scaled and let bilinear filtering do the rest. This might be easier than messing with mesh.
Posts: 666
Joined: Thu Dec 29, 2011 9:50 pm

Re: Gradient background

Postby davedes » Sun Jun 02, 2013 2:10 pm

You don't need a Mesh or shader. It's probably much faster just to utilize your SpriteBatch. You can either subclass Sprite or write the vertex colours directly to the batch. If we subclass Sprite it has the (very slight and mostly negligible) benefit of caching the vertex data.

In either case, the idea of it looks like this. First, we need to grab an opaque white texture region. Generally you can place a 3x3 white opaque pixel in your sprite sheet, and sample from it using a TextureRegion. Then you need to specify the four vertex colours that make up each corner of your sprite (bottom left, top left, top right, bottom right). The code for that looks like this:

Code: Select all
public class GradientSprite extends Sprite {
   public GradientSprite(TextureRegion white) {
   public void setGradientColor(Color a, Color b, boolean horizontal) {
      float[] vertices = getVertices();
      float ca = a.toFloatBits();
      float cb = b.toFloatBits();
      vertices[SpriteBatch.C1] = horizontal ? ca : cb; //bottom left
      vertices[SpriteBatch.C2] = ca; //top left
      vertices[SpriteBatch.C3] = horizontal ? cb : ca; //top right
      vertices[SpriteBatch.C4] = cb; //bottom right

Then you use the sprite like so:
Code: Select all
.... create ....
   //grab the center of your 3x3 white pixel
   whitePixel = new TextureRegion(sheet, ...);

   //create a sprite
   gradient = new GradientSprite(whitePixel);
   gradient.setBounds(0, 0, width, height);
   gradient.setGradientColor(Color.RED, Color.BLUE, true);

.... render .....

   .. draw your sprites in the same batch ..

The other option is to just write the vertices directly to the batch, like so:
Code: Select all
static final float[] vertices = new float[20];

public void drawGradient(SpriteBatch batch,
      TextureRegion white,
      float x, float y,
      float width, float height,
      Color colorA, Color colorB,
      boolean horizontal) {
   float ca = colorA.toFloatBits();
   float cb = colorB.toFloatBits();
   int idx = 0;
   float u = white.getU();
   float v = white.getV2();
   float u2 = white.getU2();
   float v2 = white.getV();
   //bottom left
   vertices[idx++] = x;
   vertices[idx++] = y;
   vertices[idx++] = horizontal ? ca : cb;
   vertices[idx++] = u;
   vertices[idx++] = v;

   //top left
   vertices[idx++] = x;
   vertices[idx++] = y + height;
   vertices[idx++] = ca;
   vertices[idx++] = u;
   vertices[idx++] = v2;

   //top right
   vertices[idx++] = x + width;
   vertices[idx++] = y + height;
   vertices[idx++] = horizontal ? cb : ca;
   vertices[idx++] = u2;
   vertices[idx++] = v2;

   //bottom right
   vertices[idx++] = x + width;
   vertices[idx++] = y;
   vertices[idx++] = cb;
   vertices[idx++] = u2;
   vertices[idx++] = v;
   batch.draw(white.getTexture(), vertices, 0, vertices.length);

If you want a radial gradient or another unusual gradient, it would be easy just to use shaders. Once GitHub is back up, you can see my guide below. Gradients are explained in lesson 3.
Posts: 434
Joined: Thu Oct 11, 2012 7:51 pm

Re: Gradient background

Postby lijas » Mon Jun 03, 2013 3:57 pm

kalle_h wrote:If's its just one color to other gradient you can use very small texture(like 2x2) texture scaled and let bilinear filtering do the rest. This might be easier than messing with mesh.

Thank you, I went with this approach...
Posts: 42
Joined: Thu May 30, 2013 5:36 pm

Return to Libgdx

Who is online

Users browsing this forum: CodeHeadNed, Majestic-12 [Bot], obigu and 1 guest