Chapter 45: Texture Compression
纹理压缩(Texture Compression)讨论的是纹理数据在磁盘、上传路径、显存和采样硬件之间如何保持可接受画质,同时减少内存占用、带宽访问和加载等待。读完本章后,读者应能定位一张纹理的主要成本来自容量、采样带宽、上传路径还是压缩伪影,并能为 base color、normal、UI、HDR、mask texture 选择不同压缩策略。
本章使用一组典型实时渲染资产作为贯穿材料:一个 2048×2048 的 base color,一张同尺寸 normal map,一张 roughness / metallic / AO 通道打包 mask,一张半透明 UI icon,一张 HDR skybox,以及一组可分级加载的地形纹理。每一节都回到这组资产,追踪它们从源图、离线压缩、容器封装、运行时上传到 shader 采样的完整路径。
纹理压缩的核心结论是:格式选择是一份显存、带宽、平台支持和画质之间的契约。契约一旦确定,asset 管线、运行时加载、mip streaming、shader 解包和回归截图都要围绕它组织。压缩格式本身提供的是数据布局和硬件解码路径,工程质量来自资产分类、平台 profile、自动检查和可观察画质证据。
45.1 Texture Compression Memory Bandwidth and Image Quality Contract
纹理压缩的工作定义是:把纹理按固定块或固定压缩单元存储,让 GPU 采样硬件能在纹理读取阶段直接解码成 texel 值。它解决的问题是减少显存占用、减少从内存到 texture cache 的传输量、缩短加载和上传数据规模。它的边界是有损误差会进入颜色、法线、粗糙度、透明度或 HDR 亮度,并在过滤、mip 选择、法线重建和后处理之后变成可见画质差异。
对贯穿材料中的 2048×2048 base color,未压缩 RGBA8 顶层 mip 占用约 16 MiB。完整 mip chain 增加约三分之一容量,约 21.33 MiB。BC1 以 4 bits per pixel 存储,顶层约 2 MiB,完整 mip chain 约 2.67 MiB。BC3、BC5、BC7 这类 8 bits per pixel 格式顶层约 4 MiB,完整 mip chain 约 5.33 MiB。这个计算直接解释了压缩对资源预算的作用:同样的纹理数量下,压缩格式减少 resident texture set 的显存压力,也减少 streaming 时从磁盘、内存和 upload heap 经过的字节数。
带宽收益来自采样路径。fragment shader 中一次 texture() 调用先根据 UV 和 derivative 选定 mip,再访问对应块,硬件从 compressed block 中解码需要的 texel 或 sample 值。块压缩把多个 texel 的数据收进较小块中,texture cache 以块或 cache line 为单位搬运数据。纹理坐标连续、mip 合理、压缩块较小时,cache 中的有效 texel 密度更高,采样相同屏幕区域时的外部内存访问压力下降。移动 GPU 对这一点更敏感,因为带宽、功耗和热限制通常同时约束帧时间。
画质成本来自块内重建。以 Direct3D 的 BC 系列为例,Microsoft 的 block compression 文档说明了 4×4 texel 块、端点颜色、索引插值和 block 对齐这条基本路径。压缩器在每个块里选择少量端点和索引,采样硬件按这些端点重建 texel。原图中高频颜色、尖锐 alpha、细密法线变化或平滑 HDR 渐变被压进有限端点后,会出现块边界、banding、normal wobble、透明边缘脏色和 specular flicker。
这份契约可以按资产类型表达。base color 允许轻微颜色误差,因为材质光照和后处理会吸收一部分差异;normal map 对方向误差敏感,因为微小角度变化会放大到高光位置;UI icon 对边缘和文字最敏感,因为它直接映射到屏幕;HDR skybox 对渐变和高亮能量敏感,因为 tone mapping 会把压缩误差显化;mask texture 对通道语义敏感,因为 roughness、metallic、AO 三个通道之间通常没有强相关性。
一次压缩决策应先写成可检查的约束。下面的表把贯穿材料的成本和风险放在同一组维度里:
| 资产 | 主要成本 | 可见风险 | 优先观察证据 | 常见方向 |
|---|---|---|---|---|
| Base color | 显存和采样带宽 | 色块、渐变 banding、贴图细节损失 | albedo debug view、材质球截图 | BC1、BC7、ASTC LDR |
| Normal map | 方向精度和高光稳定性 | normal wobble、接缝、高光闪烁 | normal debug view、specular highlight | BC5、ASTC normal profile |
| Packed mask | 通道独立性 | roughness 污染、AO 边界变脏 | 单通道 debug view、材质参数热力图 | BC4、BC7、ASTC 低误差块 |
| UI icon | 边缘清晰度 | 字体发糊、透明边脏色、块边界 | 1:1 屏幕截图 | 无损、未压缩、BC7 或 ASTC 4×4 |
| HDR skybox | 动态范围和渐变 | banding、亮部能量误差 | HDR debug、tone mapped 截图 | BC6H、ASTC HDR |
判断顺序应固定为:先确认这张纹理在 shader 中表达什么物理或视觉量,再计算未压缩和候选压缩格式的 mip chain 容量,然后在目标平台查询格式支持,最后用对应 debug view 检查压缩误差。格式选择跳过这条顺序时,工程里常见的症状是 base color 看起来正常,normal 或 roughness 在运动镜头里产生闪烁,因为真正敏感的量没有被单独评估。
45.2 主流格式对比(DXT/BCn/ASTC 等)
主流 GPU 纹理压缩格式可以按三个层级理解:旧名称、现代 API 格式名、硬件采样能力。DXT 是 S3TC 时代的常见叫法,DXT1、DXT3、DXT5 在现代 Direct3D / Vulkan / Metal 语境中通常对应 BC1、BC2、BC3 这类 block compression 格式。BCn 是 Direct3D 体系中的格式族,覆盖单通道、双通道、HDR 和高质量 RGBA。ASTC 是 Adaptive Scalable Texture Compression,使用 128-bit 固定块和不同 block footprint 提供连续的 bits per pixel 选择;Khronos 的 ASTC extension specification定义了它在 OpenGL / OpenGL ES 生态中的格式入口。
BC1 适合没有平滑 alpha 的 base color。它使用 4×4 块和约 4 bits per pixel,容量优势明显。它的风险是 RGB 端点精度有限,对平滑渐变、皮肤、天空和低对比区域容易产生块状误差。贯穿材料中的 2048 base color 如果是粗糙墙面、岩石、草地,BC1 往往能通过;如果是角色脸部或大面积渐变,BC7 或 ASTC 较小 footprint 更稳。
BC3 适合需要连续 alpha 的 RGBA 颜色贴图。它用类似 BC1 的 RGB 数据加单独 alpha 块,约 8 bits per pixel。贯穿材料里的半透明 UI icon 虽然包含 alpha,但它的边缘和文字直接显示在屏幕上,BC3 的容量收益常被边缘伪影抵消。对粒子烟雾、脏迹 decal、低频透明贴图,BC3 的视觉风险小很多。
BC4 和 BC5 适合非颜色数据。BC4 存单通道,BC5 存两个独立通道。normal map 常用 BC5 保存 X、Y 分量,shader 里通过单位长度约束重建 Z 分量。这样做的好处是两个方向分量有独立端点和索引,压缩误差更贴近法线用途。贯穿材料中的 normal map 使用 BC1 会把 RGB 当颜色压缩,方向向量的长度和角度都会受到颜色端点插值影响,高光更容易产生抖动。
BC6H 面向 HDR 数据,BC7 面向高质量 LDR RGBA。BC6H 适合 HDR skybox、reflection source 或预过滤环境贴图;BC7 适合质量敏感的 base color、透明材质和 UI 边缘。二者都比 BC1/BC3 编码复杂,离线压缩时间更长,运行时仍由硬件采样路径解码。工程上应把编码成本放在 asset build 阶段,用缓存保存产物,运行时只处理容器解析、上传和 residency。
ASTC 的关键变量是 block footprint。ASTC 2D 常见 footprint 包括 4×4、5×5、6×6、8×8 等,同样是 128-bit 块,footprint 越大,bits per pixel 越低,容量越小,块内可表达细节越少。ARM 的 astc-encoder encoding guide给出了 normal map 编码建议:保存单位法线的 X、Y 分量,再在 shader 中重建 Z。对移动和跨平台渲染,ASTC 的价值在于同一格式族里能按资产敏感度调节码率,例如 UI 用 4×4,角色 base color 用 5×5 或 6×6,远景地形用 8×8。
ETC2 / EAC 常出现在 OpenGL ES 和移动 Web 图形路径中。ETC2 覆盖 RGB / RGBA 颜色,EAC 覆盖单通道或双通道数据。它的工程意义是为不稳定支持 BC 或 ASTC 的平台提供 profile 分支。PVRTC 主要出现在较旧的 Apple 移动设备链路中;新项目通常通过 capability query 和平台基线决定是否保留。
格式对比应使用同一组维度,而非按名称背表。下面的表给出用于 asset profile 的判断起点:
| 格式族 | 典型块与码率 | 适合数据 | 主要风险 | 平台判断 |
|---|---|---|---|---|
| BC1 / DXT1 | 4×4,约 4 bpp | 不带连续 alpha 的 LDR base color | 渐变 banding、块边界 | 桌面和主机常见,Web / 移动需查询 |
| BC3 / DXT5 | 4×4,约 8 bpp | 带连续 alpha 的 LDR color | alpha 边缘误差、RGB 仍有 BC1 风险 | 桌面和主机常见 |
| BC4 | 4×4,约 4 bpp | 单通道 mask、高度、AO | 单通道 banding | 桌面常见,移动需变体 |
| BC5 | 4×4,约 8 bpp | normal XY、双通道数据 | Z 重建前要重新归一化 | 桌面常见,normal map 稳定 |
| BC6H | 4×4,约 8 bpp | HDR skybox、HDR environment | 渐变和亮部误差 | HDR 资源常用,需格式支持 |
| BC7 | 4×4,约 8 bpp | 高质量 LDR RGBA | 编码慢、容量高于 BC1 | 质量敏感 LDR 纹理常用 |
| ASTC LDR / HDR | 128-bit 块,可变 footprint | 移动和跨平台 LDR / HDR | footprint 过大导致块误差 | 现代移动常见,桌面需查询 |
| ETC2 / EAC | 固定块压缩 | 移动 fallback、WebGL 路径 | 质量和通道灵活性受限 | OpenGL ES 3 生态常见 |
这一节的核心判断是:格式族先由平台能力限制,具体格式再由纹理语义决定。把所有纹理统一压成同一个格式会让管线简单,但会把错误转移到视觉层。可维护的渲染工程应把格式选择写进 asset profile,并让每类纹理有明确的质量证据。
45.3 纹理压缩在 Asset 管线中的应用
纹理压缩应在 asset 管线中完成,而非在游戏或渲染程序启动时临时处理。asset 管线的输入是源图和语义标签,输出是平台可直接上传的压缩纹理容器、mip chain、格式元数据和回归截图。这样组织后,运行时只承担加载、上传、绑定和 streaming,压缩器的耗时、参数搜索和质量检查留在离线构建阶段。
源图格式决定可用信息上限。base color 和 UI 源图应保留无损或高质量源数据,normal 和 mask 应保留线性数值,HDR skybox 应使用 EXR 这类能保留动态范围的格式。颜色空间在这里要先固定:base color、emissive color 和 UI color 通常作为 sRGB 纹理进入采样器;normal、roughness、metallic、AO、height、mask 和 HDR lighting 数据作为 linear 数据处理。把 normal map 当 sRGB 编码会改变向量分量分布,把 roughness 当 sRGB 会改变高光宽度。
压缩参数应由纹理语义驱动。贯穿材料可以写成一份 asset profile:base color 在桌面 profile 使用 BC7 或 BC1,在移动 profile 使用 ASTC 6×6;normal 使用 BC5 或 ASTC normal profile;packed mask 根据通道敏感度选择 BC4、多张 BC4 或 BC7 / ASTC 较高码率;UI icon 默认保留未压缩或使用 BC7 / ASTC 4×4;HDR skybox 使用 BC6H 或 ASTC HDR。profile 的职责是把“这张纹理是什么”转换成“目标平台上传什么格式”。
下面的简化 manifest 展示了这种转换关系。它用于表达 asset build system 应记录的最小信息,具体引擎可以把字段映射到自己的资源数据库。
{
"texture": "hero_wall_basecolor",
"semantic": "base_color",
"sourceColorSpace": "sRGB",
"mipGeneration": "kaiser_or_lanczos_offline",
"profiles": {
"desktop_high": {
"format": "BC7_UNORM_SRGB",
"container": "DDS_or_KTX2",
"qualityPreset": "slow_high_quality"
},
"mobile_default": {
"format": "ASTC_6x6_SRGB",
"container": "KTX2",
"qualityPreset": "medium"
}
},
"checks": {
"requireMips": true,
"maxAngularErrorDegrees": null,
"regressionCapture": "material_ball_basecolor"
}
}
容器负责把压缩数据、format、尺寸、mip、array layer、cubemap face 和可选 supercompression 组织成可加载文件。DDS 在 Direct3D 工具链中常见,KTX2 在跨 API 和移动路径中更常见。Khronos 的 KTX 2.0 specification明确记录了 vkFormat、mip level index、data format descriptor 和 supercompression scheme 等字段,这些字段帮助加载器判断如何上传到 Vulkan、OpenGL、WebGPU 或引擎抽象层。
自动检查应覆盖结构和画质两类问题。结构检查包括尺寸、mip chain、block 对齐、format 是否支持 sRGB view、normal 是否被标成 linear、HDR 是否进入 HDR 格式、平台 profile 是否有 fallback。画质检查包括压缩前后图像差异、normal angular error、roughness 单通道误差、alpha coverage、HDR luminance 误差和材质球截图差异。PSNR 或 SSIM 可以提供数值线索,但对 normal 和 roughness 这类非颜色数据,最终还要看 shader 输出中的法线方向、高光形状和材质参数。
回归截图应绑定到材质语义。base color 的截图用 albedo debug view 和正常光照材质球;normal 的截图用 normal debug view 和移动光源高光;mask 的截图按 R、G、B、A 单通道展开,再看 roughness 对 specular lobe 的影响;UI 的截图使用 1:1 pixel view;HDR skybox 的截图同时保存 linear exposure debug 和 tone mapped view。这样做能把压缩误差放回视觉结果,而非停留在源图差异上。
asset 管线还要记录版本边界。压缩器版本、quality preset、颜色空间、mip 生成过滤器、normal swizzle、alpha premultiply 策略和平台 profile 都会改变输出。产物缓存 key 应包含这些字段。否则一次工具升级可能让大量纹理重新编码,运行时结果变化却缺少可追溯依据。
45.4 在线加载与内存布局优化策略
在线加载阶段的目标是把已经压缩好的 mip 数据放入 GPU 可采样资源,并让当前帧只驻留真正可见或即将可见的层级。它处理的是文件 IO、容器解析、转码、upload heap、resource state、descriptor / binding 和 residency。压缩格式降低了这条路径中的字节数,但它也带来 block 对齐、mip 尺寸取整和平台格式支持检查。
运行时路径可以拆成下面的资源流。图中“transcode”只出现在 KTX2 / Basis Universal 等中间格式需要转换成目标 GPU 格式的场景;DDS 或已经存好目标 GPU format 的 KTX2 可以直接进入上传路径。
这条路径的关键点是 block-aligned mip 数据。块压缩格式按 block 存储,小 mip 即使逻辑尺寸小于一个块,也要占用至少一个完整块。加载器计算每个 mip 的 row pitch、slice pitch 和数据偏移时,应使用格式的 block width、block height 和 bytes per block。采样硬件使用逻辑尺寸,上传和拷贝命令使用物理数据布局。两者混淆会导致 mip 偏移错位、颜色花屏或只在小 mip 出错。
Streaming mip 的决策来自屏幕空间需求。渲染器根据相机距离、投影大小、材质 LOD bias 和纹理 derivative 估算目标 mip,再把目标 mip 以上的更高分辨率层级排入上传队列。远处地形先驻留低分辨率 mip,靠近相机后逐步上传更高分辨率 mip。压缩格式让每个 mip 的上传字节数下降,因此同一帧预算内可以补齐更多纹理层级,视觉上表现为 texture popping 减少和清晰度更快收敛。
Texture array 和 bindless texture 解决的是绑定规模问题。大量材质使用相同尺寸和相同格式的纹理时,texture array 可以把它们放入同一资源,shader 用 layer index 访问。大量材质尺寸、格式和生命周期差异较大时,bindless 或 descriptor indexing 可以减少传统绑定切换。压缩格式在这里要求一致性:同一个 texture array 的层通常要共享 format、尺寸和 mip 结构;bindless 路径虽然更灵活,但 descriptor residency、sampler 状态和格式能力仍要受平台限制。
Sparse texture 或 tiled resources 解决的是超大纹理的 residency。Vulkan 的 sparse resources specification把 sparse binding、sparse residency、sparse image block 和 residency feature 分开描述,说明应用可以按矩形块或子资源粒度绑定内存。工程上可以把地形 mega texture、虚拟纹理页或大规模贴图集拆成页,只让当前视野和预测区域驻留。这个能力依赖平台 feature query,并且压缩格式、block 尺寸、页尺寸和 mip tail 需要一起设计。
Upload heap 或 staging buffer 的组织应服务帧预算。每帧纹理上传量可以按字节、资源数量和 copy command 数量设上限。小 mip 优先,因为它们能快速消除低清占位;可见物体优先,因为它们直接影响当前帧;高敏感资源优先,例如角色脸部和近景 normal。上传后要执行正确的 resource state transition,确保后续 shader read 看到完整数据。多队列或 async transfer 能降低 graphics queue 等待,但同步点和 residency 状态要可追踪。
内存布局优化还包括通道打包和 atlas 策略。roughness、metallic、AO 常被打包进一张 RGBA mask 以减少采样次数和 descriptor 数量。打包前要判断通道相关性:BC1/BC3 类颜色压缩会利用 RGB 共同端点,可能让互不相关的 mask 通道互相影响;BC7 或 ASTC 高质量设置更适合多通道 mask;若某个通道非常敏感,把它拆成 BC4 或更高码率资源更稳定。Atlas 能减少绑定数量,但会引入 mip bleeding、wrap mode 限制和 streaming 粒度变粗的问题。
这一节的可复用检查顺序是:先读取容器元数据和平台 format feature,再计算每个 mip 的 block-aligned byte range,然后确定当前帧需要驻留的 mip 集合,接着安排 upload heap 和 copy command,最后通过 debug view 验证 shader 采样到的 mip 与期望一致。画面出现随机花块时先查 row pitch 和 mip offset;出现近景延迟变清晰时查 streaming 预算和优先级;出现绑定错误时查 descriptor 指向、format view 和 sampler 状态。
45.5 画质与性能权衡分析
画质与性能权衡要放回具体纹理语义中判断。压缩格式减少显存和带宽,但不同数据把误差放大的方式不同。base color 的误差表现为颜色和纹理细节,normal 的误差表现为光照方向,UI 的误差表现为屏幕边缘,HDR 的误差表现为曝光和渐变,mask 的误差表现为材质参数变化。统一用一张 RGB diff 图判断所有纹理,会漏掉真正影响 frame 的管线结果。
Base color 的第一指标是材质表面在常规光照下的稳定性。自然纹理、墙面、石头、泥土、树皮这类高频但非规则内容通常能承受 BC1 或 ASTC 较低码率;角色皮肤、天空渐变、干净塑料表面和大面积品牌色更适合 BC7 或 ASTC 较小 footprint。检查时先看 albedo debug view,再看 lit material,因为光照会改变误差可见性。若压缩后出现低频色块,提升格式质量通常比调采样器更有效。
Normal map 的第一指标是角度误差。BC5 和 ASTC normal profile 的共同思路是保存 X、Y 分量,在 shader 中重建 Z。下面的 HLSL 片段展示了最小解包路径。代码目的在于说明压缩数据如何回到单位法线;完整材质函数还要接入 tangent space、TBN 变换和材质参数。
float2 encodedXY = normalTexture.Sample(normalSampler, uv).rg;
float2 xy = encodedXY * 2.0 - 1.0;
float z = sqrt(saturate(1.0 - dot(xy, xy)));
float3 normalTS = normalize(float3(xy, z));
这段代码对应的检查点是:纹理必须以 linear 数据采样,X、Y 通道要和压缩器 swizzle 一致,重建后要重新归一化。normal 压缩质量应在 normal debug view 和高光运动中观察。静态截图可能看起来接近,镜头移动或光源移动时,高光抖动会暴露块内方向误差。
UI texture 的第一指标是屏幕空间边缘。图标、文字、HUD 线条和透明边缘常处在 1:1 或接近 1:1 的屏幕映射中,压缩块边界缺少光照和材质噪声遮蔽。UI 资源可以使用未压缩 RGBA8、无损容器、BC7 或 ASTC 4×4。若 UI atlas 必须压缩,应单独检查 alpha coverage 和边缘颜色,尤其是 premultiplied alpha 与 straight alpha 的处理一致性。
HDR texture 的第一指标是能量和渐变。skybox、IBL source 和反射探针进入 lighting 后,会影响大面积背景、金属反射和 tone mapping。BC6H 或 ASTC HDR 能显著降低容量,但压缩误差会在曝光变化中放大。检查时应使用多个 exposure、tone mapped view 和高亮区域放大图。只在默认曝光下比较,可能覆盖亮部误差或暗部 banding。
Packed mask 的第一指标是通道语义。roughness 改变高光宽度,metallic 改变能量分配,AO 改变间接遮蔽。三者在图像统计上经常互不相关。若使用共享 RGB 端点的格式,某个通道的边界可能污染另一个通道。检查时应把每个通道单独显示,再看最终材质球。roughness 最好用移动光源和斜视角观察,因为它对 specular lobe 形状敏感。
性能分析要把压缩收益分成容量、带宽和 CPU / IO 三类。容量收益用 resident texture memory、mip residency 和 streaming backlog 观察;带宽收益用 GPU profiler 的 texture bandwidth、cache hit、sampler stall 或 frame pass 时间观察;CPU / IO 收益用加载队列、转码时间、上传字节数和 copy queue 等待观察。若帧时间瓶颈在 fragment shader ALU 或 overdraw,压缩可能降低内存压力,但主瓶颈仍在 shader 执行或像素覆盖。若瓶颈在 texture bandwidth 或 streaming,压缩通常能给出更直接的收益。
最终取舍可以落成一条稳定规则:先按平台能力筛掉不可用格式,再按纹理语义选择候选格式,然后用容量计算确认预算收益,接着用语义 debug view 检查画质,最后用 profiler 验证瓶颈是否移动。只要这条链路闭合,压缩策略就能在不同项目间迁移。它不会给每张纹理一个固定答案,但能让每次选择都有证据、有边界、有回归方式。
最小自检任务
给定一组纹理:2048×2048 RGBA base color、2048×2048 tangent-space normal、1024×1024 roughness / metallic / AO packed mask、512×512 半透明 UI icon、4096×2048 HDR skybox。目标平台分为 desktop high 和 mobile default。请为每类纹理选择一个 desktop 格式和一个 mobile 格式,并说明检查顺序。要求回答显存或带宽收益来自哪里、最容易出现的画质问题是什么、应使用哪个 debug view 复查。
答案要点
Base color 在 desktop high 可选 BC7_UNORM_SRGB,质量压力较低的场景可选 BC1_UNORM_SRGB;mobile default 可选 ASTC 6×6 或 5×5 sRGB。收益来自 mip chain 容量和 texture bandwidth 下降。风险是渐变 banding 和块边界,复查 albedo debug view 与 lit material 截图。
Normal 在 desktop high 可选 BC5_UNORM,mobile default 可选 ASTC normal profile 或较小 footprint 的 ASTC linear 格式。收益来自双通道压缩和采样带宽下降。风险是方向误差、高光抖动和接缝。复查 normal debug view、移动光源下的 specular highlight,并确认 shader 对 X、Y 解包后重建 Z 且重新归一化。
Packed mask 在 desktop high 可选 BC7 或按敏感通道拆成 BC4;mobile default 可选 ASTC 较小 footprint,必要时拆分高敏感通道。收益来自减少采样次数、减少 descriptor 数量和降低总容量。风险是通道互相污染,尤其是 roughness 改变高光形状。复查单通道 debug view 和材质参数热力图。
UI icon 在 desktop high 可保留 RGBA8、BC7 或高质量压缩;mobile default 可保留 RGBA8 或 ASTC 4×4。收益主要来自容量,带宽收益通常服从边缘清晰度。风险是字体发糊、透明边缘脏色和块边界。复查 1:1 屏幕截图、alpha coverage 和 premultiplied alpha 策略。
HDR skybox 在 desktop high 可选 BC6H,mobile default 可选 ASTC HDR,若平台缺少 HDR 压缩支持则保留较高精度 fallback。收益来自大尺寸 environment 资源的容量和上传字节数下降。风险是亮部能量误差、渐变 banding 和 tone mapping 后的块状痕迹。复查 HDR debug、多个 exposure 和 tone mapped view。
完整检查顺序是:先查平台 format feature,再按语义选择候选格式,接着计算每个候选格式的完整 mip chain 容量,然后用离线压缩产物生成回归截图,最后在运行时通过 profiler 查看 texture bandwidth、resident memory、streaming backlog 和 sampler stall 是否下降。
本章知识点总结
- 压缩契约:纹理压缩同时约束显存、带宽、平台支持和画质,格式选择应按纹理语义落地。
- 块式存储:BCn 和 ASTC 这类格式按块保存 texel 数据,硬件采样时从压缩块重建 texel。
- 容量计算:2048×2048 RGBA8 顶层 mip 约 16 MiB,BC1 顶层约 2 MiB,8 bpp 格式顶层约 4 MiB。
- 带宽收益:压缩减少 texture cache 和外部内存之间搬运的数据量,对纹理带宽瓶颈和移动 GPU 功耗有直接影响。
- 格式边界:BC1 适合普通 LDR base color,BC5 适合 normal XY,BC6H 适合 HDR,BC7 适合高质量 LDR RGBA。
- ASTC 码率:ASTC 通过不同 block footprint 调节 bits per pixel,footprint 越小质量越高,容量也越大。
- 颜色空间:base color 和 UI color 通常使用 sRGB,normal、mask、roughness、metallic、AO 和 HDR lighting 数据按 linear 处理。
- 管线位置:压缩应在 asset build 阶段完成,运行时主要负责容器解析、上传、绑定、streaming 和 residency。
- 容器作用:DDS 和 KTX2 负责保存格式、尺寸、mip、array、cubemap face 和可上传数据布局。
- Streaming mip:运行时根据屏幕空间需求逐级驻留 mip,压缩格式减少每级上传字节数。
- 布局检查:加载器必须按 block width、block height、bytes per block 计算 row pitch、slice pitch 和 mip offset。
- Normal 复查:normal map 压缩质量应通过角度误差、normal debug view 和移动高光观察。
- UI 复查:UI 纹理应优先检查 1:1 边缘、alpha coverage 和透明边颜色。
- HDR 复查:HDR 压缩应在多个 exposure 和 tone mapped view 下检查亮部能量与渐变。
- 取舍顺序:可靠流程是查询平台能力、按语义选格式、计算容量、检查语义 debug view,再用 profiler 验证瓶颈变化。