经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 软件/图像 » OpenGL » 查看文章
LearnOpenGL学习笔记(二)纹理
来源:cnblogs  作者:青空哲也  时间:2019/11/11 8:42:00  对本文有异议

开始学习OpenGL,参考的是著名的LearnOpenGL这个网站,在这里做一些总结性的记录,只是方便自己日后查找或者记录自己的一些拓展思考,关于OpenGL的具体内容请移步:
https://learnopengl-cn.github.io/
或英文原版:https://learnopengl.com/

纹理坐标

为了能够把纹理映射(Map)到三角形上,我们需要指定三角形的每个顶点各自对应纹理的哪个部分。这样每个顶点就会关联着一个纹理坐标(Texture Coordinate),用来标明该从纹理图像的哪个部分采样(译注:采集片段颜色)。之后在图形的其它片段上进行片段插值(Fragment Interpolation)。

所以先在顶点数据中加入纹理坐标并记得将其传入顶点着色器:

  1. float vertices[] = {
  2. // ---- 位置 ---- ---- 颜色 ---- - 纹理坐标 -
  3. 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上
  4. 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 右下
  5. -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 左下
  6. -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // 左上
  7. };

读取图片

用的stb_image.h这个头文件:

  1. //读取图片
  2. int width, height, nrChannels;//图片宽度,高度,颜色通道数量
  3. stbi_set_flip_vertically_on_load(true);//翻转y轴
  4. unsigned char* data = stbi_load("wall.jpg", &width, &height, &nrChannels, 0);

生成纹理对象

类似于之前生成VAO、VBO的流程:

  1. //生成纹理
  2. unsigned int texture1;
  3. glGenTextures(1, &texture1);//第一个参数为生成纹理的数量
  4. glBindTexture(GL_TEXTURE_2D, texture1);//绑定纹理对象

设置纹理

设置纹理环绕方式和纹理过滤选项,决定了纹理坐标超过1时如何采样以及多级渐远纹理级别之间的过滤方式,具体含义和效果见LearnOpenGL。

  1. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  2. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  3. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  4. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

生成纹理

这里要注意glTexImage2D的第3个和第7个参数,决定了纹理的源格式和我们希望的处理格式,如果原图带有Alpha通道,这里要改成GL_RGBA,原文中没有说明导致我一直加载不出带透明通道的图,后来看源码才发现。

  1. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);//生成纹理
  2. glGenerateMipmap(GL_TEXTURE_2D);//生成多级渐远纹理

结束之后记得释放图像的内存:

  1. stbi_image_free(data);//释放图像内存

片元着色器采样

纹理坐标传入顶点着色器后直接传到片元着色器即可,至于纹理对象本身定义为sampler2D类型的uniform变量,通过GLSL的texture函数即可进行采样。

  1. #version 330 core
  2. out vec4 FragColor;
  3. in vec3 ourColor;
  4. in vec2 TexCoord;
  5. uniform sampler2D ourTexture;
  6. void main()
  7. {
  8. FragColor = texture(ourTexture, TexCoord);
  9. }

结果:

纹理单元

可以看到上面片元着色器中定义了uniform的纹理变量,但我们并没有在程序中给这个uniform变量传值,这是因为OpenGL中有很多纹理单元,如果只有一个纹理对象,会默认分配至GL_TEXTURE0,sampler变量也会默认从0号单元中采样,所以如果需要渲染更多的纹理,需要分配不同的纹理单元。

更改一下片元着色器,用mix函数让两张图片进行混合:

  1. #version 330 core
  2. out vec4 FragColor;
  3. in vec3 ourColor;
  4. in vec2 TexCoord;
  5. uniform sampler2D texture1;
  6. uniform sampler2D texture2;
  7. void main()
  8. {
  9. FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.3);
  10. }

先按之前的方式读入第二张图(这里读了一张带透明通道的图所以记得glTexImage2D的参数改为GL_RGBA):

  1. unsigned int texture2;
  2. glGenTextures(1, &texture2);
  3. glBindTexture(GL_TEXTURE_2D, texture2);
  4. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  5. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  6. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  7. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  8. data = stbi_load("face.png", &width, &height, &nrChannels, 0);
  9. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
  10. glGenerateMipmap(GL_TEXTURE_2D);
  11. stbi_image_free(data);

然后再渲染循环之前给sampler指定对应的纹理单元(注意一定要先激活shader程序):

  1. shader.use();
  2. glUniform1i(glGetUniformLocation(shader.ID, "texture1"), 0);
  3. glUniform1i(glGetUniformLocation(shader.ID, "texture2"), 1);

然后激活对应的纹理单元并将纹理对象绑定上去:

  1. glActiveTexture(GL_TEXTURE0);
  2. glBindTexture(GL_TEXTURE_2D, texture1);
  3. glActiveTexture(GL_TEXTURE1);
  4. glBindTexture(GL_TEXTURE_2D, texture2);

结果:

关于像素对齐的一个小坑

在LearnOpenGL这一章的评论区发现有人说,当读取的图片宽度为奇数时显示不正常,而我试了一下宽度为奇数的图片程序直接就崩溃了,评论区也给出了解决方法,加入一行代码之后就正常了:

  1. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

这行代码的作用是设置OpenGL读取数据的对齐方式,OpenGL默认为4字节对齐,也就是说一行图像数据的长度必须是4的倍数,我又尝试了一下宽度为偶数但不是4的倍数的图片,果然显示不正确:

所以上面的代码就是设置读取数据的方式为1个字节对齐,这样OpenGL会一个一个字节读取,不会导致越界,但这样读取效率肯定也会降低,所以最好的方法还是提供宽度为4的倍数的图片。

原文链接:http://www.cnblogs.com/LiveForGame/p/11827378.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号