开始学习OpenGL,参考的是著名的LearnOpenGL这个网站,在这里做一些总结性的记录,只是方便自己日后查找或者记录自己的一些拓展思考,关于OpenGL的具体内容请移步:

https://learnopengl-cn.github.io/

或英文原版:https://learnopengl.com/

纹理坐标

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

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

	float vertices[] = {
// ---- 位置 ---- ---- 颜色 ---- - 纹理坐标 -
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 右下
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 左下
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // 左上
};

读取图片

用的stb_image.h这个头文件:

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

生成纹理对象

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

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

设置纹理

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

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);

生成纹理

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

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

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

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

片元着色器采样

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

#version 330 core
out vec4 FragColor; in vec3 ourColor;
in vec2 TexCoord; uniform sampler2D ourTexture; void main()
{
FragColor = texture(ourTexture, TexCoord);
}

结果:

纹理单元

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

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

#version 330 core
out vec4 FragColor; in vec3 ourColor;
in vec2 TexCoord; uniform sampler2D texture1;
uniform sampler2D texture2; void main()
{
FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.3);
}

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

	unsigned int texture2;
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
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);
data = stbi_load("face.png", &width, &height, &nrChannels, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(data);

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

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

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

	glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);

结果:

关于像素对齐的一个小坑

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

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

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

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

LearnOpenGL学习笔记(二)纹理的更多相关文章

  1. webgl学习笔记五-纹理

    写在前面 建议先阅读下前面我的三篇文章. webgl学习笔记一-绘图单点 webgl学习笔记二-绘图多点 webgl学习笔记三-平移旋转缩放 术语 : 纹理 :图像 图形装配区域 :顶点着色器顶点坐标 ...

  2. WPF的Binding学习笔记(二)

    原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...

  3. AJax 学习笔记二(onreadystatechange的作用)

    AJax 学习笔记二(onreadystatechange的作用) 当发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态XMLHttpRequest对象提供了on ...

  4. [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计

    源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...

  5. JMX学习笔记(二)-Notification

    Notification通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知. 这里写 ...

  6. java之jvm学习笔记二(类装载器的体系结构)

    java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...

  7. Java IO学习笔记二

    Java IO学习笔记二 流的概念 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成. 程序中的输入输 ...

  8. 《SQL必知必会》学习笔记二)

    <SQL必知必会>学习笔记(二) 咱们接着上一篇的内容继续.这一篇主要回顾子查询,联合查询,复制表这三类内容. 上一部分基本上都是简单的Select查询,即从单个数据库表中检索数据的单条语 ...

  9. NumPy学习笔记 二

    NumPy学习笔记 二 <NumPy学习笔记>系列将记录学习NumPy过程中的动手笔记,前期的参考书是<Python数据分析基础教程 NumPy学习指南>第二版.<数学分 ...

  10. Learning ROS for Robotics Programming Second Edition学习笔记(二) indigo tools

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

随机推荐

  1. asp.net Forms身份验证详解

    在做网站的时候,都会用到用户登录的功能.对于一些敏感的资源,我们只希望被授权的用户才能够访问,这让然需要用户的身份验证.对于初学者,通常将用户登录信息存放在Session中,笔者在刚接触到asp.ne ...

  2. WXSS选择器

  3. (模板)AC自动机模板

    模板1. 给出模式串和文本串,文本串长度小于1e6,模式串长度之和小于1e6,求文本串中有多少模式串出现. 题目链接:https://www.luogu.org/problem/P3808 AC co ...

  4. 修改 ubuntu NTFS 文件系统下没有执行权限的问题

    由于NTFS本身的特殊性,不能对其分区的文件权限进行修改,无论是sudo还是root都没有用. 安装以下两个插件解决问题: sudo apt-get install ntfs-3g //这个12.04 ...

  5. SpringBoot中service注入失败(A component required a bean of type 'XXService' that could not found)

    先写了JUnit,发现启动不了,注释掉有问题的service也不可以.可能是因为spring开始时会加载所有service吧. 按照网友们的说法,一般需要检查: 1.入口类有没有写MapperScan ...

  6. 第五章 模块之 struct、dis、正则表达式、异常处理

    5.15 struct模块 pack 能够把所有的数字都固定的转换成4字节 5.16 dis dis.dis 查看计算机指令 5.16 正则表达式 基础 正则表达式概念: 是一种规则(元字符,量词) ...

  7. 通用32位CPU 常用寄存器及其作用

    目录 32位CPU所含有的寄存器 数据寄存器 变址寄存器 指针寄存器 段寄存器 指令指针寄存器 标志寄存器 32位CPU所含有的寄存器 4个数据寄存器(EAX.EBX.ECX和EDX) 2个变址和指针 ...

  8. 在vue中使用ElementUI

    完整引用ElementUI: 安装:在需要使用到的vue项目目录下,使用npm下载安装: npm/cnpm i element-ui -S/--save <!-- 引入样式 --> < ...

  9. oracle DBA操作

    sqlplus sys/tiger  as sysdba; alter user scott account unlock; 用户已更改 切换用户:conn scott/tiger as sysdba ...

  10. Istio流量管理能力介绍

    1      Istio是什么? Istio 1.0版本于8月1号凌晨准点发布,核心特性已支持上生产环境,各大微信公众号.博客纷纷发文转载.那么Istio到底是什么?能解决问题什么? 1. Istio ...