Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing a variable width line in openGL (No glLineWidth) [duplicate]

Tags:

opengl

What is the best way to draw a variable width line without using glLineWidth? Just draw a rectangle? Various parallel lines? None of the above?

like image 862
Decio Lira Avatar asked Sep 19 '08 13:09

Decio Lira


4 Answers

You can draw two triangles:

// Draws a line between (x1,y1) - (x2,y2) with a start thickness of t1 and
// end thickness t2.
void DrawLine(float x1, float y1, float x2, float y2, float t1, float t2)
{
    float angle = atan2(y2 - y1, x2 - x1);
    float t2sina1 = t1 / 2 * sin(angle);
    float t2cosa1 = t1 / 2 * cos(angle);
    float t2sina2 = t2 / 2 * sin(angle);
    float t2cosa2 = t2 / 2 * cos(angle);

    glBegin(GL_TRIANGLES);
    glVertex2f(x1 + t2sina1, y1 - t2cosa1);
    glVertex2f(x2 + t2sina2, y2 - t2cosa2);
    glVertex2f(x2 - t2sina2, y2 + t2cosa2);
    glVertex2f(x2 - t2sina2, y2 + t2cosa2);
    glVertex2f(x1 - t2sina1, y1 + t2cosa1);
    glVertex2f(x1 + t2sina1, y1 - t2cosa1);
    glEnd();
}
like image 95
Ozgur Ozcitak Avatar answered Nov 20 '22 02:11

Ozgur Ozcitak


Ok, how about this: (Ozgar)


       A
      / \
     /      \
    . p1        \
   /                \
  /                    D
 B -                 .p2
      -   -    -    C

So AB is width1 and CD is width2.

Then,

// find line between p1 and p2
Vector p1p2 = p2 - p1 ;

// find a perpendicular
Vector perp = p1p2.perpendicular().normalize()

// Walk from p1 to A
Vector A = p1 + perp*(width1/2)
Vector B = p1 - perp*(width1/2)

Vector C = p2 - perp*(width2/2)
Vector D = p2 - perp*(width2/2)

// wind triangles
Triangle( A, B, D )
Triangle( B, D, C )

Note there's potentially a CW/CCW winding problem with this algorithm -- if perp is computed as (-y, x) in the above diagram then it will be CCW winding, if (y, -x) then it will be a CW winding.

like image 28
bobobobo Avatar answered Nov 20 '22 03:11

bobobobo


I've had to do the same thing earlier today.

For creating a line that spans (x1,y1) -> (x2,y2) of a given width, a very easy method is to transform a simple unit-sized square spanning (0., -0.5) -> (1., 0.5) using:

  1. glTranslatef(...) to move it to your desired (x1,y1) location;
  2. glScalef(...) to scale it to the right length and desired width: use length = sqrt( (x2-x1)^2 + (y2-y1)^2 ) or any other low-complexity approximation;
  3. glRotatef(...) to angle it to the right orientation: use angle = atan2(y2-y1, x2-x1).

The unit-square is very simply created from a two-triangle strip GL_TRIANGLE_STRIP, that turns into your solid line after the above transformations.

The burden here is placed primarily on OpenGL (and your graphics hardware) rather than your application code. The procedure above is turned very easily into a generic function by surrounding glPushMatrix() and glPopMatrix() calls.

like image 2
jpap Avatar answered Nov 20 '22 03:11

jpap


For those coming looking for a good solution to this, this code is written using LWJGL, but can easily be adapted to any implementation of OpenGL.

import java.awt.Color;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Vector2f;
public static void DrawThickLine(int startScreenX, int startScreenY, int endScreenX, int endScreenY, Color color, float alpha, float width) {

    Vector2f start = new Vector2f(startScreenX, startScreenY);
    Vector2f end = new Vector2f(endScreenX, endScreenY);

    float dx = startScreenX - endScreenX;
    float dy = startScreenY - endScreenY;

    Vector2f rightSide = new Vector2f(dy, -dx);
    if (rightSide.length() > 0) {
        rightSide.normalise();
        rightSide.scale(width / 2);
    }
    Vector2f leftSide = new Vector2f(-dy, dx);
    if (leftSide.length() > 0) {
        leftSide.normalise();
        leftSide.scale(width / 2);
    }

    Vector2f one = new Vector2f();
    Vector2f.add(leftSide, start, one);

    Vector2f two = new Vector2f();
    Vector2f.add(rightSide, start, two);

    Vector2f three = new Vector2f();
    Vector2f.add(rightSide, end, three);

    Vector2f four = new Vector2f();
    Vector2f.add(leftSide, end, four);

    GL11.glBegin(GL11.GL_QUADS);
    GL11.glColor4f(color.getRed(), color.getGreen(), color.getBlue(), alpha);
    GL11.glVertex3f(one.x, one.y, 0);
    GL11.glVertex3f(two.x, two.y, 0);
    GL11.glVertex3f(three.x, three.y, 0);
    GL11.glVertex3f(four.x, four.y, 0);
    GL11.glColor4f(1, 1, 1, 1);
    GL11.glEnd();
}
like image 2
House Avatar answered Nov 20 '22 04:11

House