3

このテーマに関する同様の投稿をここで見ましたが、私の質問は少し異なります。

さまざまなサイズのさまざまな場所にある円で構成される 2D プロットがあります。現在、私のレンダリング スキームは、表示リストを使用して、glScalef/glTranslatef を使用してユーザーがアクティブにサイズ変更および変換できる、事前に描画された円を格納します。ただし、何千もの円をレンダリングしているため、サイズ変更と描画が非常に遅くなります。各円は異なる半径と色を持つことができるため、これらの処理はループ内で行う必要があります。

ユーザーが円のサイズを変更したときに、円のレンダリングの速度を向上させるためにできることは何ですか? 上記のリンクが示すように VBO を調べましたが、オブジェクトのサイズが絶えず変化するこのタイプのアプリケーションでどれだけのパフォーマンスが得られるかはあいまいでした。

4

3 に答える 3

1

何千もの円をレンダリングしているため、サイズ変更と描画が非常に遅くなります

頂点配列だけで、10,000 円の Intel HD Graphics 3000 でフレームあたり約 60 ミリ秒を取得しています。

// g++ -O3 circles.cpp -o circles -lglut -lGL
#include <GL/glut.h>
#include <vector>
#include <iostream>
#include <cmath>
using namespace std;

// returns a GL_TRIANGLE_FAN-able buffer containing a unit circle
vector< float > glCircle( unsigned int subdivs = 20 )
{
    vector< float > buf;

    buf.push_back( 0 );
    buf.push_back( 0 );
    for( unsigned int i = 0; i <= subdivs; ++i )
    {
        float angle = i * ((2.0f * 3.14159f) / subdivs);
        buf.push_back( cos(angle) );
        buf.push_back( sin(angle) );
    }

    return buf;
}

struct Circle
{
    Circle()
    {
        x = ( rand() % 200 ) - 100;
        y = ( rand() % 200 ) - 100;
        scale = ( rand() % 10 ) + 4;
        r = rand() % 255;
        g = rand() % 255;
        b = rand() % 255;
        a = 1;
    }

    float x, y;
    float scale;
    unsigned char r, g, b, a;
};

vector< Circle > circles;
vector< float > circleGeom;
void init()
{
    srand( 0 );
    for( size_t i = 0; i < 10000; ++i )
        circles.push_back( Circle() );
    circleGeom = glCircle( 100 );
}

void display()
{
    int beg = glutGet( GLUT_ELAPSED_TIME );

    glClear( GL_COLOR_BUFFER_BIT );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    double w = glutGet( GLUT_WINDOW_WIDTH );
    double h = glutGet( GLUT_WINDOW_HEIGHT );
    double ar = w / h;
    glOrtho( -100 * ar, 100 * ar, -100, 100, -1, 1);

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glEnableClientState( GL_VERTEX_ARRAY );
    glVertexPointer( 2, GL_FLOAT, 0, &circleGeom[0] );

    for( size_t i = 0; i < circles.size(); ++i )
    {
        Circle& c = circles[i];
        c.scale = ( rand() % 10 ) + 4;

        glPushMatrix();
        glTranslatef( c.x, c.y, 0 );
        glScalef( c.scale, c.scale, 0 );
        glColor3ub( c.r, c.g, c.b );
        glDrawArrays( GL_TRIANGLE_FAN, 0, circleGeom.size() / 2 );
        glPopMatrix();
    }

    glDisableClientState( GL_VERTEX_ARRAY );

    glutSwapBuffers();

    int end = glutGet( GLUT_ELAPSED_TIME );
    double elapsed = (double)( end - beg );
    cout << elapsed << "ms" << endl;
}

void timer(int extra)
{
    glutPostRedisplay();
    glutTimerFunc(16, timer, 0);
}

int main( int argc, char **argv )
{
    glutInit( &argc, argv );
    glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
    glutInitWindowSize( 600, 600 );
    glutCreateWindow( "Circles" );

    init();

    glutDisplayFunc( display );
    glutTimerFunc(0, timer, 0);
    glutMainLoop();
    return 0;
}
于 2012-11-28T00:57:41.523 に答える
0

ARB_instanced_arraysベースのインスタンス化がおそらく最もクリーンです。

N回描画するM個の頂点を持つ単一の円があり、円ごとのx / y位置、半径、および色を頂点属性として保存し、glVertexAttribDivisor()適切に使用します。

半径に適応する LOD が必要な場合は、よりトリッキーになります。そのためには、おそらくジオメトリ シェーダーを掘り下げる必要があります。

于 2012-11-21T20:54:27.383 に答える
0

次に、glDrawElementsInstanced または glDrawArraysInstanced でインスタンス化された配列を使用して、他のタイプのジオメトリにうまく移行するクリーンなソリューションとして使用します。

OpenGL 2 に固執したい/固執する必要があり (たとえば、iThing で実行する必要がある場合)、円のみが必要な場合は、ポイント スプライトも検討してください。各円の原点はポイントの頂点値です。半径をテクスチャ座標の S 値、サーフェス法線の X 値などとして保存します。ブレンディング、GL_PROGRAM_POINT_SIZE、おそらくポイントスムージングを有効にします。gl_PointSize を必要な半径に設定するだけの頂点シェーダーを作成します。インスタントサークル。

于 2012-11-21T23:07:20.167 に答える