【我的渲染技术进阶之旅】关于OpenGL纹理压缩的相关资料

news2024/9/28 23:28:24

文章目录

  • 一、为啥要了解压缩纹理
    • 1.1 为啥要使用压缩纹理
    • 1.2 如何自定义压缩纹理以及使用压缩纹理的效果
      • 1.2.1 使用压缩纹理节省显存
      • 1.2.2 自定义压缩纹理:将压缩好的纹理数据保存在本地
      • 1.2.3 使用自定义的压缩纹理
      • 1.2.3 示例原理
  • 二、纹理压缩相关知识
    • 2.0 什么是压缩纹理
    • 2.1 通用压缩纹理格式
    • 2.2 压缩纹理相关API的使用
    • 2.3 压缩纹理的常见格式
      • ETC1
      • ETC2
      • PVRTC
      • ATITC
      • S3TC/DXTC
    • 2.4 压缩纹理工具
  • 二、相关参考链接

一、为啥要了解压缩纹理

1.1 为啥要使用压缩纹理

为什么图片导入Unity之后,默认会设置为压缩格式?
glTexImage2D这个接口里面,设置图片数据保存为压缩格式后,会有什么好处?

/** 
 * @brief 将图片数据上传到GPU;
 * @param target    目标纹理,GL_TEXTURE_2D(2D纹理)
 * @param level     当图片数据是包含多个mipmap层级时,指定使用mipmap层级。
 * @param internalformat 图片数据上传到GPU后,在显存中保存为哪种格式?
 * @param width
 * @param height
 * @param border
 * @param format 上传的图片数据格式,RGB、RGBA、Alpha等
 * @param type 图片数据变量格式,一般都是GL_UNSIGNED_BYTE(0-255范围)
 * @param pixels 图片数据
 * @return
 */
void glTexImage2D(GLenum   target, GLint   level, GLint   internalformat, GLsizei   width, GLsizei   height, GLint   border, GLenum   format, GLenum   type, const void * pixels);

答案就是:节省显存。

如今的3A大作,各种4K贴图、超高精度模型,一个场景数据量几G,这些数据都是要上传到显存的,为了让游戏适配更多的硬件,开发者们也是各显神通,压缩纹理就是OpenGL官方提供的一种手段。

1.2 如何自定义压缩纹理以及使用压缩纹理的效果

1.2.1 使用压缩纹理节省显存

比如:之前glTexImage2D这个接口的 internalformat 参数值是GL_RGB

//3. 将图片rgb数据上传到GPU;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texture2d->width_, texture2d->height_, 0, texture2d->gl_texture_format_, GL_UNSIGNED_BYTE, data);

现在只要设置为对应的压缩纹理格式GL_COMPRESSED_RGB即可。

//3. 将图片rgb数据上传到GPU;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texture2d->width_, texture2d->height_, 0, texture2d->gl_texture_format_, GL_UNSIGNED_BYTE, data);

代码编译运行后,正常绘制了立方体,但是怎么样确认压缩纹理的效果呢,就是说怎么样确认显存占用降低?
这里借助GPU状态工具 - GPU-Z 来查看实时显存。

使用未压缩纹理,glTexImage2D接口调用前后显存对比如下:
在这里插入图片描述
从52m 变动到 116m,使用了约 64m 显存。

使用压缩纹理,接口调用前后显存对比如下:
在这里插入图片描述

从52m 变动到 60m,使用了约 8m 显存。

效果很明显,压缩纹理后,占用的显存是原来的 1/6 左右。

具体查看5.6 压缩纹理

1.2.2 自定义压缩纹理:将压缩好的纹理数据保存在本地

将压缩好的纹理数据,保存到硬盘作为图片文件。

带来的好处是:

  • 无需解析,直接上传GPU。
  • 数据已经压缩,无需再次压缩。
  • 数据已经压缩,上传数据量小

压缩纹理数据已经从GPU下载到内存,并保存为.cpt文件,cpt 是我取自compressed texture的缩写。

在这里插入图片描述

具体查看5.7 图片压缩工具

1.2.3 使用自定义的压缩纹理

带来的性能提升,如下所示:

解析耗时(ms)上传耗时(ms)
jpg1571960
cpt416

有很大的性能提升。

回顾一下,我们是先将.jpg图片,解析得到RGB数据,调用OpenGL API进行压缩上传至GPU,然后再从GPU下载压缩纹理数据,保存为.cpt文件。

这其实就是Unity导入图片的时候干的活,现在你知道为什么Unity导入图片那么慢了!

具体查看 5.8 使用压缩纹理

1.2.3 示例原理

