2009-10-03 6 views
26

Zacząłem grać z OpenGL i GLUT. Chciałbym zwrócić uwagę na pewne kwestie, ale problem polega na tym, że są kwadratami i chciałbym, aby były okrągłymi kropkami (wypełnionymi kółkami).Uzyskiwanie gładkich, dużych punktów w OpenGL

To co mam zrobić:

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

Jest to wynikiem: Result of the above code

Punkty pojawiają się gdzie oczekiwano, tylko ich kształt jest źle.

+1

Nie wspomniałeś o swojej docelowej platformie. Niektóre funkcje OpenGL (takie jak GL_POINT_SMOOTH) nie są powszechnie obsługiwane. Jeśli zamierzasz, aby aplikacja działała szeroko na kartach wideo klasy konsumenckiej, sprawdź, zanim zdecydujesz się na egzotyczne rozszerzenia. Nawet jeśli wydaje się działać, sprawdź wydajność. To może spowodować przejście do trybu oprogramowania. – Alan

+0

Nie, ale wspomniałem, że po prostu zacząłem grać z OpenGL, podobnie jak hobby;) –

+0

Jeśli chcesz tylko, aby twój kod działał na twoim komputerze, to zrób wszystko, co działa na twoim komputerze. Ale warto też zrozumieć, że główną pułapką OpenGL jest to, że duże części specyfikacji nie będą działać poprawnie na żadnej platformie. Dokładnie to, które to części są bardzo słabo udokumentowanym sekretem. Fallouty w trybie programowym mają tendencję do ukrywania nieobsługiwanych funkcji. – Alan

Odpowiedz

39

W przeciwieństwie do tego, co zostało powiedziane wcześniej, jest to możliwe z rurociągu stałej funkcji, nawet z GL_POINTS prymitywnego rodzaju, tak długo, jak masz wsparcie dla OpenGL 1.4 lub przedłużenia GL_ARB_point_sprite. Zapoznaj się z tym dokumentem lub z wybraną przez Ciebie specyfikacją rdzeniową OpenGL: http://www.opengl.org/registry/specs/ARB/point_sprite.txt

GL_ARB_point_sprite zamienia punkty na "kwadraty", tj. Wielokąty o kształcie płaszczyzny. Dokładny typ, dla którego jest konwertowany, nie jest zdefiniowany w specyfikacji, ale nie jest ważny. Ważne jest to, że po włączeniu automatyczne generowanie współrzędnych tekstury dla powierzchni jest możliwe, dzięki czemu można je zamodelować za pomocą tekstury RGBA o kształcie kuli.

EDYCJA: Wygląda na to, że ty (plakat) masz rację. Punkty wygładzone są zaokrąglane zgodnie z ich promieniem. (Używam OpenGL od 2003 roku, a ja o tym nie wiedziałem. [/ Shame]) Włączając GL_POINT_SMOOTH, gdy masz format wizualny/pikselowy multisample-able, otrzymujesz zaokrąglone punkty. Mimo to, multisampling może być powolny, więc mógłbym wdrożyć oba. Teksturowane quady są tanie.

zażądać wizualny z wielowzorowość z Xlib, użyj tych dwóch atrybutów w liście do glXChooseFBConfig():

GLX_SAMPLE_BUFFERS - jego wartość powinna być True. To jest włączanie/wyłączanie.
GLX_SAMPLES - liczba próbek.

Aby zażądać PixelFormat z Win32, użyj tych dwóch atrybutów w liście do ChoosePixelFormat() lub (wglChoosePixelFormatARB):

WGL_SAMPLE_BUFFERS_ARB samo jak wyżej, przełącznik.
WGL_SAMPLES_ARB Tak jak powyżej, liczba próbek.

Wydaje się, że można lub w flaga GLUT_MULTISAMPLE do glutInitDisplayMode uzyskania wielowzorowość w GLUT, ale nie można żądać liczbę buforów próbki.

Oto, w jaki sposób quady z mieszaniem alfa mogą zostać zaimplementowane za pomocą walizki testowej.

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

Obraz zaokrąglonymi punktów, stosując mieszanie alfa + tekstury za-fragment: http://www.mechcore.net/images/gfx/sprite0.png
Obraz zaokrąglonymi punktów za pomocą GL_POINT_SMOOTH i wielodobieranie: http://www.mechcore.net/images/gfx/sprite1.png
Nieco próbki i wykonany co wskazuje obu technik. Wymaga libSDL i libGLEW skompilować: odpowiedź

#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

A co z referencją, o której wspomniałem w drugim komentarzu? Jeśli go nie rozumiem, sugeruje, że GL_POINT_SMOOTH robi punkty kołowe. A może ja? –

+0

Tak, czytałem o tym i wypróbowałem to. Zabawne, nie wiedziałem :-) –

+1

Dziękuję za bardzo szczegółową odpowiedź. –

0

Niemożliwe ze stałą funkcją OpenGL. Kropki są zawsze kwadratowe :)

Musisz narysować swój własny okrąg (budując go jak ciasto, kawałek po kawałku) lub narysować GL_QUAD z teksturą "koła" na.

pozdrawiam, andre

+2

więc co GL_POINT_SMOOTH jest dobre dla wtedy? –

+0

Zgodnie z odwołaniem do OpenGL: "Jeśli włączone jest wygładzanie krawędzi, to rasteryzacja punktów tworzy fragment dla każdego kwadratu pikseli, który przecina obszar leżący wewnątrz okręgu o średnicy równej bieżącemu rozmiarowi punktu i wyśrodkowany w punkcie xwyw punktu. każdy fragment to obszar współrzędnych okna przecięcia ** okręgu z odpowiadającym mu kwadratem pikseli. ** " –

+3

W rzeczywistości jest to możliwe, ale to zależy od sterownika OpenGL, jak dobrze (a nawet czy) będzie działać . W moich testach daje on punkty zaokrąglenia ze sprzętem/sterownikiem nVidia, ale ze sprzętem/sterownikiem ATI/AMD, daje punkty kwadratowe. –

2

Mads' zapewnia wszystko, czego potrzebujesz, jeśli pójdziesz do funkcji stałej rurociągu. Jeśli jednak masz system, który nie zapewnia rozszerzenia ARB_point_sprite lub z uszkodzoną implementacją (niektóre sterowniki ATI), możesz rozwiązać tę część również za pomocą shaderów geometrii. Rozszerzenie ARB_geometry_shader4 umożliwia przekształcenie punktu podstawowego na dwa trójkąty, które mogą być używane jako quady utworzone przez rozszerzenie ARB_point_sprite. W OpenGL 3.2, shadery geometrii są już obsługiwane w rdzeniu, bez potrzeby rozszerzenia. Wiki OpenGL ma two examples.

+0

+1 za wzmiankę o shaderze geometrii, którego należy zawsze używać, jeśli jest obsługiwany (w 2009 r. I podobnie dzisiaj). Powodem jest to, że nie wszystkie procesory graficzne obsługują zespoły strażnicze i nie masz możliwości dowiedzenia się, czy robią to, czy nie. Jeśli nie, punkty i spity punktowe pojawią się i wyskoczą, gdy zbliżą się do prostokąta klipu. Kiedy punkt środkowy ikonki wykracza poza prostokąt, widoczna połowa ikonki punktowej nagle "znika". Ponadto rozmiary punktów są zwykle ograniczone do około 64 pikseli. – Damon

Powiązane problemy