Skip to main content

Microsoft Silverlight

Answered Question Pixel shader for controlling opacity at edges of Path objectRSS Feed

(0)

TomGiam
TomGiam

Member

Member

744 points

213 Posts

Pixel shader for controlling opacity at edges of Path object

Anybody know where I can find a Pixel shader for controlling opacity at edges of a Path object?

For example if I have a Path object in the shape of a star, I want the edges of the star to gradually become more transparent (perpendicular to the edges) and blend in with the background.

It would be nice to be able to control how far from the edge to start the gradual transparency.

I'm currently using OpacityMask with RadialGradientBrush, but that does not work well because the edges are not uniformly transparent since they are at different distances from the center.

If OpacityMask supported PathGradientBrush then that would work perfectly.

Thanks

Tom

 

codenenterp
codenenterp

Member

Member

36 points

13 Posts

Re: Pixel shader for controlling opacity at edges of Path object

you can use this tool http://shazzam-tool.com/ to make your own.  Also dont just search for silverlight any pixel shader with wpf will work too.

Solutions Architect
Coden Enterprises
http://www.codenenterprises.com/iblog

SharpGIS
SharpGIS

Contributor

Contributor

3397 points

611 Posts

Re: Pixel shader for controlling opacity at edges of Path object

I think if you create the path twice, and with the first one (the one below) you apply the Blur effect to it, you will get what you are looking for. Come to think of it, you might not even need the second star on top.

--
/Morten | blog - twitter
Please click on "Mark as Answer" if this answered your question.

TomGiam
TomGiam

Member

Member

744 points

213 Posts

Re: Pixel shader for controlling opacity at edges of Path object

Codenerterp:

I'm using shazzam, but I only have basic knowledege of hlsl.  I've looked and have not found any hlsl code for this yet.

SharpGIS,

The effect I'm looking for is also callled "Vignette" and the objective is to smoothly transition the opacity to blend in with the background.  The blur effect does not give the same result because it distorts the image.  It also does not apply the blur uniformly at the edges.

I have a couple of ideas, but don't know how to implement them fully in hlsl.

IDEA #1:

  1. In order to more easily detect the edges. Convert copy of image to one where the transparent parts are in black and opaque parts in white.
  2. Use Sobel filter to detect the edges
  3. Apply differerent levels of opacity to the pixels close to and perpendicular to the edges

Note: assumes at least one 0 opacity pixel all the way around image, so that condition needs to be handled by either detecting it or pre adding a 0 opacity pixel all the away around the rectangular edge.

I believe that I can do 1 and 2, but unsure about 3

IDEA #2: Similar to #1, but detect edge based on opacity

  1. For every pixel in picture if opacity = 1 and pixel next to it has opacity = 0, apply differerent levels of opacity to the pixels close to and perpendicular to that point

Thanks

Tom

 

ksleung
ksleung

Contributor

Contributor

5342 points

1,020 Posts

Re: Pixel shader for controlling opacity at edges of Path object

Tom,

You can take a look at the WPF shader effect library if you want to see how other shader effects are written.  All effects can be used in Silverlight but the syntax of the integration code needs some minor change.

Make sure I understand your need.  You have a star, and you want the adjust the opacity of the star near the edge to achieve a vignette effect.

This is how I would approach the problem...  not sure whether it'll work: extract the alpha channel, invert (so inside star = 0, outside = 1), Gaussian blur it, and reinvert.

This can be achieved as 3 separate pixel shader effects (using the Border element hack):

