Noob question about glDrawArrays

Started by
6 comments, last by mark ds 9 years, 7 months ago

Hi,

I am looking at code from a tutorial that sets up a VBO and draws a static mesh. I noticed that the size of the vertex array is not divisible by three (it is 2904), yet the call to glDrawArrays(GL_TRIANGLES) works. How? Wouldn't that be the same as the immediate mode code I supplied in the #if/#else branch?

See the code at the very bottom.


        // Bind our texture in Texture Unit 0

        glActiveTexture(GL_TEXTURE0);

        glBindTexture(GL_TEXTURE_2D, Texture);

        // Set our "myTextureSampler" sampler to user Texture Unit 0

        glUniform1i(TextureID, 0);



        // 1rst attribute buffer : vertices

        glEnableVertexAttribArray(0);

        glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);

        glVertexAttribPointer(

            0,                  // attribute

            3,                  // size

            GL_FLOAT,           // type

            GL_FALSE,           // normalized?

            0,                  // stride

            (void*)0            // array buffer offset

            );



        // 2nd attribute buffer : UVs

        glEnableVertexAttribArray(1);

        glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);

        glVertexAttribPointer(

            1,                                // attribute

            2,                                // size

            GL_FLOAT,                         // type

            GL_FALSE,                         // normalized?

            0,                                // stride

            (void*)0                          // array buffer offset

            );



        // 3rd attribute buffer : normals

        glEnableVertexAttribArray(2);

        glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);

        glVertexAttribPointer(

            2,                                // attribute

            3,                                // size

            GL_FLOAT,                         // type

            GL_FALSE,                         // normalized?

            0,                                // stride

            (void*)0                          // array buffer offset

            );



        // Draw the triangles !

        // Aren't these two methods of rendering specifying the same command?

        // vertices.size() = 2904 (capacity=3597)

