目标
在《图形API学习工程(11):使用纹理》中我学习了如何创建纹理,在创建时都指定了其格式:
对于DirectX,是DXGI_FORMAT。
对于Vulkan,是VkFormat。
(OpenGL也有类似的东西,随后讨论)
本篇的目标是——查阅资料并结合自己的思考,对纹理格式的相关内容进行学习与讨论,具体包括:
- 讨论为何要使用和指定不同的纹理格式
- 纹理格式中常见关键字的学习
讨论为何要指定纹理格式
在一开始,我并不理解为何要有不同的纹理格式,因为我知道显示器可以显示红绿蓝三种颜色的光分别有0~255级别,即8位二进制。那这样的话纹理中每个像素不就是最多用24位吗?如果加上alpha通道那不就是32位吗?为何还需要那么多纹理格式呢?
后来,我发现这种想法是很局限的。
导致格式不同的原因
在渲染时使用的纹理,并非都是所谓的 红、绿、蓝、Alpha四通道各8位 。还有其他格式的纹理被需要,原因有很多,至少在我的理解中有以下方面:
- 并非所有的纹理都需要 红、绿、蓝、Alpha 这四个通道,比如有些纹理只需要其中一个通道即可完成它自己的任务。
- 有些纹理需要存储的光的强度并不是8位能表示的。比如HDR(high-dynamic range)。
- 有些纹理使用压缩来减少自己的内存开销,压缩方式例如 block-compression、ASTC
不同格式对应的位数
不同的纹理格式导致数据的大小不同。比如:
- 如果一个通道使用8位的
BYTE
保存,那么对于每个像素:红、绿、蓝、Alpha四通道就是4x8=32
位。 - 如果一个通道使用32位的
float
保存,那么对于每个像素:红、绿、蓝、Alpha四通道就是4x32=128
位。 - 如果使用了压缩技术,则情况更复杂一些,总体数据的大小一定比压缩前更小。
而同样数据大小可能有多种格式与之对应。例如:
- 对于每像素
32
位的大小。它既可能是“红、绿、蓝、Alpha四通道的BYTE
”,也可能是“只有一个红通道的float
”
因此创建纹理时指定格式是必要的,否则GPU就不知道如何对纹理数据进行解读。
常见关键字
这些纹理格式的命名都使用了缩写,在DXGI_FORMAT
和VkFormat
之间也有相似的共用词语。
为了能更快明白一个纹理格式名字的含义,我想对其中常见的关键词进行总结。
(对于更权威与全面的解释还需要看DXGI_FORMAT和VkFormat官方文档)
RGBA
Red、Green、Blue、Alpha。红、绿、蓝再加上一般表示不透明度的Alpha通道。
例如:
- R8G8B8A8表示红通道8位、绿通道8位、蓝通道8位、Alpha通道8位。
- R8G8相比上者只有红通道和绿通道
_UNORM
Unsigned-Normalized-Integer。无符号型归一化的整数。
所谓“无符号”指的是没有负数,即全是正值。
所谓的“归一化”指的是,最终表示的值是0.0~1.0
。例如假设这个整数是8位的即0~255
,那么255
对应1.0
,128
大约对应0.5
;假设这个整数是16位的,即0~65535
,那么65535
对应1.0
,32768
大约对应0.5
。
举例格式:
- R8G8B8A8_UNORM表示红通道8位、绿通道8位、蓝通道8位、Alpha通道8位,且8位代表的是一个无符号型归一化的整数。
_FLOAT
浮点数。对于DirectX来说是 _FLOAT,对于Vulakn来说是 _SFLOAT,不过含义相同,后者的S意思是 “signed”,即有符号的,而DirectX中同样是有符号的。
在DXGI_FORMAT文档中的说明:
- 32位的浮点数使用 IEEE 754 单精度 的标准:1位符号、8位指数偏移、23位数值部分。
- 16位的浮点数使用半精度(s10e5)的格式:1位符号、5位指数偏移、10位数值部分。
不过似乎在DXGI_FORMAT
中也有既不是32位也不是16位的浮点数:
只是似乎比较少见。
_SNORM
Signed Normalized Integer。带符号的归一化的整数。
_UINT
Unsigned integer。无符号型的整数
_SINT
Signed Integer。带符号型的整数。
BC
block-compressed 型纹理压缩格式,详见:
Texture Block Compression in Direct3D 11 - Win32 apps | Microsoft Docs
ASTC
ASTC型纹理压缩格式,详见:
Using ASTC Texture Compression for Game Assets | NVIDIA Developer
OpenGL
而OpenGL在这方面似乎稍微繁琐一些,因为它指定纹理格式方面不是由一个东西决定的:
对于glTexImage2D
这个函数,在《OpenGL红书》中有对相关参数较为权威的解释:
它指出:
internalformat
指定了OpenGL应该怎样存储纹理中的数据。- 而
format
和type
共同指定了初始数据的格式。随后OpenGL将根据这个格式来对数据进行解析并转换为internalformat
。
在《OpenGL红书》的【TextureFormats】章节可以看到对所有格式的说明
(在这篇文章中也有讨论:《OpenGL ES 3.0 纹理格式介绍及有效的内部格式、格式、类型组合_阿飞的博客-CSDN博客》值得学习)
未来问题
-
_SRGB 这个关键字似乎很频繁出现,具体的意义是什么?
-
DXGI_FORMAT中的 _TYPELESS 的含义。
-
OpenGL纹理格式更深入的学习