Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Texture grayscale in libgdx

Is there a way to transform a libgdx's Texture to a grayscale image? So far I had duplicate the images that I want to grayscale and I did it manually, but I think it is not the best solution because my game is using more and more images and it uses a lot of disk space.

like image 679
Sergio Peñafiel Avatar asked Jul 07 '13 20:07

Sergio Peñafiel


3 Answers

Thought I'd share this for anyone wanting to use some copy/paste code.

import com.badlogic.gdx.graphics.glutils.ShaderProgram;

public class GrayscaleShader {
    static String vertexShader = "attribute vec4 a_position;\n" +
            "attribute vec4 a_color;\n" +
            "attribute vec2 a_texCoord0;\n" +
            "\n" +
            "uniform mat4 u_projTrans;\n" +
            "\n" +
            "varying vec4 v_color;\n" +
            "varying vec2 v_texCoords;\n" +
            "\n" +
            "void main() {\n" +
            "    v_color = a_color;\n" +
            "    v_texCoords = a_texCoord0;\n" +
            "    gl_Position = u_projTrans * a_position;\n" +
            "}";

    static String fragmentShader = "#ifdef GL_ES\n" +
            "    precision mediump float;\n" +
            "#endif\n" +
            "\n" +
            "varying vec4 v_color;\n" +
            "varying vec2 v_texCoords;\n" +
            "uniform sampler2D u_texture;\n" +
            "\n" +
            "void main() {\n" +
            "  vec4 c = v_color * texture2D(u_texture, v_texCoords);\n" +
            "  float grey = (c.r + c.g + c.b) / 3.0;\n" +
            "  gl_FragColor = vec4(grey, grey, grey, c.a);\n" +
            "}";

    public static ShaderProgram grayscaleShader = new ShaderProgram(vertexShader,
            fragmentShader);
}

To use it call

spriteBatch.setShader(GrayscaleShader.grayscaleShader)

And when you're done with grayscale don't forget to call

spriteBatch.setShader(null);
like image 190
Will Calderwood Avatar answered Oct 17 '22 05:10

Will Calderwood


You should be able to write a GLSL shader that renders a texture in grayscale. This requires OpenGL 2.x, and doesn't really "transform" a texture, but just renders it to the display as grayscale.

For a detailed tutorial on shaders that includes a grayscale shader check out: https://github.com/mattdesl/lwjgl-basics/wiki/ShaderLesson3

(Libgdx doesn't really define the GLSL shader API, that's passed through from OpenGL, so most tutorials or code you find on the web for regular OpenGL should work.)

For a more direct hack, just take the Libgdx SpriteBatch shader and change the fragment shader so it averages the rgb components. (You can define your own ShaderProgram and provide it to a SpriteBatch to use.) Change body of the fragment shader to something like this (untested, so may not compile):

+ "  vec4 c = v_color * texture2D(u_texture, v_texCoords);\n" //
+ "  float grey = (c.r + c.g + c.b) / 3.0;\n" //
+ "  gl_FragColor = vec4(grey, grey, grey, c.a);\n" //
like image 31
P.T. Avatar answered Oct 17 '22 05:10

P.T.


You can load up textures as luminance only, or luminance and alpha in GLES (see glTexImage2D). In libgdx you can specify PixFormat.Intensity (luminance) or LuminanceAlpha (luminance and alpha) when instantiating the Texture. This will generate a grayscale texture.

You still need to have two textures (one color, one grayscale) loaded up, but they can use the same source, and the luminance only uses only 1 byte per pixel in memory. A more efficient solution is to implement a shader as suggested by P.T., but is only available from GLES 2.

like image 2
Aert Avatar answered Oct 17 '22 06:10

Aert