gpt4 book ai didi

c++ - OpenGL 的缓冲区是如何工作的?

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:36:56 25 4
gpt4 key购买 nike

我不明白 OpenGL 的缓冲区是如何工作的。我通过 OpenGL 红皮书第 8 版学习 OpenGL。例如,我有一个位置数组、一个颜色数组和一个索引数组:

static const GLfloat strip_position[] =
{
-4.0f, 0.0f, -1.0f, 1.0f, //0
-3.5f, -1.0f, -1.0f, 1.0f, //1
-3.0f, 0.0f, -1.0f, 1.0f, //2
-2.5f, -1.0f, -1.0f, 1.0f, //3
-2.0f, 0.0f, -1.0f, 1.0f, //4
-1.5f, -1.0f, -1.0f, 1.0f, //5
-1.0f, 0.0f, -1.0f, 1.0f, //6
-0.5f, -1.0f, -1.0f, 1.0f, //7
0.0f, 0.0f, -1.0f, 1.0f //8
};
static const GLfloat strip_colors[] =
{
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
};

static const GLushort strip_indices[] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8
};

很好。然后我创建顶点数组对象如下:

    GLuint vao[1]; // vertex array object
glGenVertexArrays(1, vao);
glBindVertexArray(vao[0]);

在我的理解中,第一个参数 (GLsizei n) 是位置数组的数量(或一个我的对象的顶点坐标)。然后我创建 Element Array Buffer 如下:

GLuint ebo[1]; // element buffer object
glGenBuffers(1, ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo[0]);
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
sizeof(strip_indices),
strip_indices,
GL_STATIC_DRAW
);

然后我创建顶点缓冲区对象如下:

GLuint vbo[1]; // vertex buffer object
glGenBuffers(1, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(
GL_ARRAY_BUFFER,
sizeof(strip_position) + sizeof(strip_colors),
NULL,
GL_STATIC_DRAW
);
glBufferSubData(
GL_ARRAY_BUFFER,
0, //offset
sizeof(strip_position), //size date
strip_position //data
);
glBufferSubData(
GL_ARRAY_BUFFER,
sizeof(strip_position), //offset
sizeof(strip_colors), //size data
strip_colors //data
);

接下来我调用 glVertexAttribPointer() 如下:

glVertexAttribPointer(
0, //index
4, //size
GL_FLOAT, //type
GL_FALSE, //normalized
0, //stride
NULL //pointer
);
glVertexAttribPointer(
1,
4,
GL_FLOAT,
GL_FALSE,
0,
(const GLvoid*)sizeof(strip_position)
);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);

这个函数有什么作用?(glVertexAttribPointer()glEnableVertexAttribArray())
好的。我完成了初始化我的数据。现在我可以画出如下:

glBindVertexArray(vao[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo[0]);
glDrawElements(GL_TRIANGLE_STRIP, 8, GL_UNSIGNED_SHORT, NULL);

OpenGL 如何理解,需要使用哪个缓冲区以及它在哪里? “绑定(bind)”一词是指关系吗?即某物与某物结合?如果我想显示两个对象,我该怎么做?例如,我有两个位置数组,两个位置数组和两个索引数组?

static const GLfloat TWOstrip_colors[] =
{
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f
};
static const GLfloat TWOstrip_colors[] =
{
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
};

static const GLushort TWOstrip_indices[] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8
};

这是怎么做到的?

最佳答案

OpenGL 有所谓的对象 的概念。这些不是模型或几何对象,而是内部状态的封装。如果您熟悉面向对象 的编程,并且可以将 C++ STL OpenGL 对象视为类实例。

调用 glGenBuffers(count, out_names) 可以粗略地解释成类似的东西

std::map<GLuint, openglobject*> bufferobjects;

glGenBuffers(GLuint count, std::vector<GLuint> *out_names)
{
out_names->resize(count);
for(int i=0; i < count; i++) {
GLuint name = get_next_free_handle_ID();
bufferobjects[name] = NULL;
out_names.set(i, name);
}
}

所以它所做的是,它保留一个句柄 ID(OpenGL 称它们为名称)并在句柄和缓冲区对象实例指针之间的内部映射中为其分配一个槽。

调用 glBindBuffer 实际上创建了缓冲区对象,类似的东西

glBindBuffer(GLenum target, GLuint name)
{

openglobject *objinstance = NULL;

if( name != 0 ) {
if( !bufferobjects.has_key(name) ) {
push_openglerror( INVALID_NAME );
return;
}

objinstance = bufferobjects[name];

if( NULL == bufferobjects[name] ) {
switch(target) {
case GL_ARRAY_BUFFER:
objinstance = new OpenGLArrayBuffer; break;

case GL_ELEMENT_ARRAY_BUFFER:
objinstance = new OpenGLElementArrayBuffer; break;

/* ... and so on */

default:
push_openglerror( INVALID_TARGET ); return;
}

bufferobjects[name] = objinstance;

}
}
}

if( objinstance != NULL && target_of(objinstance) != target ) {
opengl_pusherror( INVALID_TARGET );
}

switch( target ) {
case GL_ARRAY_BUFFER:
/* this would be a static function of the subclass setting
* global singleton instance pointer
*/
OpenGLArrayBuffer::make_current(objinstance);
break;

/* ... and so on */
}
}

我想你可以看到这是怎么回事:缓冲区 target 指定你正在使用的实例的子类类型及其静态成员。

glBufferData 然后实际分配特定对象的内存,并可以使用您传递给它的缓冲区的内容对其进行初始化。 glBufferSubData 只是将数据复制到内部存储。

缓冲区对象就这么多(有好几种)。


另一部分是顶点数组对象。这些是特殊的 OpenGL 对象,它们在顶点属性数组缓冲区 对象之间建立关联,顶点属性是根据属性索引传递给着色器的逐顶点数据数据是需要的。

当你调用 glGenVertexArray 时,会发生这样的事情:

std::map<GLuint, openglobject*> vertexarrayobjects;

glGenVertexArrays(GLuint count, std::vector<GLuint> *out_names)
{
out_names->resize(count);
for(int i=0; i < count; i++) {
GLuint name = get_next_free_handle_ID();
vertexarrayrobjects[name] = NULL;
out_names.set(i, name);
}
}

看起来很眼熟,不是吗?唯一的区别是,使用了不同的映射结构。 glBindVertexArray 进行实例分配等。

现在调用 glEnableVertexAttributeglVertexAttribPointer 可以被认为如下:

glEnableVertexAttribute(GLuint idx)
{
((OpenGLVertexArrayObject*)currentvertexarray)->add_attribute(idx);
}

glVertexAttribPointer(GLuint idx, ..., void *ptr)
{
((OpenGLVertexArrayObject*)currentvertexarray)->bind_attribute(
idx,
OpenGLArrayBuffer::get_current(),
(off_t)ptr );
}

好的,最后一点需要一些解释。将指针传递给 glVertexAttribPointer 是 OpenGL-1.1 的遗留问题,其中没有 OpenGL 缓冲区对象,而是直接指向程序的内存。然后引入了缓冲区对象,这些对象在绑定(bind)时不需要指针,而是字节大小的偏移量。所以 OpenGL 开发者走上了肮脏的道路,对编译器撒了谎。 I did explain the details in my answer to the question "What is the result of NULL + int?"

请注意,OpenGL-4 引入了一个新的、更强大和灵活的 API 来创建 VAO 属性 ←→ VBO 绑定(bind)。

关于c++ - OpenGL 的缓冲区是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20517961/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com