2009-10-03 14 views
26

J'ai commencé à jouer avec OpenGL et GLUT. Je voudrais tirer quelques points, mais le problème est qu'ils se transforment en carrés, et je voudrais qu'ils soient des points ronds (cercles pleins).Obtention de gros points en OpenGL

C'est ce que je fais:

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

Ceci est le résultat: Result of the above code

Les points apparaissent lorsque prévu, que leur forme ne va pas.

+1

Vous n'avez pas mentionné votre plateforme cible. Certaines fonctionnalités OpenGL (comme GL_POINT_SMOOTH) ne sont pas largement supportées. Si vous avez l'intention que votre application fonctionne largement sur des cartes vidéo grand public, assurez-vous de tester avant de vous engager dans des extensions exotiques. Même si cela semble fonctionner, vérifiez la performance. Il peut vous laisser tomber en mode logiciel. – Alan

+0

Non, mais j'ai mentionné que je viens de commencer à jouer avec opengl, un peu comme un passe-temps;) –

+0

Si vous voulez que votre code fonctionne sur votre propre ordinateur, faites tout ce qui fonctionne sur votre ordinateur. Mais il est également utile de comprendre que l'un des principaux inconvénients d'OpenGL est que de grandes parties de la spécification ne fonctionneront pas correctement sur une plate-forme donnée. Les parties exactes sont un secret très mal documenté. Les retards en mode logiciel ont tendance à masquer les fonctionnalités non prises en charge. – Alan

Répondre

39

Contrairement à ce qui a été dit précédemment, cela est possible avec la conduite à fonction fixe, même avec le GL_POINTS type primitif, aussi longtemps que vous avez le support d'OpenGL 1.4 ou l'extension GL_ARB_point_sprite. Consultez ce document, ou la spécification de base OpenGL de votre choix: http://www.opengl.org/registry/specs/ARB/point_sprite.txt

GL_ARB_point_sprite convertit les points en « quadriceps », i.e. un polygone avec la forme d'un avion. Le type primitif exact auquel il est converti n'est pas défini par la spécification, bien qu'il ne soit pas important. Ce qui est important, c'est que GL_COORD_REPLACE génère automatiquement des coordonnées de texture pour la surface lorsqu'il est activé, de sorte que vous pouvez les mapper en texture avec une texture RGBA en forme de sphère.

EDIT: Il semble que vous (l'affiche) a raison. Les points anti-aliasés sont arrondis par rapport à leur rayon. (Je l'ai utilisé OpenGL depuis 2003, et je ne savais pas. [/ Honte]) permettant ainsi GL_POINT_SMOOTH alors que vous avez un visuel/pixelformat, multisample-able vous obtenez des points arrondis. Cependant, le multi-échantillonnage peut être lent, donc j'implémenterais les deux. Les quads texturés sont bon marché.

Pour demander un visuel avec multisampling avec XLib, utiliser ces deux attributs dans la liste à glXChooseFBConfig():

GLX_SAMPLE_BUFFERS - sa valeur doit être True. C'est une bascule on/off.
GLX_SAMPLES - le nombre d'échantillons.

Pour demander une pixelformat avec Win32, utiliser ces deux attributs dans la liste à ChoosePixelFormat() ou wglChoosePixelFormatARB():

WGL_SAMPLE_BUFFERS_ARB comme ci-dessus, une bascule.
WGL_SAMPLES_ARB Comme ci-dessus, le nombre d'échantillons.

Il semble que vous pouvez ou dans le drapeau GLUT_MULTISAMPLE-glutInitDisplayMode pour obtenir multiéchantillonnage dans GLUT, mais vous ne pouvez pas demander le nombre de tampons d'échantillons.

Voici comment quads alpha-mélangés pourraient être mis en œuvre en utilisant votre cas de test.

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

image de points arrondis en utilisant par fragment mélange alpha + textures: http://www.mechcore.net/images/gfx/sprite0.png
image de points arrondis en utilisant GL_POINT_SMOOTH et multiéchantillonnage: http://www.mechcore.net/images/gfx/sprite1.png
Un petit échantillon I fait qui montre les deux techniques. LibSDL et nécessite libGLEW à compilent:

#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

Et qu'en est-il de la référence que j'ai citée à l'autre commentaire? Si je ne me trompe pas, cela suggère que GL_POINT_SMOOTH fait des points circulaires. Ou est-ce que je –

+0

Oui, j'ai lu à ce sujet et l'ai essayé. Drôle, je ne savais pas :-) –

+1

Merci pour la réponse très détaillée. –

0

Impossible avec une fonction opengl fixe. Les points sont toujours carrés :)

Vous devez dessiner votre propre cercle (en le construisant comme un gâteau, pièce par pièce) ou dessiner un GL_QUAD avec une texture "cercle".

meilleures salutations, andre

+2

alors pour quoi GL_POINT_SMOOTH est-il bon? –

+0

Selon la référence opengl: "Si l'antialiasing est activé, la pixellisation du point produit un fragment pour chaque carré de pixels qui intersecte la région située dans le cercle ayant un diamètre égal à la taille du point courant et centrée sur le point xwyw. chaque fragment est la zone de coordonnées fenêtre de l'intersection de la ** région circulaire avec le carré de pixel correspondant. ** " –

+3

En fait, c'est possible, mais c'est au pilote OpenGL de savoir si (ou même si) ça marchera . Dans mes tests, il donne des points ronds avec le matériel/pilote nVidia, mais avec le matériel/pilote ATI/AMD, il donne des points carrés. –

2

Mads réponse fournit tout ce dont vous avez besoin si vous allez pour le pipeline de fonction fixe. Cependant, si vous avez un système qui ne fournit pas l'extension ARB_point_sprite ou avec une implémentation cassée (certains pilotes ATI), vous pouvez résoudre cette partie aussi avec des shaders de géométrie. L'extension ARB_geometry_shader4 vous permet de convertir une primitive de point en deux triangles, qui peuvent être utilisés comme le quad créé par l'extension ARB_point_sprite. Sur OpenGL 3.2, les shaders de géométrie sont déjà supportés en core, aucune extension n'est nécessaire. Le wiki OpenGL a two examples.

+0

+ 1 pour la mention de geometry shader, qui est ce que vous devriez toujours utiliser quand même supporté (en 2009 et même aujourd'hui). La raison en est que tous les GPU ne supportent pas les bandes de garde, et vous n'avez aucun moyen de savoir si oui ou non ils le font. Si ce n'est pas le cas, les points et les sprites de points apparaîtront et apparaîtront alors qu'ils se rapprochent du rectangle du clip. Lorsque le point central du sprite de point sort du rectangle, la moitié visible du sprite de point "disparaît" soudainement. De plus, les tailles de point sont généralement limitées à environ 64px. – Damon