[Potentially easy question] Is this idea for a Silhouette effect possible?

Hey guys, new to the forum - I have a small amount of experience with OpenGL / GLSL.

Easy question:

I have a texture of a character that has varying amounts of alpha. Can I draw the texture with a shader that multiplies its alpha-channel by 0.8, and then draw it AGAIN with the alpha multiplied by 0.2 such that it ends up looking like the exact original image? (some form of additive blending?)

The full question:

I’m wanting to implement a version of silhouetting the player’s character when it is behind an occluder -> I was looking at this guide: How To Make Silhouettes In GameMaker | GameMaker

For various reasons, I can’t use the same process as that guide suggests (my occluders aren’t stationary, and I would like for it to be efficient enough to work on mobile).

My game is using the same viewing-angle as the game in that guide. My actors are sorted (y-order, not using any depth type stuff) for drawing.

I was thinking I could potentially go about it this way:

  1. Draw all of the actors that are behind the player (sorted, y-order)
  2. Draw the player with a shader that scales his texture’s alpha-channel by 0.8
  3. Draw all of the actors that are in front of the player
  4. Draw the player again with a shader that scales his texture’s alpha-channel by 0.2

My hope is that there is a blending setup that would cause any pixels of the player that were not occluded to have the same alpha-value as the original player-texture, and any pixels that ARE occluded to look semi-transparent (for the silhouette effect).

Does anyone know if this is possible? I appreciate any help!!

Here is one way of doing this:

  • Create a FrameBufferObject
  • Attach a texture with only 1 color component. This will be used to test for your “occluders”.
  • Render your occluders to this FBO. Every rendered fragment should result in a texel update in our texture. Set the texel value to the alpha value you want in your render pass.
  • Switch back to the original framebuffer and bind the texture from the FBO to a uniform
  • Render your scene like usual but multiply fragment colors of objects that should be occluded with the value from the texture

You can probably start with this and try to improve it as necessary.

In step 2, the alpha should be unscaled. Otherwise, pixels which should be fully opaque will let some of the background bleed through: (1-0.8)(1-0.2)=0.20.8=0.16.

Multiple overlay blends will result in the overall blending factor being slightly non-linear; for a last-stage alpha scale of 0.2 it will result in a value of 0.5 being mapped to 0.55. But provided that the first stage uses unscaled alpha, 0.0 maps to 0.0 and 1.0 maps to 1.0.

If you want to preserve the blending factor exactly, you’ll need to use a shader to modify the alpha in step 2. For a scale factor of k (=0.2 in your example), the alpha value in step 2 should be
a’ = a*(k-1)/(ak-1)
The alpha value in step 4 is just a
k, which can be achieved without shaders (glTexEnv() with GL_MODULATE) if necessary.