2013-09-05 7 views
5

私はAndroid上でOpenGL ES 2.0を使用していますが、この質問は一般的なOpenGLの質問です。glVertexAttribPointerとglEnableVertexAttribArrayの有効範囲は何ですか?

私はOpenGLを学んだし、一度だけに対して、APIはフレームごとに呼ばれるように持っている正確に理解しようとしています。私は当初、毎フレームglVertexAttribPointerglEnableVertexAttribArrayを呼び出していましたが、テストプログラムを変更してShaderプログラムごとに呼び出すようにしたとき、私は期待した動作ではありません。

glVertexAttribPointerglEnableVertexAttribArrayは、特定のShaderプログラムのコンテキスト内でのみ意味があるため、すべてのフレームではなく、一度呼び出す必要があります。これはglVertexAttribPointerがの最初のパラメータで、glGetAttribLocationから返され、シェーダプログラムの変数名に対応する文字列を指定するためです。したがって、データは特定のシェイダープログラムの特定の「属性」変数に関連付けられているようです。

私のテストプログラムは、異なるフラグメントシェーダソース、異なる頂点シェーダソース、glLinkProgramなどの別々の呼び出しなど、全く異なる2つのプログラムを使用して、2つの互いに素なシェイプ(三角形)をレンダリングします。予想どおり - 両方の図形が正しく描画されているのがわかります。

m_glhook.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); 

// Shape/Program 1   
m_glhook.glUseProgram(m_iGlProgramId); 
int iPositionLocation = m_glhook.glGetAttribLocation(m_iGlProgramId, "a_Position"); 
m_bfVertices.rewind(); 
m_glhook.glVertexAttribPointer(iPositionLocation, 4, GLES20.GL_FLOAT, false, STRIDE, m_bfVertices); 
m_glhook.glEnableVertexAttribArray(iPositionLocation);  
gl.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); 

// Shape/Program 2 
m_glhook.glUseProgram(m_iGlProgramId2); 
int iPositionLocation2 = m_glhook.glGetAttribLocation(m_iGlProgramId2, "a_Position"); 
m_bfVertices2.rewind(); 
m_glhook.glVertexAttribPointer(iPositionLocation2, 4, GLES20.GL_FLOAT, false, STRIDE, m_bfVertices2); 
m_glhook.glEnableVertexAttribArray(iPositionLocation2); 
gl.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); 

次に、すべてのフレームに対して行われた呼び出しを以下のように変更しました。 m_bFirstDrawは最初のフレームではtrue、連続するフレームではfalseです。

m_glhook.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); 

// Shape/Program 1   
m_glhook.glUseProgram(m_iGlProgramId); 
if (m_bFirstDraw) 
{ 
    int iPositionLocation = m_glhook.glGetAttribLocation(m_iGlProgramId, "a_Position"); 
    m_bfVertices.rewind(); 
    m_glhook.glVertexAttribPointer(iPositionLocation, 4, GLES20.GL_FLOAT, false, STRIDE, m_bfVertices); 
    m_glhook.glEnableVertexAttribArray(iPositionLocation); 
} 
gl.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); 

// Shape/Program 2 
m_glhook.glUseProgram(m_iGlProgramId2); 
if (m_bFirstDraw) 
{   
    int iPositionLocation2 = m_glhook.glGetAttribLocation(m_iGlProgramId2, "a_Position"); 
    m_bfVertices2.rewind(); 
    m_glhook.glVertexAttribPointer(iPositionLocation2, 4, GLES20.GL_FLOAT, false, STRIDE, m_bfVertices2); 
    m_glhook.glEnableVertexAttribArray(iPositionLocation2); 
} 
gl.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); 
m_bFirstDraw = false; 

私は上記のコードを参照して動作が(最初のフレームのための呼び出しシーケンスがまったく同じであるため、理にかなっている)最初のフレームのすべてのために、まだ罰金であるということです。しかし、連続するフレームの場合、Shape1はShape2の頂点で描画されます。だからShape2はShape1の上に正確に描画されるので、私はShape2しか見ることができません。

は、なぜ一つのプログラムのためのデータ(形状頂点)の設定は、連続フレーム内の別のプログラムによって使用されるデータには影響を与えない...私はこれを理解する助けてください? GLSLプログラム(特に頂点シェーダは)あなたが実際に頂点ポインタでGLSLプログラムを提供しない、一般的なスロット番号に基づいて、頂点の属性を使用していますが、私は...

答えて

6

何かが欠けています。

これらのポインタは、OpenGLの新しいバージョンでVertex Array Objectsによって完全に処理される頂点配列状態の一部です。各プログラムに独自のポインタセットが必要な場合は、プログラムをバインドするときに状態を格納し、VAOをバインドするVAOを作成することをお勧めします。

VAOsが利用できない場合は、GLSLプログラムを切り替えるたびに、手動でセットアップするためにあなたのポインタを持っています。この場合、頂点配列ポインタ、バインドされた頂点バッファ、有効化/無効化された配列などが格納されるグローバルコンテキストが存在することに留意されたい。そのため、使用していない頂点アトリビュート配列を無効にすることに注意しなければなりません。また、無効なメモリからGLを読み込むこともできます。

VAOsははるかにエレガントなソリューションであり、彼らが利用可能な時はいつでもあなたはそれを好む必要があります。

+0

Answer Andonに感謝します。仕様を見ると、VAOはOpenGL ES 2.0では利用できないので、私はそれらを使うことはできません。ですから、VAOがなければ、プログラムを切り替えるたびに 'glVertexAttribPointer'と' glEnableVertexAttribArray'を呼び出す必要があります。私はすべてのフレーム(同じ順序で)を実行する複数のプログラムを持っている場合、これは効果的に私はすべてのプログラムのために、これらの関数を永遠のフレームのために呼び出さなければならないことを意味します。あれは正しいですか? –

+0

@DavidStone:異なる頂点バッファを使用して描画する場合や、シェイダーに正しいバインディング位置に適切なデータを供給するために、属性ポインタを別の場所にマップする必要がある場合にのみ、これを行う必要があります。 –

+0

OK私は今理解していると思います。私の2つのシェーダは、異なる頂点で動作する必要があり、同じ順序で、すべてのフレームで実行されます。したがって、その場合は、すべてのフレームに対して 'glVertexAttribPointer' **を2回**呼び出す必要があります。何らかの理由で、私が 'glGetAttribLocation'を呼び出してOpenGLに私の頂点属性インデックスを選択させると、常に0が選択されるので、私は両方の頂点属性に同じインデックスを使用しています。しかし、私は 'glBindAttribLocation' **がOpenGL ES 2.0で利用可能であることを発見しました。そして、この問題を避けて、2つのプログラムに異なるインデックスを指定することができます。 –

関連する問題