5
\$\begingroup\$

I have a problem with a chromatic aberration shader effect...

If I produce the effect on a white background I get exactly what I want:

enter image description here

But if I do the same effect on a transparent background I get this:

enter image description here

In my code I use the following shader to produce the chromatic aberration effect:

// Chromatic Aberration

float DisplacementX = 5;
float DisplacementY = 5;

sampler TextureSampler : register(s0);

float4 main(float4 position : SV_POSITION, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{

// Offset the main texture coordinates.
float2 texCoord2 = float2(texCoord.x + DisplacementX, texCoord.y + DisplacementY);

float2 texCoord3 = float2(texCoord.x - DisplacementX, texCoord.y - DisplacementY);

float4 color1 = tex2D(TextureSampler, texCoord);
float4 color2 = tex2D(TextureSampler, texCoord2);
float4 color3 = tex2D(TextureSampler, texCoord3);

float alpha = color1.a + color2.a + color3.a;

// Look up into the main texture.
return float4 (color1.r, color2.g, color3.b, alpha);

}

technique RGBSplit
{

pass Pass0
{

PixelShader = compile ps_2_0 main();

}
}

This works great when I set the whole screen to a render target and apply the effect but I want to be able to apply this effect only to the foreground so I can choose which sprites it effects and then draw the background behind the transparent space.

My thinking so far is that I could create a white layer of the foreground image and blend it with the chromatic layer to produce the correct effect like this:

return float4(1, 1, 1, alpha); // Produces white version of layer

But I've unsuccessfully managed to blend it and I always end up with the same result as the second image.

I know this is possible because Teleglitch uses the same effect on bullets etc without effecting the background.

enter image description here

Perhaps someone with better blending knowledge than myself can help point me in the right direction?

\$\endgroup\$
  • \$\begingroup\$ I don't think it makes sense to add the alpha channels together. It might be more sensible would be to use the max of the 3. \$\endgroup\$ – user1118321 Feb 14 '16 at 2:56
1
\$\begingroup\$

I came up with a solution for this, if anyone else can think of a better way please let me know.

If I set the backbuffer of the foreground layer to white with an opacity of 99% or something like that:

GraphicsDevice.Clear(Color.White * 0.99f);

The shader will blend the foreground with the white creating the chromatic aberration like I want.

Then I pass over the final texture and remove any pixels that have transparency (which is the white background). So the new shader looks like this:

// Chromatic Aberration

float DisplacementX = 5;
float DisplacementY = 5;

sampler TextureSampler : register(s0);

float4 main(float4 position : SV_POSITION, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{

// Offset the main texture coordinates.
float2 texCoord2 = float2(texCoord.x + DisplacementX, texCoord.y + DisplacementY);

float2 texCoord3 = float2(texCoord.x - DisplacementX, texCoord.y - DisplacementY);

float4 color1 = tex2D(TextureSampler, texCoord);
float4 color2 = tex2D(TextureSampler, texCoord2);
float4 color3 = tex2D(TextureSampler, texCoord3);

float alpha = color1.a * color2.a * color3.a;

float4 finalTex = float4(color1.r, color2.g, color3.b, alpha);
if (finalTex.a <= 0.975f)
{
    clip(-1); // Abandon Pixel with transparency
}

// Look up into the main texture.
return finalTex;

}

technique RGBSplit
{

pass Pass0
{

PixelShader = compile ps_2_0 main();

}
}

The result means I can perform chromatic aberration on individual sprites then overlay them onto a background that doesn't use the effect.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.