1
votes

in my Libgdx Scene2D stage I am trying to have an actor flashing with white color. With OpenGLES 2.0 I understood I needed to use a shader to achieve this and I have a problem implementing it.

My goal is to color an actor in solid white color given a speficic game event. The problem is given this specific event, everything in the stage becomes white (all actors and the background) instead of just the selected actors textures.

My World class is where the stage is created. It is rendered like this:

public void render() {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
update();
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}

In the stage I use actors that are defined in a MyActor class. This class has its own draw method where I am trying to color the actor in solid white with the shader. Here is the draw method:

public void draw(Batch batch, float alpha) {
    if (flashing) {
        batch.setShader(shader);            
    }

    batch.flush();

    Color color = getColor();
    batch.setColor(color.r, color.g, color.b, color.a * alpha);

    batch.draw(tr, getX(), getY(), side/2, side/2, side, side, getScaleX(), getScaleY(), 0);        
}

Obviously I do something wrong with the batch. Instead of coloring this one actor in white, it colors everything. Also it remains white even after the Boolean flashing = false;

Here is how I have set up my shader, in the actor class MyActor:

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

String fragmentShader = "#ifdef GL_ES\n" +
        "precision mediump float;\n" +
        "#endif\n" + "varying vec4 v_color;\n" +
        "varying vec2 v_texCoords;\n" +
        "uniform sampler2D u_texture;\n" +
        "uniform float grayscale;\n" +
        "void main()\n" +
        "{\n" +
        "vec4 texColor = texture2D(u_texture, v_texCoords);\n" +
        "float gray = dot(texColor.rgb, vec3(5, 5, 5));\n" +
        "texColor.rgb = mix(vec3(gray), texColor.rgb, grayscale);\n" +
        " gl_FragColor = v_color * texColor;\n" +
        "}";

Then initiated with:

shader = new ShaderProgram(vertexShader, fragmentShader);

What is it that I am doing wrong?

I have to admit I probably don't understand correctly how the batch of MyActor, the drawing method and the rendering methods work together!

Thanks for your time

1
Do you reset the Shader somewhere, so that SpriteBatch uses the defaukt Shader again? Actually in your case i would not do it with a Shader, this task is not that complex. Just store the default Texture and a solid white Texture and say Texture t = flashing ? white : default; and the draw the Texture t. - Robert P
Hey @Springrbua, thanks for your answer. No I don't think I reset the shader anywhere, how can I do that? I would rather avoid using a second set of white textures manually created, there is supposed to be dozens of different textures in my game, each with a unique shape, so the programmatic approach looks way better I think - Don
You could and should use TextureAtlas anyways, but you have to decide. I think if you say batch.setShader(null) it uses the default Shader again, but i am not sure. - Robert P
The javadok of the setShader says: "Call this method with a null argument to use the default shader. " - Robert P
brilliant, that works, thanks. IF you want to write it as an answer I can approve it for you :) I already use a TextureAtlas but unless I didn't get you, I don't want to manually create png files of dozen of sprites with white solid color. Thanks for your time - Don

1 Answers

3
votes

The problem here is, that you never set the Shader back to the default Shader, so your Spritebatch always uses the "solid white" Shader. As the javadock of the setShader(ShaderProgram shader)sais you can reset the Shader by calling setShader(null).
Another possibility would be to use another Texture for the solid white and the simply say:

Texture t = flashing ? whiteTexture : defaultTexture;

and draw the Texture t.
Just a suggestion: Do not use batch.flush() if it is not absolutely neccessary, because flush() makes a draw call to the GPU and this costs some performance.