Conseguir puntos suaves y grandes en OpenGL


Empecé a jugar con OpenGL y GLUT. Me gustaría dibujar algunos puntos, pero el problema es que resultan ser cuadrados, y me gustaría que fueran puntos redondos (círculos llenos).

Esto es lo que hago:

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 < g_numPoints; ++i )
    {
        glVertex2f( g_points[i].X, g_points[i].Y );
    }
    glEnd();
    glFinish();
    glutSwapBuffers();
}

Este es el resultado:

Los puntos se muestran donde se espera, solo que su forma es incorrecta.

 27
Author: Community, 2009-10-03

3 answers

A diferencia de lo que se dijo anteriormente, esto es posible con la canalización de función fija, incluso con el tipo primitivo GL_POINTS, siempre y cuando tenga soporte para OpenGL 1.4 o la extensión GL_ARB_point_sprite. Consulte este documento, o la especificación del núcleo de OpenGL de su elección : http://www.opengl.org/registry/specs/ARB/point_sprite.txt

GL_ARB_point_sprite convierte puntos en "quads", es decir, un polígono con la forma de un plano. El tipo primitivo exacto al que se convierte no está definido por el especificación, aunque no es importante. Lo importante es que GL_COORD_REPLACE genera automáticamente coordenadas de textura para la superficie cuando está habilitado, por lo que puede mapearlas con una textura RGBA en forma de esfera.

EDITAR: Parece que usted (el póster) tiene razón. Los puntos anti-aliased se redondean con respecto a su radio. (He usado OpenGL desde 2003, y no sabía esto. [/pena]) Así que habilitando GL_POINT_SMOOTH mientras tienes un multisample-able visual/pixelformat, obtienes puntos redondeados. Aun, multisampling puede ser lento, así que implementaría ambos. Los quads texturizados son baratos.

Para solicitar un visual con multisampling con XLib, use estos dos atributos en la lista a glXChooseFBConfig():

GLX_SAMPLE_BUFFERS - su valor debe ser True. Este es un interruptor de encendido / apagado.
GLX_SAMPLES - el número de muestras.

Para solicitar un pixelformat con Win32, use estos dos atributos en la lista para elegir Epixelformat () o wglChoosePixelFormatARB ():

WGL_SAMPLE_BUFFERS_ARB Igual que la anterior, una palanca.
WGL_SAMPLES_ARB Igual que arriba, el número de muestras.

Parece que puede O en la bandera GLUT_MULTISAMPLE a glutInitDisplayMode para obtener multisampling en GLUT, pero no puede solicitar el número de búferes de muestra.

Así es como se pueden implementar los quads de mezcla alfa usando su caso de prueba.

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 < g_numPoints; ++i )
    {
        glVertex2f( g_points[i].X, g_points[i].Y );
    }
    glEnd();
    glFinish();
    glutSwapBuffers();
}

Imagen de puntos redondeados usando mezcla alfa por fragmento + texturas: http://www.mechcore.net/images/gfx/sprite0.png
Imagen de redondeado puntos utilizando GL_POINT_SMOOTH y multisampling: http://www.mechcore.net/images/gfx/sprite1.png
Una pequeña muestra que hice que muestra ambas técnicas. Requiere libSDL y libGLEW para compilar:

#include <iostream>
#include <exception>
#include <memory>
#include <SDL/SDL.h> 
#include <cmath>
#include <GL/glew.h>
#include <GL/glu.h>

#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;
}

inline float minf(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 << "Out of memory. " << e.what() << std::endl;
        exit(-1);
    }
    catch(std::exception& e)
    {
        std::cout << "Runtime exception: " << e.what() << std::endl;
        exit(-1);
    }
    catch(...)
    {
        std::cout << "Runtime exception of unknown type." << std::endl;
        exit(-1);
    }
    return 0;
}

void Init(void)
{
    const GLint texWidth = 256;
    const GLint texHeight = 256;
    const float texHalfWidth = 128.0f;
    const float texHalfHeight = 128.0f;
    printf("INIT: \n");

    unsigned char* pData = new unsigned char[texWidth*texHeight*4];
    for(int y=0; y<texHeight; ++y){
        for(int x=0; x<texWidth; ++x){
            int offs = (x + y*texWidth) * 4;
            float xoffs = ((float)x - texHalfWidth) / texHalfWidth;
            float yoffs = ((float)y - texHalfWidth) / texHalfHeight;
            float alpha = 1.0f - std::sqrt(xoffs*xoffs + yoffs*yoffs);
            if(alpha < 0.0f)
                alpha = 0.0f;
            pData[offs + 0] = 255; //r
            pData[offs + 1] = 0; //g
            pData[offs + 2] = 0; //b
            pData[offs + 3] = 255.0f * alpha; // * 
            //printf("alpha: %f\n", pData[x + y*texWidth + 3]);
        }
    }

    #ifdef ENABLE_TEXTURE
    glGenTextures(1, &texture_name);
    glActiveTexture(GL_TEXTURE0);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, texture_name);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pData);
    glEnable(GL_POINT_SPRITE);
    glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    #endif

    glPointSize(32.0f);

    glMatrixMode(GL_PROJECTION);
    glOrtho(0, Width, 0, Height, -1.0f, 1.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glDisable(GL_DEPTH_TEST);

    #ifdef ENABLE_MULTISAMPLE
        glEnable(GL_POINT_SMOOTH);
    #endif

    GLenum e;
    do{
        e = glGetError();
        printf("%s\n",gluErrorString(e));
    } while(e != GL_NO_ERROR);

    delete [] pData;
}

void Draw(void)
{
    const int gridWidth = 1024;
    const int gridHeight = 1024;
    float t1, t2;

    t1 = t2 = (float)SDL_GetTicks() * 0.001f;
    t1 = fmod(t1, 10.0f) / 10.0f;
    t2 = fmod(t2, 4.0f) / 4.0f;
    float scale = 0.5f + (-sin(t2 * 2.0 * M_PI) + 1.0f) * 1.2f;
    //glColor4f(0.4f, 0.5f, 0.9f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();

    glTranslatef((Width>>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<gridHeight; j+=64){
        for(int i=0; i<gridWidth; i+=64){ 
            glVertex2i(i-(gridWidth>>1),j-(gridHeight>>1));
        }
    }
    glEnd();
}
 39
Author: genpfault,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-03 13:19:21

La respuesta de Mads proporciona todo lo que necesita si opta por la canalización de funciones fijas. Sin embargo, si tiene un sistema que no proporciona la extensión ARB_point_sprite o con una implementación rota (algunos controladores ATI), puede resolver esta parte también con sombreadores de geometría. Las ARB_geometry_shader4 la extensión le permite convertir un punto primitivo en dos triángulos, que se pueden usar como el quad creado por la extensión ARB_point_sprite. En OpenGL 3.2, los sombreadores de geometría ya son compatibles con core, sin extensión necesario. El wiki de OpenGL tiene dos ejemplos.

 2
Author: Malte Clasen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-03 17:55:37

No es posible con una función opengl fija. Los puntos son siempre cuadrados:)

Tienes que dibujar tu propio círculo (construyéndolo como un pastel, pieza por pieza) o dibujar un GL_QUAD con una textura de "círculo".

Saludos cordiales, andre

 -1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-03 14:09:33