Drawing nearly perfect 2D line segments in OpenGL
Introduction
OpenGL is great, when it comes to line drawing most people would draw it by: glBegin(GL_LINES);
glVertex3f( x1,y1,0);
glVertex3f( x2,y2,0);
glEnd();
It does give you a straight line, but a very ugly one. To improve, most people would enable gl line smoothing: glEnable(GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
But this technique has a couple of drawbacks:
-hardware dependent. It does not necessarily look the same on different machines.
-average quality. It does not give perfect quality on most hardware.
This article focuses on 2D rendering in (sub) pixel accuracy. Make sure you view all images in its original size.
Functionality
The technique introduced in this article gives you:-premium quality anti-aliased lines
-smaller CPU overhead than any other CPU rasterizing algorithms
-line thickness control
-line color control
-alpha blend (can choose to use alpha blend or not)

Believe that it is rendered in OpenGL.
Using the code
void line(
double x1, double y1, double x2, double y2, //coordinates of the line
float w, //thickness of the line in pixel
float Cr, float Cg, float Cb, //RGB color components
float Br, float Bg, float Bb, //color of background, ignored if alphablend is true
bool alphablend); //use alpha blend or not
void hair_line( double x1, double y1, double x2, double y2, bool alphablend=0);
The first function line()
gives you all the functionality. You can choose not to use alpha blending by setting alphablend to false, in this case you will get color fading to the background. In no- alpha- blending mode you still get good result when the background is solid and lines are not dense. It is also useful when doing overdraw. The below image should tell you what does alphablend=false
mean:
The second function hair_line() draws near-perfectly a black "hair line" of thickness 1px with no color or thickness control. You can optionally use alpha blend otherwise it assumes the background is white. I provide this in case you do not need all the functionalities.
You can just include the header and it should work. If you copy only part of the code, make sure you copy also the function
static inline double GET_ABS(double x) {return x>0?x:-x;}
Make sure you render 2D in this way:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho( 0,context_width,context_height,0,0.0f,100.0f);
line(10,11,100,280, 1.0, 1,0,0.5, 0,0,0, true);
//draw a straight line from (10,11) to (100,280)
//, with width 1.0px pink (1,0,0.5) in color and enable alpha blending
//other 2D drawings,,,
glPopMatrix();
glDisable(GL_BLEND); //and whatever to restore blending options
How does that work?
Observation
You just need to know a little bit OpenGL. Look at the hello world OpenGL program. It merely draws a triangle with different colors on each vertex. What do you observe?
![]() |
glLoadIdentity();
//window size is 300x300
glOrtho( 0,300,300,0,0.0f,100.0f);
glClearColor( 1,1,1,0.5f);
glClearDepth( 1.0f);
glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT);
glBegin(GL_TRIANGLE_STRIP);
glColor3f( 1,0,0);
glVertex3f( 150,10,0);
glColor3f( 0,1,0);
glVertex3f( 280,250,0);
glColor3f( 0,0,1);
glVertex3f( 20,250,0);
glEnd();
|
Yes the edge is jaggy. Then?
Well the interpolation among colors looks perfect.
The technique
The above observation is sufficient to enable us to do what we want.Now lets draw a paralellogram which changes color from white to red.
![]() |
glBegin(GL_TRIANGLE_STRIP);<br/>
glColor3f( 1,1,1);<br/>
glVertex3f( 50,270,0);<br/>
glVertex3f( 100,30,0);<br/>
glColor3f( 1,0,0);<br/>
glVertex3f( 58,270,0);<br/>
glVertex3f( 108,30,0);<br/>
glEnd();
|
The right side is still jaggy. The left side is,,, smooth. Can you now think of anything?
Now lets draw two paralellograms, which change color from white to red then to white again.
![]() |
glBegin(GL_TRIANGLE_STRIP);<br/>
glColor3f( 1,1,1);<br/>
glVertex3f( 50,270,0);<br/>
glVertex3f( 100,30,0);<br/>
glColor3f( 1,0,0);<br/>
glVertex3f( 54,270,0);<br/>
glVertex3f( 104,30,0);<br/>
glColor3f( 1,1,1);<br/>
glVertex3f( 58,270,0);<br/>
glVertex3f( 108,30,0);<br/>
glEnd();
|
The technique is already explained.
In words: Draw a thin quadrilateral to render the core(inner) part of a line, then draw two more beside the original one that fade in color. The jaggy edge is then eliminated.
Quality
This article focuses on 2D line drawing so the meaning of “perfect quality” is with respect to 2D graphics.In particular, Maxim Shemanarev (responsible for Anti-Grain Geometry) is the boss in fine grained 2D rendering.
Let see a picture from his article.

