Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using line strip adjacency with the geometry shader

So, I've been trying to draw a cylinder out of a line strip adjacency primitive with the geometry shader and it works for 4 vertices, but I want to make it so I that can apply it to longer line strips. The problem is that, it messes up completely after the fourth vertex. I know that the primitive gives the shader access to adjacency information, but I'm not sure how to access it, so my question is:

How do I use the adjacency information? And, Would it be possible to do this for multiple lines with the same drawing call?

I would very much appreciate pseudo code examples if you can provide it.

like image 652
chromosome Avatar asked Dec 14 '14 09:12

chromosome


People also ask

How does a geometry shader work?

A geometry shader takes as input a set of vertices that form a single primitive e.g. a point or a triangle. The geometry shader can then transform these vertices as it sees fit before sending them to the next shader stage.

Why use geometry shaders?

The Geometry Shader (GS) stage processes entire primitives: triangles, lines, and points, along with their adjacent vertices. It is useful for algorithms including Point Sprite Expansion, Dynamic Particle Systems, and Shadow Volume Generation. It supports geometry amplification and de-amplification.

Does WebGL support geometry shader?

Geometry shaders are natively not supported by WebGL.

What does fragment shader do?

A Fragment Shader is the Shader stage that will process a Fragment generated by the Rasterization into a set of colors and a single depth value. The fragment shader is the OpenGL pipeline stage after a primitive is rasterized. For each sample of the pixels covered by a primitive, a "fragment" is generated.


1 Answers

The following diagram comes from the D3D10 documentation, but I feel it conveys primitive topology better than the diagrams in the OpenGL specification.

                              http://i.msdn.microsoft.com/dynimg/IC520307.png

What you need to understand is that when you use a primitive type w/Adjacency (e.g. GL_LINE_STRIP_ADJACENCY) you actually have to supply additional data in your index buffer.

Do you see the dotted lines in the diagram? Those are extra indices that you have to insert into your index buffer (or simply as extra vertices if you are not using indexed drawing commands).


You are only interested in a line strip, so your case is very simple to index.

You will add an extra index to the beginning and end of your line strip to provide adjacent vertex information (denoted as 0 and 5 in the diagram above).

Say for instance you have the following (indexed) line strip:

0,9,36,4,52,1,8   (7 indices, 6 lines)

Lines produced:

 <0,9>
   <9,36>
     <36,4>
        <4,52>
           <52,1>
              <1,8>

And you have determined the following end-adjacency:

L-hand: 45
R-hand: 63

Your line strip w/Adjacency would be indexed thus:

[45],0,9,36,4,52,1,8,[63]   (9 indices, **still** 6 lines)

 + Vertices [45] and 36 are adjacent to line <0,9> (first line)
 + Vertices 52 and [63] are adjacent to line <1,8> (last line)

As you can see, 2 extra indices (denoted using [X]) had to be added, because the first and last lines would otherwise have no vertex preceding or following them. Those indices do not form lines in the strip, they are just there to fill-in adjacency information where it would otherwise be undefined.


Pseudo-code to access adjacent vertices in a line strip with adjacency in a Geometry Shader:

#version 330

// 4 vertices per-primitive -- 2 for the line (1,2) and 2 for adjacency (0,3)
layout (lines_adjacency) in;

// Standard fare for drawing lines
layout (line_strip, max_vertices = 2) out;

void main (void) {
  // The two vertices adjacent to the line that you are currently processing
  vec4 prev_vtx = gl_in [0].gl_Position;
  vec4 next_vtx = gl_in [3].gl_Position;

  gl_Position = gl_in [1].gl_Position; // First vertex in the line
  EmitVertex ();

  gl_Position = gl_in [2].gl_Position; // Second vertex in the line
  EmitVertex ();
}

The Geometry Shader follows the description given in the OpenGL specification:

OpenGL 4.4 Core Profile Specification  -  10.1.12 Line Strips with Adjacency  -  p. 306

A line segment is drawn from the i + 2nd vertex to the i + 3rd vertex for each i = 0, 1, . . . , n − 1, where there are n + 3 vertices passed. If there are fewer than four vertices, all vertices are ignored. For line segment i, the i + 1st and i + 4th vertex are considered adjacent to the i + 2nd and i + 3rd vertices, respectively (see figure 10.3)

like image 54
Andon M. Coleman Avatar answered Oct 26 '22 03:10

Andon M. Coleman