复制粘贴运行
认识总是从低级到高级的,我是小白,处于低级的认识;只会复制粘贴运行。
那就干吧。
计算机图形学_中国大学MOOC(慕课) (icourse163.org)
直接cmake出来,也行

得设置一下启动项目


尝试学习EBO
学不会很正常,是小白的常态,所以,不要有心理负担。
首先,为什么要有EBO?这个东西为什么要存在?
之前已经了解过了一些VAO+VBO的相关函数,勉勉强强能看懂这个代码在干什么了。
完整代码在这里
运行结果是这个

但是这存在一些问题:
4边形,4个顶点就够了,这里却在显存里存了6个顶点,冗余了2个,也就是,50%。
// 四边形的顶点数据
float vertices[] = {
// 第一个三角形
0.5f, 0.5f, 0.0f, // 右上
0.5f, -0.5f, 0.0f, // 右下
-0.5f, -0.5f, 0.0f, // 左下
// 第二个三角形
-0.5f, -0.5f, 0.0f, // 左下
0.5f, 0.5f, 0.0f, // 右上
-0.5f, 0.5f, 0.0f // 左上
};
显存,很贵的。。还冗余50%。怎么才能省着用?——EBO诞生了。
有了EBO,存VBO时就可以忽略那些重复的顶点属性了。
VBO顶点属性内容很多(最多16个吧),重复一下,吃不消。。
index,一个数值而已,重复一下,没啥,可以接受。
设计的挺好的……
VAO+VBO+EBO的代码在这里
结果在这里:

索引也是占空间的,在这种小模型上,EBO说不定起不了作用。但大模型应该EBO就发挥作用了吧。
一些相关链接
网页1
短小精悍的总结
- 顶点缓冲对象VBO是在显卡存储空间中开辟出的一块内存缓存区,用于存储顶点的各类属性信息,如顶点坐标,顶点法向量,顶点颜色数据等。在渲染时,可以直接从VBO中取出顶点的各类属性数据,由于VBO在显存而不是在内存中,不需要从CPU传输数据,处理效率更高。所以可以理解为VBO就是显存中的一个存储区域,可以保持大量的顶点属性信息。并且可以开辟很多个VBO,每个VBO在OpenGL中有它的唯一标识ID,这个ID对应着具体的VBO的显存地址,通过这个ID可以对特定的VBO内的数据进行存取操作。
- VAO本身并没有存储顶点的相关属性数据,这些信息是存储在VBO中的,VAO相当于是对很多个VBO的引用,把一些VBO组合在一起作为一个对象统一管理。执行VAO绑定之后其后的所有VBO配置都是这个VAO对象的一部分,可以说VBO是对顶点属性信息的绑定,VAO是对很多个VBO的绑定。
- EBO中存储的内容就是顶点位置的索引indices,EBO跟VBO类似,也是在显存中的一块内存缓冲器,只不过EBO保存的是顶点的索引。
- VAO简单理解其实代表的就是模型的数据,当可能需要很多个模型,每个模型对应一个VAO,所以需要有个id来区分,创建vao的时候会返回一个vaoID。VAO中有一个属性列表,默认有16个属性(0 - 15),我们可以为属性指定数据,其中属性可以是顶点位置,颜色,法线,纹理坐标等等我们需要的数据,其中的每一个属性对应的数据其实就来自VBO。
引用自:
(31条消息) OpenGl(1) VAO、VBO、EBO的理解_Coder_Penguin的博客-优快云博客_vao
网页2
这个里面,给出了这几个Object的伪代码
- 数据结构的定义
还是这个熟悉的图
这段代码,和上面那个图,呼应的。。
struct VertexAttributeState { bool bIsEnabled = false; int iSize = 4; //This is the number of elements in each attrib, 1-4. unsigned int iStride = 0; VertexAttribType eType = GL_FLOAT; bool bIsNormalized = false; bool bIsIntegral = false; void * pPtrOrBufferObjectOffset = 0; BufferObject * pBufferObj = 0; }; struct VertexArrayObjectState { BufferObject *pElementArrayBufferObject = NULL; VertexAttributeState attributes[MAX_VERTEX_ATTRIB]; }
- 相关的一些函数的实现
static VertexArrayObjectState *pContextVAOState = new VertexArrayObjectState(); static BufferObject *pCurrentArrayBuffer = NULL; //绑定缓冲对象 如VBO EBO等 void glBindBuffer(enum target, uint buffer) { BufferObject *pBuffer = ConvNameToBufferObj(buffer); switch(target) { //绑定VBO 先用一个临时变量存储 case GL_ARRAY_BUFFER: pCurrentArrayBuffer = pBuffer; break; //绑定EBO 直接更新 case GL_ELEMENT_ARRAY_BUFFER: pContextVAOState->pElementArrayBufferObject = pBuffer; break; ... } } //禁用属性 void glEnableVertexAttribArray(uint index) { pContextVAOState->attributes[index].bIsEnabled = true; } //启用属性 void glDisableVertexAttribArray(uint index) { pContextVAOState->attributes[index].bIsEnabled = false; } //链接顶点属性指针 void glVertexAttribPointer(uint index, int size, enum type, boolean normalized, sizei stride, const void *pointer) { VertexAttributeState &currAttrib = pContextVAOState->attributes[index]; currAttrib.iSize = size; currAttrib.eType = type; currAttrib.iStride = stride; currAttrib.bIsNormalized = normalized; currAttrib.bIsIntegral = true; currAttrib.pPtrOrBufferObjectOffset = pointer; //此时才会保存VBO!! currAttrib.pBufferObj = pCurrentArrayBuffer; }通过这段伪代码,有以下认识
- bind索引数组就直接改变了vao,而bind顶点数组,改变了内部的顶点缓存指针,而真正的将顶点缓存指针的值写入vao其实是glVertexAttribPointer函数。
- 这段代码体现了VBO和顶点属性指针的关系,在绑定VBO后,一定要设置好顶点属性指针,不然就等于白给。
- 如果在解绑VAO之前解绑了EBO,那么该VAO存储的EBO就无了,自然绘制不出东西。这个EBO设置的就没意义了。
- VAO本来的意义就是这个结构是存储在服务端内存中的(也就是显存中),你只要bind一个VAO就能获得一次drawcall需要的所有信息,所以它快
- 绑定顺序:先绑定VAO,然后绑定VBO和EBO,再链接顶点属性指针
- 解绑顺序:在绑定VBO并链接顶点属性指针之后,即可解绑该VBO,但是解绑EBO的操作一定要放到解绑VAO的操作之后。就是说,解绑顺序是:VBO(注意要先链接顶点属性指针)、VAO、EBO
引用自:

767

被折叠的 条评论
为什么被折叠?



