Ivan P.
Ivan P.

Reputation: 926

How to correctly render meshes in separate opengl array objects?

I am trying to render two triangles using separate Vertex Array objects. I am using OpenTK on C# (it provides almost the same API compared to defined OpenGL API). Here is my code:

I start from declaring my variables.

    public partial class Form1 : Form
{
    public Form1() {
        InitializeComponent();
    }
    bool loaded = false; //do not use glcontrol before it is not loaded
    private uint VAO1; 
    private uint object1_vertex_buffer; private uint object1_vertices_size; private uint object1_index_buffer;
    private uint object2_vertex_buffer; private uint object2_vertices_size; private uint object2_index_buffer;
    private uint VAO2;
    private uint VBO;
    int VertexShader;
    int FragmentShader;
    int ShaderProgram;
    private float[] object1_vertices = new float[] {
       -0.2f, 0.0f, 0.0f, 
        0.2f, 0.0f, 0.0f, 
        0.0f, 0.2f, 0.0f
    };
    private float[] object2_vertices = new float[] {
        -0.5f, 0.0f, 0.0f,
        0.5f, 0.0f, 0.0f,
        0.0f, 0.4f, 0.0f
    };
    private int[] object1_indices = new int[] { 0, 1, 2 };
    private int[] object2_indices = new int[] { 0, 1, 2 };

I do painting of every frame here:

    private void glControl1_Paint(object sender, PaintEventArgs e)
    {
        if (!loaded)//<--------------------------------------
            return;//<--------------------------------------
        // Clear the color buffer.
        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
        GL.UseProgram(ShaderProgram);
        // Object 1
        GL.BindVertexArray(VAO1);
        // drawelements requires count of elements, not bytes
        GL.DrawElements(PrimitiveType.Triangles, object1_indices.Length, DrawElementsType.UnsignedInt, 0);

        // Object 2
        GL.BindVertexArray(VAO2);
        GL.DrawElements(PrimitiveType.Triangles, object2_indices.Length, DrawElementsType.UnsignedInt, 0);

       ErrorCode miauw = GL.GetError(); /// AND I GET HERE NO ERROR!
        /// at the end I have a screen filled by a background color, which is set in GL.ClearColor()
        glControl1.SwapBuffers();
    }

Here I do initialization of OpenGL arrays and buffers. I init here two Vertex Array Objects ( one for each triangle ), and two Buffers (for each) : vertices and indices. I set the proper length in bytes for them

    private void glControl1_Load(object sender, EventArgs e) {
        loaded = true;
        GL.ClearColor(Color.SkyBlue);
        GL.Enable(EnableCap.DepthTest);
        GL.DepthFunc(DepthFunction.Less);

        // Load the source of the vertex shader and compile it.
        VertexShader = GL.CreateShader(ShaderType.VertexShader);
        GL.ShaderSource(VertexShader, MyOpenglThings.VertexShaderSource);
        GL.CompileShader(VertexShader);

        // Load the source of the fragment shader and compile it.
        FragmentShader = GL.CreateShader(ShaderType.FragmentShader);
        GL.ShaderSource(FragmentShader, MyOpenglThings.FragmentShaderSource);
        GL.CompileShader(FragmentShader);

        // Create the shader program, attach the vertex and fragment shaders and link the program.
        ShaderProgram = GL.CreateProgram();
        GL.AttachShader(ShaderProgram, VertexShader);
        GL.AttachShader(ShaderProgram, FragmentShader);
        GL.LinkProgram(ShaderProgram);


        // https://stackoverflow.com/questions/34068792/drawing-multiple-objects-in-opengl-with-different-buffers
        // https://stackoverflow.com/questions/34072056/rendering-two-objects-with-opengl-and-vertex-array-objects
        GL.GenVertexArrays(1, out VAO1);
        GL.BindVertexArray(VAO1);
        GL.GenVertexArrays(1, out VAO2);
        GL.BindVertexArray(VAO2);

        // Object 1 vertex positions
        GL.GenBuffers(1, out object1_vertex_buffer);
        GL.BindBuffer(BufferTarget.ArrayBuffer, object1_vertex_buffer);
        GL.BufferData(BufferTarget.ArrayBuffer, object1_vertices.Length * sizeof(float), object1_vertices,BufferUsageHint.StaticDraw);
        GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0);
        // Object 1 vertex indices
        GL.GenBuffers(1, out object1_index_buffer);
        GL.BindBuffer(BufferTarget.ElementArrayBuffer, object1_index_buffer);
        GL.BufferData(BufferTarget.ElementArrayBuffer, object1_indices.Length * sizeof(int), object1_indices, BufferUsageHint.StaticDraw);

        GL.BindVertexArray(VAO2);
        // Object 2 vertex positions
        GL.GenBuffers(1, out object2_vertex_buffer);
        GL.BindBuffer(BufferTarget.ArrayBuffer, object2_vertex_buffer);
        GL.BufferData(BufferTarget.ArrayBuffer, object2_vertices.Length * sizeof(float), object2_vertices, BufferUsageHint.StaticDraw);
        GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0);
        // Object 2 vertex indices
        GL.GenBuffers(1, out object2_index_buffer);
        GL.BindBuffer(BufferTarget.ElementArrayBuffer, object2_index_buffer);
        GL.BufferData(BufferTarget.ElementArrayBuffer, object2_indices.Length*sizeof(int), object2_indices, BufferUsageHint.StaticDraw);

    }

