#Clipping Related Bug - Wireframe Rendering

12 messages · Page 1 of 1 (latest)

trail trench
#

Questions

  1. After clipping, does the GPU always find out new varying values by linearly interpolating the varying values of the original vertices? Or does it matter what interpolation qualifier was used? (I know that it matters afterwards, for interpolation across the triangle to get per-fragment values for use in the fragment shader. I'm specifically asking for the clipping stage, not the rasterization.)

  2. How are the negative varyings (vertex-to-edge-midpoint-distances) explained?

#

By the way, I know about the fwidth approach and that is what I'll be using for wireframe rendering at the end of the day. This question post is purely for educational purposes.

I'll share the code and an example scenario below.

#

Vertex shader simply transform the position to the clip space so I'm not sharing that explicitly.

#

Geometry Shader:

#version 460 core

#include "_Intrinsic_Other.glsl"

layout ( triangles ) in;
layout ( triangle_strip, max_vertices = 3 ) out;

/* Strategy: Convert bary coords (which are trivially defined as <1,0,0>, <0,1,0> & <0,0,1> for the triangle vertices/corners) to edge distances in screen-space pixels by:
 * Vertex pos. in clip space -> To NDC -> To pixels in screen space -> Calculate the distance from the edge midpoint to the vertex in screen space -> Multiply with bary coords for that vertex. */

noperspective out vec3 varying_edge_distances_in_pixels;

void main()
{
     vec2 vertex_0_in_screen_space = ( ( gl_in[ 0 ].gl_Position.xy / ( gl_in[ 0 ].gl_Position.w ) ) * 0.5 + 0.5 ) * _INTRINSIC_VIEWPORT_SIZE.xy;
    vec2 vertex_1_in_screen_space = ( ( gl_in[ 1 ].gl_Position.xy / ( gl_in[ 1 ].gl_Position.w ) ) * 0.5 + 0.5 ) * _INTRINSIC_VIEWPORT_SIZE.xy;
    vec2 vertex_2_in_screen_space = ( ( gl_in[ 2 ].gl_Position.xy / ( gl_in[ 2 ].gl_Position.w ) ) * 0.5 + 0.5 ) * _INTRINSIC_VIEWPORT_SIZE.xy;

    /* Vertex 1: */
    gl_Position = gl_in[ 0 ].gl_Position;

    varying_edge_distances_in_pixels = vec3( length( ( vertex_1_in_screen_space + vertex_2_in_screen_space ) * 0.5 - vertex_0_in_screen_space ), 0.0f, 0.0f );

    EmitVertex();

    /* Vertex 2: */
    gl_Position = gl_in[ 1 ].gl_Position;

    varying_edge_distances_in_pixels = vec3( 0.0f, length( ( vertex_0_in_screen_space + vertex_2_in_screen_space ) * 0.5 - vertex_1_in_screen_space ), 0.0f );

    EmitVertex();

    /* Vertex 3: */
    gl_Position = gl_in[ 2 ].gl_Position;

    varying_edge_distances_in_pixels = vec3( 0.0f, 0.0f, length( ( vertex_0_in_screen_space + vertex_1_in_screen_space ) * 0.5 - vertex_2_in_screen_space ) );

    EmitVertex();

    EndPrimitive();
}
#

Fragment Shader:

#version 460 core

#include "_Intrinsic_Other.glsl"

noperspective
 in vec3 varying_edge_distances_in_pixels; // Each component holds the distance to an edge of the triangle, in pixels, for the barycentric weights respectively.

out vec4 out_color;

uniform vec4 uniform_color;
uniform float uniform_line_thickness;

void main()
{
    float closest_edge_distance = min( min( varying_edge_distances_in_pixels.x, varying_edge_distances_in_pixels.y ), varying_edge_distances_in_pixels.z );

    float edge_factor = 1.0f - smoothstep( 0.0f, uniform_line_thickness, closest_edge_distance );

    out_color = vec4( uniform_color.rgb, edge_factor );
}

#

Clipping Related Bug - Wireframe Rendering

#

I've prepared an example scenario so we can be on the same page and maybe get to the bottom of this easier:

#

The engine is left handed, x right y up z forward.

Matrices are row major, vectors are transformed by vector * matrix.

I've assumed a 1000x1000 resolution to make things are simpler (1:1 aspect ratio).

#

For this scenario, and the shader code I've shared, this is the outcome (The vertices in the spreadsheet are the ones from the left wall/quad, top triangle):

#

Notice that the left wall/quad is completely shaded with uniform_color This means that the edge_factorin the fragment shader is 1.0. That means that smoothstep returns 0 and that is only possible if the closest_edge_distance is <= 0.

#

If I back the camera up just a tiny bit (from -29.99 to -30.00), the output becomes:

#

Edge thickness uniform was set to 2.0 for both images.

Camera at Z = -29.99 ==> Clipping against the near plane occurs.
Camera at Z = -30.00 ==> No clipping.