2009-10-03 13 views
26

Empecé a jugar con OpenGL y GLUT. Me gustaría señalar algunos puntos, pero el problema es que resultan ser cuadrados, y me gustaría que sean puntos redondos (círculos rellenos).Conseguir puntos grandes y suaves en OpenGL

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: Result of the above code

Los puntos aparecen cuando se esperaba, sólo su forma es incorrecta.

+1

No mencionó cuál es su plataforma de destino. Algunas características de OpenGL (como GL_POINT_SMOOTH) no son ampliamente compatibles. Si tiene la intención de que su aplicación se ejecute ampliamente en tarjetas de video de consumo, asegúrese de realizar pruebas antes de comprometerse con extensiones exóticas. Incluso si parece funcionar, verifica el rendimiento. Puede dejarte caer al modo de software. – Alan

+0

No, pero mencioné que recién comencé a jugar con OpenGL, como un hobby;) –

+0

Si solo quiere que su código se ejecute en su propia computadora, haga lo que sea que funcione en su computadora. Pero también es valioso entender que un gran escollo de OpenGL es que grandes partes de la especificación no funcionarán correctamente en una plataforma determinada. Exactamente qué partes son estos es un secreto muy mal documentado. Los retrocesos en modo software tienden a oscurecer las funciones no compatibles. – Alan

Respuesta

39

A diferencia de lo que se dijo anteriormente, esto es posible con la tubería de función fija, incluso con el tipo primitivo GL_POINTS, siempre y cuando usted tiene soporte para OpenGL 1.4 o la extensión GL_ARB_point_sprite. Consulte este documento, o la especificación OpenGL núcleo 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 la especificación, aunque no es importante. Lo que es importante es que GL_COORD_REPLACE autogenera coordenadas de textura para la superficie cuando está habilitada, por lo que puede texturizarlas con una textura RGBA esférica.

EDITAR: Parece que usted (el póster) tiene razón. Los puntos antialias se redondean con respecto a su radio. (He usado OpenGL desde 2003, y no lo sabía. [/ Vergüenza]) Habilitando GL_POINT_SMOOTH mientras tiene un formato visual/pixel multisample-able, obtiene puntos redondeados. Aún así, la multimuestreo puede ser lenta, así que implementaría ambos. Los cuádriceps con textura son baratos.

Para solicitar una visual con multisampling con XLIB, utilice estos dos atributos de la lista para glXChooseFBConfig():

GLX_SAMPLE_BUFFERS - su valor debe ser True. Esta es una palanca de encendido/apagado.
GLX_SAMPLES - el número de muestras.

Para solicitar una PixelFormat con Win32, utilice estos dos atributos de la lista para ChoosePixelFormat() o wglChoosePixelFormatARB():

WGL_SAMPLE_BUFFERS_ARB Igual que el anterior, un conmutador.
WGL_SAMPLES_ARB Igual que el anterior, el número de muestras.

que parezca que pueda O en la bandera GLUT_MULTISAMPLE a glutInitDisplayMode para obtener multisampling en GLUT, pero no se puede solicitar el número de buffers de muestra.

Así es como los cuádriceps alfa-combinados podrían implementarse utilizando 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 utilizando alpha de mezcla per-fragmento + texturas: http://www.mechcore.net/images/gfx/sprite0.png
Imagen de puntos redondeados utilizando GL_POINT_SMOOTH y multisampling: http://www.mechcore.net/images/gfx/sprite1.png
una pequeña muestra hice que muestra ambas técnicas. Requiere libSDL y libGLEW para compilar: Respuesta

#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(); 
} 
+0

¿Y la referencia que cité en el otro comentario? Si no lo malinterpreto, sugiere que GL_POINT_SMOOTH sí hace puntos circulares. ¿O sí? –

+0

Sí, lo leí y lo probé. Gracioso, no sabía :-) –

+1

Gracias por la respuesta muy detallada. –

0

No es posible con una función de apertura 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".

mejores deseos, andre

+2

, entonces, ¿para qué sirve GL_POINT_SMOOTH? –

+0

De acuerdo con la referencia opengl: "Si se habilita el antialiasing, la rasterización de puntos produce un fragmento para cada píxel cuadrado que interseca la región que se encuentra dentro del círculo con un diámetro igual al punto actual y centrado en xwyw del punto. cada fragmento es el área de coordenadas de la ventana de la intersección de la ** región circular con el cuadrado de píxeles correspondiente. ** " –

+3

En realidad, es posible, pero depende del controlador OpenGL qué tan bien (o incluso si) funcionará . En mi prueba, proporciona puntos redondos con el hardware/controlador nVidia, pero con el hardware/controlador ATI/AMD, proporciona puntos cuadrados. –

2

Mads ofrece todo lo que necesita si usted va para la tubería de función fija. Sin embargo, si tiene un sistema que no proporciona la extensión ARB_point_sprite o una implementación interrumpida (algunos controladores ATI), puede resolver esta parte también con sombreadores de geometría. La extensión ARB_geometry_shader4 le permite convertir una primitiva de punto en dos triángulos, que se puede utilizar como el cuadrigrama creado por la extensión ARB_point_sprite. En OpenGL 3.2, los sombreadores de geometría ya son compatibles en el núcleo, no se necesita extensión. La wiki de OpenGL tiene two examples.

+0

+1 para mencionar el sombreador de geometría, que es lo que siempre debe usar de todos modos si es compatible (en 2009 y también hoy). La razón es que no todas las GPU admiten bandas de guardias, y no hay manera de saber si lo hacen o no. Si no lo hacen, los puntos y los puntos aparecerán y saldrán mientras se mueven cerca del rectángulo del clip. Cuando el punto central del sprite de punto sale del rectángulo, la mitad visible del sprite de punto "desaparece" de repente. Además, los tamaños de los puntos generalmente están limitados a alrededor de 64px. – Damon