Using line strip adjacency with the geometry shader
Asked Answered
P

1

7

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.

Pichardo answered 14/12, 2014 at 9:2 Comment(1)
Yes, you can provide adjacency information for multiple lines in a drawing call. That is what a line strip is - a series of connected lines. The adjacency information is built-in to the strip for all except for the first and last lines in the strip, as I will explain in my answer.Dill
D
27

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

                              https://static.mcmap.net/file/mcmap/ZG-Ab5ovKRkQa7Mkai2tZVMwa1MvXn3QWRft/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)

Dill answered 14/12, 2014 at 18:26 Comment(3)
Thank you so much for your answer, this is exactly what I've been struggling with, and been having a hard time figuring out. Also do you think this could be used with primitive restart somehow or would the geometry shader just get mixed up with the restart index beacuse of the adjacency?Pichardo
@chromosome: Primitive restart should work with adjacency. You still need 4 vertices after the restart though. So you could split a strip with adjacency into two strips like this: 3,5,6,7,-1,4,8,9,10. That would draw two lines (<5,6> and <8,9>, assuming you use -1 as your restart index).Dill
Well that's what I thought too, but whenever I enable primitive restart it stops rendering adjacency primitives, though I think I'm probably doing something wrong so I'll try to giving it another try and post back with the results. And again, thank you for your answer.Pichardo

© 2022 - 2024 — McMap. All rights reserved.