2009-10-03 14 views
26

我開始玩OpenGL和GLUT。我想提出一些觀點,但問題是它們變成了正方形,我希望它們是圓點(實心圓)。在OpenGL中獲得流暢,大分

這是我做的:

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

這是結果: Result of the above code

的點出現在預期的位置,只有它們的形狀是錯誤的。

+1

你沒有提到你的目標平臺是什麼。某些OpenGL功能(如GL_POINT_SMOOTH)並未得到廣泛支持。如果您打算讓您的應用在消費級視頻卡上廣泛運行,請確保在承諾進行異國情調的擴展之前進行測試。即使它看起來工作,檢查性能。它可能會讓你進入軟件模式。 – Alan 2009-10-05 18:58:20

+0

不,但我確實提到過我剛開始使用opengl,很像一個愛好;) – 2009-10-07 13:47:16

+0

如果你只是想讓自己的代碼在你自己的計算機上運行,​​那麼千萬不要在你的計算機上執行任何操作。但是,瞭解OpenGL的一個主要缺陷是規範的大部分內容在任何給定的平臺上無法正確運行也是有價值的。究竟哪些部分是一個記錄非常不明確的祕密。軟件模式回退將會掩蓋不支持的功能。 – Alan 2009-10-08 21:36:07

回答

39

不像原先預想說,這是可能的固定功能管線,甚至與GL_POINTS原始類型,只要你有對OpenGL 1.4或GL_ARB_point_sprite擴展支持。請參閱本文檔或您選擇的OpenGL核心規範:http://www.opengl.org/registry/specs/ARB/point_sprite.txt

GL_ARB_point_sprite將點轉換爲「四邊形」,即具有平面形式的多邊形。它被轉換的確切原始類型不是由規範定義的,儘管它並不重要。重要的是,GL_COORD_REPLACE在啓用時會自動生成表面的紋理座標,因此您可以使用球形RGBA紋理對它們進行紋理貼圖。

編輯:看起來像你(海報)是正確的。防鋸齒點在其半徑方向取整。 (我從2003年開始使用OpenGL,並且我不知道這一點。)[0128]儘管如此,多重採樣可能會很慢,所以我會實現這兩個。紋理四邊形便宜。

要請求視覺與XLIB多重採樣,在列表中使用這兩個屬性glXChooseFBConfig():

GLX_SAMPLE_BUFFERS - 其值應True。這是一個開/關切換。
GLX_SAMPLES - 樣本數量。

要請求的Win32一個像素格式,在列表中使用這兩個屬性ChoosePixelFormat()或wglChoosePixelFormatARB():

WGL_SAMPLE_BUFFERS_ARB與上述相同,進行切換。
WGL_SAMPLES_ARB與上面相同,樣本的數量。

這似乎是你可以或標誌GLUT_MULTISAMPLEglutInitDisplayMode獲得在GLUT多重採樣,但你不能要求樣本緩衝區的數目。

下面是如何使用測試用例實現alpha混合四邊形。使用每片段alpha混合+紋理圓形點的

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

圖片:http://www.mechcore.net/images/gfx/sprite0.png
通過使用GL_POINT_SMOOTH和多重採樣圓形點的圖片:http://www.mechcore.net/images/gfx/sprite1.png
我製成的小樣品示出這兩種技術。需要libSDL和libGLEW進行編譯:

#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

那麼我在其他評論中引用的參考文獻呢?如果我沒有誤解它,則表明GL_POINT_SMOOTH確實會生成圓點。或者我? – 2009-10-03 15:31:44

+0

是的,我讀了一下,並試用了它。有趣的是,我不知道:-) – 2009-10-03 17:43:57

+1

謝謝你的非常詳細的答案。 – 2009-10-03 18:59:18

0

固定的opengl函數不可能。圓點總是方形的:)

你必須繪製自己的圓圈(通過像蛋糕一樣一塊一塊地構建)或繪製一個帶有「圓形」紋理的GL_QUAD。

最好的問候, 安德烈

+2

那麼GL_POINT_SMOOTH對於那麼好呢? – 2009-10-03 14:18:13

+0

根據opengl參考文獻:「如果啓用了抗鋸齒功能,那麼點光柵化將爲每個像素方塊生成一個片段,該片段與位於該圓的直徑等於當前點大小並以該點的xwyw爲中心的區域相交。每個片段是**圓形區域與相應像素平方的交點的窗口座標區域**「 – 2009-10-03 14:31:52

+3

實際上,這是可能的,但是它取決於OpenGL驅動程序的工作效果(甚至是否可以) 。在我的測試中,它給出了使用nVidia硬件/驅動程序的要點,但使用ATI/AMD硬件/驅動程序,它給出了方點。 – 2009-10-03 18:51:11

2

如果您需要固定功能管道,Mads的答案將提供您需要的一切。但是,如果您的系統不提供ARB_point_sprite擴展或具有破壞​​的實現(某些ATI驅動程序),則可以使用幾何着色器來解決該部分。使用擴展名ARB_geometry_shader4 可以將點基元轉換爲兩個三角形,這可以用作由ARB_point_sprite擴展名創建的四元組。在OpenGL 3.2中,核心中已經支持幾何着色器,不需要擴展。 OpenGL wiki有two examples

+0

+1提到幾何着色器,這是你應該總是使用,無論如何,如果支持(早在2009年,今天也是如此)。原因在於並不是所有的GPU都支持防護帶,而且你無法知道它們是否支持。如果他們不這樣做,點和點精靈會彈出並彈出,因爲它們靠近剪切矩形。當點精靈的中心點離開矩形時,點精靈的可見一半突然「消失」。另外,點的大小通常限制在64px左右。 – Damon 2013-09-05 09:14:35