A geometric shader that creates gaps between lines

I wrote a geometric shader to calculate the intersection of the grid and the plane, but at the intersection between the two lines there are sometimes gaps of 1 pixel wide.

enter image description here

The shader first calculates the sign distances of the vertices of the triangle to the plane. He then checks to see if the two distances have a different sign to determine if there is an intersection with the edge. If so, it emits a vertex at the intersection, which is calculated as the weighted average between the points of the edge.

#version 330 layout(triangles) in; layout(line_strip, max_vertices = 3) out; out vec3 vertexPosition; uniform vec3 planePos; uniform vec3 planeNormal; uniform mat4 mvpMatrix; uniform vec2 screenSize; void intersection(in vec4 a, in float distA, in vec4 b, in float distB) { if (sign(distA) * sign(distB) <= 0.0f && !(sign(distA) == 0 && sign(distB) == 0)) { float fa = abs(distA); float fb = abs(distB); float fab = fa + fb; vec4 ptIntersection; // Don't divide by zero. if (fab < 0.001) ptIntersection = (a + b) * 0.5; else ptIntersection = (fa * b + fb * a) / fab; gl_Position = mvpMatrix * ptIntersection; vertexPosition = gl_Position.xyw; EmitVertex(); } } void main() { vec4 a = gl_in[0].gl_Position; vec4 b = gl_in[1].gl_Position; vec4 c = gl_in[2].gl_Position; float distA = dot(a.xyz - planePos, planeNormal); float distB = dot(b.xyz - planePos, planeNormal); float distC = dot(c.xyz - planePos, planeNormal); intersection(a, distA, b, distB); intersection(b, distB, c, distC); intersection(c, distC, a, distA); } 

I know this is cheap, because I ignored the special case where all three points lie on a plane. !(sign(distA) == 0 && sign(distB) == 0) guarantees that if two points lie on the plane, a vertex will not be selected for this edge. Therefore, if all three are on the plane, there will be no way out. But I think this is not necessarily a bad thing. I like that there is no crazy branching, and I would like to keep it that way if possible.

So, I wonder: why do I see these gaps? Let them say that there are two triangles (a, b, c) and (c, b, d). a and b above the plane, c and d below. For the first triangle, the shader generates the intersection with (b, c), for the second - the intersection with (c, b). Assuming that adding two floats is commutative, the intersection function is symmetrical in inputs, so the results should be the same. Why am I still seeing these spaces?

+2
source share
2 answers

The answer lies in the specification of the Bresenham line rasterization algorithm, which is provided by the OpenGL specification. Quote from OpenGL 3.3 Spec , section 3.5.1:

Rasterizing a line segment starting with pa and ending with pb produces those fragments f for which a segment starting with pa and ending with pb intersects Rf, except that pb is contained in Rf [the diamond region centered on the fragment].

So that the end point is not rasterized at all, if two adjacent lines, unfortunately, work in opposite directions (i.e., end at the same point), and this end point is contained in the diamond mentioned around the center of the pixel. Thus, you will see a noticeable gap.

Since you are already using geometric shaders, you can (with a little extra computation) emit triangles to make a β€œtrue” wide line.

+3
source

Here the final code may be useful to someone.

 #version 330 layout(triangles) in; layout(line_strip, max_vertices = 3) out; uniform vec4 plane; uniform mat4 mvpMatrix; void emitIntersection(in vec4 a, in float distA, in vec4 b, in float distB) { if (sign(distA) * sign(distB) <= 0.0f && !(sign(distA) == 0 && sign(distB) == 0)) { float fa = abs(distA); float fb = abs(distB); gl_Position = mvpMatrix * ((fa * b + fb * a) / (fa + fb)); EmitVertex(); } } void main() { float dist[3]; for (int i=0; i<3; i++) dist[i] = dot(gl_in[i].gl_Position, plane); // Find the smallest i where vertex i is below and vertex i+1 is above the plane. ivec3 ijk = ivec3(0, 1, 2); // use swizzle to permute the indices for (int i=0; i < 3 && (dist[ijk.x] > 0 || dist[ijk.y] < 0); ijk=ijk.yzx, i++); emitIntersection(gl_in[ijk.x].gl_Position, dist[ijk.x], gl_in[ijk.y].gl_Position, dist[ijk.y]); emitIntersection(gl_in[ijk.y].gl_Position, dist[ijk.y], gl_in[ijk.z].gl_Position, dist[ijk.z]); emitIntersection(gl_in[ijk.z].gl_Position, dist[ijk.z], gl_in[ijk.x].gl_Position, dist[ijk.x]); } 
+2
source

Source: https://habr.com/ru/post/946994/


All Articles