2012-03-22 38 views
4

我目前使用opengl來繪製幾千個多邊形,它的運行速度非常慢。需要apx 100 ms來繪製8000個多邊形。用OpenGL高效地繪製大量的多邊形?

這裏是我的設置了一些信息:

  • 我有我的設置爲2D多邊形面的集合3D領域的每個對象,所以方將包括6,4頂點的飛機。所以我可以訪問每一架飛機。
  • 我不能保證每個多邊形將具有相同數量的頂點
  • 我目前正在繪製如下:

    for(allPlanes){ 
        glBegin(GL_POLYGON); 
        for(allPointsInThePlane){ 
         glVertex(pointX,pointY,pointZ); 
        } 
        glEnd(); 
    } 
    

這比我預期的要慢,我已經調查改爲使用glDrawElements(),並將多邊形平面分解爲三角形,並使用三角形或條來繪製它們。

我只是尋找一些建議,以最有效的方式來做到這一點,或任何批評在我接近繪圖的方式。

+5

您正在做大量的OpenGL調用。每次通話都有一些開銷,這會讓你的工作變慢。您必須將所有數據存儲在緩衝區中,並使用幾個調用來呈現所有內容。請參閱@genpfault答案。 – lvella 2012-03-22 19:39:13

回答

9

Triangulate everything and toss the triangles into a big VA/VBO

編輯:GLUtesselator包裝:

struct TessContext 
{ 
    ~TessContext() 
    { 
     for(size_t i = 0; i < combined.size(); ++i) 
     { 
      delete[] combined[i]; 
     } 
    } 

    vector<Eigen::Vector2d> pts; 
    vector< GLdouble* > combined; 
}; 

#define APIENTRY __stdcall 

void APIENTRY tess_begin(GLenum type) {} 
void APIENTRY tess_edgeFlag(GLboolean flag) {} 
void APIENTRY tess_end() {} 

void APIENTRY tess_vertex(void *data, TessContext* ctx) 
{ 
    GLdouble* coord = (GLdouble*)data; 
    ctx->pts.push_back(Eigen::Vector2d(coord[0], coord[1])); 
} 

void APIENTRY tess_combine(GLdouble coords[3], void *vertex_data[4], GLfloat weight[4], void **outData, TessContext* ctx) 
{ 
    GLdouble* newVert = new GLdouble[3]; 
    ctx->combined.push_back(newVert); 

    newVert[0] = coords[0]; 
    newVert[1] = coords[1]; 
    newVert[2] = coords[2]; 
    *outData = newVert; 
} 

template< typename Vec > 
vector<Vec> Triangulate 
    ( 
    const vector<Vec>& aSimplePolygon 
    ) 
{ 
    vector<GLdouble> coords; 
    for(size_t i = 0; i < aSimplePolygon.size(); ++i) 
    { 
     coords.push_back(aSimplePolygon[i].x()); 
     coords.push_back(aSimplePolygon[i].y()); 
     coords.push_back(0); 
    } 

    GLUtesselator* tess = gluNewTess(); 
    //gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); 
    //gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); 

    gluTessCallback(tess, GLU_TESS_BEGIN,   (GLvoid (APIENTRY *)()) tess_begin  ); 
    gluTessCallback(tess, GLU_TESS_EDGE_FLAG,  (GLvoid (APIENTRY *)()) tess_edgeFlag ); 
    gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (GLvoid (APIENTRY *)()) tess_vertex ); 
    gluTessCallback(tess, GLU_TESS_END,   (GLvoid (APIENTRY *)()) tess_end  ); 
    gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (GLvoid (APIENTRY *)()) tess_combine ); 
    gluTessNormal(tess, 0.0, 0.0, 1.0); 

    TessContext ctx; 

    gluTessBeginPolygon(tess, &ctx); 
    gluTessBeginContour(tess); 

    for(size_t i = 0; i < aSimplePolygon.size(); ++i) 
    { 
     gluTessVertex(tess, &coords[i*3], &coords[i*3]); 
    } 

    gluTessEndContour(tess); 
    gluTessEndPolygon(tess); 

    gluDeleteTess(tess); 

    vector<Vec> ret(ctx.pts.size()); 
    for(size_t i = 0; i < ret.size(); ++i) 
    { 
     ret[i].x() = ctx.pts[i].x(); 
     ret[i].y() = ctx.pts[i].y(); 
    } 

    return ret; 
} 

用途Eigen但不是什麼有趣的事。

6

glDrawArrays()glDrawElements()(或glDrawRangeElements())是首選的方式,也是唯一不被棄用的方式。即時模式(您的示例)是最慢和最不優選的方法,主要用於OpenGL教程和(根據我自己的經驗)調試。也有display lists,OpenGL的「宏」,僅使用立即模式進行繪圖的一步,以及vertex buffer objects (VBOs)

除立即模式外,任何應該足夠快以滿足您的需求。

+0

@aid,我試圖使用glDrawArrays()函數時遇到了麻煩。我創建了一個浮點數組來作爲我每個飛機的頂點。我啓用GL_VERTEX_ARRAY,然後爲每個數組分配一個glVerterxPointer(3,GL_FLOAT,0,plane#array)。所以現在我的每個飛機都有一個頂點指針。然後我調用glDrawArrays(GL_TRIANGLE_FAN,0,???)我很困惑如何處理最後一個參數,它會是我所做的頂點指針的總數量嗎? – Dark 2012-03-23 18:22:39

+0

第三個參數是要繪製的頂點數。 – aib 2012-03-24 09:04:32

2

是使用三角測量(這是鑲嵌的特殊情況)來計算點,然後繪製它們是優選的方式(您使用哪個已被棄用立即模式)

當前圖形架構使用shaders

所以不是所有的頂點在每次發送一個小組頂點處理器和GPU,你應該之間,

  • 過程中一旦其保存到一個數據結構,並將其發送到克PU

  • 繪製它在一次(使用glDraw *()函數),

這是更快,因爲

  • 整個陣列只計算一次,並在數據被保留結構以便可以重複使用

  • 然後將數據完全發送到GPU內存,以便在沒有任何額外瓶的情況下執行進一步的操作(通過使用可編程着色器)的數據傳輸和相關開銷的領域