首页 > 编程知识 正文

OpenGL VBO学习,学习opengl要买显卡吗

时间:2023-05-06 05:40:16 阅读:179344 作者:1456

OpenGLVertexbufferobject(VBO ) GL_ARB_vertex_buffer_object扩展通过提供顶点阵列和显示列表点来提高OpenGL的性能,同时实现它们顶点缓冲区对象(VBO )将顶点数组数据存储在服务器端的高性能显存中,有助于实现高效的数据传输。 如果缓冲区对象用于存储像素数据,则称为像素缓冲区对象(PBO )。

使用顶点数组可以减少函数调用的次数,并减少共享顶点的冗馀。 但是,顶点数组的缺点是顶点数组函数处于客户端状态,每次引用数组中的数据时都必须将其重新发送到服务器。

另一方面,显示列表是服务器端的功能,所以不受数据传输开销的影响。 但是,一旦编译了显示列表,就不能更改显示列表中的数据。

顶点缓冲区对象(VBO )在服务器端的高性能存储器中为顶点属性创建“缓冲区对象”,并生成glVertexPointer、glNormalPointer、glTexCoordPointer和

根据用户的指示,顶点缓冲区对象中的内存管理器将缓冲区对象放置在内存的最佳位置:“目标”和“使用”模式。 因此,内存管理器可以平衡三种内存类型:系统内存、AGP内存和显存,以优化缓冲区。

与显示列表不同,顶点缓冲区对象中的数据可以通过将缓冲区映射到客户端的内存空间来读取和更新。

VBO的另一个重要优点是与许多客户端共享缓冲区对象,如显示列表和纹理。 因为VBO在服务器端,所以多个客户端可以使用适当的标识符访问同一缓冲区。

Creating VBO创建VBO需要三个步骤。

使用glGenBuffers ()生成新的缓冲区对象。 使用glBindBuffer ()绑定缓冲区对象。 使用glBufferData ()将顶点数据复制到缓冲区对象。 lgenbuffers(glgenbuffers )创建缓冲区对象并返回缓冲区对象的标识符。 需要两个参数。 第一个是要创建的缓冲区对象的数量,第二个是包含单个ID或多个ID的GLuint变量或数组的地址。

voIDglgenbuffers(glsizein,GLuint* ids ) glBindBuffer ) )创建缓冲区对象后,必须先挂接到相应的id,然后才能使用该缓冲区对象。 glBindBuffer ()有两个参数: target和ID。

voidglbindbuffer(glenumTarget,GLuint id ) target提示VBO此缓冲区对象是存储顶点数组数据还是索引数组数据。 GL_ARRAY_BUFFER或GL_ELEMENT_ARRAY_BUFFER。 对于顶点属性(如顶点坐标、纹理坐标、法线和颜色组件数组),必须使用GL_ARRAY_BUFFER。 用于glDrawRangeElements ()的索引数组必须绑定到GL_ELEMENT_ARRAY_BUFFER。 此目标标志可帮助VBO确定缓冲区对象的最有效位置。 例如,在某些系统上,您可能希望将索引存储在AGP或系统内存中,并将顶点存储在图形内存中。

首次调用glBindBuffer () )后,VBO将使用大小为零的内存缓冲区初始化缓冲区并设置初始VBO状态,例如使用属性和访问。

可以使用glBufferData (缓冲区初始化后为glBufferData )将数据复制到缓冲区对象。

与voidglbufferdata(glenumtarget,GLsizei size,const void* data,GLenum usage )类似,第一个参数target也是GL_ARRAY_BUFFER 第三个参数是指向源数据数组的指针。 如果数据为空指针,则VBO只保留指定数据大小的内存空间。 最后一个参数“usage”标志是VBO的另一个性能提示,它提供了如何使用静态、动态或流缓冲区对象,以及如何读取读、复制或裸

VBO为usage标志指定了9个枚举值

GL _ static _ draw GL _ static _ read GL _ static _ copy GL _ dynamic _ draw GL _ dynamic _ copy GL “Draw”表示将数据发送到GPU进行绘制,“read”表示客户端APP应用程序将读取数据,“copy”表示同时使用Draw和read。

对于VBO,draw和read标志仅适用于像素/帧缓冲区对象(PBO或FBO )。

VBO内存管理器根据这些使用标志选择最适合缓冲区对象的内部

存位置,例如,GL_STATIC_DRAW 和 GL_STREAM_DRAW可能使用显存,而 GL_DYNAMIC_DRAW可能使用 AGP 内存。任何 _READ_相关缓冲区存放在系统或 AGP 内存中都可以,因为数据应该易于访问。

glBufferSubData() void glBufferSubData(GLenum target, GLint offset, GLsizei size, void* data)

与 glBufferData()一样,glBufferSubData()用于将数据复制到 VBO 中,但它仅将一系列数据替换到现有缓冲区中,从给定的偏移量开始。缓冲区的总大小必须在使用 glBufferSubData() 之前由 glBufferData()设置。)

GLuint vboId; // ID of VBOGLfloat* vertices = new GLfloat[vCount*3]; // create vertex array...// generate a new VBO and get the associated IDglGenBuffers(1, &vboId);// bind VBO in order to useglBindBuffer(GL_ARRAY_BUFFER, vboId);// upload data to VBOglBufferData(GL_ARRAY_BUFFER, dataSize, vertices, GL_STATIC_DRAW);// it is safe to delete after copying data to VBOdelete [] vertices;...// delete VBO when program terminatedglDeleteBuffers(1, &vboId); Drawing VBO

