• Advertisement
Sign in to follow this  

Noob question about glDrawArrays

This topic is 1250 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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
Edited by BobMcGee123

Share this post


Link to post
Share on other sites
Advertisement

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

        }
Edited by BobMcGee123

Share this post


Link to post
Share on other sites

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();

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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 ) );
Edited by BobMcGee123

Share this post


Link to post
Share on other sites

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. 

Edited by BobMcGee123

Share this post


Link to post
Share on other sites

 

 

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/

Edited by mark ds

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement