Sign in to follow this  
AvengerDr

Drawing an Ellipse via its implicit equation in a PIxel Shader

Recommended Posts

In this thread we were discussing the possibility of drawing an ellipse in a pixel shader through its implicit equation. I went ahead and tried it but it is not as easy as it seems. In this particular case, I'm trying to generate the outline of an ellipse, so I have two parameters: an outline "width" and a "fade to black" distance, which generates a gradient from the outline color and the transparent background (for no particular reason, I just wanted to smooth the edges). This is the image generated by the pixel shader: As you may have noticed, the width of the outline is wider at the points where its curve changes orientation (ie at the full extents of its semimajor axis in this case) and thinner at its semiminor axis. This is due to the code that I'm using to generate it, I guess. Here follows the pixel shader code:
float a; // Semimajor Axis
float b; // Semiminor Axis

float fOutlineWidth = 0.05;
float fFadeWidth = 0.25;

float4 circleColor = float4(1,0,0,0);
float4 cBlack = float4(0,0,0,0);

float h = 0; // Center X coordinate
float k = 0; // Center Y coordinate

float4 ps_main( float2 texCoord  : TEXCOORD0 ) : COLOR
{

   float x = texCoord.x;
   float y = texCoord.y;

   float fEllipse = pow(x-h,2) / (a*a) + pow(y-k,2) / (b*b);
   float fDistance = abs(1-fEllipse);
   
   float4 color;
   
   if (fDistance <= fOutlineWidth)
      color = circleColor;
   else if (fDistance <= fOutlineWidth + fFadeWidth)
      color = lerp(circleColor,cBlack, (fDistance-fOutlineWidth)/fFadeWidth);
   else
      color = cBlack;
      
   return color;
}

It's very simple. Just compute the ellipse's implicit equation. When it's very close to 1, if it's under a certain value (fOutlineWidth or fOutlineWidth < x < fOutlineWidth + fFadeWidth) apply a certain color. But it provokes the above effect, which is due to these distances not being as "linear" as say, in the case of a circle. So what should I do in order to make it render a "perfect" ellipse? Maybe using two ellipses? With the semimajor/minor axis slightly larger and compute the distance between these two ellipses, and use that value to see which color to apply? Or is there a more elegant way? Thanks in advance!

Share this post


Link to post
Share on other sites
this is the best I could do tonight, I will see if i can refine it later if I feel like it.
Time1 advances 0.005f per frame in the program



float a = (sin(Time1)+1)/6+0.05; // Semimajor Axis
float b = (cos(Time1)+1)/6+0.05; // Semiminor Axis
float h = 0.5; // Center X coordinate
float k = 0.5; // Center Y coordinate


float x = texCoord.x;
float y = texCoord.y;

float theta = acos((x-h)/a);

if (y < k)
theta = Pi - theta + Pi;

float x2 = h + a * cos(theta);
float y2 = k + b * sin(theta);

float fEllipse = pow(x-h,2) / (a*a) + pow(y-k,2) / (b*b);
float fDistance = abs(1-fEllipse);
float fDistance2 = sqrt((x2 - x)*(x2 - x) + (y2-y)*(y2-y));


float4 color;
if (fDistance2 <= fOutlineWidth/10)
color.x = circleColor.x;
else if (fDistance <= fOutlineWidth)
color.y = circleColor2.y;
else
color = cBlack;


return color;




the green color is your original function, the red addition is my new function, both of them overlapping make a fairly decent ellipse, but the smoothing function as you wrote it doesn't work on my addition because the coordinates go screwy on the left and right extremes of the ellipse.

program and fx file

anyway hope this helps

Share this post


Link to post
Share on other sites
Can you maybe for a given pixel position, compute a vector that is perpendicular to the closest point on the ellipse, and then project the pixel position onto that vector, telling you how far off the curve you are, to give a uniform width around the whole ellipse?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this