(1) first shader blur the inverts of the alpha channel horizontally (but don't touch the RGB components).

(2) the second shader blur the alpha channel vertically, and invert the final alpha value.

(3) the third shader takes the alpha from the original and the alpha from the second shader and set the alpha to be minimum of the two.

This is actually similar to how Gaussian blur is implemented (as a two-pass 1D blur).  It is easy to find 1D Gaussian blur HLSL code.  The key is to pre-blur inversion in step (1) and the post-blur inversion in step (2) so the alpha channel is blurred from the edge inward.  The step (3) combines the new opacity mask with the original image with the minor tweak that the alpha outside of the star stays zero (instead of being blurred to a non-zero value).

SharpGIS
SharpGIS

Contributor

Contributor

3397 points

611 Posts

Re: Re: Pixel shader for controlling opacity at edges of Path object

I dont think pixel shaders is your answer then. Since they operate at the pixel level, there is really no telling what is perpendicular to an edge or not, unless you want to write a really complex and slow shader. Perhaps the writeable bitmap would be an option for you.

--
/Morten | blog - twitter
Please click on "Mark as Answer" if this answered your question.

TomGiam
TomGiam

Member

Member

744 points

213 Posts

Re: Pixel shader for controlling opacity at edges of Path object

Yes, you understand my requirements correctly.  I have many different Path elements (including a star) filled with an image brush.  I want to create a Vignette effect where as you get closer to any edge of the Path element it becomes evenly more transparent.  It's kind of like creating a PathGradientBrush for OpacityMask as opposed to only being able to use LinearGradientBrush and RadialGradientBrush.

I think I understand your approach, it will take me a while to implement.

Do you think that the following approach would work?  It seems easier for me to understand and implement (if only I knew how to compare a pixel with the 8 surrounding pixels):

1. For every pixel in the image whose alpha is == 1

  a. If any of it's surrounding pixels have alpha of 0 (i.e. at the edge)

     i. Change any surrounding pixels whose alpha is 1 to .1

     ii.. Change any surrounding pixel from step i. whose alpha == 1 to .2

  b. repeat step ii with values up to .9

 

Tom

 

 

ksleung
ksleung

Contributor

Contributor

5342 points

1,020 Posts

Re: Pixel shader for controlling opacity at edges of Path object

This would be an iterative algorithm but not an shader-like algorithm.

Shader algorithm is like this:  given a pixel location (x, y), compute the alpha at (x, y) based on its neighborhood.

Therefore, if you really want to do the way you described, you can look at N neighbors (say a 5x5 neighborhood which means N = 25).  You can sample your neighbors, say of the form (x + k1 * dx, y + k2 * dy), where k1 = -2, -1, 0, 1, 2 and k2 = -2, -1, 0, 1, 2 and dx and dy are 2 pixels each.  Obviously the runtime of this algorithm is proportional to N.  Also HLSL supports only 64 instructions which mean that for all practical purpose N cannot exceed 25.

TomGiam
TomGiam

Member

Member

744 points

213 Posts

Answered Question

Re: Pixel shader for controlling opacity at edges of Path object

I got something to work using a simple alpha averaging of surrounding pixels like this:

float off : register(C0);

sampler RT;

float4 main(float2 textCoord: TEXCOORD0) : COLOR

{

//Sample the neighboor cells

float4 s00 = tex2D(RT, textCoord + float2(-off, -off));

float4 s01 = tex2D(RT, textCoord + float2(0, -off));

float4 s02 = tex2D(RT, textCoord + float2(off, -off));

float4 s10 = tex2D(RT, textCoord + float2(-off, 0));

float4 s11 = tex2D(RT, textCoord + float2(0, 0));

float4 s12 = tex2D(RT, textCoord + float2(off, 0));

float4 s20 = tex2D(RT, textCoord + float2(-off, off));

float4 s21 = tex2D(RT, textCoord + float2(0, off));

float4 s22 = tex2D(RT, textCoord + float2(off, off));

float total = s00.a + s01.a + s02.a + s10.a + s11.a + s12.a + s20.a + s21.a + s22.a;

float avg = total/9;

//if(avg > 0.1 && avg < .8)

//avg = avg*adjust;

if(s11.a == 1.0)

s11.a = avg;

return s11;

}

It's a little more banded than I would like, but it may be good enough. 

A 5x5 was running into instruction limits and multiple iterations of 3x3 has no effect since the average comes out the same.

As I learn more about shaders I'll improve on this.

However, I'm having problems getting it inside my SL app, I'll post a separate thread on that problem.

Thanks for your help

Tom

 

ksleung
ksleung

Contributor

Contributor

5342 points

1,020 Posts

Re: Pixel shader for controlling opacity at edges of Path object

This sounds right.  I think you can apply it multiple times if you change your if statement from:

if (s11.a == 1.0)

to

if (s11.a > 0.0)

BTW you can also use for loop to write this, but of course the net effect is the same because loops are unrolled by the compiler.

  • Unanswered Question
  • Answered Question
  • Announcement
Microsoft Communities