OpenGL(四) 纹理贴图

news/2024/9/20 13:54:28/

几何模型&材质&纹理

渲染一个物体需要:

  • 几何模型:决定了物体的形状
  • 材质:绝对了当灯光照到上面时的作用效果
  • 纹理:决定了物体的外观

纹理对象

纹理有2D的,有3D的。2D图像就是一张图片,3D图像是在渲染大气层等立体物体的时候会用到。此外多个2D纹理还可以组成Texture Array,如进行大地渲染的时候,需要沙砾,石头,杂草等多种纹理混合,就可以使用Texture Array进行存储,读取的时候加上index就可以读取出相应的纹理。
虽然被称为纹理,但是里面存储的数据也可以不是外观信息,如在进行天空渲染的时候,Precomputed Atmospheric Scattering算法需要与预计算并存储大气中点的通透度和散射值,就可以使用2D Texture存储大气中点的通透度,使用3DTexture存储大气中点的散射值。
即,纹理作为一种属性存储形式,根据需要有2D纹理和3D纹理,他们不仅可以存储外观属性,还可以存储描述物体的其他数据。

在渲染时,有些时候物理离相机很远,可能经过变换后,到显示中只占用极少的像素点,这几个像素点的值如何决定?
如果仍然使用采样方式,可能会出现相机稍微移动,采样对应的位置就大幅变化,效果就是这几个像素一直在抖动。
而且这么远的情况下,完全不需要使用相同精细度的纹理图像,可以节省很多空间。
为了适应不同远近情况下的纹理使用,提出了mipmap,即,存储不同精细程度的纹理,方便不同距离使用,这种思想和计算机视觉中的图像金字塔思想基本相同。其存储代价非常小,只占用了不到 4 3 \frac{4}{3} 34大小的存储空间【每次边长对半,存储为四分之一,级数求和】。
在这里插入图片描述
OpenGL中提供了一键生成mipmap的API

glGenerateMipmap(GL_TEXTURE_2D);

读取纹理涉及到图像解析,libpng、FreeImage、stb_image都是图像解析的开源库,这里使用stb_image,因为stb_image非常简单,只有头文件,但是相应的支持的图片格式也只有常用的几种。FreeImage支持的格式比较多,功能全面,但是相应的也复杂一些。
直接在此处下载stb_image.h文件,然后加入到自己的工程中,并新建一个cpp文件输入:

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

使用stb_iamge的stbi_load函数加载纹理图像文件并生成纹理:

int width, height, nrChannels;
unsigned char *data = stbi_load("container.jpg", &width, &height, &nrChannels, 0);
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
stbi_image_free(data); //注意释放已经不用的图片

OpenGL每种纹理有多个纹理单元,默认纹理单元是0,且默认激活。可以通过激活别的纹理单元位置,来存储多个纹理,当需要使用多个纹理时很有用。

glActiveTexture(GL_TEXTURE0); // 在绑定纹理之前先激活纹理单元
//OpenGL规定至少16个纹理单元,可以通过GL_TEXTURE15访问,也可以通过GL_TEXTURE0 + 15来访问
glBindTexture(GL_TEXTURE_2D, texture);

采样器

模型大小通常与纹理大小是不一样的,需要进行采样,负责采样的被称为采样器。

采样方式

纹理坐标的范围通常是从(0, 0)到(1, 1),(u,v)代表%u,%v处的纹理值。
如果将uv值设到了这个范围以外,OpenGL默认的行为是重复这个纹理图像,但是也可以自定义

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
// 第一个表示要设置的纹理,第二个表示要设置的坐标轴,
// 第三个是策略,REPEAT就是重复,MIRRORED_REPEAT镜像重复,CLAMP_TO_EDGE边缘拉伸,CLAMP_TO_BORDER默认颜色

因为uv是浮点值,不一定对应某一个像素,尤其是在纹理较小,物体较大的时候。输入uv,如何计算出输出像素值,称为纹理过滤,OpenGL提供了多种不同选择,如:

  • GL_NEAREST:选取临近像素的值输出
  • GL_LINEAR:选择附近的像素进行线性插值,计算出的值作为结果。

设置方式:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// 第一个选择设置的纹理,第二个表示要设置的情况,放大or缩小,第三个表示过滤模式。

根据上篇blog讲解的,渲染的流程中,在片段着色器中进行纹理渲染,所以片段着色器才是真正使用纹理的地方,GLSL有一个供纹理对象使用的内建数据类型,叫做采样器(Sampler)。

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

