Using line strip adjacency with the geometry shader

chromosome picture chromosome · Dec 14, 2014 · Viewed 8k times · Source

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.

Answer

Andon M. Coleman picture Andon M. Coleman · Dec 14, 2014

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)