《OpenGL宝典》--纹理

news2025/7/27 17:13:55

文章目录

  • 创建并初始化纹理
    • 创建纹理
    • 更新纹理数据
  • 纹理目标和类型
  • 从着色器中读取纹理数据
    • 采样器类型
    • 使用texelFetch内置函数从着色器读取纹理
    • 使用texture()函数从着色器读取纹理
    • 获取更多信息
  • 控制纹理数据的读取方式
    • 使用采样器对象存储采样器包装和过滤模式的参数
      • 创建一个或多个采样器
      • 设置采样器对象参数
      • 绑定采样器到纹理单元
      • 设置存储在纹理对象内的采样器对象
    • 纹理对象参数
      • 纹理过滤
        • 过滤器
      • 纹理环绕
        • 设置采样器纹理环绕方式
    • 使用多个纹理
      • 将纹理绑定到特定纹理单元
      • 着色器中的采样器统一变量引用不同单元
    • mipmap
      • 层数设置,数据输入,限制层数使用
      • mip贴图过滤
      • 构建mip层
  • 数组纹理
    • 2D数组纹理与3D纹理的区别
    • 加载2D数组纹理
    • 使用数组纹理
  • 在着色器中向纹理写入数据
    • 使用image变量表示纹理的单个图像
      • 声明图像单元
      • 读取存储数据
      • 将纹理层绑定到图像单元
      • 在着色器使用图像单元绑定的图像

创建并初始化纹理

创建纹理

GLuint texture;
glCreateTextures(GL_TEXTURE_2D, 1, &texture);
glTextureStorage2D(	texture,		//纹理对象
					1,				//mipmap等级
					GL_RGBA32F,		//纹理数据类型
					256,256);		//纹理大小
glBindTexture(GL_TEXTURE_2D,texture);

更新纹理数据

glTextureSubImage2D(	texture,	//纹理对象
						0,			//等级
						0, 0,		//偏移量
						256, 256,	//大小
						GL_RGBA,	//通道类型
						GL_FLOAT,	//数据类型
						data);		//数据指针

glTextureSubImage2D将保留原始纹理数据副本,因此可将data指向的内存释放。

如果只是想将纹理初始化为一个固定值,则可使用glClearTexSubImage()

void glClearTexSubImage(	GLuint texture,	//纹理对象
							GLint  level,	//想要清除的mip贴图层
							GLint  xoffset,	//待清除区域起始偏移量
							GLint  yoffset,	//
							GLint  zoffset,	//
							GLsizei width,	//区域尺寸
							GLsizei height,	//
							GLsizei depth,	//
							GLenum  format,	//通道类型
							GLenum  type,	//数据类型
							const void *data);//单纹素数据

纹理目标和类型

纹理目标GL_TEXTURE_*
1D/2D/3D
RECTANGLE矩形纹理(2D纹理的子集)
1D_ARRAY/2D_ARRAY聚合到单个对象中的纹理*
CUBE_MAP/CUBE_MAP_ARRAY六个正方形图像的集合/数组纹理
BUFFER特殊的纹理类型
2D_MULTISAMPLE/2D_MULTISAMPLE_ARRAY多采样抗锯齿

从着色器中读取纹理数据

采样器类型

常用的有sampler2D, sampler2Darray, samplerCube, samplerCubearray, sampler2DMS, sampler2DMSArray
sampler2D表示符点数据,若要表示有符号整数数据、无符号整数数据,则使用isampler2D,usampler2D

使用texelFetch内置函数从着色器读取纹理

vec4 texelFetch(sampler1D s, int P, int lod);//P为读取位置,lod为mip层
vec4 texelFetch(sampler2D s, ivec2 P, int lod);
ivec4 texelFetch(isampler2D s, ivec2 P, int lod);
uvec4 texelFetch(usampler1D s, ivec3 P, int lod);

返回值都为4通道,若只返回一个通道,则G、B默认值为0,A默认值为1。

使用texture()函数从着色器读取纹理

texture()与texelFetch()的区别主要是:
texture采用函数会涉及归一化、过滤以及插值等复杂操作,基本无法得到某一确切像素的值。
texelFetch 使用的是未归一化的坐标直接访问纹理中的纹素,不执行任何形式的过滤和插值操作,坐标范围为实际载入纹理图像的宽和高。

gvec4 texture(	gsampler2D sampler,
 				vec2 P,
 				[float bias]);

获取更多信息

使用textureSize返回纹理大小

int textureSize(sampler1D sampler, int lod);
ivec2 textureSize(sampler2D sampler, int lod);
ivec3 textureSize(gsampler3D sampler, int lod);

使用textureSamples()了解多重采样纹理包含多少样本

int textureSamples(sampler2DMS sampler);

控制纹理数据的读取方式

使用采样器对象存储采样器包装和过滤模式的参数

创建一个或多个采样器

void glCreateSamplers(GLsizei n, GLuint *samplers);

设置采样器对象参数

void glSamplerParameter*(	GLuint sampler,	//采样器对象名称
							GLenum pname,	//指定采样器参数的符号名称
							参数类型(与*有关) param);	//指定pname的值

GLenum pname
GL_TEXTURE_WRAP_S,
GL_TEXTURE_WRAP_T,
GL_TEXTURE_WRAP_R,
GL_TEXTURE_MIN_FILTER,
GL_TEXTURE_MAG_FILTER,
GL_TEXTURE_BORDER_COLOR,
GL_TEXTURE_MIN_LOD,
GL_TEXTURE_MAX_LOD,
GL_TEXTURE_LOD_BIAS ,
GL_TEXTURE_COMPARE_MODE,
GL_TEXTURE_COMPARE_FUNC.

绑定采样器到纹理单元

void glBindSampler(GLuint uint, GLuint sampler);

设置存储在纹理对象内的采样器对象

每个纹理都有一个默认采样参数,当没有采样器对象绑定到相应纹理时,则将使用默认采样参数。可以使用如下函数设置默认采样参数

//Texture直接作用于纹理对象
void glTextureParameterf(	GLuint texture,
							GLenum pname,
							GLfloat param);
//Tex作用于指定绑定点的纹理对象----glBindTexture(GLenum target,GLuint texture);				
void glTexParameterf(		GLenum target,
 							GLenum pname,
 							GLfloat param);

纹理对象参数

纹理过滤

从拉伸或收缩的纹理图中计算颜色片段的过程称为纹理过滤(texture filtering)。

过滤器

利用采样器参数函数,支持我们在放大和缩小的情况下分别设置构造纹素值

放大过滤器参数名称:GL_TEXTURE_MAG_FILTER
缩小过滤器参数名称:GL_TEXTURE_MIN_FILTER

最近邻过滤:GL_NEAREST
线性过滤:GL_LINEAR

设置采样器的过滤器

glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

直接设置纹理的默认过滤器

//Texture直接作用于纹理对象
void glTextureParameterf(	GLuint texture,
							GLenum pname,
							GLfloat param);
//Tex作用于指定绑定点的纹理对象----glBindTexture(GLenum target,GLuint texture);				
void glTexParameterf(		GLenum target,
 							GLenum pname,
 							GLfloat param);

纹理环绕

正常情况,我们只会在0.0~1.0之间指定纹理坐标,如果纹理坐标在此范围外,OpenGL会根据采样器对象中指定的当前纹理环绕模式方式进行设置。

设置采样器纹理环绕方式

使用如下函数:

glSampleParameter*(	GLuint sampler,
				 	GLenum pname,
				 	*      param)

纹理环绕参数有:

GL_TEXTURE_WRAP_S		//1D/2D/3D
GL_TEXTURE_WRAP_T		//2D/3D
GL_TEXTURE_WRAP_R		//3D

纹理环绕值有:

GL_REPEAT			//重复
GL_MIRRORED_REPEAT	//镜面重复			
GL_CLAMP_TO_EDGE	//超出部分对边缘采样
GL_CLAMP_TO_BORDER	//超出部分使用边框颜色
GL_MIRROR_CLAMP_TO_EDGE	//	只在(-1.0~0.0, 1.0~2.0上镜面重复,其余部分使用边缘颜色)

其中边框颜色使用如下函数设置。

glSamplerParameterfv(sampler, GL_TEXTURE_BORDER_COLOR, color);

使用多个纹理

使用函数glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &units);得到所有着色器阶段每次可访问的最大纹理单元数量
在这里插入图片描述

将纹理绑定到特定纹理单元

glBindTexture()只能将纹理绑定到glActiveTexture(GL_TEXTURE0 + i) 绑定的纹理点上。

void glBindTextureUnit(	GLuint unit,	//想要我们绑定的以零为基准的索引
						GLuint texture);//

// 方法1:
glActiveTexture(GL_TEXTURE0 + i); // active proper texture unit before binding
glBindTexture(GL_TEXTURE_2D, textures[i].id);
// 方法2:
glBindTextureUnit(i, textures[i].id);

着色器中的采样器统一变量引用不同单元

方法一:在程序中获取采样器地址,并为它设置引用单元数

glUniform1i(glGetUniformLocation(shader, name), unit);

方法二:在着色器代码中使用binding配置限定符设置。

layout(binding = 1) uniform sampler2D texture_diffuse1;

mipmap

层数设置,数据输入,限制层数使用

mip贴图层通过如下函数输入2D纹理mipmap数据。

void glTexSubImage2D(	GLenum target,
 						GLint level,
 						GLint xoffset,
					 	GLint yoffset,
					 	GLsizei width,
					 	GLsizei height,
					 	GLenum format,
					 	GLenum type,
					 	const void * pixels);

level参数指定图像数据应用于哪一层。

但在输入数据前,首先需要开辟对应层数的空间。
使用如下函数开辟纹理空间时,设置levels的值将确定该纹理有多少层。(0表示未使用mipmap)

void glTexStorage2D(	GLenum target,
					 	GLsizei levels,
					 	GLenum internalformat,
					 	GLsizei width,
					 	GLsizei height);

同时可以使用如下函数限制渲染过程中可使用的mip层。

glTextureParameteri(texture, GL_TEXTURE_BASE_LEVEL, 0);
glTextureParameteri(texture, GL_TEXTURE_MAX_LEVEL, 4);

mip贴图过滤

GL_NEAREST
GL_LINEAR
GL_LEAREST_MIPMAP_NEAREST		//选择最邻近的mip层,并执行最邻近过滤
GL_NEAREST_MIPMAP_LINEAR
GL_LINEAR_MIPMAP_NEARSET
GL_LINEAR_MIPMAP_LINEAR			//在mip层之间使用线性插值并执行线性过滤(三线性插值)

构建mip层

使用glTexSubImage2D函数输入mipmap图其他层数不大方便,使用OpenGL构建纹理十分方便。

void glGenerateMipmap(	GLenum target);
void glGenerateTextureMipmap(GLuint texture);

如:
glGenerateMipmap(GL_TEXTURE_2D);

但使用快速构建会一定程度影响程序运算速度,在性能关键型应用程序中需要优先考虑加载自己预先构建的mip贴图。

数组纹理

多个1D纹理可映射为1D数组纹理
多个2D纹理、立方体纹理可映射为2D数组纹理
不能创建3D数组纹理(OpenGL不支持)

2D数组纹理与3D纹理的区别

2D数组纹理的层之间不能进行过滤操作(线性过滤等),但2D数组纹理拥有比3D纹理更大的空间。

加载2D数组纹理

GLuint texture2Ds;
glCreateTextures(GL_TEXTURE_2D_ARRAY, 1, &texture2Ds);
void glTextureStorage3D(	GLuint texture,			//texture2Ds
 							GLsizei levels,			//
 							GLenum internalformat,	//内部格式
 							GLsizei width,
 							GLsizei height,
 							GLsizei depth);			//数组元素 或 层
//输入数据
for(int i=0;i<depth;++i){
	void glTextureSubImage3D(	GLuint texture,		
							 	GLint level,
							 	GLint xoffset,		//0
							 	GLint yoffset,		//0
							 	GLint zoffset,		//层数
							 	GLsizei width,		//图片宽
							 	GLsizei height,		//图片高
							 	GLsizei depth,		//如果输入为2D图形,depth = 1
							 	GLenum format,		//输入数据的格式
							 	GLenum type,		//输入数据的类型
							 	const void *pixels);	//数据指针
}

使用数组纹理

layout (binding = 0) uniform sampler2DArray texture2DArray;
void main()
{
	color = texture( texture2DArray, vec3( vec2(x,y), float(layer) ) );
	//texture( 2D数组纹理采样器, vec3( vec2采样点, float(采样层数) ) );
}

注意:采样层数为整数,但在texture输入采样位置时,要转化为float值。

在着色器中向纹理写入数据

使用image变量表示纹理的单个图像

声明图像单元

uniform image2D my_image;

读取存储数据

//从P指定的坐标处读取image数据
vec4 imageLoad(readonly image2D image, ivec2 P);
//将data的数据存入P指定的image中
void imageStore(image2D image, ivec2 P, vec4 data);

其他:
有符号整数数据(i)和无符号整数(u)数据图像的存取
ivec4 imageLoad(readonly iimage2D image, ivec2 P);
void imageStore(iimage2D image, ivec2 P, ivec4 data);

注意:P为整数型,加载时不执行过滤(与textelFetch()函数一样)。

将纹理层绑定到图像单元

void glBindImageTexture(	GLuint unit,
						 	GLuint texture,
						 	GLint level,
						 	GLboolean layered,
						 	GLint layer,
						 	GLenum access,
						 	GLenum format);

在着色器使用图像单元绑定的图像

rgba32ui为格式限定符,见书P125

layout (binding = 0 , rgba32ui) readonly uniform uimage2D image_in;
layout (binding = 1) uniform writeonly uimage2D image_out;

void main(){//将image_in 中的数据复制入 image_out
	ivec2 P = ivec2(gl_FragCoord.xy);
	uvec4 data = imageLoad(image_in, P);
	imageStore(image_out, P, ~data);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/394663.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AVL树的介绍和实现

我们知道&#xff0c;二叉搜索树是会出现单向的。单向在查找时效率是非常低的&#xff0c;时间复杂度会退化成O(N)&#xff0c;而AVL树就是解决这个问题。 文章目录1. AVL 树1.1 AVL树的概念1.2 AVL树节点的定义1.3 插入后的平衡因子1.4 AVL树的旋转1.4.1 右右&#xff1a;左单…

JavaScript 循环实例集合

文章目录JavaScript 循环实例集合For 循环循环输出 HTML 标题While 循环Do while 循环break 语句continue 语句使用 For...In 声明来遍历数组内的元素JavaScript 循环实例集合 For 循环 源码 <!DOCTYPE html> <html> <head> <meta charset"utf-8&q…

PG数据库入门知识

前言 Linux和windows的路劲分隔符是不同的&#xff0c;Linux下是斜杠/,而windows是反斜杠&#xff08;\&#xff09;。但在PG里window下也要使用linux的/作为路劲分隔符。 基础知识 为什么选择PG PostgreSQL是一款企业级关系型数据库管理系统。PostgreSQL之所以如此特别&am…

如何成为程序员中的牛人/高手?

目录 一、牛人是怎么成为牛人的&#xff1f; 二、关于牛人的一点看法 三、让程序员与业务接壤&#xff0c;在开发团队中“升级” 四、使用低代码平台 目标效果 五、最后 祝伟大的程序员们梦想成真、码到成功&#xff01; 一、牛人是怎么成为牛人的&#xff1f; 最近在某…

Android开发学习—手机开机启动的AMS流程

前言 AMS是Android中最核心的服务&#xff0c;主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作&#xff0c;其职责与操作系统中的进程管理和调度模块相类似&#xff0c;因此它在Android中非常重要。 客户端使用ActivityManager类。由于AMS是系统核心服…

浅谈ChatGPT 和 对AI 的思考

新世纪以来&#xff0c;人工智能作为一个非常热门话题&#xff0c;一直收到大众的广泛的关注。从一开始的图像的分类&#xff0c;检测&#xff0c;到人脸的识别&#xff0c;到视频分析分类&#xff0c;到事件的监测&#xff0c;到基于图片的文本生成&#xff0c;到AI自动写小说…

机器学习-卷积神经网络CNN中的单通道和多通道图片差异

背景 最近在使用CNN的场景中&#xff0c;既有单通道的图片输入需求&#xff0c;也有多通道的图片输入需求&#xff0c;因此又整理回顾了一下单通道或者多通道卷积的差别&#xff0c;这里记录一下探索过程。 结论 直接给出结论&#xff0c;单通道图片和多通道图片在经历了第一…

QUIC 多流桥接、新增 DDS 协议转换代理

驽马十驾&#xff0c;功在不舍。新春之交&#xff0c;NanoMQ 继续保持稳步更新&#xff0c;最新的 0.16 版本将于三月初发布。NanoMQ 为用户提供了 2 个重要新功能&#xff1a;MQTT over QUIC 的多流桥接和 DDS 协议转换代理&#xff0c;拓宽了 NanoMQ 的弱网桥接传输性能和在边…

08 CSS05

目标&#xff1a; 1、定位 2、装饰 3、选择器拓展 一、定位 1、定位的基本介绍 2、定位的基本使用 3、静态定位 4、相对定位 5、绝对定位 6、子绝父相 7、固定定位 8、元素的层级关系1、定位的基本介绍 1.1 网页常见布局方式 &#xff08;1&#xff09;标准流 块级元素独…

CVTE前端面经(2023)

CVTE前端面经项目介绍&#xff08;重点&#xff09;在数据B中找到数组A对应的值&#xff0c;并把数组B对应的值放在数据最前面css1 定位2 外边距3 css高级应用3.1. 过渡3.2. 变形2. 浮动2.1 浮动元素特点2. 2 清除浮动3. html5语义标签4. 实现圣杯布局的两种方式4.1 定位浮动4.…

不会吧,难道真的有程序员不知道怎么接单赚钱吗?

随着大环境逐渐转好&#xff0c;跳槽、新工作、兼职等等机会都浮出水面。抛开跳槽、新工作不谈&#xff0c;今天就专门来说说程序员接单赚钱有哪些靠谱的平台。 首先分享一波关于接私活有哪些注意事项&#xff0c;给大家提个醒&#xff0c;避免盲目入坑。 一、程序员接单须知…

搬得进来,搬得出去!快来过一把数据迁移的“瘾”

欢迎访问OceanBase官网获取更多信息&#xff1a;https://www.oceanbase.com/ 经过前几次“剧透”&#xff0c;我们知道了 OceanBase 开发者大会有嘉宾、有演讲&#xff0c;有开源生态专场&#xff0c;也知道我们还会有 3 场 Hands-on Workshop 动手实验营&#xff0c;从部署到…

从LiveData迁移到Kotlin的 Flow,才发现是真的香!

LiveData 对于 Java 开发者、初学者或是一些简单场景而言仍是可行的解决方案。而对于一些其他的场景&#xff0c;更好的选择是使用 Kotlin 数据流 (Kotlin Flow)。虽说数据流 (相较 LiveData) 有更陡峭的学习曲线&#xff0c;但由于它是 JetBrains 力挺的 Kotlin 语言的一部分&…

一文搞定!postman接口自动化测试【附项目实战详解】

目录&#xff1a;导读 | 接口结果判断 功能区 脚本相关 代码模板 | 集合(批量)测试 变化的参数数据 定期任务 接口执行顺序 数据传递 | 解决依赖问题 假设场景 Postman 中的操作 运行 写在最后 附带项目实战教程地址&#xff1a;postman接口自动化测试使用教程项…

[计算机组成原理(唐朔飞 第2版)]第一章 计算机系统概论 第二章 计算机的发展及应用(学习复习笔记)

第1章 计算机系统概论 1.1 计算机系统简介 1.1.1 计算机的软硬件概念 计算机系统由“硬件”和“软件”两大部分组成。 硬件 是指计算机的实体部分&#xff0c;它由看得见摸得着的各种电子元器件&#xff0c;各类光、电、机设备的实物组成如主机、外部设备等 软件 软件看不见…

【protoc自定义插件】「go语言」实现rpc的服务映射成http的服务,protoc生成gin的插件,(详解实现原理及过程)

文章目录前言一、工程实践中如何更好的使用proto文件&#xff1f;二、protoc命令如何查询依赖的proto文件以及执行原理1. protoc命令如何查询依赖的proto文件2. protoc执行的插件加载原理是什么&#xff1f;3. proto文件中的package和go_package的作用三、protoc插件开发原理体…

春招冲刺(十): Vue2 技术复盘

vue2 技术复盘 Q1&#xff1a;MVVM框架的理解&#xff1f; MVVM模型&#xff1a; M&#xff1a;模型&#xff08;Model&#xff09;&#xff0c;data中的数据V&#xff1a;视图&#xff08;View&#xff09;&#xff0c;模板代码VM&#xff1a;视图模型&#xff08;ViewModel…

Me-and-My-Girlfriend-1靶场通关

Me-and-My-Girlfriend-1靶场通关 靶机ip:192.168.112.135 信息收集 端口&#xff1a;22、80 还是从80WEB服务器端口入手 对服务器目录进行扫描&#xff0c;扫出以下目录 访问80端口WEB服务&#xff0c;显示一段文字只允许本地用户访问。 一眼伪造ip&#xff0c;查看页面…

基于土壤数据与机器学习算法的农作物推荐算法代码实现

1.摘要 近年来&#xff0c;机器学习方法在农业领域的应用取得巨大成功&#xff0c;广泛应用于科 学施肥、产量预测和经济效益预估等领域。根据土壤信息进行数据挖掘&#xff0c;并在此基础上提出区域性作物的种植建议&#xff0c;不仅可以促进农作物生长从而带来经济效益&#…

为什么想到微前端,是巨石应用?

为什么想到微前端&#xff0c;是巨石应用&#xff1f; 现代的前端应用的发展趋势正在变得越来越富功能化&#xff0c;富交互化&#xff0c;也就是传说中的SPA(单页面应用)&#xff1b;这样越来越复杂的单体前端应用&#xff0c;背后的后端应用则是数量庞大的微服务集群。被一个…