#if 0

        for(int i=0;i<vertices.size();i+=3)

        {

            for(int j=0;j<3;j++)

            {

                glBegin(GL_TRIANGLES);

                    glm::vec3 &v=vertices[i+j];

                    glm::vec2 &t=uvs[i+j];

                    glm::vec3 &n=normals[i+j];

                    glNormal3fv(&n.x);

                    glTexCoord2fv(&t.x);

                    glVertex3fv(&v.x);

                glEnd();

                GLenum err=glGetError(); //1282 = GL_INVALID_OPERATION

        }

#else
        glDrawArrays(GL_TRIANGLES, 0, vertices.size() ); // Why doesn't this fail. 
        GLenum err=glGetError(); //Success
#endif
Advertisement

2904 / 3 = 968. (it is divisible)

New C/C++ Build Tool 'Stir' (doesn't just generate Makefiles, it does the build): https://github.com/space222/stir

Awesome. Epic brain fart.

Isn't this immediate mode version equivalent to the glDrawArrays call? e.g., shouldn't this work.

I believe the glBegin can come outside the entire for loop, I'm just trying to understand this conceptually.


        for(int i=0;i<vertices.size();i+=3)

        {

            for(int j=0;j<3;j++)

            {

                glBegin(GL_TRIANGLES);

                    glm::vec3 &v=vertices[i+j];

                    glm::vec2 &t=uvs[i+j];

                    glm::vec3 &n=normals[i+j];

                    glNormal3fv(&n.x);

                    glTexCoord2fv(&t.x);

                    glVertex3fv(&v.x);

                glEnd();

                GLenum err=glGetError(); //1282 = GL_INVALID_OPERATION

        }

A triangle needs three vertices, but you are only emitting one vertex before closing the triangle. At the very least, you need to put the glBegin/glEnd around the inner for-loop so that all three vertices are emitted for one triangle. Furthermore, the constant is called GL_TRIANGLES, not GL_TRIANGLE; observe the plural form, so you can emit as many triangles as necessary before closing the series of triangles.

glBegin(GL_TRIANGLES);
 
for(int i=0;i<vertices.size();i+=3) {
    for(int j=0;j<3;j++) {
        ...
        glNormal3fv(&n.x);
        glTexCoord2fv(&t.x);
        glVertex3fv(&v.x);
    }
}
 
glEnd();

Btw, if you don't provide enough vertices for a triangle, draw call will be issued, and nothing will be drawn. It doesn't fails, it just does nothing.

Say for example that you provide 8 vertices, only two triangles would get drawn, last one wouldn't because you're missing the last vertex. OpenGL doesn't crashes right away on that sort of thing, prefers to silently fail.

"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

My journals: dustArtemis ECS framework and Making a Terrain Generator

Thank you for your responses, it is very helpful. Does changing to immediate mode rendering require setting up the texturing and shader properties in a different manner? The mesh does not currently show on the screen, but I believe the immediate mode loop is correct this time.

Here is the rendering loop as it stands. I have deleted large portions of it that related to setting up the VBO, as shown in the first post. It did not work with that code, either, but the VBO code listed things like attribute 1, 2 and 3 which related to the vertex pointer, texture coordinate pointer and normal pointer. I do not know if that still needs to be enabled (doesn't make a difference when I put it back in).


    do{

        // Clear the screen
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Use our shader
        glUseProgram(programID);

        // Compute the MVP matrix from keyboard and mouse input
        computeMatricesFromInputs();
        glm::mat4 ProjectionMatrix = getProjectionMatrix();
        glm::mat4 ViewMatrix = getViewMatrix();
        glm::mat4 ModelMatrix = glm::mat4(1.0);
        glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;

        // Send our transformation to the currently bound shader,
        // in the "MVP" uniform
        glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
        glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &ModelMatrix[0][0]);
        glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);

        glm::vec3 lightPos = glm::vec3(4,4,4);
        glUniform3f(LightID, lightPos.x, lightPos.y, lightPos.z);

        // Bind our texture in Texture Unit 0
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, Texture);
        // Set our "myTextureSampler" sampler to user Texture Unit 0
        glUniform1i(TextureID, 0);

        //Immediate mode rendering I am trying to get working
        glBegin(GL_TRIANGLES);
        for(int i=0;i<vertices.size();i++)
        {
            //for(int j=0;j<3;j++)
            {
                glm::vec3 &v=vertices[i];
                glm::vec2 &t=uvs[i];
                glm::vec3 &n=normals[i];
                glNormal3fv(&n.x);
                glTexCoord2fv(&t.x);
                glVertex3fv(&v.x);
                GLenum err=glGetError(); //0 = Success
            }
        }
        glEnd();

        // Swap buffers
        glfwSwapBuffers();

    } // Check if the ESC key was pressed or the window was closed
    while( glfwGetKey( GLFW_KEY_ESC ) != GLFW_PRESS &&
        glfwGetWindowParam( GLFW_OPENED ) );

The goal for my little exercise is to alter this tutorial code such that I can manipulate the vertices individually through the shader such that they follow a sine wave. The reason I am doing immediate mode rendering is because that's how I saw it done in NeHe's shader tutorial. I don't want to use cg. I'm not sure if any of this VBOs right approach. My understanding is that VBOs are really for static meshes, that's cumbersome to use them for dynamic meshes (but it can be done).

NeHe shader tutorial

EDIT:

I am still unsure why the immediate mode code above doesn't work, but, as I understand it the point is moot as immediate mode is pretty much obsolete, from what I've read. Furthmore I just created the necessary variables to modify the verts through the shader, so, I am all set for the time being. I'm pretty much an expert now.

I am still unsure why the immediate mode code above doesn't work, but, as I understand it the point is moot as immediate mode is pretty much obsolete, from what I've read. Furthmore I just created the necessary variables to modify the verts through the shader, so, I am all set for the time being. I'm pretty much an expert now.

In the olden days experts rode horses, now they drive cars. I suspect you're riding a horse! Move away from immediate mode rendering, and look into data stored on the GPU - it's MUCH faster! wink.png

Try here: http://www.arcsynthesis.org/gltut/index.html and here http://antongerdelan.net/opengl/

This topic is closed to new replies.

Advertisement