当前位置: 首页 > ops >正文

计算机图形学编程(使用OpenGL和C++)(第2版)学习笔记 05.纹理贴图

1. 纹理贴图

纹理贴图是 OpenGL 中用于将图像数据映射到几何体表面的技术。通过纹理贴图,可以为 3D 模型添加细节和真实感,例如颜色、光照、凹凸效果等。

1.1. 纹理坐标

每个顶点(x,y,z)都对应一个纹理坐标(u,v),纹理坐标用于确定纹理图像在顶点上的映射位置。纹理坐标通常是一个二维向量,其中 u 和 v 分别表示纹理图像的 U 和 V 坐标。U 坐标表示纹理图像在水平方向上的位置,V 坐标表示纹理图像在垂直方向上的位置。

上图是纹理坐标的示意图,其中 (0,0) 表示纹理图像的左下角,(1,1) 表示纹理图像的右上角。


上图是纹理坐标在 3D 模型上的应用示例,其中顶点 (0,0,0) 对应纹理坐标 (0,0)

注意:

  • 由于模型面的宽高比与纹理图像的宽高比可能存在不一致的情况,这就为涉及到图像的变形。
  • 模型面的大小与纹理图像的大小也可能存在不一致的情况,这就为涉及到图像的拉伸或缩放。
  • 纹理坐标通常使用 0 到 1 之间的浮点数表示,而不是使用像素坐标。

1.2. 纹理贴图步骤

  1. 加载纹理图像
  2. 创建纹理对象
  3. 将纹理对象绑定到目标
  4. 将纹理图像传递给纹理对象
  5. 使用纹理坐标将纹理映射到几何体表面

1

1.2.1. 加载纹理图像

 // 生成纹理对象texture = util.loadTexture("./texture/brick1.jpg"); // 加载纹理if (texture <= 0){cout << "Error loading texture" << endl;// exit(1);} // 检查纹理加载是否成功glActiveTexture(GL_TEXTURE0);                                     // 激活纹理单元 0glBindTexture(GL_TEXTURE_2D, texture);                            // 绑定纹理对象glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // 设置纹理过滤参数:最小过滤

纹理图像加载成功且绑定到GL_TEXTURE0后,在片段着色器中,纹理图像会自动传递给纹理单元 0
即片段着色器中采用如下代码拿到纹理图像

layout (binding=0) uniform sampler2D tex0;

layout(binding = 0): 这个语法告诉图形驱动程序,这个特定的资源(例如一个纹理采样器)应该在绑定点 0 上被访问。绑定点是一个抽象的概念,用于在着色器和应用程序之间映射资源。

可用纹理单元的数量取新决于GPU上提供的数量 ,据据OpenGL 规范,要求每个着色器至少有 16 个纹理单元。

1.2.2. 纹理坐标定义

纹理坐标定义有两种方式:

  1. 在定义顶点坐标时,同时定义纹理坐标,即每个顶点除了有(x,y,z)坐标外,还有(u,v)纹理坐标 。这种方式参见第4章 定义顶点坐标同时定义顶点颜色的示例
  2. 顶点坐标和纹理坐标分开定义,此种方式容易理解,在配置时也比较灵活,本节代码使用此种方式
float pyramidPositions[54] ={-1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f,    // front1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f,    // right1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f,  // back-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f,  // left-1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, // LF1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f  // RR};float textureCoordinates[36] ={0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f,0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f,0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f,0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f,0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f};glGenVertexArrays(1, vao);  // 生成 VAOglBindVertexArray(vao[0]);  // 绑定 VAOglGenBuffers(numVBOs, vbo); // 生成 VBOglBindBuffer(GL_ARRAY_BUFFER, vbo[0]);                                                     // 绑定 VBOglBufferData(GL_ARRAY_BUFFER, sizeof(pyramidPositions), pyramidPositions, GL_STATIC_DRAW); // 将顶点数据传递到 VBO// glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // 绑定 VBOglVertexAttribPointer(0, 3, GL_FLOAT, false, 0, (void *)0); // 设置顶点属性指针:坐标glEnableVertexAttribArray(0);                               // 启用顶点属性glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);                                                         // 绑定 VBOglBufferData(GL_ARRAY_BUFFER, sizeof(textureCoordinates), textureCoordinates, GL_STATIC_DRAW); // 将纹理坐标数据传递到 VBOglVertexAttribPointer(1, 2, GL_FLOAT, false, 0, (void *)0); // 设置顶点属性指针:坐标glEnableVertexAttribArray(1);                               // 启用顶点属性

由于我们已经启用了顶点属性,纹理坐标数据会自动传递到顶点着色器中

1.2.3. 顶点着色器

#version 430
// 指定 GLSL 的版本为 4.30layout (location=0) in vec3 position;
layout (location=1) in vec2 texCoord; // 输入变量,表示顶点的颜色,绑定到 location = 1// 输入变量,表示顶点的三维位置,绑定到 location = 0uniform mat4 mv_matrix;
// uniform 变量,表示模型-视图矩阵,用于将顶点从模型空间变换到视图空间uniform mat4 proj_matrix;
// uniform 变量,表示投影矩阵,用于将顶点从视图空间变换到裁剪空间out vec2 tc;
// 输出变量,表示顶点的颜色,绑定到 location = 0
void main(void)
// 主函数,计算顶点的最终位置
{gl_Position = proj_matrix * mv_matrix * vec4(position,1.0);// 将顶点位置从模型空间依次变换到视图空间和裁剪空间// 最终结果存储在内置变量 gl_Position 中,用于后续的光栅化阶段tc = texCoord;}

每个顶点的纹理坐标会自动经过插值传递到片段着色器中

1.2.4. 片段着色器

#version 430
// 指定 GLSL 的版本为 4.30in vec2 tc;
// 输入变量,表示顶点的颜色(未使用)
out vec4 color;
// 输出变量,表示片段的最终颜色uniform mat4 mv_matrix;
// uniform 变量,模型-视图矩阵(未使用)uniform mat4 proj_matrix;
// uniform 变量,投影矩阵(未使用)
//layout (binding=0) uniform sampler2D tex0;
uniform sampler2D tex0;
void main(void)
// 主函数,计算片段的最终颜色
{color = texture(tex0, tc);
}

1.3. 多级渐远纹理贴图

多级渐隐纹理映射(Mipmapping),是一种在计算机图形学中用于提高纹理渲染质量和性能的技术。其主要目的是在不同距离和分辨率下提供合适的纹理细节,同时减少渲染过程中的资源消耗和视觉上的瑕疵,如闪烁和摩尔纹。

工作原理

  1. 生成多级纹理:

原始纹理(Level 0)被缩小,生成一系列逐渐缩小的纹理图像,形成一个纹理金字塔,每一级(Level)的纹理大小是前一级的一半。
例如,一个256x256的纹理会有8级(包括原始纹理),尺寸分别为256x256、128x128、64x64、32x32、16x16、8x8、4x4、2x2和1x1。
2. 选择合适的纹理级别:

在渲染过程中,根据物体表面的观察距离和屏幕上像素的大小,动态选择最合适的纹理级别。
靠近观察者的表面使用较高分辨率的纹理(较高级别),而远离观察者的表面使用较低分辨率的纹理(较低级别)。
3. 过滤和混合:

为了在不同级别之间实现平滑过渡,通常会使用线性插值等方法进行混合,以避免出现明显的纹理切换痕迹。
优点

提高渲染质量:通过提供适合当前观察条件的纹理细节,减少了视觉上的瑕疵,提高了图像的整体质量。
提升性能:使用较低分辨率的纹理来渲染远距离物体,减少了显存带宽和处理器的负担,提高了渲染速度。

1.3.1. 函数说明

1.3.1.1. glTexParameteri

在OpenGL中,glTexParameteri函数用于设置纹理参数。其函数原型如下:

void glTexParameteri(GLenum target, GLenum pname, GLint param);

参数说明

  1. target:

指定纹理目标的类型。常见的值包括:

  • GL_TEXTURE_1D:一维纹理。
  • GL_TEXTURE_2D:二维纹理。
  • GL_TEXTURE_3D:三维纹理。
  • GL_TEXTURE_CUBE_MAP:立方体贴图。
  1. pname:

指定要设置的纹理参数名称。常见的值包括:

  • GL_TEXTURE_MIN_FILTER:设置纹理缩小过滤模式。
  • GL_TEXTURE_MAG_FILTER:设置纹理放大过滤模式。
  • GL_TEXTURE_WRAP_S:设置纹理在S(水平)方向的环绕模式。
  • GL_TEXTURE_WRAP_T:设置纹理在T(垂直)方向的环绕模式。
  • GL_TEXTURE_WRAP_R:设置纹理在R(深度)方向的环绕模式(仅适用于3D纹理)。
  1. param:

指定参数的具体值。根据pname的不同,param可以取不同的值。例如:
对于GL_TEXTURE_MIN_FILTER和GL_TEXTURE_MAG_FILTER,常见的值包括:

  • GL_NEAREST:最近邻过滤。
  • GL_LINEAR:线性过滤。
  • GL_NEAREST_MIPMAP_NEAREST:最近邻Mipmap过滤。
  • GL_LINEAR_MIPMAP_NEAREST:线性Mipmap过滤。
  • GL_NEAREST_MIPMAP_LINEAR:最近邻Mipmap线性过滤。
  • GL_LINEAR_MIPMAP_LINEAR:线性Mipmap线性过滤(三线性过滤)。
    对于GL_TEXTURE_WRAP_S、GL_TEXTURE_WRAP_T和GL_TEXTURE_WRAP_R,常见的值包括:
  • GL_REPEAT:重复纹理。
  • GL_MIRRORED_REPEAT:镜像重复纹理。
  • GL_CLAMP_TO_EDGE:将纹理坐标钳制到边缘。
  • GL_CLAMP_TO_BORDER:将纹理坐标钳制到边框颜色。
1.3.1.2. glGenerateMipmap

在OpenGL中,glGenerateMipmap函数用于生成纹理的Mipmap。其函数原型如下:

void glGenerateMipmap(GLenum target);

参数说明
target
指定纹理目标的类型。常见的值包括:

  • GL_TEXTURE_1D:一维纹理。
  • GL_TEXTURE_2D:二维纹理。
  • GL_TEXTURE_3D:三维纹理。
  • GL_TEXTURE_CUBE_MAP:立方体贴图。

1.4. 各向异性过滤

标准的多级渐远纹理映射(Mipmapping)技术通过将纹理缩小到不同级别来提高渲染质量,但同时也会引入一些问题,如摩尔纹和锯齿。为了解决这些问题,引入了各向异性过滤(Anisotropic Filtering)技术。

标准的多级渐远纹理贴图以各种正方形分辨率(如 256 像素×256 像素、 128 像素×128 像素等)对纹理图像进行采样,而各向异性过滤却以多种矩形分辨率对纹理进行采样(如 256 像素×128 像素、 64像素×128 像素等)。这使得从各种角度观看的纹理都保留尽可能多的细节成为可能

1.5. 参考

  1. OpenGLshader开发实战学习笔记:第三章 使用纹理_qopenglwidget 绘制三维坐标系-CSDN博客
  2. 学习笔记完整代码下载
http://www.xdnf.cn/news/4623.html

相关文章:

  • Ubuntu 服务器管理命令笔记
  • 系统重装之后,通过ssh无法登录
  • 安卓基础(XML)
  • Vue2 中 el-dialog 封装组件属性不生效的深度解析(附 $attrs、inheritAttrs 原理)
  • DApp开发:开启去中心化应用新时代
  • LLaMA模型本地部署全攻略:从零搭建私有化AI助手
  • Algolia - Docsearch的申请配置安装【以踩坑解决版】
  • 2025年渗透测试面试题总结-某步在线面试(题目+回答)
  • 枚举 · 例8扩展-校门外的树:hard
  • 2025年APP安全攻防指南:抵御DDoS与CC攻击的实战策略
  • 神经网络—感知器、多层感知器
  • matlab实现模型预测控制
  • Qt/C++面试【速通笔记八】—Qt的事件处理机制
  • Solidity语言基础:区块链智能合约开发入门指南
  • 软件设计师教程——第一章 计算机系统知识(上)
  • tmux 入门与实用指南
  • 从零开始用 AI 编写一个复杂项目的实践方法论
  • R语言数据挖掘:从“挖井”到“淘金”
  • C31-形参与实参的区别
  • Google 发布 Gemini 2.5 Pro Preview (I/O Edition),具有增强的编程能力
  • 多模态文档检索开源方案-三大竞赛获奖方案技术链路
  • Flink SQL DataStream 融合开发模式与动态配置热加载机制实战
  • C++ STL 入门:map 键值对容器
  • Centos离线安装mysql、redis、nginx等工具缺乏层层依赖的解决方案
  • 全面解析 iTextSharp:在 .NET 中高效处理 PDF
  • 贵州安全员考试内容有哪些?
  • Python学习笔记--Django的安装和简单使用(一)
  • 【Linux网络】Socket 编程预备
  • 图像管理与人脸识别工具深度解析
  • 查看单元测试覆盖率