I started playing around with OpenGL and GLUT. I would like to draw some points, but the problem is that they turn out to be squares, and I would like them to be round dots (filled circles).
This is what I do:
void onInitialization( ) { glEnable( GL_POINT_SMOOTH ); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glPointSize( 6.0 ); } void onDisplay() { glClearColor( 1.0f, 1.0f, 1.0f, 1.0f ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glBegin( GL_POINTS ); glColor3f( 0.95f, 0.207, 0.031f ); for ( int i = 0; i
This is the result:
The points show up where expected, only their shape is wrong.
Unlike what was said previously, this is possible with the fixed-function pipeline, even with the GL_POINTS
primitive type, as long as you have support for OpenGL 1.4 or the GL_ARB_point_sprite
extension. Consult this document, or the OpenGL core specification of your choice : http://www.opengl.org/registry/specs/ARB/point_sprite.txt
GL_ARB_point_sprite
converts points into "quads", i.e a polygon with the form of a plane. The exact primitive type it gets converted to is not defined by the specification, though it is not important. What is important is that GL_COORD_REPLACE
auto-generates texture coordinates for the surface when enabled, so you can texture-map them with a sphere-shaped RGBA-texture.
EDIT: It seems like you (the poster) is right. Anti-aliased points get rounded with respect to their radius. (I've used OpenGL since 2003, and I didn't know this. [/shame]) So enabling GL_POINT_SMOOTH
while you have a multisample-able
visual/pixelformat, you get rounded points. Still, multisampling can be slow, so I'd implement both. Textured quads are cheap.
To request a visual with multisampling with XLib, use these two attributes in the list to glXChooseFBConfig():
GLX_SAMPLE_BUFFERS
- its value should be True
. This is an on/off toggle.
GLX_SAMPLES
- the number of samples.
To request a pixelformat with Win32, use these two attributes in the list to ChoosePixelFormat() or wglChoosePixelFormatARB():
WGL_SAMPLE_BUFFERS_ARB
Same as above, a toggle.
WGL_SAMPLES_ARB
Same as above, the number of samples.
It seem that you can OR in the flag GLUT_MULTISAMPLE
to glutInitDisplayMode
to get multisampling in GLUT, but you can't request the number of sample buffers.
Here is how alpha-blended quads could be implemented using your test case.
void onInitialization( ) { glEnable( GL_POINT_SPRITE ); // GL_POINT_SPRITE_ARB if you're // using the functionality as an extension. glEnable( GL_POINT_SMOOTH ); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glPointSize( 6.0 ); /* assuming you have setup a 32-bit RGBA texture with a legal name */ glActiveTexture(GL_TEXTURE0); glEnable( GL_TEXTURE_2D ); glTexEnv(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); glTexEnv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glBindTexture(GL_TEXTURE_2D, texture_name); } void onDisplay() { glClearColor( 1.0f, 1.0f, 1.0f, 1.0f ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glBegin( GL_POINTS ); glColor4f( 0.95f, 0.207, 0.031f, 1.0f ); for ( int i = 0; i
Image of rounded points using per-fragment alpha blending + textures: http://www.mechcore.net/images/gfx/sprite0.png
Image of rounded points by using GL_POINT_SMOOTH
and multisampling: http://www.mechcore.net/images/gfx/sprite1.png
A little sample I made which shows both techniques. Requires libSDL and libGLEW to compile:
#include #include #include #include #include #include #include #define ENABLE_TEXTURE #define ENABLE_MULTISAMPLE int Width = 800; int Height = 600; void Draw(void); void Init(void); inline float maxf(float a, float b) { if(a b) return b; return a; } GLuint texture_name; int main(void) { try { SDL_Init(SDL_INIT_VIDEO); SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); #ifdef ENABLE_MULTISAMPLE SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); #endif SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1); SDL_SetVideoMode(Width, Height, 32, SDL_OPENGL); glewInit(); Init(); SDL_Event event; bool running = true; while(running){ while(SDL_PollEvent(&event)){ switch(event.type) { case SDL_KEYDOWN: if(event.key.keysym.sym == SDLK_ESCAPE) running = false; break; case SDL_QUIT: running = false; break; } } Draw(); SDL_GL_SwapBuffers(); } SDL_Quit(); } catch(std::bad_alloc& e) { std::cout >1), (Height>>1), 0.0f); glScalef(scale,scale,scale); glRotatef(t1 * 360.0f, 0.0f, 0.0f, 1.0f); glBegin(GL_POINTS); for(int j=0; j>1),j-(gridHeight>>1)); } } glEnd(); }
Mads' answer provides everything you need if you go for the fixed function pipeline. However, if you have a system that does not provide the ARB_point_sprite
extension or with a broken implementation (some ATI drivers), you can solve this part also with geometry shaders. The ARB_geometry_shader4
extension allows you to convert a point primitive to two triangles, which can be used as the quad created by the ARB_point_sprite
extension. On OpenGL 3.2, geometry shaders are already supported in core, no extension needed. The OpenGL wiki has two examples.
Not possible with a fixed opengl function. Dots are always square :)
You have to draw your own circle (by building it up like a cake, piece by piece) or draw a GL_QUAD with a "circle" texture on.
best regards, andre