Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use VBOs without VAOs with OpenGL core profile?

I'm having trouble using vertex buffer objects without using a vertex array object.

My understanding was that VAOs are just encapsulating the state around VBOs. But shouldn't the VBOs be usable without a VAO?

Here's a mini-example. With use_vao=true this works correctly (renders orange rect). With use_vao=false this renders nothing and generates a GL_INVALID_OPERATION error upon glDrawElements.

// make sure the modern opengl headers are included before any others
#include <OpenGL/gl3.h>
#define __gl_h_
#include <GLUT/glut.h>
#include <string>
#include <cassert>

// For rendering a full-viewport quad, set tex-coord from position
std::string tex_v_shader = R"(
#version 330 core
in vec3 position;
void main()
{
  gl_Position = vec4(position,1.);
}
)";
// Render directly from color or depth texture
std::string tex_f_shader = R"(
#version 330 core
out vec4 color;
void main()
{
  color = vec4(0.8,0.4,0.0,0.75);
}
)";
// shader id, vertex array object
GLuint tex_p_id;
int w=1440,h=480;
const GLfloat V[] = {-0.5,-0.5,0,0.5,-0.5,0,0.5,0.5,0,-0.5,0.5,0};
const GLuint F[] ={0,1,2, 0,2,3};
int main(int argc, char * argv[])
{
  // Init glut and create window + OpenGL context
  glutInit(&argc,argv);
  glutInitDisplayMode(GLUT_3_2_CORE_PROFILE|GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH); 
  glutInitWindowSize(w,h);
  glutCreateWindow("test");
  // Compile shaders
  const auto & compile = [](const char * src,const GLenum type)->GLuint
  {
    GLuint s = glCreateShader(type);
    glShaderSource(s, 1, &src, NULL);
    glCompileShader(s);
    return s;
  };
  tex_p_id = glCreateProgram();
  glAttachShader(tex_p_id,compile(tex_v_shader.c_str(), GL_VERTEX_SHADER));
  glAttachShader(tex_p_id,compile(tex_f_shader.c_str(), GL_FRAGMENT_SHADER));
  glLinkProgram(tex_p_id);
  glutDisplayFunc(
    []()
    {
      glViewport(0,0,w,h);
      glUseProgram(tex_p_id);
      glClearColor(0.0,0.4,0.7,0.);
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      const bool use_vao = true;
      GLuint VAO;
      if(use_vao)
      {
        glGenVertexArrays(1, &VAO);
        glBindVertexArray(VAO);
      }
      GLuint VBO, EBO;
      glGenBuffers(1, &VBO);
      glGenBuffers(1, &EBO);
      glBindBuffer(GL_ARRAY_BUFFER, VBO);
      glBufferData(GL_ARRAY_BUFFER, sizeof(V), V, GL_STATIC_DRAW);
      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
      glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(F), F, GL_STATIC_DRAW);
      glBindBuffer(GL_ARRAY_BUFFER, 0); 
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 
      glBindBuffer(GL_ARRAY_BUFFER, VBO); 
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); 
      if(use_vao)
      {
        glEnableVertexAttribArray(0);
        glBindBuffer(GL_ARRAY_BUFFER, 0); 
      }
      assert(glGetError() == GL_NO_ERROR);
      glDrawElements(GL_TRIANGLES,sizeof(F)/sizeof(GLuint),GL_UNSIGNED_INT, 0);
      assert(glGetError() == GL_NO_ERROR);
      glutSwapBuffers();
    }
    );
  glutReshapeFunc( [](int w,int h){::h=h, ::w=w;});
  glutMainLoop();
}

On my machine glGetString(GL_VERSION) produces 4.1 INTEL-10.6.20.

like image 774
Alec Jacobson Avatar asked May 05 '15 15:05

Alec Jacobson


2 Answers

Using VAOs is required in the core profile. From the OpenGL 3.3 spec, page 342, in the section E.2.2 "Removed Features":

The default vertex array object (the name zero) is also deprecated.

This means that you can't set up vertex attributes without creating and binding your own VAO.

like image 100
Reto Koradi Avatar answered Oct 27 '22 00:10

Reto Koradi


No with a core 3.3+ profile you need a VAO to render.

You can however just create and bind a VAO and forget about it (keep it bound).

Besides that glEnableVertexAttribArray(0); must still be called even when using compatibility profile and not using a VAO.

A few other remarks is that you regenerate all buffers and VAOs every frame but don't clean it up. You should do that once during initialization and then rebind when drawing:

if(!use_vao){
      glBindBuffer(GL_ARRAY_BUFFER, VBO);
      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
}
else
{
      glBindVertexArray(VAO);
}
like image 22
ratchet freak Avatar answered Oct 26 '22 23:10

ratchet freak