web-dev-qa-db-fra.com

Obtenir de gros points fluides dans OpenGL

J'ai commencé à jouer avec OpenGL et GLUT. Je voudrais tirer quelques points, mais le problème est qu'ils se révèlent être des carrés, et je voudrais qu'ils soient des points ronds (cercles pleins).

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

Voici le résultat: Result of the above code

Les points apparaissent là où prévu, seule leur forme est fausse.

27
Tamás Szelei

Contrairement à ce qui a été dit précédemment, cela est possible avec le pipeline à fonction fixe, même avec le GL_POINTS type primitif, tant que vous avez pris en charge OpenGL 1.4 ou le GL_ARB_point_Sprite extension. 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 "quads", c'est-à-dire un polygone ayant la forme d'un plan. Le type primitif exact dans lequel 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 les coordonnées de texture de la surface lorsque cette option est activée, vous pouvez donc les mapper avec une texture RGBA en forme de sphère.

EDIT: Il semble que vous (l'affiche) avez raison. Les points anticrénelés sont arrondis par rapport à leur rayon. (J'utilise OpenGL depuis 2003 et je ne le savais pas. [/ Shame]) Donc, activer GL_POINT_SMOOTH pendant que vous avez un multisample-able visual/pixelformat, vous obtenez des points arrondis. Pourtant, le multi-échantillonnage peut être lent, donc je mettrais en œuvre les deux. Les quads texturés sont bon marché.

Pour demander un visuel avec multi-échantillonnage avec XLib , utilisez ces deux attributs dans la liste pour glXChooseFBConfig ():

GLX_SAMPLE_BUFFERS - sa valeur doit être True. Il s'agit d'une bascule marche/arrêt.
GLX_SAMPLES - le nombre d'échantillons.

Pour demander un format pixel avec Win32 , utilisez ces deux attributs dans la liste pour 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 puissiez OR dans le drapeau GLUT_MULTISAMPLE à glutInitDisplayMode pour obtenir un multi-échantillonnage dans GLUT , mais vous ne pouvez pas demander le nombre d'exemples de tampons.

Voici comment les quads alpha peuvent être implémentés à l'aide de votre scénario 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 utilisant un mélange alpha par fragment + textures:
(source: mechcore.net )
Image des points arrondis en utilisant GL_POINT_SMOOTH et multi-échantillonnage:
(source: mechcore.net )
Un petit échantillon que j'ai fait qui montre les deux techniques. Nécessite libSDL et libGLEW pour compiler:

#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
Mads Elvheim

La réponse de Mads fournit tout ce dont vous avez besoin si vous optez pour le pipeline de fonctions fixes. Cependant, si vous avez un système qui ne fournit pas le ARB_point_Sprite extension ou avec une implémentation cassée (certains pilotes ATI), vous pouvez également résoudre cette partie avec des shaders de géométrie. Le ARB_geometry_shader4 l'extension vous permet de convertir une primitive ponctuelle en deux triangles, qui peuvent être utilisés comme le quadruple créé par le ARB_point_Sprite extension. Sur OpenGL 3.2, les shaders de géométrie sont déjà pris en charge dans le noyau, aucune extension n'est requise. Le wiki OpenGL a deux exemples .

2
Malte Clasen