tags:

views:

3897

answers:

8

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?

A: 

yes, but I would like some algorithm for creating the variable thickness for use with a bresenham line algorithm.

Decio Lira
Can you please elaborate? I do not think I fully understand your question or requirements
freespace
The bresenham line algorithm is best used just for single pixel width lines otherwise you can end up doing a lot of individual surrounding pixel testing (depending on the width), I think you're better off using a polygon such as quad for a thick line in conjunction with a filling algorithm.
Ross Anderson
+2  A: 

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();
}
Ozgur Ozcitak
This is way too complicated! Too much trigonometry where it's not needed too.
PierreBdR
It turned out this is not what the OP wanted (see his answer below). But I'd love to see a simpler algorithm, if you would care to share it.
Ozgur Ozcitak
@Ozgur I added a trig free version here now
bobobobo
A: 

A rectangle (i.e. GL_QUAD or two GL_TRIANGLES) sounds like your best bet by the sounds of it, not sure I can think of any other way.

Ross Anderson
+1  A: 

Assume your original points are (x1,y1) -> (x2,y2). Use the following points (x1-width/2, y1), (x1+width/2,y1), (x2-width/2, y2), (x2+width/2,y2) to construct a rectangle and then use quads/tris to draw it. This the simple naive way. Note that for large line widths you'll get weird endpoint behavior. What you really want to do then is some smart parallel line calculations (which shouldn't be that bad) using vector math. For some reason dot/cross product and vector projection come to mind.

basszero
A: 

Thanks for all the answers guys! :D

I was hoping to do some smart parallel line thing, but I guess quads are the best/simple way.

Decio Lira
+1  A: 

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.

bobobobo
A: 

Another way to do this, if you are writing a software rasterizer by chance, is to use barycentric coordinates in your pixel coloration stage and color pixels when one of the barycentric coordinates is near 0. The more of an allowance you make, the thicker the lines will be.

bobobobo