0

In a Libgdx 1.x Stage, my goal is to apply a dark semi transparent mask on my screen except an area that should display the original screen.

My global render method:

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

    batch.begin();      
    darkener.draw(batch, 0.7f);     
    spotlight.draw(batch, 1f);      
    batch.end();                
}

Both instances of objects Darkener and Spotlight are Sprites made from a pure white 4x4 texture:

spotlight = new Sprite(new Texture(Gdx.files.internal("data/ui/whitepixel.png")));

darkener = new Sprite(new Texture(Gdx.files.internal("data/ui/whitepixel.png")));

I give my Darkener object the size of the screen, and my Spotlight object the size of the area I want not to be darkened.

Here is the draw method of my object darkener:

public void draw(Batch batch, float alpha) {        
    darkener.draw(batch, alpha);        
}

And the draw method of my Spotlight object:

public void draw(Batch batch, float alpha) {
    batch.setBlendFunction(GL20.GL_DST_COLOR, GL20.GL_SRC_ALPHA);
    spotlight.draw(batch, alpha);
    batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
}

My problem is about blending: With the parameters:

darkener.draw(batch, 0.7f);     
spotlight.draw(batch, 1f);  

The preserved (spotlight) area is darker than the original.

With the parameters:

darkener.draw(batch, 0.3f);     
spotlight.draw(batch, 1f);  

The preserved (spotlight) area is brighter (saturated) than the original.

With the paremeters:

darkener.draw(batch, 0.5f);     
spotlight.draw(batch, 1f);  

The preserved (spotlight) area is exactly like the original (so, as I want it). The problem is that I want to be able to set different values for my Darkener either < 0.5f or > 0.5f.

What I am doing wrong?

Don
  • 977
  • 3
  • 10
  • 28

1 Answers1

2

The blend function you're using for the spotlight takes the current pixel brightness and multiplies it by (1+alpha).

So if you darken to 0.7 of brightness (using a darkener alpha of 0.3), you want the spotlight to multiply the brightness by 1/0.7 = 1.429 so you should use a spotlight alpha of 0.429. So:

spotlightAlpha = 1/(1-darkenerAlpha) - 1; //assuming darkener RGB is black

The problem is if you darken to less than 0.5 brightness (darkner alpha > 0.5), because alpha cannot be greater than 1. You would have to run the spotlight with alpha 1 repeatedly until the brightness is above 0.5 and then one more time with the appropriate value.

You will lose color precision the darker you go so this method may not be suitable. Might want to consider drawing 8 dark boxes instead. And if you want the spotlight to be non-rectangular you can make its sprite inverted to fill in the middle rectangle.

Tenfour04
  • 83,111
  • 11
  • 94
  • 154
  • Hi @Tenfour04, and thanks for your answer. You are definitely right about the cause of the problem, but are you sure the formula to find the required alpha for the spotlight is 1/darkener alpha? It never gives me a desired result, however by tweaking the values I have found ok results for darkener = 0.6, 0.7 etc. Also could you please elaborate a bit on drawing 8 dark boxes instead? I feel dumb but I didn't get it at all! Thanks for your time and good ideas – Don Feb 06 '15 at 09:10
  • I think it's right, but I might be missing some info. Based on your description above, the darkener would actually make the screen paler, because it draws a translucent white rectangle. I was assuming you made it black. And actually I think I may have it inverted based on that assumption. By 8 dark boxes I mean: imagine a Sudoku grid of 9 boxes, except you stretch it to fit your screen, and shift the inner lines so the center box is the size of your spotlight. You can draw the darkener to the coordinates of the 8 surrounding boxes, and draw a spotlight sprite to the center box. – Tenfour04 Feb 06 '15 at 13:45
  • I just realized my explanation was unclear. By 'darken to 0.7" I mean darken it to 70% of original brightness, which would be like using a darkener alpha of 0.3, assuming the darkener sprite is black. So the formula for spotlight alpha is `1/(1-darkenerAlpha) - 1`. – Tenfour04 Feb 06 '15 at 13:54
  • Hello @Tenfour, thanks again for your comments and suggestions. I get the 9-1 boxes idea, it's a good one. I also understand better the formula to set the right amount of alpha. thanks again for your help and good ideas, have a nice week – Don Feb 09 '15 at 09:43