Search code examples
c++openglglslshaderblending

Render a texture (decal) with an alpha value?


I tried to draw two textures of decals and background, but only the alpha part of the decals becomes white.

I simply tried the following.

  • Draw 2 textures (background & decals)
  • Add glBlendFunc to apply decals alpha value
#version 330 core

in vec2 UV;

out vec3 color;

uniform sampler2D background;

in      vec3      decalCoord;
uniform sampler2D decal;

void main(){

    vec3 BGTex     = texture( background, UV ).rgb;
    vec3 DecalTex  = texture(decal, decalCoord.xy).rgba;

    color = 
    vec4(BGTex,1.0) +   // Background texture is DDS DXT1 (I wonder if DXT1 is the cause?)
    vec4(DecalTex,0.0); // Decal texture is DDS DXT3 for alpha

}
// Set below...
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);

enter image description here

I was able to draw normally but there are the following problems.   -The alpha part of the decals can not be made transparent.

Is this a problem that can be solved within the fragmentshader? In that case, how should I rewrite the code?

The texture is DDS, one of which is DXT1 type (Background. Because this texture doesn't need alpha) and the other is DXT3 type (Decal). Is this also the cause?(Both need to be the DXT3 type?)

Also, should I look for another way to put on the decals?


Solution

  • The DecalTex has an alpha channel. The alpha channel is "weight", which indicates the intensity of the DecalTex. If the alpha channel is 1, then the color of DecalTex has to be used, if the alpha channel is 0, then the color of BGTex has to be used.
    Use mix to mix the color of BGTex and DecalTex dependent on the alpha channel of DecalTex. Of course the type of the DecalTex has to be vec4:

    vec3 BGTex     = texture( background, UV ).rgb;
    vec4 DecalTex  = texture(decal, decalCoord.xy).rgba;
    
    color = vec4(mix(BGTex.rgb, DecalTex.rgb, DecalTex.a), 1.0);
    

    Note, mix linear interpolates between the 2 values:

    mix(x, y, a) = x * (1−a) + y * a
    

    This is similar the operation which is performed by the blending function and equation:

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glBlendEquation(GL_FUNC_ADD);
    

    But Blending is applied to the fragment shader output and the current value in the framebuffer.
    You don't need any blending at all, because the textures are "blended" in the fragment shader and the result is put in the framebuffer. Since the alpha channel of the fragment shader output is >= 1.0, the output is completely "opaque".