Index Buffer

Everything we draw in opengl is actually composed of triangles. If we want to draw a rectangle then we need to two triangles to create it. We have to know something that is important called Index Buffer at this point. 
a rectange which is created with two triangles
Normally, we can draw this shape with 6 vertices. But, if you notice 2 vertices are same for these triangles. Therefore, we need to store two extra vertices. Maybe, that's not a problem just for one rectangle. But it is a problem when drawing thousands vertices. As a solution for this issue, there is an option called Index Buffer. 
First we collect the vertices to be used in an float array that like we did before. For example, I'm going to use these vertices for this post:
  1. (-0.5, 0.5, 0)
  2. (0.5, 0.5, 0)
  3. (0.5, -0.5, 0)
  4. (-0.5, -0.5, 0)
If you notice each one of these vertices has own index value like (1,2,3,..). So, these vertices will be represented by unsigned integer typed values.
  1. (1, 2, 3) -> draw first triangle
  2. (2, 3, 4) -> draw second triangle
Let's how to do it in source code:
    public class App
    {
        Window? window;
        int vbo, vao, ebo;
I added new field called ebo which stands for element buffer object. Also the vertices and indices were added like in the below:
            float[] vertices = 
            {
                -0.5f, 0.5f, 0f,	// 0
                 0.5f, 0.5f, 0f,	// 1
                 0.5f, -0.5f, 0f,	// 2
                -0.5f, -0.5f, 0f	// 3
            };

            uint[] indices = 
            {
                0, 1, 3,
                1, 2, 3
            };
The ebo is created as follows and bind it and copied data from indices array to it:
            GL.GenVertexArrays(1, out vao);
            GL.BindVertexArray(vao);
            // create vbo to store the data in opengl and copy data to vbo
            GL.GenBuffers(1, out vbo);
            GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
            GL.BufferData(BufferTarget.ArrayBuffer, sizeof(float) * vertices.Length, vertices, BufferUsageHint.StaticDraw);
            // create ebo
            GL.GenBuffers(1, out ebo);
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, ebo);
            GL.BufferData(BufferTarget.ElementArrayBuffer, sizeof(int) * indices.Length, indices, BufferUsageHint.StaticDraw);
            // tell opengl how to use the data via attributes
            // position attribute
            int attrPosition_Position = GL.GetAttribLocation(shader.ShaderProgram, "aPos");
            GL.EnableVertexAttribArray(attrPosition_Position);
            GL.VertexAttribPointer(attrPosition_Position, 3, VertexAttribPointerType.Float, false, 0, 0);
                    
            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
            GL.BindVertexArray(0);
After that, we need to change draw method as DrawElements instead of DrawArrays method:
        private void Draw()
        {
            Clear();

            // draw triangle
            GL.UseProgram(shader.ShaderProgram);

            GL.BindVertexArray(vao);
            // GL.DrawArrays(PrimitiveType.Triangles, 0, 3);
            GL.DrawElements(PrimitiveType.Triangles, 6, DrawElementsType.UnsignedInt, 0);
            GL.BindVertexArray(0);
        }
We got this result:
Rectangle in OpenTK

No comments:

Post a Comment