3.2 纹理系统:采样、mipmap与压缩


3.2 纹理系统:采样、mipmap与压缩

本节摘要:纹理是 GPU 侧的多维像素阵列,采样是从阵列里按浮点坐标取色的过程。本节剖开「坐标 → 颜色」这步看似简单的映射:环绕与过滤规则决定边缘和缩放的行为,mipmap 金字塔同时解决远处闪烁与带宽爆炸,各向异性过滤修正斜视角的采样失真,压缩纹理把带宽成本砍掉四分之三。结尾给出采样的完整决策表。这是第 5 章全部贴图技术的地基。

「取一个像素」为什么值得解剖一章

片元着色器里一行 texture(tex, uv) 背后藏着至少四层决策:坐标落在纹理边界外怎么办(环绕模式)?浮点坐标落在两个像素之间怎么办(过滤模式)?纹理在屏幕上被缩成一小块时取哪个分辨率的版本(mipmap 层级)?这块纹理值不值得为它花显存带宽(压缩格式)?每一层都有默认值,默认值能跑,但四层全用默认值的画面,正是「远处闪成噪点、斜着看全糊」的典型患者。

先建立数据观:纹理在 GPU 眼里只是「带宽度高度深度的像素数组」。数组本身无语义——用法线当颜色画出来是蓝紫色的调试常用技巧,反过来把颜色数据当法线采样就是病变。语义由采样它的着色器代码决定,这个「数据与解释分离」的思想贯穿第 5 章所有花式贴图(法线贴图、粗糙度贴图都是同一数组不同解释)。

环绕与过滤:边界的两条规则

环绕模式(GL_REPEAT、GL_MIRRORED_REPEAT、GL_CLAMP_TO_EDGE、GL_CLAMP_TO_BORDER)回答边界外的问题。砖墙、地面这类需要无缝平铺的贴图必须 REPEAT;镜面地板的倒影纹理常用 MIRRORED 省一半贴图;而 CLAMP_TO_EDGE 是「边缘像素拉出去」的封口处理,非平铺纹理的默认安全选项。选错的症状很直白:该平铺的贴了 CLAMP,地面远处拉成条纹;该封口的贴了 REPEAT,贴图边缘出现诡异的接缝渗色。

过滤模式回答「像素之间」的问题。GL_NEAREST 取最近的那个像素——像素风、马里奥式硬边效果的正选,也是诊断纹理坐标是否正确的调试工具(硬块状至少看得清采样到哪)。GL_LINEAR 双线性插值四个邻居——平滑质感的默认选择。纹素与像素的尺寸关系决定谁更合适:纹理被放大(一个纹素占多个屏幕像素)时 LINEAR 显著更平滑;纹理被缩小时,双线性只插值 4 个邻居远远不够——这引出主角 mipmap。

mipmap:金字塔的两层收益

把 1024×1024 的纹理缩到屏幕上 16×16 的区域,双线性过滤每次只在纹素网格里取 4 个样本——这 4 个样本随机落点,帧与帧之间相机一动就换一批,表现为远处的闪噪。更深的问题是带宽:缩小 64 倍意味着要正确表现颜色,理论需要把约 4096 个纹素平均成一个颜色,而管线只肯采 4 个。

图 3-2 mipmap 金字塔:按屏幕尺寸取对的那一层

图 3-2 mipmap 金字塔:按屏幕尺寸取对的那一层

生成 mipmap 只要一行 glGenerateMipmap,但忘记调用是新手高发病:只上传了第 0 层却请求 mip 过滤,采样落到不存在的层,整张纹理黑掉;或者没开 GL_TEXTURE_MIN_FILTER 的 mip 档位(注意最小过滤与放大过滤是两个独立参数,mip 只属于最小侧),金字塔生成了也没用上。

压缩纹理:带宽视角的选型

未压缩的 RGBA 纹理每像素 4 字节。4K 贴图一按计算器:4096×4096×4 ≈ 64 兆字节,VRAM 吃紧之外,每帧被采样的带宽才是真账单。GPU 原生压缩格式(桌面端的 BC 系列、移动端的 ETC/ASTC)按 4×4 像素块压缩,每像素约 0.5 到 1 字节——带宽与显存同时砍到四分之一到八分之一,且解压由采样硬件即时完成、零运行时成本。代价是固定的块状有损压缩,渐变色带、法线精度需要留意(法线贴图有专门的压缩变体)。

压缩格式里有两处选型细节。其一,BC7 与 BC1 的分水岭:BC1 每像素半字节、适合漫反射这类容差大的贴图;BC7 每像素一字节、质量接近无损,法线与需要精确颜色的贴图选它——同一套资产里混用两种格式是常态,按贴图语义分配预算。其二,压缩是资产管线的一环:压缩在离线工具里完成、随资产分发,运行时直接上传压缩数据(glCompressedTexImage2D 一族);把未压缩贴图留到运行时再压,既慢又白白多传一遍数据。

选型逻辑一句话:运行时下载的中间产物(渲染到纹理的中间层)保持原生格式;美术资产(漫反射、法线、粗糙度)一律离线压成块格式

采样决策表

现象/需求 该动哪层 推荐设置
无缝平铺(地面砖墙) 环绕模式 REPEAT,贴图边缘要可拼接
贴图边缘渗色 环绕模式 改 CLAMP_TO_EDGE 检查是否消失
远处闪噪 mip 层级 确认生成 mipmap 且 MIN_FILTER 开 mip
整张纹理纯黑 mip 层级 上传后只传了 0 层的典型指纹
斜视角地板糊 各向异性 采样各向异性设 4 到 8
像素风格 过滤模式 NEAREST,放大也用 NEAREST
带宽吃紧 压缩格式 美术资产离线压块格式

⚠️ 常见坑:纹理尺寸不是 2 的幂。旧时代直接不可采样;现代OpenGL 放开了限制,但非 2 幂纹理拿不到完整 mipmap 链和 REPEAT 环绕,性能路径也劣化。贴图尺寸尽量对齐 2 的幂,资产管线里就当规矩定死。

再补一个新手高频疑问:同一张纹理被多个着色器共用时要重复绑定吗?绑定是纹理单元级的状态——同一帧里换着色器但不换纹理时,纹理绑定可以不动(省一次切换);反过来,一个着色器要同时读多张纹理(PBR 的四张贴图)时才需要多单元绑定(4.1 节三车道图的 sampler 多槽位)。理解「纹理单元是插槽、绑定是把图插进插槽」这个模型,绑定策略就有章可循:按「材质切换频率」组织插槽,而不是随手乱占——6.2 节的无绑定纹理正是把这套插槽管理整个免掉的升级件。

本节要点回顾

  • 纹理是无语义数组:数据与解释分离,法线贴图只是「同一数组换种解释」
  • 环绕管边界、过滤管像素之间:两个独立参数,症状对照表排查
  • mipmap 双收益:消灭远处闪噪 + 带宽骤降,代价仅多 1/3 显存
  • 忘生成 mipmap 的指纹:远处闪噪或整片黑,一行 glGenerateMipmap 的账
  • 各向异性治斜视角:地板糊成条是它的主治,倍数按需设
  • 美术资产一律块压缩:带宽显存双赢,解压免费

纹理这条补给线通了。下一节解剖输出端的路由器——帧缓冲对象:渲染结果怎么离开屏幕、进入纹理、再被下一遍渲染消费,离屏渲染的闭环就此建立。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U