C-4. 对正方体加载纹理

  • 初始化OpenGL
  • 准备数据
  • 纹理图片准备
  • 建立着色器
    • 顶点着色器
    • 片段着色器
  • 纹理过滤方式的切换
  • 渲染纹理
  • 效果图

作业要求:
1、使用三种纹理过滤方式加载纹理(线性采样、mipmap 和最近点采样);
2、加载纹理的图片可以自己设定;
3、各个面的纹理不同;
4、鼠标或者键盘控制纹理过滤方式的切换。

初始化OpenGL

同之前C-2和C-3的报告。

准备数据

建立顶点数组对象。同时注册顶点的位置属性和纹理坐标属性。属性的序号值指明了数据的存放位置,以在着色器中通过对应位置找到位置和纹理坐标数据。
顶点的position属性满足题设的立方体要求。在后面渲染时使用glDrawArrays(GL_TRIANGLES, 0, 36)来绘制每个三角形,即不同的三角形面片之间不复用顶点数据。

 float vertices[] = {// positions          // texture coords-0.5f, -0.5f, -0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 0.0f,-0.5f, -0.5f, -0.5f,  1.0f, 0.0f,-0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,-0.5f,  0.5f,  0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  1.0f, 0.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,-0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  0.0f, 1.0f,0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f, -0.5f, -0.5f,  1.0f, 0.0f,-0.5f, -0.5f,  0.5f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f,-0.5f, -0.5f,  0.5f, 0.0f, 1.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f,0.5f, -0.5f,  0.5f, 1.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f,  0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f};// first, configure the pyramid's VAO, VBO, EBOunsigned int VBO, VAO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// position attributeglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);// texture attributeglVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3*sizeof(float)));glEnableVertexAttribArray(1);glBindVertexArray(0);//unbind

纹理图片准备

根据作者本人喜好,采用了如下的6张贴图。

图1 图2 图3
图4 图5 图6

使用stb_image.h库加载纹理。通过glTexParameteri设置纹理的wrapfilter参数。wrap参数选择GL_REPEAT使得纹理坐标超出[0, 1]范围时按周期性重复采样,另外有GL_CLAMP_TO_EDGE选项使超出范围的采样延拓到边缘。初始化加载纹理时filter参数都先采用GL_LINEAR的过滤方式。具体根据用户输入而切换的控制放在渲染循环中。stbi_load读入图片的数据后,根据图片的分量通道数通过glTexImage2D生成纹理。

 GLuint textures[6];const char * textPaths[] = {"../resources/gantayipao.jpg","../resources/jingrui.jpg","../resources/kaipao.jpg","../resources/kongerlengzi.jpg","../resources/tiancai.jpg","../resources/yidalipao.jpg"};// glGenTextures(6, textures);for (int i = 0; i < 6; i++) {//初始化加载纹理时都采用GL_LINEAR的过滤方式glGenTextures(1, &textures[i]);glBindTexture(GL_TEXTURE_2D, textures[i]);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);stbi_set_flip_vertically_on_load(true);int width, height, nrChannels;unsigned char *data = stbi_load(textPaths[i], &width, &height, &nrChannels, 0);if (data) {GLenum format;if (nrChannels == 1)format = GL_RED;else if (nrChannels == 3)format = GL_RGB;else if (nrChannels == 4)format = GL_RGBA;glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);glGenerateMipmap(GL_TEXTURE_2D);stbi_image_free(data);} else {std::cout << "Texture failed to load at path: " << textPaths[i] << std::endl;stbi_image_free(data);}}

建立着色器

由于使用纹理贴图,不涉及任何光照,因此顶点着色器和片段着色器都非常简单。只需要在顶点着色器中读入纹理坐标并传送给片段着色器即可。

顶点着色器

#version 460 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;out vec2 TexCoord;uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;void main()
{gl_Position = projection * view * model * vec4(aPos, 1.0);TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}

片段着色器

#version 460 core
out vec4 FragColor;in vec2 TexCoord;// texture samplers
uniform sampler2D texture;void main()
{FragColor = texture(texture, TexCoord);
}

纹理过滤方式的切换

通过在process_input函数中接受键盘输入的信号而改变变量filter_mode的值,

void processInput(GLFWwindow *window) {... ...if (glfwGetKey(window, GLFW_KEY_0) == GLFW_PRESS)filter_mode = LINEAR;else if (glfwGetKey(window, GLFW_KEY_1) == GLFW_PRESS)filter_mode = MIPMAP;else if (glfwGetKey(window, GLFW_KEY_2) == GLFW_PRESS)filter_mode = NEAREAST;
}

进而在渲染循环中,对每张纹理图修改filter参数。需要注意的是,利用glTexParameteri修改时需要先用glBindTexture绑定到GL_TEXTURE_2D纹理的位置上。需要注意的是,LearnOpenGL指出:

一个常见的错误是,将放大过滤的选项设置为多级渐远纹理过滤选项之一。这样没有任何效果,因为多级渐远纹理主要是使用在纹理被缩小的情况下的:纹理放大不会使用多级渐远纹理,为放大过滤设置多级渐远纹理的选项会产生一个GL_INVALID_ENUM错误代码。

因此选择MIPMAP选项时,只将缩小过滤设置为多级,而放大过滤仍采用GL_LINEAR

 switch (filter_mode){case LINEAR:for (int i = 0; i < 6; i++) {glBindTexture(GL_TEXTURE_2D, textures[i]);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);}break;case NEAREAST:for (int i = 0; i < 6; i++) {glBindTexture(GL_TEXTURE_2D, textures[i]);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);}break;case MIPMAP:for (int i = 0; i < 6; i++) {glBindTexture(GL_TEXTURE_2D, textures[i]);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);}break;default:std::cout << "invalid filter_mode of " << filter_mode << std::endl;break;}

渲染纹理

在渲染循环中,除了需要设定着色器的三个坐标变换的矩阵,还要通过setInt("texture", 0)设定片段着色器中的sampler2D值:uniform sampler2D texture,这个数需要与后续激活的纹理单元号保持一致glActiveTexture(GL_TEXTURE0)(不显式激活时默认为0),片段着色器才能正确地采样到纹理。

ourShader.use();
ourShader.setInt("texture", 0);
ourShader.setMat4("model", glm::mat4(1.0f));
ourShader.setMat4("view", camera.GetViewMatrix());
ourShader.setMat4("projection", glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f));glBindVertexArray(VAO);
//依次画两个三角形(六个顶点)
for (int i = 0; i < 6; i++) {glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, textures[i]);// bind corresponding textureglDrawArrays(GL_TRIANGLES, 6*i, 6);
}

效果图

整体效果图如下所示。

图1 图2

在放大到超出原有图片分辨率的情况下,观察不同纹理过滤方式的效果,如下图所示。

  • 线性采样

  • mipmap

  • 最近点采样

C-4:对正方体加载纹理相关推荐

  1. java3d立方体_java3d 立方体 加载纹理

    研究了很久的java3d,从昨天开始研究怎么加载纹理,今天终于搞定.原本想用数组加载图片,但是总是ava.lang.NullPointerException.于是就放弃了 一个个加载..有点傻- 本人 ...

  2. OpenGL.Shader:2-Android Cpp下加载assets图片资源 / 各种格式加载纹理 / 在线找AndroidNative源码

    OpenGL.Shader:2-Android Cpp下读取assets图片资源 / 读取图片加载纹理 / 在线找AndroidNative源码 (AS3.x rebuild出现More than o ...

  3. cocos2dx 3.3 异步加载纹理

    这里以3d场景加载为例,2d情况类似. 先同步加载模型数据和尺寸缩小了100倍的贴图,创建mesh.然后异步加载所有精细纹理并每加载完一个就替换一个,并进入场景. 如此做法的效果是当刚进入场景时看到的 ...

  4. 使用 wxImage 为 OpenGL 加载纹理

    使用 wxImage 为 OpenGL 加载纹理 使用 wxImage 为 OpenGL 加载纹理 使用 wxImage 为 OpenGL 加载纹理 您可以使用 wxImage 为 OpenGL 加载 ...

  5. OpenGL LoadTexture加载纹理的实例

    OpenGL LoadTexture加载纹理 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #define USE_GL3W #include <vermi ...

  6. opengl es java_java – 在Android OpenGL ES App中加载纹理

    1)您应该根据需要分配尽可能多的纹理名称.一个用于您正在使用的每个纹理. 加载纹理是一项非常繁重的操作,会使渲染管道停顿.所以,你永远不应该在游戏循环中加载纹理.您应该在呈现纹理的应用程序状态之前具有 ...

  7. OpenGL加载纹理glGenTextures——内存优化(OpenGL内存泄漏)

    前言 先上图看我程序在加载纹理时,内存泄漏情况: 正常内存大小 5分钟内存泄漏情况 因为程序一直在接收二维数组(图像像素数据)然后实时绘制到界面,所以会一直加载纹理图像,OpenGL产生纹理id函数g ...

  8. lua/cocos加载动画以及可以使用加载纹理的方式来替换图片并且加载个人制作的艺术字体(fnt字体)

    1.加载spine/json(ExportJson)骨骼动画 现在用的比较多 local spineAnim = sp.SkeletonAnimation:create("base/res/ ...

  9. 使用FreeImage加载纹理

    DirectX9中提供了函数D3DXCreateTexureFromFile函数,但是对用户是透明的,不知道其实现,并且在实际当中一般都是用多线程来进行资源的处理,就像自己实现一下 考虑了两种方法来适 ...

最新文章

  1. UVa 11624,两次BFS
  2. 软件测试-PR录制脚本程序的时候出现license invalid,error code=-13或者-24的错误
  3. iOS Assigning to 'idXXXDelegate' from incompatible type 'BViewController *__strong'
  4. MySQL优化INSERT的性能
  5. 微信APP支付的坑 - errorcode=-1
  6. ruby中的回调方法和钩子方法
  7. mysql查看事件任务内容_MySql事件计划任务
  8. 查看grafana版本_使用 Prometheus 与 Grafana 为 Kubernetes 集群建立监控与警报机制
  9. 洛谷 P1164:小A点菜(DP/DFS)
  10. SQL Server 2008 对 T-SQL 语言的增强
  11. apache ii评分怎么评_APACHE-II评分表.doc
  12. 企业级静态代码分析工具清单
  13. VUE项目实战(一)
  14. 【渝粤教育】广东开放大学 跨文化商务沟通 形成性考核 (42)
  15. 撤销 git rebase
  16. 安卓小游戏之2048
  17. android ExtCertPathValidatorException: Could not validate
  18. 数组名和数组名取地址 的区别
  19. 新乡学院二批计算机类分数线,新乡学院录取分数线2021是多少分(附历年录取分数线)...
  20. Python 文件目录操作

热门文章

  1. Mac下大文件压缩成多个包,即分卷压缩
  2. CentOS安装X Window
  3. 机器学习原来这么有趣!第一章:全世界最简单的机器学习入门指南
  4. 疫情持续反复、远程工作加重职业倦怠,员工“安全感”将是企业关键考虑因素 | 美通社头条...
  5. 【链块技术36期】智能合约基础语言(一)——Solidity概述和开发工具的使用
  6. sysbench cpu 性能测试
  7. 游戏策划学习第二十七天
  8. Linux下的豆瓣FM音乐播放器和虾米音乐播放器
  9. 8. 邵婷 校展示课二年级下册《数学广角--推理》照片
  10. excel到期弹窗提醒桌面弹_求助Excel到期自动弹窗提醒