10

いくつかのチュートリアルに従い、独自の実験をコーディングすることで、OpenGLを数日間学習しています。しかし、私が継続するのを妨げるものが本当に理解できないことが1つあります。私は数時間グーグルをしていて、私の質問に対する答えはまだ見つかりませんでした。

個々の頂点ごとに、個別のカラー値とテクスチャ座標をどこで指定する必要がありますか?これらのプロパティは、常に頂点の位置と同じ配列(構造体)にリストする必要がありますか?そのようです:

const Vertex Vertices[] = {
    // Front
    {{1, -1, 0}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
    {{1, 1, 0}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
    {{-1, 1, 0}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
    {{-1, -1, 0}, {0, 0, 0, 1}, {0, 0}},

    ...

または、色の値とテクスチャの座標を別々の配列に配置する方法はありますか?しかし、次に疑問が生じglDrawElementsます。別々の配列でどのように呼び出すのですか?

なぜこれらの値を分離したいのか疑問に思っている場合:私は現在obj-cで独自の.objパーサーを作成していて、疑問に思っていました:テクスチャなしでモデルをロードし、物体?または:テクスチャのみがマップされ、頂点ごとに個別の色がないモデルをロードする場合はどうなりますか?そして:あまりにも多くのデータで頂点構造体を膨らませる色の値とテクスチャ座標を入れていません。

4

3 に答える 3

22

実際には、いくつかの配列/バッファを使用して、頂点データを位置、色などに分離する通常の方法です。

前回ES2.0に接触したのは、WebGLのコンテキストでした(仕様は少し異なりますが、最終的にはES 2.0に基づいています)。

基本的に行われるのは、を使用して個別のバッファにデータを書き込むことです。

glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), positions, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), colors, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

...

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(ushort), indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

この場合、位置と色は頂点データを含むフロート配列であり、インデックスは符号なしショートとしてインデックスを含みます。

このデータをレンダリングするには、シェーダーへのバッファーと属性ポインターを使用します。

glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(vertexPositionAttribute, 3,  GL_FLOAT, false, 0, 0);

glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glVertexAttribPointer(vertexColorAttribute, 4, GL_FLOAT, false, 0, 0);

最後に、インデックスバッファをバインドします。

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);

レンダリング:

glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, 0);

属性を取得するには:

glUseProgram(shaderProgram);

vertexPositionAttribute= glGetAttribLocation(shaderProgram, "vertexPosition");
glEnableVertexAttribArray(vertexPositionAttribute);

vertexColorAttribute = glGetAttribLocation(shaderProgram, "vertexColor");
glEnableVertexAttribArray(vertexColorAttribute );

...

カスタムシェーダー(固定機能を使用)がない場合は、使用できる可能性があります

glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexPointer(3,  GL_FLOAT, false, 0, 0);

glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glColorPointer(4, GL_FLOAT, false, 0, 0);

代わりは。ただし、古くなっているので(ES 2.0で利用できる場合)、これには反対することをお勧めします。それでも使用したい場合は、バッファビジネス全体をスキップして使用できます

glVertexPointer(3, GL_FLOAT, false, 0, positions);
glColorPointer(4, GL_FLOAT, false, 0, colors);

glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, indices);

それがあまり混乱せず、少し役立つことを願っています。さらに読むために、OpenGLを対象としていますが、Neheチュートリアルをお勧めします。

于 2012-01-06T12:24:18.053 に答える
2

もちろん、データを別のバッファーに入れることもできます。glVertexAttribPointer属性のソースを決定するのは呼び出しであることに注意してください。GL_ARRAY_BUFFERしたがって、属性に別のバッファーを使用するには、を呼び出す前に別のバッファーをバインドするだけglVertexAttribPointerです。glDrawElementsそれとは何の関係もありません:

glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
glVertexAttribPointer(0, ...);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glVertexAttribPointer(1, ...);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glDrawElements(...);

glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);

VBOを使用しない場合(ES 2.0で可能かどうかはわかりません)、glVertexAttribPointer属性ごとに異なる配列を使用して呼び出します。

