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?
yes, but I would like some algorithm for creating the variable thickness for use with a bresenham line algorithm.
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();
}
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.
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.
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.
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.
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.