I want to utilize shaders to not only discard fragments if they are on one side of a predefined plane but also render a contour along the intersection.

My fragment shader currently does something along the lines of:

float dot = dot(world_coordinate, normalize(clipping_normal.xyz)) - clipping_normal.w;
if (dot > 0.0f) 

this works but without the desired contour. I tried comparing the dot product against values close to 0.0 but this results in a contour with varying width depending on view etc...

This is what I am trying to achieve. Notice that the white contour/edge of where the plane intersects the sphere is of consistent width:


So below is what the result I currently see:


With the fragment shader:

in vec4 color;
in vec3 world_position; 

out vec4 frag_color;

void main()
    float dist = (dot(clipping_plane.xyz, world_position) - clipping_plane.w) / 
              dot(clipping_plane.xyz, clipping_plane.xyz);

    if(dist >= 0.0f && dist < 0.05f)
        frag_color = vec4(0.0f, 0.0f, 0.0f, 1.0f);
    else if(dist < 0.0f) 
        frag_color = ComputePhong(color);
  • \$\begingroup\$ Why not just "if z is close to zNear -> draw contour". The shields do something similar in overwatch when close to any wall, and they look decent \$\endgroup\$
    – Bálint
    Commented Feb 28, 2019 at 11:52
  • \$\begingroup\$ Your question isn't clear. In the first image it looks like there is some geometry filled into the gap. In the second image it seems to match the shader fairly well. Can you elaborate on how what you are doing differs from what you want? \$\endgroup\$
    – Jay
    Commented Mar 1, 2019 at 0:01
  • \$\begingroup\$ I updated the question with more information. I now use a different calculation to determine whether the position is on the plane (A,B,C,D plane form) but didn't really fix the issue. \$\endgroup\$ Commented Mar 1, 2019 at 9:21
  • 1
    \$\begingroup\$ You can use screenspace partial derivatives to get a more consistent line thickness, but this will only help you in places where the mesh itself is drawn at least as wide as the line. If you're looking at the mesh edge-on, so the drawn polygon is narrower than the line you want to draw, you're out of luck. For cases like that, you'll need to draw the line in a separate pass - either as a post effect, or as its own strip of geometry. \$\endgroup\$
    – DMGregory
    Commented Mar 2, 2019 at 1:41
  • \$\begingroup\$ Thank you for a very informative post. I'm not extremely well versed in shader techniques so I wouldn't really know how to go about drawing the line in a separate pass as a post effect (specifically how to store the contour data from the fragment shader for later use). I have for now resorted to using a CPU bound slicing algorithm to generate the contour(s) and am rendering them in a different pass as simple line loops... \$\endgroup\$ Commented Mar 4, 2019 at 10:36


You must log in to answer this question.

Browse other questions tagged .