Skip to main content
Home Forums General Silverlight New Features in Silverlight 3 Pixel shader for controlling opacity at edges of Path object
9 replies. Latest Post by ksleung on July 5, 2009.
(0)
TomGiam
Member
744 points
213 Posts
07-03-2009 8:47 PM |
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
36 points
13 Posts
07-04-2009 12:19 AM |
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.
SharpGIS
Contributor
3397 points
611 Posts
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.
07-04-2009 9:01 AM |
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:
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
ksleung
5342 points
1,020 Posts
07-04-2009 1:07 PM |
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.
07-04-2009 1:17 PM |
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.
07-04-2009 2:25 PM |
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
07-04-2009 5:51 PM |
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.
07-05-2009 11:43 AM |
I got something to work using a simple alpha averaging of surrounding pixels like this:
float
sampler
float4
{
//avg = avg*adjust;
}
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
07-05-2009 1:22 PM |
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.