因为 VBO 位于现有顶点数组实现之上,所以渲染 VBO 几乎等同于使用顶点数组。唯一的区别是指向顶点数组的指针现在作为当前绑定的缓冲区对象的偏移量。因此,除了 glBindBuffer()之外,不需要额外的 API 来绘制 VBO。

使用 0 绑定缓冲区对象会关闭 VBO 操作。使用后关闭 VBO 是个好主意,这样使用绝对指针的顶点法线数组操作将被重新激活。

// bind VBOs for vertex array and index arrayglBindBuffer(GL_ARRAY_BUFFER, vboId1); // for vertex attributesglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboId2); // for indicesglEnableClientState(GL_VERTEX_ARRAY); // activate vertex position arrayglEnableClientState(GL_NORMAL_ARRAY); // activate vertex normal arrayglEnableClientState(GL_TEXTURE_COORD_ARRAY); // activate texture coord array// do same as vertex array except pointerglVertexPointer(3, GL_FLOAT, stride, offset1); // last param is offset, not ptrglNormalPointer(GL_FLOAT, stride, offset2);glTexCoordPointer(2, GL_FLOAT, stride, offset3);// draw 6 faces using offset of index arrayglDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, 0);glDisableClientState(GL_VERTEX_ARRAY); // deactivate vertex position arrayglDisableClientState(GL_NORMAL_ARRAY); // deactivate vertex normal arrayglDisableClientState(GL_TEXTURE_COORD_ARRAY); // deactivate vertex tex coord array// bind with 0, so, switch back to normal pointer operationglBindBuffer(GL_ARRAY_BUFFER, 0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

OpenGL 2.0 版添加了 glVertexAttribPointer()、glEnableVertexAttribArray()和 glDisableVertexAttribArray()函数来指定通用顶点属性。因此,您可以指定所有顶点属性;位置、法线、颜色和纹理坐标,使用单一 API。

// bind VBOs for vertex array and index arrayglBindBuffer(GL_ARRAY_BUFFER, vboId1); // for vertex coordinatesglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboId2); // for indicesglEnableVertexAttribArray(attribVertex); // activate vertex position arrayglEnableVertexAttribArray(attribNormal); // activate vertex normal arrayglEnableVertexAttribArray(attribTexCoord); // activate texture coords array// set vertex arrays with generic APIglVertexAttribPointer(attribVertex, 3, GL_FLOAT, false, stride, offset1);glVertexAttribPointer(attribNormal, 3, GL_FLOAT, false, stride, offset2);glVertexAttribPointer(attribTexCoord, 2, GL_FLOAT, false, stride, offset3);// draw 6 faces using offset of index arrayglDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, 0);glDisableVertexAttribArray(attribVertex); // deactivate vertex positionglDisableVertexAttribArray(attribNormal); // deactivate vertex normalglDisableVertexAttribArray(attribTexCoord); // deactivate texture coords// bind with 0, so, switch back to normal pointer operationglBindBuffer(GL_ARRAY_BUFFER, 0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); Updating VBO

VBO优于display list的优点是客户端可以读取和修改缓冲区对象数据,但display list不能。更新 VBO 的最简单方法是使用 glBufferData()或 glBufferSubData() 再次将新数据复制到绑定的 VBO 中。对于这种情况,您的应用程序应该始终在运行中具有一个有效的顶点数组。这意味着您必须始终拥有 2 个顶点数据副本:一个在您的应用程序中,另一个在 VBO 中。

另一种修改缓冲区对象的方法是将缓冲区对象映射到客户端的内存中,客户端可以使用指向映射缓冲区的指针来更新数据。下面介绍如何将 VBO 映射到客户端的内存中以及如何访问映射的数据。

glMapBuffer()

VBO 提供 glMapBuffer()以便将缓冲区对象映射到客户端的内存中。

void* glMapBuffer(GLenum target, GLenum access)

如果 OpenGL 能够将缓冲区对象映射到客户端的地址空间,则 glMapBuffer()将返回指向缓冲区的指针。否则返回NULL。

第一个参数 target 之前在 glBindBuffer() 中提到过,第二个参数 access flag 指定如何处理映射数据:读取、写入或两者兼而有之。

GL_READ_ONLYGL_WRITE_ONLYGL_READ_WRITE

glMapBuffer()会导致同步问题。如果 GPU 仍在使用缓冲区对象,glMapBuffer()将不会返回,直到 GPU 使用相应的缓冲区对象完成其工作。

为了避免等待(空闲等待),您可以先用空指针调用glBufferData(),然后再调用glMapBuffer()。

在这种情况下,即使 GPU 仍在处理先前的数据,先前的数据将被丢弃并且glMapBuffer()会立即返回一个新分配的指针。但是,此方法仅在您想更新整个数据集时有效,因为您丢弃了以前的数据。如果您只想更改部分数据或读取数据,最好不要释放先前的数据。

glUnmapBuffer() GLboolean glUnmapBuffer(GLenum target)

修改 VBO 的数据后,必须从客户端的内存中取消映射缓冲区对象。如果成功,glUnmapBuffer() 返回 GL_TRUE。当它返回 GL_FALSE 时,VBO 的内容在缓冲区被映射时被破坏。损坏是由屏幕分辨率更改或窗口系统特定事件引起的。在这种情况下,必须重新提交数据。

这是使用映射方法修改 VBO 的示例代码。

// bind then map the VBOglBindBuffer(GL_ARRAY_BUFFER, vboId);float* ptr = (float*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);// if the pointer is valid(mapped), update VBOif(ptr){ updateMyVBO(ptr, ...); // modify buffer data glUnmapBuffer(GL_ARRAY_BUFFER); // unmap it after use}// you can draw the updated VBO

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。