LeSam
LeSam

Reputation: 1265

Change sprite color into white

I'm trying to change the color of a sprite (which is red and gray), in white color.

sprite.setColor(1, 1, 1, 1);

But nothing is happening.

How can I change all the sprite colors in white?

Upvotes: 3

Views: 2354

Answers (4)

Numeron
Numeron

Reputation: 8823

You can achieve this without any OpenGL2 functions or shaders or a pre-whiteouted copy of the sprite or any other crazy stuff by using a stencil buffer.

First you draw your sprite to the stencil buffer, then draw an appropriately colored filled rectangle over the stencil and it will only draw where the stencil was, leaving you with a coloured silhouette.

here is how it works:

//Turn off drawing to the color buffers
Gdx.gl.glColorMask(false, false, false, false);

//Enable drawing to the stencil buffer
Gdx.gl.glEnable(GL10.GL_STENCIL_TEST);

//Set the stencil mask you want to use, mask 1 is as good as any other
Gdx.gl.glStencilMask(1);

//When drawing, Always attempt to draw a 1 into mask 1 for every pixel
Gdx.gl.glStencilFunc(GL10.GL_ALWAYS, 1, 1);
//When drawing, replace whatever is currently in the mask
Gdx.gl.glStencilOp(GL10.GL_REPLACE, GL10.GL_REPLACE, GL10.GL_REPLACE);

//unlike the name would have you believe, this call actually sets the 'color'
//to clear the stencil with and doesnt actually clear the stencil. We want to
//set the mask to all 0's
Gdx.gl.glClearStencil(0); 
//This then clears the stencil buffer with all 0's
Gdx.gl.glClear(GL10.GL_STENCIL_BUFFER_BIT);

//A sprite typically has transparent pixels, and we don't want to draw them
//into the mask, so filter out pixels with an alpha less than 0.5f. Only
//those greater are drawn into the stencil buffer
Gdx.gl.glEnable(GL10.GL_ALPHA_TEST);
Gdx.gl10.glAlphaFunc(GL10.GL_GREATER, 0.5f);

//Draw the sprite into the stencil buffer
spriteBatch.begin();
spriteBatch.draw(...)
spriteBatch.end();

//Finished filtering the alpha channel
Gdx.gl.glDisable(GL10.GL_ALPHA_TEST);

//Now that we want to use the mask instead of drawing into it so we turn
//drawing to the color buffer back on
Gdx.gl.glColorMask(true, true, true, true);
//Set us up to only draw where the stencil buffer equals 1
Gdx.gl.glStencilFunc(GL10.GL_EQUAL, 1, 1);
//And since drawing into the mask is actually still on, we set this to keep the
//values in the stencil buffer, and not overwrite them
Gdx.gl.glStencilOp(GL10.GL_KEEP, GL10.GL_KEEP, GL10.GL_KEEP);

//Draw a coloured rectangle over the mask, and it will only draw pixels where the
//stencil buffer has been set giving you a silhoutte of your sprite! You can also
//use a transparent rect and draw over a normal render of your sprite to fade the
//sprite up into whatever color you want
shapeRenderer.begin(ShapeType.Fill);
shapeRenderer.rect(...);
shapeRenderer.end();

//Done with the stencil
Gdx.gl.glDisable(GL10.GL_STENCIL_TEST);

Upvotes: 1

SteveL
SteveL

Reputation: 3389

If you want to change the color of all the shapes in the sprite to white then the only way you can do this is to use a pixel shader and set all the fragments that they are not black(i assume black renders as transperant in your game) to white. Something like that:

varying vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
void main() {
    vec4 color=v_color * texture2D(u_texture, v_texCoords);

    if(color.r!=0 && color.g!=0 && color.b!=0){
        gl_FragColor=vec4(1,1,1,1);
    }
    else{
        gl_FragColor=color;
    }
}

If you are unfortunate and you use opengl 1.0(fixed pipeline), I suggest you to switch to gles 2.0 now that you are a beginer.Fixed pipeline is from the 90' , we are at 2013!

The code:

Initialize:

  ShaderProgram.pedantic = false;

  ShaderProgram defaultShader=SpriteBatch.createDefaultShader();

  ShaderProgram shaderWhiteTexture=new ShaderProgram(Gdx.files.internal("vertexShader.vs").readString(),Gdx.files.internal("fragShader.fs").readString());

Render:

//Render the textures with the normal colors 
spriteBatch.begin();
spriteBatch.draw(sprite1,sprite2,sprite3...);//or whatever code u use to render them
spriteBatch.end();

//Render the textures with the shader
spriteBatch.setShader(shaderWhiteTexture);
spriteBatch.begin();
spriteBatch.draw(sprite4,sprite5,sprite6...);//or whatever code u use to render them
spriteBatch.end();
spriteBatch.setShader(defaultShader);

Shaders:

//vertexShader.vs:
attribute highp vec4 a_position;
attribute highp vec4 a_color;
attribute highp vec2 a_texCoord0;
uniform mat4 u_projTrans;

varying highp vec4 v_color;
varying highp vec2 v_texCoords;

void main() {
    v_color = a_color;
    v_texCoords = a_texCoord0;
    gl_Position = u_projTrans * a_position ;
}

//fragShader.fs:
varying highp vec4 v_color;
varying highp vec2 v_texCoords;
uniform sampler2D u_texture;
void main() {

    gl_FragColor = vec4(0.0);

    highp vec4 color = texture2D(u_texture, v_texCoords);

    if(color.a > 0.0) {
       gl_FragColor = vec4(1.0,0,0,1.0);
}

}

EDITED BY QUESTION OWNER : Now works with transparent texture

What have been added ? :

1 . the highp precision to variables
2 . the fragmentShader file Main() fonction edited

Upvotes: 4

Daahrien
Daahrien

Reputation: 10320

That won't work. The color WHITE does not affect darker colors (read: every other color).

Thats actually the sprite default, so it renders exactly as the image you created it from (thats the reason you don't see a change). If you are going to use Sprite Color to affect how a sprite is rendered at running time, consider making it white and then changing it to any other color.

Upvotes: 1

Tekkzz
Tekkzz

Reputation: 638

Answer before my is right! You can do: sprite.setColor(new Color(Color.WHITE)); This is more simply for you i think...

Upvotes: -2

Related Questions