← ALL ARTICLES
纹理技术4 MIN READ

纹理图集

全库目录221
本文目录13

子图近看正常,拉远却混进相邻颜色,说明采样足迹跨出了它的区域。图集用UV矩形共享一张纹理,过滤、边距和mip生成必须共同保证子图隔离;能否合批还取决于渲染状态。

表面坐标与共享纹理

边距与串色

过滤和 Mipmap 会读取 UV 岛边缘以外的 Texel。如果岛屿间距不够,远处 Mip 会混入别的岛或背景颜色。

需要:

  • UV 岛之间保留与目标分辨率和 Mip 数匹配的间距;
  • 烘焙时做 Dilation/Edge Padding;
  • Atlas 子图保持边缘扩展;
  • Clamp 不能代替岛屿内部 Padding。

间距的定量估算

每向下一级Mip,图集分辨率减半,基级固定宽度的间距在该级包含的纹素数也减半。第k级一个纹素对应基级约2^k个纹素,这是估算尺度;安全间距还要乘过滤核与各向异性足迹,并匹配mip生成方式。边缘扩展只能提供邻近颜色,不能保证任意大足迹完全隔离。

“近距离看正常、拉远就串色”常见于边距不足或mip已混入邻图:近距离用的是较细Mip,间距够;远处切到较粗Mip,一个采样核覆盖的范围已经超过岛屿间距。Clamp 只能保证不越出整张纹理,挡不住同一纹理内相邻岛屿的颜色渗入。

Texture Atlas

Atlas 把多张小纹理放进一张大纹理,通过 UV Rect 选择区域。

可能收益:

  • 减少纹理和材质切换;
  • 为 UI、Sprite、粒子或同类材质创造合批条件;
  • 减少大量小资源的管理成本。

代价:

  • 任一小图更新可能导致整个 Atlas 重建;
  • 不同内容被迫共享分辨率、压缩和 Mip 策略;
  • 动态加载粒度变粗;
  • Padding 浪费空间;
  • 重复纹理和不可见内容可能一起驻留。

Atlas 本身不会自动减少 Draw Call。材质状态、Shader、Render State、网格提交和引擎 Batching 条件仍要一致。

Trim Sheet

Trim Sheet 把可重复的边、面板和装饰带放在一张纹理中,多资产通过 UV 复用。它适合模块化硬表面和建筑。

相比唯一展开,它减少纹理数量和制作成本,但会限制局部独特细节,需要 Decal、Vertex Color 或额外 Mask 补充变化。

Texture Array

Texture Array 保存一组尺寸、格式和 Mip 一致的纹理层。Shader 用 Layer Index 选择,不需要改变 Sampler 绑定。

它避免 Atlas UV 重映射和边缘串色,适合地形、材质集合和粒子。但所有层仍共享尺寸/格式,并且整个 Array 的流送策略受引擎实现影响。

图集 UV 变换

以下HLSL函数要求 uvLocal 在 [0,1] 内,把0和1映射到子图首尾纹素中心。rectPixels的xy为整数起点,zw为正整数宽高;atlasSize为同一级图集的正尺寸。它适用于子图中心到中心的采样约定,在基级双线性过滤下避免直接读取相邻子图:

hlsl
float2 AtlasUv(float2 uvLocal, float4 rectPixels, float2 atlasSize)
{
    float2 minUv = (rectPixels.xy + 0.5) / atlasSize;
    float2 maxUv = (rectPixels.xy + rectPixels.zw - 0.5) / atlasSize;
    return lerp(minUv, maxUv, uvLocal);
}

假设图集宽64、子图横向起点16且宽8,输出横坐标范围是16.5/64到23.5/64,跨度为7个纹素中心间距。这与把[0,1]映射到整个8纹素边界宽度不同,必须按Sprite、UI或平铺材质所需的坐标语义选择。重复子图通常先在局部UV计算周期,同时保留原始连续导数;单纯frac后隐式求导会在重复边界选错mip。

半纹素内缩不能代替Padding。较低 Mip 会把更大范围的 Texel 混合进一个样本,因此子图边缘仍要复制扩展,并按最大使用 Mip 预留间距。用高对比相邻子图和倾斜平面测试;若只在远处出现串色,问题通常来自 Mip Padding 或 Atlas Mip 生成。

逐级隔离

若直接缩小整张图集,滤波器会混合相邻子图,污染会被后续mip继续传播。可分别生成每个子图的mip,再在每一级填充边缘扩展。使用普通硬件mip采样时,各级子图必须保持相同的归一化位置和尺度,让同一个UV始终指向同一内容。若每级独立重新排列子图,则需要按级查询各自矩形、显式采样两个相邻级并自行混合;单个固定UV配硬件三线性无法追踪这种布局。两种方式都要求该级子图仍有足够空间。若基级边框8纹素,到mip3只剩1纹素,双线性边界读取得到保护并不意味着宽各向异性核也安全。最终粗级可能无法容纳独立子图,需要限制使用范围、设计专门布局或使用Texture Array。

资产展开与密度

UV展开

展开 UV 时需要平衡:

  • 拉伸;
  • 接缝;
  • Texel Density;
  • 岛屿方向;
  • Padding;
  • 烘焙和 Lightmap 约束。

没有一种展开能同时最小化所有指标。角色脸部可能优先连续和高密度,硬表面可能优先直线、对齐和 Trim Sheet 复用。

纹素密度

Texel Density 描述单位世界尺寸对应多少纹理像素。统一密度让同类资产的细节尺度一致,也方便估算内存。

它不是所有资产必须同值。主角、背景、可交互物体和远景可以使用不同预算,但差异应来自可见性和项目规范,而不是随意缩放 UV。

验证方法

使用高对比相邻子图逐级检查mip,比较半纹素内缩与边缘扩展。记录拉伸、密度和驻留浪费,对照Texture Array。2^k仅是第k级一个纹素对应基级尺度,实际安全边距还取决于核半径、各向异性与mip生成,不能作为完全隔离的固定保证。

上述UV函数是HLSL机制片段,未建立图集构建器或执行GPU采样。正文16.5/64至23.5/64的坐标可直接复算;双线性中心语义由 reference.py 的bilinear模型检查。逐级隔离与真实跨页过滤仍为尚未验证。

相关主题

参考资料

  • OpenGL 4.6 Core规范:8.14的归一化纹理坐标、线性过滤和地址模式;子矩形不会自动成为采样器边界。
  • Microsoft,Texture Arrays:2026-10-22核读1D Texture Arrays与2D Textures and 2D Texture Arrays的同尺寸、同格式、同mip数量要求;本文图集坐标与边距算例为独立推导。