Jump to content
  • Advertisement
Sign in to follow this  
TheStudent111

Clarification on how OpenGL draws entities

This topic is 608 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

Not exactly sure how OpenGL draws individual geometric meshes with glDrawArray and glDrawElement. When you call glDrawArray, how exactly does OpenGL know which geometric mesh you are referring to? I used to think it was through VAO, but now I'm not sure. 

 

As shown in the attached image, I have two cubes, one acting as a lamp and another acting like a regular entity in a scene. I'm hazy as to how one draws each individual entity, I know the programmer would have to write the glDrawArray command, but does OpenGL know which one I'm referring to.

 

Initialization:



    GLfloat vertices[] = {

        -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,

         0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,

         0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,

         0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,

        -0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,

        -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,



        -0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,

         0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,

         0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,

         0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,

        -0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,

        -0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,



        -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,

        -0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,

        -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,

        -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,

        -0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,

        -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,



         0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,

         0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,

         0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,

         0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,

         0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,

         0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,



        -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,

         0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,

         0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,

         0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,

        -0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,

        -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,



        -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,

         0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,

         0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,

         0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,

        -0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,

        -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f

    };



    GLuint VBO1, containerVAO;

    glGenVertexArrays(1, &containerVAO);

    glGenBuffers(1, &VBO1);



    glBindBuffer(GL_ARRAY_BUFFER, VBO1);

    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);



   glBindVertexArray(containerVAO);

    // Position attribute

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);

    glEnableVertexAttribArray(0);

    // Normal attribute

    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));

    glEnableVertexAttribArray(1);







    GLuint VBO2;

    GLuint lampVAO;

    glGenVertexArrays(1, &lampVAO);

   glBindVertexArray(lampVAO);





        glGenBuffers(1, &VBO2);

        glBindBuffer(GL_ARRAY_BUFFER, VBO2);

        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);



    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);

    glEnableVertexAttribArray(0);

 

Loop:



        glClearColor(0.1f, 0.1f, 0.1f, 1.0f);

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);



        lightingShader.Use();

        GLint objectColorLoc = glGetUniformLocation(lightingShader.Program, "objectColor");

        GLint lightColorLoc  = glGetUniformLocation(lightingShader.Program, "lightColor");

        GLint lightPosLoc    = glGetUniformLocation(lightingShader.Program, "lightPos");

        GLint viewPosLoc     = glGetUniformLocation(lightingShader.Program, "viewPos");

        glUniform3f(objectColorLoc, 1.0f, 0.5f, 0.31f);

        glUniform3f(lightColorLoc,  1.0f, 1.0f, 1.0f);

        glUniform3f(lightPosLoc,    lightPos.x, lightPos.y, lightPos.z);

        glUniform3f(viewPosLoc,     camera.Position.x, camera.Position.y, camera.Position.z);



  

        glm::mat4 view;

        view = camera.GetViewMatrix();

        glm::mat4 projection = glm::perspective(camera.Zoom, (GLfloat)WIDTH / (GLfloat)HEIGHT, 0.1f, 100.0f);



        GLint modelLoc = glGetUniformLocation(lightingShader.Program, "model");

        GLint viewLoc  = glGetUniformLocation(lightingShader.Program, "view");

        GLint projLoc  = glGetUniformLocation(lightingShader.Program, "projection");



        glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));

        glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));





       glBindVertexArray(containerVAO);

        glm::mat4 model;

        glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));

        glDrawArrays(GL_TRIANGLES, 0, 36);











        lampShader.Use();



        modelLoc = glGetUniformLocation(lampShader.Program, "model");

        viewLoc  = glGetUniformLocation(lampShader.Program, "view");

        projLoc  = glGetUniformLocation(lampShader.Program, "projection");

        // Set matrices

        glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));

        glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));

        model = glm::mat4();

        model = glm::translate(model, lightPos);

        model = glm::scale(model, glm::vec3(1.0f));

        glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));



        glBindVertexArray(lampVAO);

        glDrawArrays(GL_TRIANGLES, 0, 36);



 
 

Vertex Shader (Regular Entity):

#version 330 core

layout (location = 0) in vec3 position;

layout (location = 1) in vec3 normal;



out vec3 Normal;

out vec3 FragPos;



uniform mat4 model;

uniform mat4 view;

uniform mat4 projection;



void main()

{

    gl_Position = projection * view *  model * vec4(position, 1.0f);

    FragPos = vec3(model * vec4(position, 1.0f));

    Normal = mat3(transpose(inverse(model))) * normal;  

}

Fragment Shader (Regular Entity)

#version 330 core

out vec4 color;



in vec3 FragPos;  

in vec3 Normal;  

 

uniform vec3 lightPos;

uniform vec3 viewPos;

uniform vec3 lightColor;

uniform vec3 objectColor;



void main()

{

    // Ambient

    float ambientStrength = 0.1f;

    vec3 ambient = ambientStrength * lightColor;

      

    // Diffuse

    vec3 norm = normalize(Normal);

    vec3 lightDir = normalize(lightPos - FragPos);

    float diff = max(dot(norm, lightDir), 0.0);

    vec3 diffuse = diff * lightColor;

    

    // Specular

    float specularStrength = 0.5f;

    vec3 viewDir = normalize(viewPos - FragPos);

    vec3 reflectDir = reflect(-lightDir, norm);  

    float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);

    vec3 specular = specularStrength * spec * lightColor;  

        

    vec3 result = (ambient + diffuse + specular) * objectColor;

    color = vec4(result, 1.0f);

}

