2012-03-22 22 views
4

私は現在、数千のポリゴンを描画するためにOpenGLを使用していますが、非常に遅いです。 8000ポリゴンを描画するには、100ミリ秒かかる。ここでOpenGLで効率的に多数のポリゴンを描画できますか?

は私のセットアップに関するいくつかの情報です:

  • 私は、正方形が6、4頂点面で構成されます、2Dポリゴン面の集合として設定私の3Dフィールド内の各オブジェクトを持っています。だから私はそれぞれの飛行機にアクセスできる。

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

は、これは私が予想よりはるかに遅いですし、私はに見てきた:

  • 私は次のように各ポリゴンは、私が現在描いてる頂点
  • の数が同じになることを保証することはできませんglDrawElements()を使用し、ポリゴンプレーンを三角形に分割し、三角形またはストリップを使用して描画します。

    私はこれを行うための最も効率的な方法や、私が図面に近づいている方法に対する批判に関するアドバイスを探しています。

  • +5

    OpenGL呼び出しをたくさん行っています。それぞれの呼び出しにはオーバーヘッドがあります。すべてのデータをバッファに格納し、すべてをレンダリングするためにわずかな呼び出しを使用する必要があります。 @genpfaultの回答を参照してください。 – lvella

    答えて

    9

    Triangulateすべてを三角形を大きなVA/VBOに投げる。

    EDIT: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、描画のための直接モードを使用して上記の1つだけのステップであるOpenGLの "マクロ"、およびvertex buffer objects (VBOs)もあります。

    すべてのモードは、イミディエイトモードを除いて、必要に応じて十分に高速である必要があります。

    +0

    @aid、私は問題にglDrawArrays()関数を使用しようとしています。私はそれぞれの飛行機の頂点として使う浮動小数点配列を作成します。私はGL_VERTEX_ARRAYを有効にし、各配列に対してglVerterxPointer(3、GL_FLOAT、0、plane#配列)を割り当てます。だから私は私の飛行機のそれぞれの頂点ポインタを持っています。私はglDrawArrays(GL_TRIANGLE_FAN、0、???)を呼び出します。最後のパラメータをどうすればいいのか混乱しています。それは私が作成した頂点ポインタの総数ですか? – Dark

    +0

    3番目のパラメータは、描画される頂点の数です。 – aib

    2

    はい(あなたが廃止され、即時モードを使用)

    の点を計算する(テッセレーションの特別な場合である)、三角測量を使用して、その後、好ましい方法、それらをされている描画現在のグラフィックスアーキテクチャはshaders

    を使用一度にすべての頂点は、データ構造に保存してグラムにこれを送る

    ので、代わりの頂点の小さなセットにあなたがすべきプロセッサとGPU間の各時間を送る、

    • プロセスPU

    • (glDraw *()関数を使用して)一度にそれを描き、アレイ全体を一度だけ計算され、データが保持される

      • ため

      これは高速であります構造を再利用できるようにする

    • データはGPUメモリに完全に送信され、追加のボトルなしでさらなる操作が実行できます(プログラム可能なシェーダを使用して)データ転送の首と関連するオーバーヘッド(プログラム可能なシェーダを使用)

    関連する問題