截图的效果可以参考下面几篇博客:

  • 5.6 压缩纹理
  • 5.7 图片压缩工具
  • 5.8 使用压缩纹理
  • 5.9 DXT压缩纹理扩展

二、纹理压缩相关知识

2.0 什么是压缩纹理

纹理压缩(Texture compression)是一种专为在三维计算机图形渲染系统中存储纹理而使用的图像压缩技术。与普通图像压缩算法的不同之处在于,纹理压缩算法为纹素的随机存取做了优化。

在实际应用特别是游戏中纹理占用了相当大的包体积,而且GPU无法直接解码目前流行的图片格式,图片必须转换为RGB等类型的格式才能上传到GPU内存,这显然增加了GPU内存的占用。为了处理这些问题于是出现了GPU支持的压缩纹理格式,在GPU中进行解码。压缩纹理属于有损压缩,更在意解码速度,而编码在程序运行之前,因此速度较慢。

2.1 通用压缩纹理格式

在这里插入图片描述

2.2 压缩纹理相关API的使用

  1. 获得GPU的型号
glGetString(GL_RENDERER)
  1. 获得GPU的生产厂商
glGetString(GL_VENDOR);
  1. 获取GPU支持哪些压缩纹理
string extensions = (const char*)glGetString(GL_EXTENSIONS);
  1. 判断是否支持ETC1格式的压缩纹理
return (extensions.find("GL_OES_compressed_ETC1_RGB8_texture")!= string::npos);
  1. 判断是否支持DXT格式的压缩纹理
return (extensions.find("GL_EXT_texture_compression_dxt1")!= string::npos ||
    extensions.find("GL_EXT_texture_compression_s3tc")!= string::npos);
  1. 判断是否支持PVRTC格式的压缩纹理
return (extensions.find("GL_IMG_texture_compression_pvrtc")!= string::npos);
  1. 判断是否支持ATITC格式的压缩纹理
return (extensions.find("GL_AMD_compressed_ATC_texture")!= string::npos ||
    extensions.find("GL_ATI_texture_compression_atitc")!= string::npos);
  1. 上传压缩纹理数据
void glCompressedTexImage2D(
        GLenum target,
        GLint level,
        GLenum internalformat,
        GLsizei width,
        GLsizei height,
        GLint border,
        GLsizei imageSize,
        const GLvoid * data);

internalformat即是压缩纹理格式的类型。

  1. 查看设备支持的texture压缩格式
int num_formats;
glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_formats);
std::cout<<"Texture extensions: "<<num_formats<<std::endl;

int *formats = (int*)alloca(num_formats * sizeof(int));
glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats);
for(int i=0; i<num_formats; i++)
{
    std::cout<<i<<" 0x"<<hex<<formats[i]<<dec<<std::endl;
} 

//注意使用PVRTC格式纹理时,纹理的filter mode不能设置为 GL_LINEAR_MIPMAP_LINEAR, 
//否则的话加载出来的画线显示黑色, 这里有提到。
  1. glTexImage中指定压缩格式可以对上传的纹理进行压缩以改善内存使用,通过设置intenalFormat为表中一个值实现。通过这种方式进行图像压缩增加了纹理加载的开销,但却能够通过更有效地使用纹理存储空间来增加纹理性能,如果由于某些原因无法对纹理进行压缩,OpenGL就会使用下表中所列出的基本内部格式,并加载未经压缩的纹理。
GL_COMPRESSED_RGB : GL_RGB
GL_COMPRESSED_RGBA : GL_RGBA
GL_COMPRESSED_SRGB : GL_SRGB
GL_COMPRESSED_SRGB_ALPHA : GL_RGBA
GL_COMPRESSED_RED : GL_RED
GL_COMPRESSED_RG : GL_RG

在这里插入图片描述
除了这些压缩格式外,OpenGL中还加入了一些特定的压缩格式,即

  • GL_COMPRESSED_SIGNED_RED_RGTC1
  • GL_COMPRESSED_SIGNED_RED_RGTC2
  • GL_COMPRESSED_SIGNED_RG_RGTC2

它们用于各种单颜色通道和双颜色通道压缩纹理,他们代替了兼容版本中GL_LUMINANCEGL_LUMINANCE_ALPHA的功能

  1. 判断纹理是否被成功压缩 和 指定选择压缩格式的方式
//判断纹理是否被成功压缩 
GLint comFlag;
glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_COMPRESSED,&comFlag);

//根据选择的压缩纹理格式,
//选择最快、最优、⾃行选择的算法⽅式选择压缩格式。 
glHint(GL_TEXTURE_COMPRESSION_HINT,GL_FASTEST);  	//最快
glHint(GL_TEXTURE_COMPRESSION_HINT,GL_NICEST);   	//质量最好
glHint(GL_TEXTURE_COMPRESSION_HINT,GL_DONT_CARE);	//自行选择

参数说明:

  • target: GL_TEXTURE_1DGL_TEXTURE_2DGL_TEXTURE_3D
  • Level: 指定所加载的mip贴图层次。⼀一般我们都把这个参数设置为0。 internalformat:每个纹理理单元中存储多少颜⾊色成分。
  • width、height、depth参数: 指加载纹理理的宽度、⾼高度、深度。==注意!==这些值必须是2的整数次⽅方。(这是因为O
    旧版本上的遗留留下的⼀一个要求。当然现在已经可以⽀支持不不是2的整数次⽅方。但是开发者们还是习惯使⽤用以2的整数次⽅方去
    参数。)
  • border参数: 允许为纹理理贴图指定⼀一个边界宽度。

format、type、data参数:与我们在讲glDrawPixels函数对应的参数相同

glGetTexLevelParameter函数提取的压缩纹理格式如下:
在这里插入图片描述

GL_TEXTURE_COMPRESSED:如果纹理被压缩返回1,否则返回0
GL_TEXTURE_COMPRESSED_IMAGE_SIZE:获取压缩后的纹理大小(以字节为单位)
GL_TEXTURE_INTERNAL_FORMAT:所使用的压缩格式
GL_NUM_COMPRESSED_TEXTURE_FORMATS:支持的压缩纹理格式数量
GL_COMPRESSED_TEXTURE_FORMATS:支持的压缩纹理格式数组
GL_TEXTURE_COMPRESSION_HINT: 选择压缩格式的方式

GL_EXT_texture_compression_s3tc压缩格式如下:
在这里插入图片描述

2.3 压缩纹理的常见格式

基于OpenGL ES的压缩纹理有常见的如下几种实现:

  1. ETC1(Ericsson texture compression)
  2. ETC2(Ericsson texture compression)
  3. PVRTC (PowerVR texture compression)
  4. ATITC (ATI texture compression)
  5. S3TC (S3 texture compression)

ETC1

ETC1格式是OpenGL ES图形标准的一部分,并且被所有的Android设备所支持。
扩展名为: GL_OES_compressed_ETC1_RGB8_texture不支持透明通道,所以仅能用于不透明纹理。 且要求大小是2次幂。
当加载压缩纹理时,参数支持如下格式: GL_ETC1_RGB8_OES(RGB,每个像素0.5个字节)

ETC2

ETC2ETC1 的扩展,压缩比率一样,但压缩质量更高,而且支持透明通道,能完整存储 RGBA 信息。

ETC2 需要 OpenGL ES 3.0(对应 WebGL 2.0)环境,目前还有不少低端 Android 手机不兼容,iOS 方面从 iPhone5S 开始都支持 OpenGL ES 3.0。
ETC2 和 ETC1 一样,长宽可以不相等,但要求是 2 的幂次方。

PVRTC

支持的GPU为Imagination TechnologiesPowerVR SGX系列。
OpenGL ES的扩展名为: GL_IMG_texture_compression_pvrtc

当加载压缩纹理时,参数支持如下几种格式:

  • GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG (RGB,每个像素0.5个字节)
  • GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG (RGB,每个像素0.25个字节)
  • GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG (RGBA,每个像素0.5个字节)
  • GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG (RGBA,每个像素0.25个字节)

ATITC

支持的GPU为Qualcomm的Adreno系列。
支持的OpenGL ES扩展名为: GL_ATI_texture_compression_atitc
当加载压缩纹理时,参数支持如下类型的纹理:

  • GL_ATC_RGB_AMD (RGB,每个像素0.5个字节)
  • GL_ATC_RGBA_EXPLICIT_ALPHA_AMD (RGBA,每个像素1个字节)
  • GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD (RGBA,每个像素1个字节)

S3TC/DXTC

也被称为DXTC,在PC上广泛被使用,但是在移动设备上还是属于新鲜事物。支持的GPU为NVIDIA Tegra系列。

OpenGL ES扩展名为: GL_EXT_texture_compression_dxt1GL_EXT_texture_compression_s3tc
当加载压缩纹理时,参数有如下几种格式:

  • GL_COMPRESSED_RGB_S3TC_DXT1 (RGB,每个像素0.5个字节)
  • GL_COMPRESSED_RGBA_S3TC_DXT1 (RGBA,每个像素0.5个字节)
  • GL_COMPRESSED_RGBA_S3TC_DXT3 (RGBA,每个像素1个字节)
  • GL_COMPRESSED_RGBA_S3TC_DXT5 (RGBA,每个像素1个字节)

2.4 压缩纹理工具

每种压缩纹理以及相应的厂商都提供了压缩纹理的工具,包括可视化工具和命令行工具,可自行下载

  1. Imagination Technologies PowerVR
    PVETextTool

  2. Qualcomm Adreno
    Adreno Texture Tool

  3. ARM Mali
    Mail Texture Compression Tool

  4. nVIDIA Tegra
    DirectX Texture Tool

二、相关参考链接

  • 2020 年了,该如何压缩纹理?
  • OpenGL-纹理压缩
  • OpenGL ES 压缩纹理
  • 几种主流的纹理压缩算法
  • ASTC纹理压缩格式详解
  • 下面几篇博客从底层实现原理来说明如何进行纹理压缩
    • 5.6 压缩纹理
    • 5.7 图片压缩工具
    • 5.8 使用压缩纹理
    • 5.9 DXT压缩纹理扩展

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

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

相关文章

FOLOLane论文阅读

论文地址&#xff1a;https://arxiv.org/pdf/2105.13680.pdf 一、论文创新点 主流的车道线检测方法使用语义分割和聚类实现&#xff0c;但像素级的输出存在信息冗余&#xff0c;同时会带来大量噪声。而该论文使用两个分支&#xff0c;一个输出heatmap用于判断像素是否是关键点…

干货 | 初窥 Pytest 测试框架,基础薄弱也能轻松 hold 住

pytest 是一个成熟的全功能Python测试工具&#xff0c;可以帮助您编写更好的程序。它与 python 自带的 unittest 测试框架类似&#xff0c;但 pytest 使用起来更简洁和高效&#xff0c;并且兼容 unittest 框架。pytest 能够支持简单的单元测试和复杂的功能测试&#xff0c;pyte…

java中修改List的对象元素时碰到的坑

坑 case1 case1:Data class Person {Integer age;String name;public Person(Integer age, String name) {this.age age;this.name name;} } List<Person> v1List new ArrayList<>(); v1List.add(new Person(11, "小刚")); v1List.add(new Person(1…

前端基础(五)_运算符(算术运算符、赋值运算符、比较运算符、逻辑运算符、三目运算符、运算符优先级和结合性、数据类型的隐式转换)

一、算术运算符 算术运算符即&#xff1a;加&#xff08;&#xff09;减&#xff08;-&#xff09;乘&#xff08;*&#xff09;除&#xff08;/&#xff09;取余&#xff08;%&#xff09;加加&#xff08;&#xff09;减减&#xff08;–&#xff09; 算术运算符里比较特殊的…

CleanMyMacX软件有哪些优缺点?值不值得下载

CleanMyMac X 2023是一款可靠且功能强大的Mac清洁工具工具&#xff0c;他可以让你随时检查Mac电脑的健康情况&#xff0c;并删除电脑中的垃圾文件&#xff0c;来腾出存储空间&#xff0c;保持Mac系统的整洁。至问世以来&#xff0c;CleanMyMac 系统倍受国内外用户推崇&#xff…

【4】SCI易中期刊推荐——神经科学研究(中科院4区)

🚀🚀🚀NEW!!!SCI易中期刊推荐栏目来啦 ~ 📚🍀 SCI即《科学引文索引》(Science Citation Index, SCI),是1961年由美国科学信息研究所(Institute for Scientific Information, ISI)创办的文献检索工具,创始人是美国著名情报专家尤金加菲尔德(Eugene Garfield…

C#使用迷宫地图来模拟新冠疫情的传播速度(一)

国家开始发布疫情放开政策&#xff0c;本人于2022-12-21开始感染并发高烧。 最近才康复。有感于此 我们用初始感染源来影响九宫网格来查看新冠的传播速度 小游戏规则如下&#xff1a; 一个感染源 可以传播附近相邻的8个网格【类似于扫雷】&#xff0c;假如每个感染源一天只…

Vue--》setup、ref、reactive函数使用讲解

目录 setup ref函数 reactive函数 Vue3中的响应式原理 setup Vue3中的一个新的配置项&#xff0c;值为一个函数。组件中所用到的数据、方法等等&#xff0c;均要配置在setup中。setup函数的两种返回值&#xff0c;如下&#xff1a; 若返回一个对象&#xff0c;则对象中的…

使用Docker快速搭建Hfish蜜罐

HFish简介 HFish是一款社区型免费蜜罐&#xff0c;侧重企业安全场景&#xff0c;从内网失陷检测、外网威胁感知、威胁情报生产三个场景出发&#xff0c;为用户提供可独立操作且实用的功能&#xff0c;通过安全、敏捷、可靠的中低交互蜜罐增加用户在失陷感知和威胁情报领域的能…

源码讲解ThreadLocal父子线程通信问题(图+文+源码)

1 缘起 在复习ThreadLocal相关应用的知识&#xff0c; 有一个老生常谈的问题&#xff1a;父子线程通信&#xff0c; 起初&#xff0c;对于父子线程通信&#xff0c;仅了解ThreadLocal无法通过子线程获取线程数据&#xff0c; 并不了解为什么会这样&#xff1f;以及为什么Inher…

15.4 宏任务和微任务

宏任务和微任务 start 如果彻底理解了事件循环&#xff0c;其实大多数 JS 执行的逻辑都能理解了但是在 ES6 中引入了 Promise, 就引出了两个新概念&#xff0c;宏任务和微任务。 1.宏任务和微任务 1.1 名词 宏任务&#xff1a;macrotask 微任务&#xff1a;microtask 在 E…

异构操作系统的“融合计算”

这些年&#xff0c;由随着应用场景日益丰富和多样化&#xff0c;计算工作越来越复杂&#xff0c;传统的计算方式&#xff08;单机计算/分布式计算&#xff09;已经不能满足&#xff0c;需要一种新的更强大的计算模式来解决这些问题&#xff0c;这是融合计算产生的背景。 …

117.(leaflet之家)leaflet空间判断-点与geojson面图层的空间关系(turf实现)

听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行完整代码包,运行如有问题,可“私信”博主。 效果如下所示: 下面献上完整代码,代码重要位置会做相应解释 <!DOCTYPE html> <html>

Linux系统下的服务管理

文章目录Linux系统下的服务管理1.基本介绍2.service管理指令3.chkconfig指令4.systemctl管理指今4.1.基本语法4.2.systemctl设置服务的自启动状态4.3.防火墙实验案例4.4.防火墙Linux系统下的服务管理 1.基本介绍 服务(service) 本质就是进程&#xff0c;但是是运行在后台的&a…

软考高项(信息系统项目管理师)经验分享

文章目录前言考试过程第一步&#xff1a;日常刷选择题第二步&#xff1a;考前一个月之前刷完精讲课第三步&#xff1a;计算题统一学习第四步&#xff1a;论文早准备第五步&#xff1a;反复刷冲刺视频第六步&#xff1a;刷近几年真题第七步&#xff1a;准备几份考试当天复习资料…

vue组件之间的数据传递和组件的生命周期

一、组件之间的通信1、组件之间的关系&#xff1a;父子关系、兄弟关系、跨级关系2、父子组件之间的通信&#xff08;数据传递&#xff09;&#xff1a;&#xff08;1&#xff09;父组件 ——-> 子组件&#xff1a;使用propsA、第一步&#xff1a;在父组件中使用子组件时&…

【K哥爬虫普法】大数据风控第一案:从魔蝎科技案件判决,看爬虫技术刑事边界

我国目前并未出台专门针对网络爬虫技术的法律规范&#xff0c;但在司法实践中&#xff0c;相关判决已屡见不鲜&#xff0c;K 哥特设了“K哥爬虫普法”专栏&#xff0c;本栏目通过对真实案例的分析&#xff0c;旨在提高广大爬虫工程师的法律意识&#xff0c;知晓如何合法合规利用…

线段树 - 从入门到入土

普通线段树 线段树是什么 我们要学习线段树&#xff0c;首先要了解线段树的结构长什么样。 线段树是一颗二叉树&#xff0c;树上的节点储存数据&#xff08;可以是值、字符串、数组、多个值&#xff09;。 作用 一般来说&#xff0c;线段树是用来维护一个数组的。 数据储…

手写RPC框架02-路由模块设计与实现

源码地址&#xff1a;https://github.com/lhj502819/IRpc/tree/v3 系列文章&#xff1a; 注册中心模块实现路由模块实现序列化模块实现过滤器模块实现 为什么需要路由模块&#xff1f; 在当今互联网日益发展的情况下&#xff0c;我们一个服务一般都会部署多个&#xff0c;一方…

Python绘制表白代码,又是一个表白神器

前言 嗨呀&#xff0c;又是我&#xff0c;又给你们带来了表白的代码 之前发了那些 照片里面加文字的…还有烟花…还有跳动爱心…emm你们也可以去看看哦 今天带来的这个&#xff0c;也是很不错哦 只不过它出来的有些慢&#xff0c;我这里先给你们看看这个效果图吧 效果展示…