原博主博客地址:http://blog.csdn.net/qq21497936
本文章博客地址:http://blog.csdn.net/qq21497936/article/details/79196615
《OpenGL学习笔记》系列博客目录地址:http://blog.csdn.net/qq21497936/article/category/7315532
OpenGL学习笔记(十三):将纹理贴图应用到四边形上,对VAO/VBO/EBO/纹理/着色器的使用方式进行总结
前话
上一章节,我们使用了纹理进行贴图,但是是三角形了,如何把四边形的贴上去,就是本章节的要点,通过本章节,您可能对使用EBO有更深刻的认识,同时在最后,读者对VAO、VBO和EBO的使用方法进行再一次的梳理和总结,加强学习效果。
《OpenGL学习笔记》系列博客目录地址:http://blog.csdn.net/qq21497936/article/category/7315532
基础程序
本章节基础程序使用《OpenGL学习笔记(十二):纹理的使用》完成的demo。(CSDN目前无法设置免积分下载):
文章地址:http://blog.csdn.net/qq21497936/article/details/79184344
demo下载:http://download.csdn.net/download/qq21497936/10227600
本章完成的Demo
下载地址:http://download.csdn.net/download/qq21497936/10229560
额外修改了修改了片段着色器:
#version 330 core out vec4 FragColor; in vec3 ourColor; in vec2 texCoord; uniform sampler2D ourTexture; void main() { // FragColor = texture(ourTexture, texCoord); FragColor = texture(ourTexture, texCoord) * vec4(ourColor, 1.0); }
纹理贴到四边形上
之前的Demo中,我们将窗户纸贴到了三角形上,之所以把四边形(举一反三:多边形)单独一章节,是因为四边形与大家潜意识里面的四边形贴图不一样,下面是上章节使用的图片
我们上章节(笔记十二)解析纹理如下:
下面笔者猜想大家在读到之前章节的笔记上,应该是认为可以直接画一个正方向,毕竟之前的代码是直接画线和三角形,那么应该像程序一样有可以直接画四边形,并对四边形贴图。所以大家所认为的四边形的顶点数据应该这样如下:
但是实际对绘制只能是三角形,纹理对于绘制,所以实际情况是下图:
(注意:随边画哪个三角形,只要能覆盖全部即可),笔者选择的是上图的2个。
原来的顶点数据是:
float vertices[] = { // 三角形坐标 颜色 纹理坐标 -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,0.0f, 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.5f,1.0f };
修改为:
// 四边形,共四个点,因为只能画三角形,所以要6个点(可使用EBO来实现,即可只要四个点) float vertices[] = { -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,0.0f, // 左下角 * 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,0.0f, // 右下角 ** 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,1.0f, // 右上角 *** -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,0.0f, // 左下角 *** 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,1.0f, // 右下角 ** -0.5f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,1.0f // 左上角 * };
之前的demo画了一个三角形:
glDrawArrays(GL_TRIANGLES, 0, 3);
修改为:
glDrawArrays(GL_TRIANGLES, 0, 6);
画2个三角形,共6个点(注意:要是用画2个点则不会画,或4个点则只画一个,具体opengl是否绘制多余的点,笔者未研究,理论上认为画2个点纹理是1D的,肯能是画了表现不出来,可能是没画,以后有机会再研究)。
效果截图如下:
上图的效果修改了着色器的:
#version 330 core out vec4 FragColor; in vec3 ourColor; in vec2 texCoord; uniform sampler2D ourTexture; void main() { // FragColor = vec4(ourColor, 1.0f); FragColor = texture(ourTexture, texCoord) * vec4(ourColor, 1.0); }
使用EBO
不使用EBO时,使用的顶点数据如下:
// 四边形,共四个点,因为只能画三角形,所以要6个点(可使用EBO来实现,即可只要四个点) float vertices[] = { -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,0.0f, // 左下角 * 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,0.0f, // 右下角 ** 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,1.0f, // 右上角 *** -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,0.0f, // 左下角 *** 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,1.0f, // 右下角 ** -0.5f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,1.0f // 左上角 * };
发现其实总共就四个顶点,但是每次重复时候,都要写出来,不但增加工作量还容易导致不好计算,不符合人类的认知(我们认为四边形就四个顶点),此时,我们可以使用EBO,EBO是使用索引数,我们定义如下:
// 使用EBO float vertices[] = { -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,0.0f, // 左下角 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,0.0f, // 右下角 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,1.0f, // 右上角 -0.5f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,1.0f // 左上角 }; // 索引 unsigned int indices[] = { 0,1,2, // 第一个三角形 0,2,3 // 第二个三角形 };
使用EBO步骤:
- 创建(标识ID)。
- 绑定(顶点数据绑定缓存)。
- 解绑。
- 绘制(再次绑定使用的EBO,并使用Elements绘制)。
- 删除(末尾删除)。
… unsigned int VBO, VAO, EBO; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); // 第一步:获取EBO唯一标识 glGenBuffers(1, &EBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 第二步:绑定EBO缓存 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(0 * sizeof(float))); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); // 添加进缓存,启用纹理 glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); glEnableVertexAttribArray(2); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); while (!glfwWindowShouldClose(window)) { processInput(window); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); shader.use(); glBindVertexArray(VAO); // 第三步:使用索引,绘制三角形,6个顶点 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // 使用点 // glDrawArrays(GL_TRIANGLES, 0, 6); glfwSwapBuffers(window); glfwPollEvents(); } glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); // 第四步:删除EBO glDeleteBuffers(1, &EBO); glfwTerminate(); …
可以从以上代码中返现,EBO与VBO其实使用步骤是一样的。
效果如图:
总结VAO、VBO、EBO、纹理
现阶段总结使用过程大致如下(如有错误请留言批评指正,谢谢各位大神):
方式 |
VAO |
VBO |
EBO |
纹理 |
获取 |
getGenVertexArrays |
getGenBuffers |
getGenBuffers |
glGenTextures |
绑定 |
glBindBuffer |
glBindBuffer |
glBindBuffer |
glBindTexture |
属性定义 |
glVertexAttribPointer |
glVertexAttribPointer |
不需要 |
glTexImage2D glGenerateMipmap |
解绑 |
glBindVertexArray |
glBindBuffer |
glBindBuffer |
不解绑 |
使用 |
glBindVertexArray glDrawArrays |
默认作用于绑定时的顶点 |
glBindBuffer glDrawElements |
默认使用 |
删除 |
glDeleteVertexArrays |
glDeleteBuffers |
glDeleteBuffers |
|
总结Shader着色器使用
顶点着色器:创建(标识),绑定(代码),编译(着色器),获取编译结果
片段着色器:创建(标识),绑定(代码),编译(着色器),获取编译结果
着色器程序:创建(表示) ,绑定(各着色器id),连接(全局连接到着色器程序标识上),删除(释放使用的着色器内存)
着色器使用:使用该着色器id
具体细节查看《OpenGL学习笔记(十一):封装自己的着色器类》
文章地址:http://blog.csdn.net/qq21497936/article/details/79181818
原博主博客地址:http://blog.csdn.net/qq21497936
本文章博客地址:http://blog.csdn.net/qq21497936/article/details/79196615