3

Vertex Array を使用して、非常に高速に多くの三角形を描画しています。

void initializeGL() { 
   ...
   glEnableClientState(GL_VERTEX_ARRAY);
   glEnableClientState(GL_COLOR_ARRAY);
   glVertexPointer(3, GL_FLOAT, 0, vertices);
   glColorPointer(3,  GL_FLOAT, 0,   colors);
}

void paintGL() {
   ...  
   glDrawElements(GL_TRIANGLES, 3*numTriangles, GL_UNSIGNED_INT, indices);
 }

ただし、Vertex Buffer Objects (VBO) を使用して、レンダリングをさらに高速化したいと考えています。

glVertexPointer() が CPU のどこで頂点データを取得できるかを GPU に伝え、GPU がそれぞれの paintGL() に対して CPU のこの場所からデータをコピーすることを理解していますか?

また、VBO を使用すると、頂点データを GPU に 1 回だけ書き込むことでこれが改善されますか?

私はQtを使用しているので、QGLBufferクラスを使用しようとしています:

void GLWidget::initializeGL() {
   ... 
   vertexBuffer = new QGLBuffer(QGLBuffer::VertexBuffer);
   vertexBuffer->create();
   vertexBuffer->bind();
   vertexBuffer->setUsagePattern(QGLBuffer::StaticDraw);
   vertexBuffer->allocate(vertices, 3*numVertices*sizeof(float)); // copies vertices to GPU? 
   vertexBuffer->release();

   #define BUFFER_OFFSET(bytes) ((GLubyte*) NULL + (bytes)) 
   glEnableClientState(GL_VERTEX_ARRAY);
   glEnableClientState(GL_COLOR_ARRAY);
   glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));
   glColorPointer(3, GL_FLOAT, 0,  colors);
}  

これを実行すると、クラッシュする前に長時間ハングします:-(。 vertexBuffer->release(); 行をコメントアウトすると、何も表示されず、クラッシュしません。

ここで何が間違っていますか?

また、同様に色を一度だけ GPU に送信するにはどうすればよいですか? QGLBuffer::ColorBuffer 型がない!?

編集: プロジェクトに GLee.[h/c] を含め、QGLBuffer 呼び出しを次のように置き換えました。

unsigned int vbufferid;
glGenBuffers(1, &vbufferid);  
glBindBuffer(GL_ARRAY_BUFFER, vbufferid); 
int size = 3*numVertices*sizeof(float);
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);

しかし、コードはまだ何も描画しません!?

vbufferid には glGenBuffers 呼び出しによって値 1 が割り当てられるため、問題はグラフィック カードにあるとは思いません。

編集 2: glEnableClientState(GL_COLOR_ARRAY); をコメントアウトすると、三角形がVBOで表示されている行(ただし、色はありません)!

では、頂点に VBO を使用する場合、どのように色を GPU に転送すればよいでしょうか?

GL_COLOR_BUFFER型がない!?

4

1 に答える 1

1

glVertexPointer() が GPU に頂点データを取得できる CPU の場所を伝え、GPU がそれぞれの paintGL() に対して CPU のこの場所からデータをコピーすることを理解していますか?

また、VBO を使用すると、頂点データを GPU に 1 回だけ書き込むことでこれが改善されますか?

これは一般的な考え方ですが、実際の実行 (気にする必要はありません) は少しトリッキーです。

あなたがよく陥る誤解の 1 つ: OpenGL は「初期化」されていません。もちろん、初期段階で特定のリソースを OpenGL にアップロードできますが、OpenGL はステート マシンとして、必要になる直前に必要な状態にする必要があります。

そして、あなたの本当の問題があります.頂点の位置はバッファオブジェクトにあります。しかし、あなたの色はそうではありません。しかし、OpenGL にポインターを与えているため、頂点バッファーへのオフセットとして誤って解釈されます。

glDrawElementsしたがって、呼び出しの直前に次の行を移動することをお勧めします。

#define BUFFER_OFFSET(bytes) ((GLubyte*) NULL + (bytes)) 
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);

glBindBuffer(GL_ARRAY_BUFFER, vbufferid);
glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));

glBindBuffer(GL_ARRAY_BUFFER, 0); // or put the colors into a VBO as well
glColorPointer(3, GL_FLOAT, 0,  colors);

glDrawElements(…

また、バッファは glVertexPointer への呼び出しを行う前に明示的にバインドされ、カラー ポインタの前にバインド解除されることに注意してください。

しかし、VBO にいくつかの属性を持ち、いくつかを持たないことは、目的を無効にします。したがって、すべての頂点属性を VBO に移動することをお勧めします。できれば単一の VBO を、配列を 1 つずつ (ストライド 0 とそれらの間のオフセットを使用) またはインターリーブ (ストライド = 属性ベクトル全体のサイズ、オフセットはオフセットへのオフセット) に移動することをお勧めします。最初の属性ベクトル)。

更新コードの例:

VBO へのアップロード

unsigned int vbufferid;
glGenBuffers(1, &vbufferid);  
glBindBuffer(GL_ARRAY_BUFFER, vbufferid); 

int vertexbufsize = (3)*numVertices*sizeof(float);
int colorbufsize = (3)*numVertices*sizeof(float);
glBufferData(GL_ARRAY_BUFFER, vertexbufsize + colorbufsize, NULL, GL_STATIC_DRAW); // data=NULL : initialize, but don't copy

glBufferSubData(GL_ARRAY_BUFFER, 0, vertexbufsize, vertices);
glBufferSubData(GL_ARRAY_BUFFER, vertexbufsize, colorbufsize, vertices);

VBOを組み合わせた描画

#define BUFFER_OFFSET(bytes) ((GLubyte*) NULL + (bytes)) 
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);

glBindBuffer(GL_ARRAY_BUFFER, vbufferid);
glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));
glColorPointer(3, GL_FLOAT, 0,  BUFFER_OFFSET(vertexbufsize));

glDrawElements(…
于 2012-12-21T14:33:46.930 に答える