draw line 3d with opengl

Context

This tutorial is more expanded version of an answer on my stackoverflow question. To summarize the goal, we desire to be able to draw lines in 3D that satisfy the next conditions:

  • At that place is no visible border between the adjacent lines in polyline, which occurs when we utilise the default OpenGL geometry mode such as GL_LINE_STRIP_ADJACENCY.
  • The lines take a 2D expect which ways the width of lines does not depend on the distance from the camera view. Think of a CAD application and how the lines have the same thickness no matter of their location of viewpoint.
  • Possibility to draw lines thicker than immune default thickness. For example, when I was doing tests on my motorcar, I could not overcome the thickness of 10.f.

The default OpenGL drawing of line strip geometry does not allow to render smooth (not-broken) lines, every bit well as to return them of customary thicker than default width:

Line strip geometry polyline

Master principle

One of the means to solve the problem is to stand for each line segment as a fix of triangles. Adjacent triangles (or quads) are fatigued without any gaps between them. It is possible to draw those geometries past using GL_TRIANGLE_STRIP. In this case we have to deal with two problems:

  1. In 3D a prepare of triangles looks like a ribbon, i.e., it may look like a solid line under sure view, but the line expect is lost when the view point is changed.
  2. The line width depends on the camera view.

To address the trouble 1, nosotros take to brand sure the geometry is always facing the photographic camera, i.e., recompute the geometries every time the viewpoint is changed. For the problem 2, the solution is similar - re-adjust the ribbon width with the modify of viewport.

A very effective style to achieve the desired effect is to employ GLSL shaders. Assuming the familiarity of the same programs, nosotros will motion directly to the implementation details.

Implementation details

The presented code is heavily based on the Cinder library discussion thread, and the principal principle of triangle coordinates calculation is taken from at that place as well. In this part I will simply provide some details on how to port the shader's lawmaking into OpenSceneGraph program.

Shaders

Hither we will provide brief description of each shader.

Vertex shader

The vertex shader is what helps to transform the 3D earth coordinates into screen coordinates. But speaking, this is where we deal with lines being always faced towards the photographic camera. In gild to implement it, we have to utilize model-view-projection (MVP) matrix which is the matrix that is updated on every view change.

The calculation of each vertex is then washed and so:

                          gl_Position              =              ModelViewProjectionMatrix              *              Vertex              ;                      

Geometry shader

The geometry shader's main goal is to accept each line segment (which is represented by lines_adjacency) and turn information technology into a strip of triangles that have enough filling on each sides and so that the consecutive line segment is connected without the gap. The position of each vertex of the triangle is calculated in relation towards the viewport of the widget which displays the whole scene. This allows the lines to have a constant thickness in spite of the their location in 3D world. Refer to the source lawmaking for more details on shader implementation.

Fragment shader

The fragment shader is a elementary pass-through shader. It takes the incoming color and assigns information technology to each fragment:

                          gl_FragColor              =              VertexData              .              mColor              ;                      

For debugging purposes, I ready the color in the shader to green, so that to verify all the previous steps of shader program has completed successfully.

Callbacks

We need to provide two uniforms: for MVP matrix and the Viewport. When using OSG, the best way to do it is by using callbacks. In this case we demand to derive from osg::Uniform::Callback. Below are the code snippets for each of the callbacks:

                          struct              ModelViewProjectionMatrixCallback              :              public              osg              ::              Uniform              ::              Callback              {              ModelViewProjectionMatrixCallback              (              osg              ::              Camera              *              camera              )              :              _camera              (              photographic camera              )              {              }              virtual              void              operator              ()(              osg              ::              Compatible              *              compatible              ,              osg              ::              NodeVisitor              *              nv              )              {              osg              ::              Matrixd              viewMatrix              =              _camera              ->              getViewMatrix              ();              osg              ::              Matrixd              modelMatrix              =              osg              ::              computeLocalToWorld              (              nv              ->              getNodePath              ());              osg              ::              Matrixd              modelViewProjectionMatrix              =              modelMatrix              *              viewMatrix              *              _camera              ->              getProjectionMatrix              ();              compatible              ->              set up              (              modelViewProjectionMatrix              );              }              osg              ::              Camera              *              _camera              ;              };                      

Of course, we need to pass the pointer on a photographic camera that is fastened to the viewer that displays the scene. In a similar mode nosotros ascertain the callback for viewport:

                          struct              ViewportCallback              :              public              osg              ::              Compatible              ::              Callback              {              ViewportCallback              (              osg              ::              Photographic camera              *              camera              )              :              _camera              (              camera              )              {              }              virtual              void              operator              ()(              osg              ::              Compatible              *              uniform              ,              osg              ::              NodeVisitor              *              /*nv*/              )              {              const              osg              ::              Viewport              *              viewport              =              _camera              ->              getViewport              ();              osg              ::              Vec2f              viewportVector              =              osg              ::              Vec2f              (              viewport              ->              width              (),              viewport              ->              height              ());              compatible              ->              set              (              viewportVector              );              }              osg              ::              Camera              *              _camera              ;              };                      

Shader programme

By following the OSG tutorials on how to prepare and use shaders withing an OSG programme, we create an osg::Programme case and attach to it the created shaders. Now given the set of vertices of type GL_LINES_ADJACENCY_EXT, we need to also set up the vertex and colour attributes and then that they are correctly used from withing the shaders. This is how it can be washed in OpenSceneGraph:

                          geometry              ->              setVertexAttribArray              (              0              ,              vertices              ,              osg              ::              Array              ::              BIND_PER_VERTEX              );              geometry              ->              setVertexAttribArray              (              1              ,              colors              ,              osg              ::              Array              ::              BIND_PER_VERTEX              );                      

After nosotros need to add the necessary uniforms, including the MVP matrix and viewport. And finally connect the shader programme to the state prepare of the geometry.

Note: in order to avert an aliased await of the shadered lines, nosotros have to enable multi-sampling.

E.1000.:

                          osg              ::              DisplaySettings              ::              instance              ()              ->              setNumMultiSamples              (              iv              );                      

Results

Some screenshots of the consequence lines. The red colour line is drawn by using OpenGL default GL_LINE_STRIP, while the greenish line is drawn by using the shader program. Annotation how the connection between the ballast betoken does non look broken compared to the carmine line. For this instance nosotros turned on the multi-sampling.

Smooth connection

The demonstration of ability to produce much thicker lines. Not only the connection is smoother, but the line width can be ready to any value. For this exam nosotros turned off the multi-sampling, just to demonstrate the visual difference.

Thicker line

Some other, more full general example of two lines drawn by different methods, side by side:

General comparison

Codes

This tutorial had skipped many implementation details, that is why it is useful to refer to the source lawmaking for the fully functional example. Refer to the corresponding github repo. Notation, the presented code includes some additional elements from 3D curves tutorial.

guzmannoned1974.blogspot.com

Source: https://vicrucann.github.io/tutorials/osg-shader-3dlines/

0 Response to "draw line 3d with opengl"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel