OpenGL ESプレミアムステップ:VBOとIBO

10267 ワード

皆さん、こんにちは、これは私の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 shaderattribute変数に指定する役割を果たしています.ここでは詳細については言及していません.glVertexAttribPointer()という方法で頂点データを指定していますが、頂点データを常に表示に保存することはありません.私たちがレンダリングするとき、アクセスするデータはすべて表示に保存する必要があります.そのため、レンダリングするたびに、OpenGLでは、これらの頂点データをメモリからビデオメモリにコピーする操作があります.これにより、いくつかの問題が発生します.
  • は、レンダリングのたびにコピーされるため、メモリの頂点データはずっと残っていなければなりません.そうしないと、コピーするときにデータがコピーされません.
  • もう1つは、頂点のデータ量が大きい場合、レンダリングのたびにこのようなコピーをすると、性能に問題があります.私たちの例では、頂点は非常に少ないですが、頂点が多いのはいつですか.例えば、いくつかの変形効果を作ると、グリッドを分割することがよくあります.一般的には、分割が多ければ多いほど、効果が繊細になると、頂点が多くなります.また、3 Dレンダリングをするとき、通常は頂点も多く、1つの3 Dモデルには1万個以上の頂点があります.

  • レプリケーションを避ける方法はありますか?この場合、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の頂点を教えてくれる頂点インデックスを使用します.これにより、パッチの数が多い場合に役立ちます.
    次に、VBOIBOの使用方法について説明します.まず、頂点データと頂点インデックスデータを見てみましょう.
    //  、 
    // 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
                            )
    

    ここでは、頂点とテクスチャ座標を組み合わせていきます.これもVBOIBOの従来の最適化方法に合わせて行われています.その利点は、頂点とテクスチャ座標を記憶に近づけることであり、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]
    

    作成時にはVBOIBOの違いはなく、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をバインドすることです.この点は、textureframe 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バイト目のデータの開始位置を指定します.
    これにより、VBOIBOを設定し、レンダリング時にVBOIBOを直接バインドすることで、対応する頂点とテクスチャデータを使用することができます.
    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枚の図をレンダリングして、効果から何の違いも見えません.
    コードは私のgithubOpenGLESProプロジェクトの中で、本文はSampleVBOAndIBOに対応して、プロジェクトのリンク:github.com/kenneycode/…
    読んでくれてありがとう!
    転載先:https://juejin.im/post/5ce55ae95188253114078ad7