Vertex Shader (Lamp):



#version 330 core



layout (location = 0) in vec3 position;



uniform mat4 model;

uniform mat4 view;

uniform mat4 projection;



void main()

{

    gl_Position = projection * view * model * vec4(position, 1.0f);

}

Fragment Shader (Lamp):



#version 330 core



out vec4 color;



void main()

{

    color = vec4(1.0f); 

}

 

I used to think it was

 

Loop:

glbindVertexArray(lampVAO);        // <-- where glDrawArray would draw VAO that was last bound?
glDrawArray(GL_TRIANGLES, 0, 36);

But then I started tinkering with the above code and commented out both glbindVertexArray commands (lamp and regular entity) in loop and commented out the lamp vertex array during initialization in order to remove it from the scene.

 
 
    //   glBindVertexArray(containerVAO);



        glm::mat4 model;



        glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));



       glDrawArrays(GL_TRIANGLES, 0, 36);









        lampShader.Use();







        modelLoc = glGetUniformLocation(lampShader.Program, "model");



        viewLoc  = glGetUniformLocation(lampShader.Program, "view");



        projLoc  = glGetUniformLocation(lampShader.Program, "projection");



        // Set matrices



        glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));



        glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));



        model = glm::mat4();



        model = glm::translate(model, lightPos);



        model = glm::scale(model, glm::vec3(1.0f));



        glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));







     //   glBindVertexArray(lampVAO);



        glDrawArrays(GL_TRIANGLES, 0, 36);

However, both cubes still rendered.

 

 

In a nutshell, I'm trying to understand the OpenGL equivalent of the following SFML code

sf::RenderWindow Window();
sf::RectangleShape rect;
 
while(Window.isOpen()){
 
Window.draw(rect); // <-- SFML knows to draw the rect entity to the display due to this command.
}
 

Note: I understand OpenGL does not have

Window.draw(rect);

The above code has wrapped around the OpenGL commands. Looking for the GL equivalent of draw this entity.

 

Share this post


Link to post
Share on other sites
Advertisement

That part of the source code is admittedly a bit hard to follow. I'm not sure if I'd like to design it that way, but alas.

 

RectangleShape is-a Shape, is-a Drawable. Window is-a RenderTarget, which has a member function draw. This one calls the draw member on the respective Drawable, which in turn calls back RenderTarget's draw function with m_vertices as parameter... which is *drum roll* a class intriguingly called VertexArray. Which, again, is-a Drawable that again calls back to the RenderTarget's draw function, this time with a different overload, passing a std::vector of vertices, a size, a primitive type, and texture state.

 

So.... long story short, the bottom line of this convoluted going up and down class hierarchies is simply calling glDrawArrays on the four corner points of the rectangle. The relevant code can be found in RenderTarget.cpp, lines 200 to 300.

Share this post


Link to post
Share on other sites
OpenGL has a bunch of internal state. You configure the state then make draw calls. Both cubes use the same vertex information. In your setup code you have this.
glBindVertexArray(containerVAO);

    // Position attribute

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);

    glEnableVertexAttribArray(0);

    // Normal attribute

    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));

    glEnableVertexAttribArray(1);
It will configure OpenGL to use that vertex information. First you bind a vertex array, then with glVertrexAttribPointer you tell OpenGL how the positions and normals are packed into that array. Inside your loop, the glUniform... functions such as glUniform3f and glUniformMatrix4fv are used to configure the shader and in your specific case control the position and color of the geometry being rendered.

Share this post


Link to post
Share on other sites

So as long as the number of glDrawArray commands match the number of VAO, OpenGL will know internally which VAO you are referring to and draw to the display?

 

So I do not need to

glBindVertexArray
every frame?

Share this post


Link to post
Share on other sites
It will use the last bound vertex buffer so you will probably want to be binding every frame, you need to bind whenever you want to change the source of data. If you will only ever be rendering cubes then you won't need to rebind, but you probably will want to be rebinding.

Share this post


Link to post
Share on other sites

 

So as long as the number of glDrawArray commands match the number of VAO, OpenGL will know internally which VAO you are referring to and draw to the display?

 

So I do not need to

glBindVertexArray
every frame?

 

When you draw you're essentially asking OpenGL to take the data in whatever vertex buffer(VBO/vertex data) is bound, and draw it. It draws using the state you have set up at the time you issue the draw command, a simple way to think of it is that it has a bunch of global variables with different information set about how to draw the thing.

 

A VAO is like a shortcut to set that state. You either have a VAO currently bound or you don't, when it's bound and you change state it "records" that state. So if you want to set a VAO up you'd create it, then bind it, then set your state, then unbind it(bind the 0 id VAO.) Then whenever you want to draw you just bind it again, and voila, all the settings are set.

 

However since the VAO "records" the state changes you make, that means you generally need to unbind it between draw calls, because if you don't then if some other code later on changes some state, it's going to change the settings on your VAO, so when you get back to using it, it won't have the same setup.

 

EDIT: I should probably clarify that in large scale you wouldn't actually want to bind and unbind a separate VAO for every single draw call. The point of using VAO's is so that you can switch between sets of similar drawing settings(shader inputs and such) easily and efficiently.

 

Link here explains the basic idea.

Edited by Satharis

Share this post


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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!