glVertexAttribPointer(0, ..., positionArray);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, ..., colorArray);
glEnableVertexAttribArray(1);

glDrawElements(..., indexArray);

glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);

ただし、通常は、例のように単一の頂点の属性をまとめておく方が、キャッシュに適しているため、パフォーマンスが向上します。ほぼすべてのオブジェクトがすべての配列を使用している場合は、それらをまとめて、それを使用しないいくつかのオブジェクトの属性を有効にしない方がよい場合があります。ただし、使用される属性がオブジェクトごとに実際に異なる場合は、個別のバッファーソリューションの方が適している場合があります。また、すべての個別の属性配列を1つのVBOに次々に格納し、対応するバッファーオフセットをglVertexAttribPointer呼び出しで使用できるため、オブジェクトごとに1つのVBOのみが必要です。

ただし、もちろん、オブジェクトごとに1つのインデックス配列のみを使用でき、位置と色に異なるインデックス配列を使用することはできません。OBJファイルは実際に位置、法線、texCoordsに異なるインデックスを使用できるため、これにはOBJファイルから読み取ったデータを少し後処理する必要がある場合があります。

于 2012-01-06T12:46:28.443 に答える
1

それらをサブバッファに分けることができますが、それらを使用する場合はすべての頂点にそれらを使用する必要があり、インデックスバッファを使用する場合はすべて(位置、色、texcoordなど)に1つのインデックスバッファを使用する必要があります。これが私のコードからの抜粋です:

との割り当て

glBindBuffer(GL_ARRAY_BUFFER, mId);
glBufferData(GL_ARRAY_BUFFER,
               mMaxNumberOfVertices * (mVertexBlockSize + mNormalBlockSize + mColorBlockSize + mTexCoordBlockSize),
               0,
               mDrawMode);

で埋める

glBufferSubData(GL_ARRAY_BUFFER, mVertexOffset, numberOfVertsToStore * mVertexBlockSize, vertices);
glBufferSubData(GL_ARRAY_BUFFER, mNormalOffset, numberOfVertsToStore * mNormalBlockSize, normals);
glBufferSubData(GL_ARRAY_BUFFER, mColorOffset, numberOfVertsToStore * mColorBlockSize, colors);
glBufferSubData(GL_ARRAY_BUFFER, mTexCoordOffset, numberOfVertsToStore * mTexCoordBlockSize, texCoords);

とこれでの使用法(ただし、clientStatesを絶えず切り替えることがベストプラクティスではないと思います)

void Vbo::draw(GLenum primMode)
{
  glEnableClientState(GL_VERTEX_ARRAY);
  glVertexPointer(mVertexComponents, GL_FLOAT, 0, (void*)mVertexOffset);

  if(mNormalBlockSize){
    glEnableClientState(GL_NORMAL_ARRAY);
    glNormalPointer(GL_FLOAT, 0, (void*)mNormalOffset);
  }
  if(mColorBlockSize){
    glEnableClientState(GL_COLOR_ARRAY);
    glColorPointer(mColorComponents, GL_FLOAT, 0, (void*)mColorOffset);
  }
  if(mTexCoordBlockSize){
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glTexCoordPointer(mTexCoordComponents, GL_FLOAT, 0, (void*)mTexCoordOffset);
  }

  if (mAttachedIndexBuffer)
  {
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mAttachedIndexBuffer);
    glDrawElements(primMode,
                   mAttachedIndexBuffer->getNumberOfStoredIndices(),
                   mAttachedIndexBuffer->getDataType(),
                   0);
  }
  else
  {
    glDrawArrays(primMode, 0, mNumberOfStoredVertices);
  }

  if(mTexCoordBlockSize)
  {
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  }
  if(mColorBlockSize)
  {
    glDisableClientState(GL_COLOR_ARRAY);
  }
  if(mNormalBlockSize)
  {
    glDisableClientState(GL_NORMAL_ARRAY);
  }
  glDisableClientState(GL_VERTEX_ARRAY);
}    
于 2012-01-06T12:03:30.130 に答える