glGenVertexArrays 和 glGenBuffers 参数

glGenVertexArrays and glGenBuffers arguments

在关于 OpenGL 3.0+ 的教程中,我们以这种方式创建顶点数组对象和顶点缓冲区对象:

GLuint VAO, VBO; 
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);

这里,VAO是一个unsigned intGLuint),我们在函数glGenVertexArray中将a̶̶r̶e̶f̶e̶r̶e̶n̶c̶e̶其地址传递给它。但是,根据文档,函数的第二个参数应该是 array of unsigned int (GLuint*)。 VBO 和 glGenBuffers 也是如此。我不明白为什么上面的代码使用这样的参数。

我已经尝试用这个替换上面的代码(并在我的代码的其他地方做必要的修改):

GLuint VAO[1];
GLuint VBO[1];
glGenVertexArrays(1, VAO);
glGenBuffers(1, VBO);
glBindVertexArray(VAO[1]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);

它编译并执行了,但我得到了一个意想不到的行为:我的纹理矩形使用第一种语法呈现,而不是第二种语法。我也不明白为什么会这样。

编辑:谢谢。如前所述,第二个代码中存在索引错误。

第一个索引是 0

GLuint VAO[1];
GLuint VBO[1];
glGenVertexArrays(1, VAO);
glGenBuffers(1, VBO);
glBindVertexArray(VAO[0]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);

C 和 C++ 中的数组表示为指针。换句话说,指针相当于一个元素的数组。因此,如果您正在创建单个缓冲区对象,您可以像在第一个示例中那样简单地声明一个变量并传递一个指向它的指针(它不是引用,它是一个指针)并且没有任何问题。我自己一直都是这样做的。

为什么您的第二个示例不起作用,请参阅上面乔纳森·奥尔森的回答。

规范中的函数签名是:

void glGenVertexArrays( GLsizei n,
                        GLuint *arrays);

因此 arrays 需要一个 GLuint 指针 可以有效写入 n * sizeof(GLuint) 字节的数据。

完全可以这样写:

GLuint VAO, VBO; 
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);

因为 glGenVertexArrays 想要一个指向 GLuint 的指针,其中可以有效地将 n * sizeof(GLuint) 字节的数据写入(在您的情况下 1)并且因为 VAO能装下这个数据量,这样写是对的。如果每次调用只创建一个 ID,and 更可取。

正如其他人所说,数组中的第一个元素具有索引 0。截至那时它必须是:

GLuint VAO[1];
GLuint VBO[1];
glGenVertexArrays(1, VAO);
glGenBuffers(1, VBO);
glBindVertexArray(VAO[0]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);

如果您想在一次调用中创建更多元素,您希望使用 std::array 而不是 []

std::array<GLuint,3> VAOs;
std::array<GLuint,3> VBOs;

glGenVertexArrays(VAOs.size(), &VAOs[0]);
glGenBuffers(VBOs.size(), &VBOs[0]);

请注意,unsigned intGLuint 不一定是相同的类型或大小,unsigned int 有最小保证数量范围,但大小在不同平台上仍可能有所不同。另一方面,GLuint 具有定义的大小。