OpenGL中还内置了texture函数,第一个参数是采样器,第二个是纹理uv坐标点,输出就是该点对应的像素值。不用考虑采样器与纹理间的绑定,在进行glBindTexture时就自动将纹理绑定到采样器上了。多个纹理单元时需要配多个采样器,会依次与采样器绑定。

混合

纹理体现的是对不同颜色光照的反射程度,光照体现的是不同光照的射入量,二者分量相乘得到的结果就是最终的显示效果。
多个纹理混合时,需要使用GLSL中内置的函数mix进行混合。

当没有纹理时,可以理解为纹理是(1,1,1,1),所以前面的三角形颜色变化,可以理解为光照颜色变化导致的,而三角形本身始终是不变的。只不过(1,1,1,1)的纹理表示全反射,光照没有损失全部反射出来了。如果纹理是渐变的,那么最终渲染出来的结果就也是不一样的

只有一个纹理的时候,其实约等于默认乘以了一个(1,1,1,1)的白光光照,如果想没有光照,需要乘以(0,0,0,1)

FragColor = texture(Texture1, TexCoord);

在这里插入图片描述

纹理和光照间需要分量相乘

FragColor = texture(Texture1, TexCoord) * timeColor;

在这里插入图片描述
当两个纹理的时候,要使用mix进行混合,

FragColor = mix(texture(Texture1, TexCoord),texture(Texture2, TexCoord),0.5) * timeColor;

在这里插入图片描述

参考

LearnOpenGL
LearnOpenGL CN
《计算机图形学编程(使用OpenGL和C++)第二版》


http://www.ppmy.cn/news/1528007.html

相关文章

MPN – 制造商物料编号(延伸)

SAP从放弃到入门系列之-制造商零件编号-MPN 物料_sap mpn-CSDN博客 MPN – 制造零件号_hers物料类型-CSDN博客 启用制造商物料编号(MPN) – 枫竹丹青SAP学习与分享 (fenginfo.com) MPN在QM中的使用_sap q-info-CSDN博客 关于制造商物料,每篇文章侧重点不同&…

【Qt笔记】QTabWidget控件详解

目录 引言 一、基本功能 二、核心属性 2.1 标签页管理 2.2 标签位置 2.3 标签形状 2.4 标签可关闭性 2.5 标签可移动性 三、信号与槽 四、高级功能 4.1 动态添加和删除标签页 4.2 自定义标签页的关闭按钮行为 4.3 标签页的上下文菜单 五、样式设置 六、应用示例…

Pandas中的聚合函数,及空值计算(与numpy adarray对比)

目录 常用聚合函数 pandas中聚合函数的处理方式 Series对象使用聚合函数 DataFrame对象使用聚合函数 Pandas中聚合函数对空值的处理,及与numpy ndarray进行对比 常用聚合函数 FunctionDescription备注countNumber of non-NA observations个数sumSum of values求和meanMea…

【学术会议征稿】2024年先进控制系统与自动化技术国际学术会议(ACSAT 2024)

2024年先进控制系统与自动化技术国际学术会议(ACSAT 2024) 2024 International Conference on Advanced Control Systems and Automation Technologies 2024年先进控制系统与自动化技术国际学术会议(ACSAT 2024)将于2024年11月15…

微信支付开发-支付工厂AppApi产品代码

一、JSAPI支付产品、APP支付产品、小程序支付产品流程图 二、工厂父类抽象类代码开发 <?php /*** 微信父类抽象类* User: 龙哥三年风水* Date: 2024/9/19* Time: 11:33*/ namespace Payment\WechatPay; abstract class WechatPaymentHandle {/*** 下单* User: 龙哥三年风水…

如何查看电脑什么时候被人动过及看过的文件?

一、查看Windows事件查看器 Windows系统具有强大的日志记录功能&#xff0c;通过“事件查看器”可以查看电脑的使用记录。具体步骤如下&#xff1a; 按下Win R组合键打开运行窗口&#xff0c;输入eventvwr.msc命令并回车&#xff0c;打开事件查看器。 在事件查看器中&#x…

2.计算机网络基础

2. 计算机网络基础 (1) 计算机网络的定义 计算机网络是指将地理位置不同、具有独立功能的多个计算机系统通过通信线路和设备连接起来,以功能完善的网络软件实现网络中资源共享的系统。最简单的定义是:计算机网络是一些互相连接的、自治的计算机系统的集合。最庞大的计算机网…

Kafka基础概念

1.kafka概念 Producer&#xff1a;生产消息实例 Broker&#xff1a;管理和存储消息服务端服务器 Consumer&#xff1a;消费消息的实例 Record&#xff1a;kafka系统中的消息 2.kafka概念-主题 topic&#xff1a;主题&#xff0c;消息的类别 主要用于区别一个broker&#…