I'm currently porting an old OpenGL 1.1 application which makes use of wireframe models to OpenGL 3.0.
In 1.1 following code is used to create a dashed line:
glPushAttrib(GL_ENABLE_BIT);
glLineStipple(1, 0x0F0F);
glEnable(GL_LINE_STIPPLE);
Here as usual the parameters are pushed to the stack in order to influence all following drawing operations.
My question: how is this done in OpenGL3 where this stack is no longer used? How can I set up my lines to be dashed (probably before handing the coordinates over to glBufferData()?
For separate line segments, this is not very complicated at all. For example drawing the
GL_LINES
primitives.The trick is to know the start of the line segment in the fragment shader. This is quite simple by using the
flat
interpolation qualifier.The vertex shader has to pass the normalized device coordinate to the fragment shader. Once with default interpolation and once with no (
flat
) interpolation. This causes that in the fragment shade, the first input parameter contains the NDC coordinate of the actual position on the line and the later the NDC coordinate of the start of the line.Additionally to the varying inputs, the fragment shader has uniform variables.
u_resolution
contains the width and the height of the viewport.u_dashSize
contains the length of the line andu_gapSize
the length of a gap in pixel.So the length of the line from the start to the actual fragment can be calculated:
And fragments on the gap can be discarded, by the
discard
command.Fragment shader:
For the following simple demo program I've used the GLFW API for creating a window, GLEW for loading OpenGL and GLM -OpenGL Mathematics for the math. I don't provide the code for the function
CreateProgram
, which just creates a program object, from the vertex shader and fragment shader source code:Things get a bit more complicated, if the goal is to draw a dashed line along a polygon. For example drawing a
GL_LINE_STRIP
primitive.The length of the line cannot be calculated in the shader program, without knowing all the primitives of the line. Even if all the primitives would be known (e.g. SSBO), then the calculation would have to be done in a loop.
I decided to add an additional attribute to the shader program, which contains the "distance" from the start of the line to the vertex coordinate. By "distance" is meant the length of the projected polygon on to the viewport.
This causes that the vertex shader and fragment shader is even simpler:
Vertex shader:
Fragment shader:
In the demo program the
inDist
attribute is calculated on the CPU. Each vertex coordinate is transformed by the model, view, projection matrix. Finally it is transformed from normalized device space to window space. The XY distance between adjacent coordinates of the line strip is calculated and the lengths are summed along the line strip and assigned to the corresponding attribute value:Demo program:
See also
glLineStipple deprecated in OpenGL 3.1
OpenGL ES - Dashed Lines