经过多年关于顶点缓冲对象(VBO)的讨论,我终于决定尝试它们(我的东西通常不是性能关键,显然......)
我将在下面描述我的实验,但总而言之,我看到"简单"直接模式(glBegin()/ glEnd()),顶点数组(CPU端)和VBO(GPU端)之间无法区分性能渲染模式.我试图理解为什么会这样,并且在什么条件下我可以期待看到VBO明显优于他们原始(双关语)的祖先.
对于实验,我生成了一个具有大量点的(静态)3D高斯云.每个点都有与之关联的顶点和颜色信息.然后我在连续的帧中围绕云旋转相机,这是一种"轨道"行为.同样,这些点是静态的,只有眼睛移动(通过gluLookAt()).数据在任何渲染之前生成一次并存储在两个数组中以用于渲染循环.
对于直接渲染,整个数据集在单个glBegin()/ glEnd()块中呈现,其中包含一个循环,每个循环包含glColor3fv()和glVertex3fv().
对于顶点数组和VBO渲染,整个数据集使用单个glDrawArrays()调用进行渲染.
然后,我只需在紧凑的循环中运行一分钟左右,并使用高性能计时器测量平均FPS.
如上所述,我的台式机(XP x64,8GB RAM,512 MB Quadro 1700)和笔记本电脑(XP32,4GB RAM,256 MB Quadro NVS 110)的性能难以区分.然而,它确实按照预期的点数进行了扩展.显然,我也禁用了vsync.
笔记本电脑运行的具体结果(使用GL_POINTS渲染):
在glBegin()/ glEnd():
顶点阵列(CPU端):
顶点缓冲对象(GPU端):
有人会关心解释VertexBuffer,VertexArray,VertexBufferObject和VertexArrayObject之间的区别吗?我甚至不确定这些是否是针对不同事物的所有术语,但我已经看到它们都出现在OpenGL规范中.
我知道VertexBuffer只包含顶点而没有其他任何东西,一旦绑定,一旦我设置了顶点指针,我就可以使用DrawArrays来绘制它.我已经多次这样做了.
我正在使用我认为的VertexArray,它存储所设置的任何顶点缓冲区的状态,以及任何顶点指针.绑定VertexArray会自动绑定顶点缓冲区并设置顶点指针.我也成功地使用了这个(大部分).
但什么是VertexBufferObject和VertexArrayObject?他们更好吗?VertexArray不能给我我需要的一切吗?
我正在使用OpenGL某种批量绘图.为此,我创建了一个vertex buffer存储数据.
注意:此缓冲区通常会在每个帧上更新,但永远不会减小大小(但仍然可以增加).
我的问题是:使用glBufferData(用s treaming write-only mode)更新它(而不是例如glMapBuffer)在技术上是否正确?我想没有必要映射它,因为更新了完整的数据,所以我只需要立即发送一个完整的数据包.如果当前的缓冲区大小比我发送的少,它会自动增加,不是吗?我现在才确定它的实际工作方式(也许它会在每次调用时重新创建缓冲区,不是吗?).
我想在创建VBO后更新对象的顶点列表.我已经看到了两者glBufferSubData并且glMapBuffer它们似乎都做了类似的事情,这意味着我现在不确定使用哪一个.
我的伪工作流程是:
创建对象
开始顶点更新(使用data = nullptr调用glBufferData)
更新对象的顶点
结束顶点更新(采用更新的顶点和调用glBufferSubData或glMapBuffer)
当您使用交错的VBO而不是使用多个VBO时,通常会加快速度.这在使用VAO时也有效吗?
因为对于位置有一个VBO,对于法线等有一个VBO更方便.你可以在多个VAO中使用一个VBO.
我可以安全地使用glm ::*类型(例如vec4,mat4)来填充顶点缓冲区对象吗?
std::vector<glm::vec3> vertices;
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * vertices.size(), &vertices[0], GL_STATIC_DRAW);
Run Code Online (Sandbox Code Playgroud)
我不太确定,因为在我看来,struct padding(成员对齐)可能会导致一些麻烦,尽管我测试的所有编译器都会返回预期的大小.
我正在为C++ 11编译器开发(也许这会有所不同).
这可能是一个菜鸟问题.据我了解,只要AAA是唯一的,glBindAttribLocation(...,AAA,...)就会将程序中的属性绑定到AAA的位置ID.如果我有以下代码:
glBindAttribLocation(..., 0, "XXX");
glBindAttribLocation(..., 1, "YYY");
Run Code Online (Sandbox Code Playgroud)
这会将我的两个变量绑定到位置ID 0和1.然后我会调用:
glBindBuffer(GL_ARRAY_BUFFER, VBId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBId);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void *) 0 + sizeof(float) * 3);
glEnableVertexAttribArray(1);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
Run Code Online (Sandbox Code Playgroud)
到目前为止,我理解0和1的ID作为第一个参数传递给glVertexAttribPointer().
如果我通过glGetAttribLocation()调用获得属性的位置ID(如上所述),以便返回的ID是5和6而不是0和1,我是否可以安全地将5和6传递给glVertexAttribPointer( )和glEnableVertexAttribArray()而不是0和1 ??
当我在OpenGL 2.0中更新iOS上的顶点数组时,原始顶点数据停留在屏幕上 - 即第一次刷新是持久的(我向下发送到GPU的初始点集每帧渲染),但是第二次,第3,第4,...第n次冲洗似乎都覆盖了相同的记忆.
所以我在做:
vector<VertexType> rawDynamicData ;
glGenVertexArraysOES( 1, &va ) ; CHECK_GL ;
glBindVertexArrayOES( va ) ; CHECK_GL ;
glGenBuffers( 1, &vb ) ; CHECK_GL ;
glBindBuffer( GL_ARRAY_BUFFER, vb ) ; CHECK_GL ;
glBufferData( glBufferData(
GL_ARRAY_BUFFER, //Specifies the target buffer object.
rawDynamicData.size() * sizeof( VertexType ),
&rawDynamicData[0],
GL_DYNAMIC_DRAW // I plan to update the data every frame
) ; CHECK_GL ;
Run Code Online (Sandbox Code Playgroud)
在随后的帧中,我只是再次打电话:
// update the data
glBufferData( glBufferData(
GL_ARRAY_BUFFER, //Specifies the target buffer object.
rawDynamicData.size() * sizeof( VertexType …Run Code Online (Sandbox Code Playgroud) 我假设这将是"未定义"的事情之一,但我似乎无法从谷歌找到具体的答案.
让我们在我的顶点着色器中说:
layout(location = 0) in vec3 vPosition;
layout(location = 1) in vec3 vNormal;
layout(location = 2) in vec4 vColour;
Run Code Online (Sandbox Code Playgroud)
但是没有任何缓冲到位置2的glEnableVertexAttribArray()或glVertexAttribPointer().我可以期待价值是什么特别的吗?
我假设vec4它将沿着{0,0,0,0},{0,0,0,1}或{1,1,1,1}的线,但在我的情况下,它是{0,0,1,1}.
当我之前使用glBindAttribLocation()指定位置时,它使用3种不同的操作系统(ubuntu 12.04,windows 7和ubuntu 10.04)在4台不同的机器上默认为{1,1,1,1}.
假设机器上的值为{0,0,1,1}是否安全?或者这简直是巧合?
我在构建图形引擎时正在研究arcsynthesis的优秀教程,并发现我不像我想象的那样理解VAO.
从教程第5章深入的对象
缓冲区绑定和属性关联
您可能会注意到glBindBuffer(GL_ARRAY_BUFFER)不在该列表中,即使它是用于渲染的属性设置的一部分.对GL_ARRAY_BUFFER的绑定不是VAO的一部分,因为当调用glBindBuffer(GL_ARRAY_BUFFER)时,缓冲区对象和顶点属性之间的关联不会发生.调用glVertexAttribPointer时会发生此关联.
当您调用glVertexAttribPointer时,OpenGL会将此调用时的任何缓冲区绑定到GL_ARRAY_BUFFER,并将其与给定的顶点属性相关联.将GL_ARRAY_BUFFER绑定视为glVertexAttribPointer读取的全局指针.因此,在进行glVertexAttribPointer调用之后,您可以自由地将任何您想要的内容绑定到GL_ARRAY_BUFFER; 它会影响最终渲染中的任何内容.因此VAO确实存储哪些缓冲区对象与哪些属性相关联; 但它们不存储GL_ARRAY_BUFFER绑定本身.
我最初错过了最后一行"......但他们没有存储GL_ARRAY_BUFFER绑定本身".在我注意到这一行之前,我认为一旦调用了glVertexAttribPointer,就会保存当前绑定的缓冲区.缺少这些知识,我构建了一个网格类,并且能够获得一个具有正确渲染的多个网格的场景.
下面列出了该代码的一部分.请注意,我不在draw函数中调用glBindBuffer.
// MESH RENDERING
/* ... */
/* SETUP FUNCTION */
/* ... */
// Setup vertex array object
glGenVertexArrays(1, &_vertex_array_object_id);
glBindVertexArray(_vertex_array_object_id);
// Setup vertex buffers
glGenBuffers(1, &_vertex_buffer_object_id);
glBindBuffer(GL_ARRAY_BUFFER, _vertex_buffer_object_id);
glBufferData(GL_ARRAY_BUFFER, _vertices.size() * sizeof(vertex), &_vertices[0], GL_STATIC_DRAW);
// Setup vertex attributes
glEnableVertexAttribArray(e_aid_position);
glEnableVertexAttribArray(e_aid_normal);
glEnableVertexAttribArray(e_aid_color);
glEnableVertexAttribArray(e_aid_tex);
glVertexAttribPointer(e_aid_position, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, pos));
glVertexAttribPointer(e_aid_normal, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, norm));
glVertexAttribPointer(e_aid_color, 4, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, col));
glVertexAttribPointer(e_aid_tex, 2, GL_FLOAT, GL_FALSE, …Run Code Online (Sandbox Code Playgroud) vertex-buffer ×10
opengl ×8
shader ×2
arraybuffer ×1
attributes ×1
c++ ×1
c++11 ×1
graphics ×1
ios ×1
performance ×1
streaming ×1
vbo ×1
vertex-array ×1
vertexdata ×1