I free the allocated opengl resources (it does not relate to my question, it is not even called by now heh)

    private void CleanupOpenGL() {
          // ...
    }

}

I have copied shader codes:

class MyOpenglThings
{

    // A simple vertex shader possible. Just passes through the position vector.
    public const string VertexShaderSource = @"
        #version 330
        layout(location = 0) in vec4 position;
        void main(void)
        {
            gl_Position = position;
        }
    ";

    // A simple fragment shader. Just a constant red color.
    public const string FragmentShaderSource = @"
        #version 330
        out vec4 outputColor;
        void main(void)
        {
            outputColor = vec4(1.0, 0.0, 0.0, 1.0);
        }
    ";
}

But when I launch a program, I get only a window filled with SkyBlue Color. At least, opengl is capable of rendering background color. But I want to get two red triangles too.

What's wrong in there? How do I get rendering two meshes in Vertex Array Objects?

Upvotes: 2

Views: 1126

Answers (2)

Ivan P.
Ivan P.

Reputation: 926

The answer above really helped. (I am posting here, because comment does not fit code well.) So, my load code now looks like:

        private void glControl1_Load(object sender, EventArgs e) {
        loaded = true;
        GL.ClearColor(Color.SkyBlue);
        GL.Enable(EnableCap.DepthTest);
        GL.DepthFunc(DepthFunction.Less);

        // Load the source of the vertex shader and compile it.
            // ....
        // Load the source of the fragment shader and compile it.
            // ....
        // Create the shader program, attach the vertex and fragment shaders and link the program.
            // ....
        GL.GenVertexArrays(1, out VAO1);
        GL.BindVertexArray(VAO1);

        // Object 1 vertex positions
        GL.GenBuffers(1, out object1_vertex_buffer);
        GL.BindBuffer(BufferTarget.ArrayBuffer, object1_vertex_buffer);
        GL.BufferData(BufferTarget.ArrayBuffer, object1_vertices.Length * sizeof(float), object1_vertices,BufferUsageHint.StaticDraw);
        GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0);
        GL.EnableVertexAttribArray(0);
        // Object 1 vertex indices
        GL.GenBuffers(1, out object1_index_buffer);
        GL.BindBuffer(BufferTarget.ElementArrayBuffer, object1_index_buffer);
        GL.BufferData(BufferTarget.ElementArrayBuffer, object1_indices.Length * sizeof(int), object1_indices, BufferUsageHint.StaticDraw);

        GL.GenVertexArrays(1, out VAO2);
        GL.BindVertexArray(VAO2);
        // Object 2 vertex positions
        GL.GenBuffers(1, out object2_vertex_buffer);
        GL.BindBuffer(BufferTarget.ArrayBuffer, object2_vertex_buffer);
        GL.BufferData(BufferTarget.ArrayBuffer, object2_vertices.Length * sizeof(float), object2_vertices, BufferUsageHint.StaticDraw);
        GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0);
        GL.EnableVertexAttribArray(0);
        // Object 2 vertex indices
        GL.GenBuffers(1, out object2_index_buffer);
        GL.BindBuffer(BufferTarget.ElementArrayBuffer, object2_index_buffer);
        GL.BufferData(BufferTarget.ElementArrayBuffer, object2_indices.Length*sizeof(int), object2_indices, BufferUsageHint.StaticDraw);

    }

parameter of GL.EnableVertexAttribArray should match the value in shader program.

Also changed a bit geometry coordinates, because triangles used to overlap.

Upvotes: 0

Rabbid76
Rabbid76

Reputation: 210928

When you define an array of generic vertex attribute data (GL.VertexAttribPointer), the Vertex array object which should store the definition has to be bound.
This is the case for the specification of VAO2, but not for VAO1, because after

GL.GenVertexArrays(1, out VAO1);
GL.BindVertexArray(VAO1);
GL.GenVertexArrays(1, out VAO2);
GL.BindVertexArray(VAO2);

the vertex array object VAO2 is bound.

Furthermore, the generic vertex attribute array has to be enabled by GL.EnableVertexAttribArray. The state if a vertex array is enabled or disabled is stored in the vertex array object, too:

GL.GenVertexArrays(1, out VAO1);
GL.BindVertexArray(VAO1);

// Object 1 vertex positions
GL.GenBuffers(1, out object1_vertex_buffer);
GL.BindBuffer(BufferTarget.ArrayBuffer, object1_vertex_buffer);
GL.BufferData(BufferTarget.ArrayBuffer, object1_vertices.Length * sizeof(float), object1_vertices,BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0);
GL.EnableVertexAttribArray(0);
// [...]

GL.GenVertexArrays(1, out VAO2);
GL.BindVertexArray(VAO2);

// Object 2 vertex positions
GL.GenBuffers(1, out object2_vertex_buffer);
GL.BindBuffer(BufferTarget.ArrayBuffer, object2_vertex_buffer);
GL.BufferData(BufferTarget.ArrayBuffer, object2_vertices.Length * sizeof(float), object2_vertices, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0);
GL.EnableVertexAttribArray(0);
// [...]

Upvotes: 2

Related Questions