Smoothing of Circles

Started by
6 comments, last by Erik Rufelt 13 years, 9 months ago
Hello,
I am new to this forum and opengl. I have been trying to solve this problem for quite a while now. I need to smooth the circles which I draw. On searching, I came to know it can be done with texture mapping.

I have tried texture mapping in my code which I have shown below. I am not able to smooth the edges even when I apply the texture (actually array of white pixels. Any help on pointing me the mistake or any other method would be higly appreciated

[spoiler]

/***************************************/


void create_texture(void)
{
width = 128;
height = 128;

texture_data = (unsigned char *)malloc( width * height * 3 );

for(int i = 0 ; i < width * height * 3 ; i++)
{
texture_data = 0Xff;
}


}

/*****************************************/


Then in the init() function I wrote the following


//Function that creates the white color texture to be used in smoothing the circle boundary
create_texture();

//Initialize the 2D texture parameters

// allocate a texture name
glGenTextures( 1, &texture );


// select our current texture
glBindTexture( GL_TEXTURE_2D , texture );


// select modulate to mix texture with color for shading
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );



// when texture area is small, bilinear filter the closest mipmap
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);

// when texture area is large, bilinear filter the original
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );


// the texture wraps over at the edges (repeat)
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );



glNewList(texture = glGenLists(1),GL_COMPILE);
glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_data); //check these parrameters
glEndList();

free(texture_data);

/*************************************/
void drawCircle(float radius)
{
double k;


float x , y;



glLineWidth(0.05);


glEnable(GL_TEXTURE_2D);
glCallList(texture);
glBegin(GL_LINE_LOOP);


for ( k=0; k <= 360.0;)
{
float degInRad = k*DEG2RAD;

x = cos(degInRad)*radius;
y = sin(degInRad)*radius;

glTexCoord2f(0.5,0.5);
glVertex2f(x,y);


k = k + 5;
}



glEnd();
glDisable(GL_TEXTURE_2D);

glLineWidth(1.5);


}
[/spoiler]
Advertisement
Do you mean anti-aliasing of the circle edges ?
Try line-smoothing:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_LINE_SMOOTH);
Yes. Anti-aliasing of circles.

I already tried GL_LINE_SMOOTH along with blend. The anti-aliasing works for circles with bigger radius. But for tiny circles, the edges look spongy or foggy. But when I zoom these tiny circles they look smooth.

Hence I moved to texture mapping.
I think with a texture, you are supposed to actually save an image of an anti-aliased circle, that you draw in Photoshop or something, and then use that image as a texture and draw a quad in OpenGL, displaying the circle texture at the correct spot.
You could also write a function that draws the anti-aliased circle pixel by pixel into the texture, though that might be harder, depending on how familiar you are with those types of algorithms.

Another thing you can try, is to draw points with point-smoothing. For example, if your circle is supposed to be 10 pixels in radius and have a thickness of 1 pixel, first draw a black point of radius 10 pixels at the circle center, and then draw another point with the background color and radius 9 pixels at the same position, which should leave a black circle edge. Experimenting with the radii you might be able to get nice looking circles.
You're drawing your line using linestrips or linelists.
The bigger the radius, you're gonna need more vertices.

I think this should do the trick:

const int nIterations = 72 * ((radius < 1) ? 1.0f : radius);for ( k=0; k <= nIterations; ++k ){float degInRad = (360.0f / (float)(nIterations)) * k * DEG2RAD;x = cos(degInRad)*radius;y = sin(degInRad)*radius; glTexCoord2f(0.5,0.5);glVertex2f(x,y);}


Haven't tested, may be there's some typo. Just wrote it. But should work.

Cheers
Dark Sylinc
Hi all,
Thanks for the replies. I was able to get smooth circles. But when the circles are close to each other, the texture of one circle hides the other. This is because, the texture is obtained from a bmp image which can be only a square (64 X 64 etc). Hence the empty areas in the square where the circle is not present hide the adjacent circle.
Please find the file hidden_circles.bmp in the following link, which shows a circle hidden by another.

hidden_circles
Any ways to overcome this???



This is how I did.

1. I drew really smooth circles with protractor and other stuffs of required sizes.
2. You can go for scanning these images to get a .bmp image. But I found taking a photograph of this drawing and converting them to a .bmp to be of superior quality.
3. Then load the bmp image into your program as texture.
4. If you need a circle of radius 10 and center (0.0,0.0). Find the enclosing square, which has sides of length 20.
Let A (-10,-10) B(10,-10) C(10,10) and D(-10,10) be the vertices of the square

5. glTextCoord2f(0.0,0.0)
glCoord2f(point A)

glTextCoord2f(1.0,0.0)
glCoord2f(point B)

glTextCoord2f(1.0,1.0)
glCoord2f(point C)

glTextCoord2f(0.0,1.0)
glCoord2f(point D)

This will draw the circle image in the square area





You can avoid this with blending. The best way is probably to create a texture with an alpha-channel, which can be used to draw parts of the texture transparently, avoiding overdrawing another circle with white. If you Google for alpha blending tutorials with OpenGL you should find plenty.
Another way is to create a black and white texture, where the circle is white and the other parts of the texture is black, and then drawing with:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_COLOR, GL_ONE);

glColor3f(circle-color);

...draw quad...
If you use a black circle on white background instead, using glBlendFunc(GL_ZERO, GL_SRC_COLOR); might work OK instead.

This topic is closed to new replies.

Advertisement