如何在没有 VAO 的情况下使用具有 OpenGL 核心配置文件的 VBO?
How to use VBOs without VAOs with OpenGL core profile?
我在使用顶点缓冲区对象时遇到问题而不 使用顶点数组对象。
我的理解是 VAO 只是封装了 VBO 周围的状态。但 VBO 不应该在没有 VAO 的情况下使用吗?
这是一个小例子。使用 use_vao=true
这可以正常工作(呈现橙色矩形)。使用 use_vao=false
这不会呈现任何内容并在 glDrawElements
时生成 GL_INVALID_OPERATION
错误。
// 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();
}
在我的机器上 glGetString(GL_VERSION)
生成 4.1 INTEL-10.6.20
.
没有核心 3.3+ 配置文件,您需要 VAO 来渲染。
然而,您可以只创建并绑定一个 VAO 而忘记它(保持绑定)。
除此之外,即使在使用兼容性配置文件而不使用 VAO 时,仍然必须调用 glEnableVertexAttribArray(0);
。
其他几点说明,您每帧都重新生成所有缓冲区和 VAO,但不清理它。你应该在初始化时做一次,然后在绘图时重新绑定:
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);
}
核心配置文件中需要使用 VAO。来自 OpenGL 3.3 规范,第 342 页,在 E.2.2 部分 "Removed Features":
The default vertex array object (the name zero) is also deprecated.
这意味着您不能在不创建和绑定您自己的 VAO 的情况下设置顶点属性。
我在使用顶点缓冲区对象时遇到问题而不 使用顶点数组对象。
我的理解是 VAO 只是封装了 VBO 周围的状态。但 VBO 不应该在没有 VAO 的情况下使用吗?
这是一个小例子。使用 use_vao=true
这可以正常工作(呈现橙色矩形)。使用 use_vao=false
这不会呈现任何内容并在 glDrawElements
时生成 GL_INVALID_OPERATION
错误。
// 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();
}
在我的机器上 glGetString(GL_VERSION)
生成 4.1 INTEL-10.6.20
.
没有核心 3.3+ 配置文件,您需要 VAO 来渲染。
然而,您可以只创建并绑定一个 VAO 而忘记它(保持绑定)。
除此之外,即使在使用兼容性配置文件而不使用 VAO 时,仍然必须调用 glEnableVertexAttribArray(0);
。
其他几点说明,您每帧都重新生成所有缓冲区和 VAO,但不清理它。你应该在初始化时做一次,然后在绘图时重新绑定:
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);
}
核心配置文件中需要使用 VAO。来自 OpenGL 3.3 规范,第 342 页,在 E.2.2 部分 "Removed Features":
The default vertex array object (the name zero) is also deprecated.
这意味着您不能在不创建和绑定您自己的 VAO 的情况下设置顶点属性。