The above picture shows lines with thickness starting from 0.3 pixels and increasing by 0.3 pixel.
Using triangles to approximate line segments in the correct dimension is not easy. I do it by experiment and hand calibrated the drawing code,

then obtained:

It is not perfect though, the end points are a little bit not sharp enough, so I say “nearly perfect”.
I found fltk-cairo convinent to build so I actually took Cairo, the popular 2D rendering API on Linux, as a benchmark.

Their difference is subtle, so make sure you view them in original resolution and flip them in a slideshow program to observe. I have made one for you here.
It is seen that Cairo draws thin lines a little bit thicker than it should look. The circular fan on the right is drawn as 1px black lines by
cairo_set_line_width (cr, 1.0)
.
But you see the horizontal line is a 2px grey line. In my code I tried hard to give a 1px #000000 line when you request a 1px #000000 line on exact pixel coordinate, especially at horizontal/ vertical condition. But there is no guarantee in sub- pixel coordinate, other colors and orientations.
Ideal 1px black lines should look very close to aliased raw 1px lines, but just being smoother. Now take a closer look at the fan on the right and flip to compare there.

Hope you agree with my judgment.
A final compare:


Performance
Today's graphics card can render millions of triangles per second. Although alphablend is not as fast, it is still faster than any other method.Some how (by a breif benchmark) it is 100 times faster than OpenGL native line drawing with smoothing turned on (on my machine, maybe that's why it looks so good). And 40 times faster than Cairo when drawing 10000 5px thick lines. Later if I have time I can include a more formal benchmark.
If you want to boost things up further, this technique allows you to separate opaque drawing from semi- transparent drawing (identify it easily by
glColor4f( C,C,C, 0);
). You can draw the solid part of all lines first then the those which require alphablend. However this ends up an drawing engine which is not easy to incorperate into existing code. Anyhow this technique is already very fast, when putting completely opaque (alpha=1.0) pixels, it takes only one statement if src_alpha!=1.0
to not call the blending function.Portability
I have not tested the code on many machines, so I cannot guarantee.This technique depends on rasterizing. There is (always) a higher chance that a GL driver implements rasterization correctly than smooth- line drawing.
As far as I know most hardware support sub- pixel accuracy rasterization. In my testings, there are often rounding errors which cause tiny artifact. That is not perfect, but still good.
Again I cannot guarantee, the best way is to test it yourself.
Final words
Download the zip file to play with the code. But I assume you know how to compile fltk 1.3 with cairo and gl enabled.If you find this useful I just hope you to cite this page. If you used it in a program make sure you email me to let me see how well it would work.
By Chris Tsang tyt_52@hotmail.com, 2011 May
Post Comment
Интернет-журнал о стоматологии
Лечение зубов Уход за зубами
Уход за зубамиHello There. I found your blog using msn. This is an extremely well written article.
I will be sure to bookmark it and return to read more of your useful information. Thanks for the post.
I will definitely return. Maglia Inter 2019Good day! I know this is kinda off topic however , I'd figured I'd ask.
Would you be interested in trading links or maybe guest writing a blog
article or vice-versa? My blog covers a lot
of the same topics as yours and I believe we could greatly benefit from each other.
If you're interested feel free to send me an email. I look forward to hearing from you!
Wonderful blog by the way! Valencia TrøjeHello to every one, the contents existing at this site are truly remarkable for people experience, well, keep
up the good work fellows. Billiga Arsenal Matchtröjor
MonaSpahn nuova Maglia Napoli MelindaLiYou are so cool! I don't believe I have read anything like this before.
So good to find another person with genuine thoughts on this issue.
Seriously.. thank you for starting this up. This site is something that is required on the
web, someone with a bit of originality! barcelona drakter med trykk JudySneed maglie calcio a poco prezzo BufordStrHey There. I found your blog using msn. This is an extremely well written article.
I will be sure to bookmark it and come back to read more of your useful
info. Thanks for the post. I'll certainly comeback. Jorge DraktMy coder is trying to convince me to move to .net from PHP.
I have always disliked the idea because of the costs.
But he's tryiong none the less. I've been using Movable-type on several websites for about
a year and am worried about switching to another platform.
I have heard very good things about blogengine.net.
Is there a way I can transfer all my wordpress content into it?
Any help would be really appreciated! chelsea fotballdraktIf some one needs to be updated with most up-to-date technologies afterward he must be visit this
website and be up to date daily. magliette Atletico MadridVery Fascinating Weblog! Thank You For This Weblog!
You have observed very interesting details ! ps decent site.
Woh I enjoy your content, saved to fav!.
I reckon something truly interesting about your web blog so I bookmarked.
Truly appreciate the posting you made available.. Great thought processes you possess here.. sure, investigation is paying off. Enjoy the entry you offered..
The city couldn at request for virtually any much better outcome than what has occurred right here, she mentioned.
This is a topic that as near to my heart Many thanks! Where are your contact details though?
you are not sure if they really are the Search Engine Optimization Expert they say they are.
Pretty! This has been an extremely wonderful article. Many thanks for supplying these details.
Wow! This could be one particular of the most useful blogs We ave ever arrive across on this subject. Basically Fantastic. I am also an expert in this topic so I can understand your hard work.
Yayoo.fr mail tirage gratuit tarot de l amour
Really appreciate you sharing this blog.Thanks Again. Cool.
wow, awesome blog post.Thanks Again. Much obliged.
very good publish, i definitely love this web site, carry on it
tips on how to lose weight fast WALSH | ENDORA
Well I really liked studying it. This article offered by you is very constructive for correct planning.
Wow, amazing blog layout! How long have you been blogging for?
Thank you for your article post.Really looking forward to read more. Really Cool.
You are not right. I can defend the position. Write to me in PM.
webpage or even a weblog from start to end.
I was suggested this website by my cousin. I am not sure whether this post is written by him as nobody else know such detailed about my problem. You are incredible! Thanks!
This is a list of words, not an essay. you are incompetent
I really liked your article.Much thanks again. Keep writing.
You have brought up a very superb points , thankyou for the post.
Please let me know if you're looking for
a article author for your weblog. You have some really good posts and I think I would be a good asset.
If you ever want to take some of the load off, I'd love to write some content for your blog in exchange for a link back to mine.
Please send me an e-mail if interested. Thanks!
BilligaThank you for your post.Really thank you! Keep writing.
I similar to Your Post about Khmer Funny
This website is known as a stroll-by way of for the entire data you wished about this and didn?t know who to ask. Glimpse right here, and also you?ll positively uncover it.
This is my first time pay a quick visit at here and i am genuinely happy to read all at alone place.
Whats up, I?m I have been reading out some of your stories and i must say clever stuff. I will make sure to bookmark your site.
It as nearly impossible to find experienced people for this subject, however, you sound like you know what you are talking about! Thanks
I was suggested this web site by my cousin. I am not sure whether this post is written by him as nobody else know such detailed about my difficulty. You are amazing! Thanks!
I visited a lot of website but I conceive this one contains something extra in it in it
I truly appreciate this article.Thanks Again. Awesome.
It as nearly impossible to find educated people on this subject, but you seem like you know what you are talking about! Thanks
very couple of web-sites that occur to become comprehensive beneath, from our point of view are undoubtedly well really worth checking out
Oh my goodness! Awesome article dude! Thank you
so much, However I am going through problems with your RSS.
I don't understand why I can't subscribe to it.
Is there anybody else having identical RSS problems? Anyone that knows the solution will you
kindly respond? Thanx!! PSG Fodboldtrøjer børnYou have brought up a very superb details , thanks for the post.
Wow! I cant think I have found your blog. Extremely helpful info.
Really enjoyed this article post.Much thanks again.
Really appreciate you sharing this post. Want more.
Thank you for producing the powerful, dependable, educational and as well as easy tips about your topic.