0
\$\begingroup\$

I try to implement a HLSL shader the does the normal Alphablend with premultiplied colors (just as XNA4 does) but depending on some existing colors. One can think of adding a glow to a 2D terrain where the glow should only be applied to the not fully transparent parts of the terrain.

My current code is:

sampler TextureSampler1 : register(s1); // Addition (Terrain-only particles)
sampler TextureSampler2 : register(s2); // Existing (Terrain)

float4 main(float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
    // Look up color from partly transparent existing texture (premultipied colors)
    float4 existing = tex2D(TextureSampler2, texCoord);

    // For transparent pixels -> Color stays the same
    if ((existing.r + existing.g + existing.b + existing.a) == 0) return existing;

    // Look up color from partly transparent addition-texture (e.g. glow) (using premultipied colors) that should be added to existing color
    float4 addition = tex2D(TextureSampler1, texCoord);

    // Rescale light that is added by existing alpha
    addition.rgb *= existing.a;

    // Use this color to blend
    existing.rgb *= (1 - addition.a) + addition.rgb; 

    return existing;
}

However, there still seems to be a problem with the alpha channel. Any ideas?

\$\endgroup\$
1
  • \$\begingroup\$ You might want to look into the lerp() function to make blending easier. \$\endgroup\$
    – ChrisC
    Jan 25 '13 at 23:05
1
\$\begingroup\$

Your line:

existing.rgb *= (1 - addition.a) + addition.rgb; 

does

existing.rgb = existing.rgb * ((1 - addition.a) + addition.rgb);

what you probably wanted is

existing.rgb = existing.rgb * (1 - addition.a) + addition.rgb;
\$\endgroup\$
0
\$\begingroup\$

Interestingly, the following code works. But why?

float4 main(float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
    // Look up color from partly transparent existing texture (premultipied colors)
    float4 existing = tex2D(TextureSampler2, texCoord);

    // For transparent pixels -> Color stays the same
    if ((existing.r + existing.g + existing.b + existing.a) == 0) return existing;

    // Look up color from partly transparent addition-texture (e.g. glow) (premultipied colors) that should be added to existing color
    float4 addition = tex2D(TextureSampler1, texCoord);

    float4 output;

    // Keep light blocking properties
    output.a = existing.a; 
    // Rescale light that is added by existing alpha
    addition.rgb = addition.rgb * existing.a;
    // Use this color to blend
    output.rgb = existing.rgb * (1 - addition.a) + addition.rgb; 

    return output;
}
\$\endgroup\$
4
  • \$\begingroup\$ Is this an answer to your question or an additional question? If it's an answer, it's a poor one, since good answers should also tell you the why. \$\endgroup\$
    – House
    Jan 25 '13 at 22:00
  • \$\begingroup\$ @Byte56: Sure, I would love to know why. To my knowledge the below code seem equivalent to the upper one. Thos only difference is that the output color is accumulated in existing and not in an additional variable output. I am not sure why this makes a difference here. \$\endgroup\$
    – ares_games
    Jan 25 '13 at 23:13
  • 1
    \$\begingroup\$ Sorry, I didn't understand your reply. I was suggesting that you merge this answer with your question, since it doesn't appear to stand as an answer on its own. \$\endgroup\$
    – House
    Jan 25 '13 at 23:26
  • 2
    \$\begingroup\$ You used the *= operator incorrectly, see my answer. It has a lower precedence than +. Basically everything on the right side of *= gets resolved before executing the multiplication. \$\endgroup\$
    – Archy
    Jan 26 '13 at 1:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .