ETC1压缩纹理格式详解

简介: 本来以为,ETC1作为Android 设备的OpenGL标准,开源且最常用的的一种压缩纹理格式,总会有人去翻译一下khronos的文档,读一下代码,给大家作个普及的,不料就是搜不到。没办法,尽管英文不好,还是硬啃了下文档,把 ETC1压缩纹理的实现原理弄清楚了。 https://www.khronos.org/registry/gles/extensions/OES/OES_

本来以为,ETC1作为Android 设备的OpenGL标准,开源且最常用的的一种压缩纹理格式,总会有人去翻译一下khronos的文档,读一下代码,给大家作个普及的,不料就是搜不到。没办法,尽管英文不好,还是硬啃了下文档,把 ETC1压缩纹理的实现原理弄清楚了。
https://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt

至于什么是压缩纹理,如何使用,可以参考:
http://blog.csdn.net/wanglang3081/article/details/8869589

ETC1的文件头

文件头大小为16:

#define ETC_PKM_HEADER_SIZE 16

将ETC1纹理存成pkm文件时,加上这个文件头,便于读取时获知大小、格式,上传压缩纹理时把这个头去掉。

文件头内容为:特征符——编码宽——编码高——实际宽——实际高

static const char kMagic[] = { 'P', 'K', 'M', ' ', '1', '0' };

static const etc1_uint32 ETC1_PKM_FORMAT_OFFSET = 6;
static const etc1_uint32 ETC1_PKM_ENCODED_WIDTH_OFFSET = 8;
static const etc1_uint32 ETC1_PKM_ENCODED_HEIGHT_OFFSET = 10;
static const etc1_uint32 ETC1_PKM_WIDTH_OFFSET = 12;
static const etc1_uint32 ETC1_PKM_HEIGHT_OFFSET = 14;

尽管ETC1是固定的压缩比,但考虑到像素不对齐的情况,实际宽和实际高还是有必要存储的。

编码构成

Jpeg压缩标准是把图像划分为一系列8X8的像素块,然后每个像素块压缩成变长编码的。ETC1则是4X4的像素块压缩成固定的64位编码(8字节),由于固定,才有利于GPU内部实现并行解压缩。

#define ETC1_ENCODED_BLOCK_SIZE 8
#define ETC1_DECODED_BLOCK_SIZE 48 // RGB 三分量 * 4 * 4

因此,不考虑像素非4对齐的情况,它的压缩比是固定的48/8=6,至于常用的把ARGB分别存储为两张ETC1纹理的做法,压缩比是64/16=4。
像素不对齐的情况如何处理,就自己想想吧,反正不是大问题。

4X4的像素点与64位编码对应关系如下:
1、将 4X4 的像素点划分为两个subblock,横分或者竖分【1个位表示:flipbit】。
2、两部分的像素RGB求均值,总共用24个位表示两个RGB均值,分两种方案【1个位表示:diffbit】
(1)两个subblock的RGB均值都用4位表示。刚好4*3*2=24位。
(2)两个subblock的RGB值相差在 [-4,3]区间(5位表示的情况下,对应常规的8位表示是[-32,24]),第一个subblock的RGB值用5位表示,第二个用3位差值表示。
3、解码时,像素值由RGB均值加上差值而得,差值表为8X4大小。每一个subblock使用的是其中一行【行号需要3个位,两个subblock,加起来6个位】,每个像素点对应所取差值行中一个数【编号需要2个位,这样就16X2=32个位】。PS:RGB三个分量是用同一个差值。

64位的编码分成两部分,高位和低位。
低位存储每个像素点的差值行序号,按大端存储方式,分两部分,前一部分存储高位,后一部分存储低位。
高位存储RGB均值,subblock所用的差值表行号,再加上 flipbit 和 diffbit
详细内容直接上文档上的图:
total

横分/竖分示例图,图中每个字母代码一个像素:
flip

编码过程

ETC1的编码流程如下:
1、将图像划分为一系列 4X4 的子块。
2、对每个子块,尝试所有的编码可能性,取解码后和原block像素差值和最小的一种编码。
(1)是否flip,这个决定subblock如何划分
(2)每个subblock用哪一行差值表
(3)每个像素取哪一列的差值
注:决定好flip之后,颜色均值和是否能用diff方式已经确定,这个不用遍历。
3、合并所有子块编码。

不难看出,编码过程需要遍历所有可能性,其复杂度远大于解码,每一个 RGB 像素变成了一个精度较低的RGB均值和一个2位差值号,因此产生压缩。这种预测式表述自然本身就存在偏差,压缩损失亦来自于此。

目录
相关文章
|
编解码 安全 iOS开发
如何将ISO转换为MP4格式
将 ISO 文件转换为 MP4 格式,可以更方便地保存和在常用设备上播放。这里有 8 款适用于 Windows 和 Mac 的最佳软件程序,可用于将 ISO 文件转换为数字格式,以便在任何设备上欣赏您的视频。
|
2月前
如何将 2024-11-26 20:55:26 转换成 OffsetDateTime 格式?
如何将 2024-11-26 20:55:26 转换成 OffsetDateTime 格式?
26 0
|
8月前
|
XML JSON 缓存
数据的格式与描述
数据的格式与描述
70 4
|
XML 存储 JSON
文本数据交换格式 -- JSON
文本数据交换格式 -- JSON
103 0
|
8月前
|
Shell Linux 开发工具
linuxShell_格式和工具
linuxShell_格式和工具
|
JSON JavaScript 前端开发
JSON的三种格式
JSON的三种格式
|
JSON 数据格式
pkl转换json(pkl格式如何打开,pkl2json)
pkl转换json(pkl格式如何打开,pkl2json)
|
存储 编解码 算法
MP4格式解析
MP4视频文件封装格式是基于QuickTime容器格式定义的,因此参考QuickTime的格式定义对理解MP4文件格式很有帮助。MP4文件格式是一个十分开放的容器,几乎可以用来描述所有的媒体结构,MP4文件中的媒体描述与媒体数据是分开的,并且媒体数据的组织也很自由,不一定要按照时间顺序排列,甚至媒体数据可以直接引用其他文件。同时,MP4也支持流媒体。MP4目前被广泛用于封装h.264视频和AAC音频,是高清视频的代表。MP4格式的官方文件后缀名是“.mp4”,还有其他的以mp4为基础进行的扩展或者是缩水版本的格式,包括:M4V, 3GP, F4V等。
327 0
Wl,-rpath的格式问题,Wl,--rpath
Wl,-rpath的格式问题,Wl,--rpath
100 0
C# 中GUID生成格式的四种格式
C# 中GUID生成格式的四种格式
273 0