使用 UVAtlas (Direct3D 9)

注意

UVAtlas 最初在现已弃用的 D3DX9 utilty 库中提供。 最新版本可从 UV Atlas Command-Line 工具 (uvatlas.exe) 获取。

许多呈现和内容生成技术都需要 2D 信号 ((如纹理) 网格)的唯一非重叠贴图。 此类技术包括:

  • 法线/位移映射
  • 纹理空间 PRT 模拟和光线贴图
  • Surface 画图
  • 纹理空间照明

手动生成唯一的 UV 映射通常既耗时又繁琐;当输入几何图形复杂且需要高效/低失真纹理空间利用率时,尤其如此。 下图显示了一个示例网格及其相应的纹理图集。

显示示例网格及其相应的纹理图集。

此示例演示左侧) 的网格 (,右侧) 上 (相应的 UV 空间法线映射。 请注意,纹理图集包含多个数据组或群集;每个分类称为图表,在上面的示例中,显示包含部分网格的正常数据。

D3DX UVAtlas API 自动生成最佳、不重叠的纹理图集。 API 提供用于以下操作的输入参数:

  • 最大程度地减少纹理拉伸、失真和采样不足。
  • 最大化纹理空间打包密度,以高效利用内存。
  • 跨网格提供均匀采样,从而最大程度地减少采样频率的不连续性。

UVAtlas 的工作原理

UVAtlas API (查看 UVAtlas Functions) 通过将图面分区为图表并将图表打包为纹理图集来生成纹理图集。 使用 D3DXUVAtlasPartitionD3DXUVAtlasPack 单独执行这些步骤;或使用 D3DXUVAtlasCreate 在单个调用中分区、参数化和打包。

对网格进行分区和参数化

首先,将网格分区为图表,然后将每个图表参数化为自己的 [0,1] UV 空间。 柱形可以通过一个图表参数化;另一方面,球体需要两个图表,如下图所示。

分区为两个图表的球体的插图

可使用单个图表参数化的网格被归类为“与磁盘同形”,这意味着你可以在图表上分布一个无限灵活、可无限拉伸的磁盘,并完美地覆盖几何图形。 这种拉伸称为同形,是一个双向函数:这意味着你可以从一个参数化转到另一个参数化,而不会丢失信息。

极少数实际网格可以参数化为两个维度,而无需将网格分离为簇或图表。 下图显示了另一个示例网格及其相应的纹理图集。

显示具有不同形状及其相应纹理图集的示例网格。

有两个参数用于确定创建的图表数:

  • 地图集允许的最大图表数
  • 每个图表允许的最大拉伸量

拉伸量将决定生成的图表数以及采样的总体质量。 拉伸范围从 0.0 (无拉伸) 到 1.0, (任意拉伸) 量。 D3DXUVAtlasCreate 和 D3DXUVAtlasPartition 返回算法生成的最大拉伸。 下图显示了另一个示例网格及其相应的纹理图集。

示例网格及其相应纹理图集的插图

使用集成的指标张量控制参数化

可以按每个三角形指定纹理空间优先级。 可以提供集成的指标张量来控制如何在生成的纹理空间图谱中拉伸三角形。 可以使用 D3DX IMT 计算函数直接指定 IMT 或基于输入信号计算 IMT。 集成的指标张量 (或 IMT) 是一个对称的 2x2 矩阵,用于描述三角形在图集中的拉伸方式。 每个 IMT 由 3 个浮点数定义, (a,b,c) 调用它们。 它们可以按对称的 2x2 矩阵进行排列,如下所示:

a b
b c

然后,IMT 可用于查找两个向量之间的距离。 给定两个向量 v1 和 v2,其中:

vector v1
vector v2 = v1 + (s,t)

v1 和 v2 之间的距离可按以下方式计算:

sqrt((s, t) * M * (s, t)^T)

换句话说,矢量 (s,t) 可以是 u-v 空间中任意方向的拉伸幅度。 在这种情况下,s 向量是从第一个顶点到第二个顶点的方向,t 是法线和 s 的交叉乘积。 例如:

(1,1) * (1,1) = (2,2)
        (1,1)
IMT(1,1,1) scales by 2
(1,-1) * (1,1) = (0,0)
         (1,1)
IMT(2,0,2) scales by 2 with no shearing

可以使用 D3DX IMT 计算函数直接指定 IMT 或基于输入信号计算 IMT:D3DXComputeIMTFromPerVertexSignal、D3DXComputeIMTFromPerTexelSignal、D3DXComputeIMTFromSignal 和 D3DXComputeIMTFromTexture_graphics。

如果要控制纹理空间分配给单个三角形的方式,请直接指定 IMT 数据。 通过执行此操作,将地图集中的更多区域分配给网格 (的重要区域,例如角色的面部或胸部徽标,或玩家步行路径) 附近的场景区域。 通过指定标识矩阵的倍数的 IMT,生成的三角形将在纹理空间中统一缩放。

例如,给定高分辨率法线贴图,可以计算 IMT,为法线映射中频率较高的信号区域提供更多纹理空间。 映射到原始法线地图) 常量区域的“平面” (三角形将接收较少的纹理空间。 包含大量法线贴图详细信息的三角形将在最终结果中接收更多的纹理区域。 然后,可以将法线贴图重新采样为较小的纹理,但保留详细信息,或者可以使用更优化的 UV 映射重新计算法线贴图。

对用户指定的折痕使用相邻数据

用户定义的邻接信息可以提供给分区函数,以描述网格中的预定义折痕,从而定义相邻面之间的图表边界。 这是调用方将自己的图表分区指定为算法输入的简单方法,这将进一步优化图表,使拉伸量低于允许的最大。

示例

此示例演示了如何使用 UVAtlas API 和 DirectX Viewer (Dxviewer.exe) 查找并修复模型中可能会显著影响纹理图集大小的不连续性。 可以从 DirectX SDK 获取Dxviewer.exe并了解它。 Dxviewer.exe在 2009 年 8 月版本之后从 DirectX SDK 中删除,因此至少需要 2009 年 8 月 DirectX SDK 才能获取它。 有关 DirectX SDK 的信息,请参阅 DirectX SDK 在哪里?

假设你从喜欢的内容生成软件中的某个模型开始 (此示例使用在 Maya) 中创建的矮头模型。 将纹理模型导出到 .x 文件,并使用 D3DXUVAtlasCreate 创建纹理图集。 生成的纹理图集如下图所示。

矮人模型的图集图示

地图集有 22 个图表,最大延伸为 0.994。

现在,查看纹理模型,了解纹理图集与几何图形的映射程度。 为此,请将模型加载到查看器工具中:

  • 从 DirectX 实用工具打开查看器工具。
  • 单击“打开”按钮加载 .x 文件。
  • 通过单击视图按钮并从弹出窗口中选择“折痕”来启用折痕查看选项。

下图显示了应在查看器工具中看到的内容。

查看器工具中纹理网格的插图

每条线都是一个折痕,它是纹理图集中两个图表之间的相邻边缘。 算法生成的图表数量是由轻微差异引起的,这些差异可能是由于法线中的不连续。 这些小差异可以通过焊接数据来减少,即强制几乎等于等于的数据。 焊接法线和皮重:

  • 在网格上使用以下命令行运行 DirectX Ops (dxops.exe) 工具, (将“modelName.x”替换为模型) 的名称:
    Dxops.exe -s "load 'modelName.x'; Optimize n:2.01 w:2.01 uv0:0.01;  save 'newModelName.x';"
    

这将比较法线和皮肤重量,如果它们的值相差小于 2.01,则数据相等。 下图显示了在左) 焊接 (之前和右) 焊接 (后的折痕的眼睛特写:

焊接前折痕插图 焊接后折痕图

图 7:通过焊接消除折痕

在此示例中,焊接从输入网格中删除了 86 个顶点。 在网格中折痕减少的情况下,可以重新生成图集,如下图所示。

删除了折痕的新地图集的插图

地图集只有 7 个图表,最大延伸范围约为 0.0776。 在此示例) 中,新的地图集现在适合较小的纹理 (大约小 30%。

将图表打包到 Atlas 中

将网格分区为单独参数化的图表后,图表需要有效地打包到单个纹理贴图中。 这是作为 D3DXUVAtlasCreate 的第二个步骤执行的,也可以通过调用 D3DXUVAtlasPack 显式调用。

打包图表由用户指定的装订线宽度分隔。 装订线宽度是图表之间的分隔量,允许进行双线性内插和 mip 映射,以避免在图表边界上呈现项目。 D3DX 提供了用于自动填充这些装订线的接口 - 有关详细信息,请参阅 ID3DXTextureGutterHelper

将 UVAtlas 集成到管道中

除了在纹理绘制之前由艺术家调用之外,这些功能还可以集成到自动化艺术管道中。 例如,在执行 PRT 模拟或正常映射传递之前,可以在资产更新后自动发出 UVAtlas 调用。 这样就无需手动修复对象的 UV 映射(如果已修改网格的拓扑)。

有关 UVAtlas 函数的示例用法,请参阅 UV Atlas Command-Line工具 (uvatlas.exe)

高级主题