OpenGL ESプレミアムステップ:VBOとIBO
10267 ワード
皆さん、こんにちは、これは私の
今日は
このコードはよく知られているはずですが、頂点データをは、レンダリングのたびにコピーされるため、メモリの頂点データはずっと残っていなければなりません.そうしないと、コピーするときにデータがコピーされません. もう1つは、頂点のデータ量が大きい場合、レンダリングのたびにこのようなコピーをすると、性能に問題があります.私たちの例では、頂点は非常に少ないですが、頂点が多いのはいつですか.例えば、いくつかの変形効果を作ると、グリッドを分割することがよくあります.一般的には、分割が多ければ多いほど、効果が繊細になると、頂点が多くなります.また、3 Dレンダリングをするとき、通常は頂点も多く、1つの3 Dモデルには1万個以上の頂点があります.
レプリケーションを避ける方法はありますか?この場合、
これは普通の頂点データで、私たちのチュートリアルで何度も使ったことがあります.それは2つの三角形で矩形を構成し、
次に、
ここでは、頂点とテクスチャ座標を組み合わせていきます.これも
次に、
作成時には
次に、頂点のテクスチャデータを
主なキーは、まず
これにより、
効果を見てみると、1枚の図をレンダリングして、効果から何の違いも見えません.
コードは私の
読んでくれてありがとう!
転載先:https://juejin.im/post/5ce55ae95188253114078ad7
OpenGL ES
の高級進級シリーズの文章で、私のgithub
の上で本シリーズの文章に対応するプロジェクトがあって、注目を歓迎して、リンク:github.com/kenneycode/… 今日は
VBO(Vertex Buffer Object)
とIBO(Index Buffer Object)
を紹介します.まず、コードから始めて、徐々に紹介しましょう.// buffer
// Put the triangle vertex data into the vertexDataBuffer
vertexDataBuffer = ByteBuffer.allocateDirect(vertexData.size * java.lang.Float.SIZE / 8)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
vertexDataBuffer.put(vertexData)
vertexDataBuffer.position(0)
// , LOCATION_ATTRIBUTE_POSITION, OpenGL 2.0 location
// Enable the parameter of the location. Here we can simply use LOCATION_ATTRIBUTE_POSITION, while in OpenGL 2.0 we have to query the location of the parameter
GLES30.glEnableVertexAttribArray(LOCATION_ATTRIBUTE_POSITION)
// a_position
// Specify the data of a_position
GLES30.glVertexAttribPointer(LOCATION_ATTRIBUTE_POSITION, VERTEX_COMPONENT_COUNT, GLES30.GL_FLOAT, false, 0, vertexDataBuffer)
このコードはよく知られているはずですが、頂点データを
vertex shader
のattribute
変数に指定する役割を果たしています.ここでは詳細については言及していません.glVertexAttribPointer()
という方法で頂点データを指定していますが、頂点データを常に表示に保存することはありません.私たちがレンダリングするとき、アクセスするデータはすべて表示に保存する必要があります.そのため、レンダリングするたびに、OpenGL
では、これらの頂点データをメモリからビデオメモリにコピーする操作があります.これにより、いくつかの問題が発生します.レプリケーションを避ける方法はありますか?この場合、
VBO
を使用します.これは頂点データとバインドできます.バインドされた頂点データは常に表示メモリに格納されています.これらの頂点データを使用する必要がある場合は、このVBO
を直接バインドすればいいので、コピープロセスはありません.IBO
は何ですか?VBO
と似ています.VBO
は頂点データの複製を避けるため、IBO
は頂点インデックスデータの複製を避けるためです.頂点インデックスとは何ですか.まず、頂点データを見てみましょう.//
// The vertex data of a triangle
private val vertexData = floatArrayOf(
-1f, -1f, //
-1f, 1f, //
1f, 1f, //
-1f, -1f, //
1f, 1f, //
1f, -1f //
)
これは普通の頂点データで、私たちのチュートリアルで何度も使ったことがあります.それは2つの三角形で矩形を構成し、
GL_TRIANGLES
を適用した描画モードをレンダリングします(描画モードは私の文章「Android OpenGL ES 2.0ハンドヘルド教育(5)-描画モード」を参考にすることができます).この6つの頂点は重複しており、1つの矩形は4つの頂点だけでいいことが簡単にわかります.いくつかの点は異なる三角形の間で共用されていますが、どのようにして異なる三角形の間で共用されますか?これは、各ポイントが座標で与えられるのではなく、インデックスの方法でOpenGL
の頂点を教えてくれる頂点インデックスを使用します.これにより、パッチの数が多い場合に役立ちます.次に、
VBO
とIBO
の使用方法について説明します.まず、頂点データと頂点インデックスデータを見てみましょう.// 、
// The vertex data and texture coordinate data of triangles
private val vertexData = floatArrayOf(
-1f, -1f, 0f, 1f, // x, y, u, v
-1f, 1f, 0f, 0f,
1f, 1f, 1f, 0f,
1f, -1f, 1f, 1f
)
ここでは、頂点とテクスチャ座標を組み合わせていきます.これも
VBO
とIBO
の従来の最適化方法に合わせて行われています.その利点は、頂点とテクスチャ座標を記憶に近づけることであり、OpenGL
がデータを取得し、性能を向上させることができます.特に、3 Dレンダリングでは、データは一般的にこのように組織されています.次に、
glGenBuffers
を使用してVBO
およびIBO
を作成します.// VBO IBO
// Create VBO and IBO
val buffers = IntArray(2)
GLES30.glGenBuffers(buffers.size, buffers, 0)
vbo = buffers[0]
ibo = buffers[1]
作成時には
VBO
とIBO
の違いはなく、buffer
と呼ばれ、実際に使用されているときに違いが現れることがわかります.次に、頂点のテクスチャデータを
VBO
にロードします.// VBO
// Load vertex data into VBO
val vertexDataBuffer = ByteBuffer.allocateDirect(vertexData.size * java.lang.Float.SIZE / 8)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
vertexDataBuffer.put(vertexData)
vertexDataBuffer.position(0)
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo)
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, vertexDataBuffer.capacity() * java.lang.Float.SIZE / 8, vertexDataBuffer, GLES30.GL_STATIC_DRAW)
GLES30.glEnableVertexAttribArray(LOCATION_ATTRIBUTE_POSITION)
GLES30.glEnableVertexAttribArray(LOCATION_ATTRIBUTE_TEXTURE_COORDINATE)
GLES30.glVertexAttribPointer(LOCATION_ATTRIBUTE_POSITION, 2, GLES30.GL_FLOAT, false, 16, 0)
GLES30.glVertexAttribPointer(LOCATION_ATTRIBUTE_TEXTURE_COORDINATE, 2, GLES30.GL_FLOAT, false, 16, 8)
主なキーは、まず
glBindBuffer
で私たちが操作しているbuffer
をバインドすることです.この点は、texture
とframe buffer
を操作しているときとよく似ていて、操作前にバインドされています.次にglBufferData
でデータを与え、ここで最後のパラメータはOpenGL
にいくつかの最適化を促すために使用され、例えばここではGL_STATIC_DRAW
を伝えた.すなわち、私たちのデータは変わらない.また、GL_DYNAMIC_DRAW
のようにOpenGL
というbuffer
のデータが変わることを示す他の設定もある.glVertexAttribPointer
で頂点とテクスチャデータを指定する場合、私たちは以前のように直接データを転送しません.このとき、私たちのデータはVBO
の中にあるので、ここでは再転送する必要はありません.ここでは最後の2つのパラメータに重点を置いています.最後から2番目のパラメータはstride
、つまりOpenGL
を指定してデータを取りに行ったときのスパンです.ここでは頂点とテクスチャデータを組み合わせたので、したがって、1つのデータは、2つの頂点と2つのテクスチャ座標、すなわち4つのfloat
、16バイトである.最後から最初のパラメータは、1つのデータで頂点を配置してからテクスチャ座標を配置するため、頂点では0、テクスチャ座標では8バイト目のデータの開始位置を指定します.これにより、
VBO
とIBO
を設定し、レンダリング時にVBO
とIBO
を直接バインドすることで、対応する頂点とテクスチャデータを使用することができます.override fun onDrawFrame(gl: GL10?) {
//
// Set the color which the screen will be cleared to
GLES30.glClearColor(0.9f, 0.9f, 0.9f, 1f)
//
// Clear the screen
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)
// , GLSurfaceView
// Set the viewport to the full GLSurfaceView
GLES30.glViewport(0, 0, glSurfaceViewWidth, glSurfaceViewHeight)
// ,
// Set the status before rendering
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo)
GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, ibo)
GLES30.glActiveTexture(GLES30.GL_TEXTURE0)
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, imageTexture)
// draw TRIANGLES , 3
// Call the draw method with GL_TRIANGLES to render 3 vertices
GLES30.glDrawElements(GLES30.GL_TRIANGLES, indexData.size, GLES30.GL_UNSIGNED_INT, 0)
}
効果を見てみると、1枚の図をレンダリングして、効果から何の違いも見えません.
コードは私の
github
のOpenGLESPro
プロジェクトの中で、本文はSampleVBOAndIBO
に対応して、プロジェクトのリンク:github.com/kenneycode/… 読んでくれてありがとう!
転載先:https://juejin.im/post/5ce55ae95188253114078ad7