☰
Modly UV展开器工作原理:Box Mapping六面投影到Atlas打包的完整流程
2026/10/23 4:49:46 网站建设 项目流程

Modly UV展开器工作原理:Box Mapping六面投影到Atlas打包的完整流程

【免费下载链接】modlyDesktop app to generate 3D models from images or prompt using local AI — runs entirely on your GPU项目地址: https://gitcode.com/GitHub_Trending/mo/modly

Modly 是一款本地 AI 3D 模型生成桌面应用,支持从图片或提示词在本地 GPU 上生成 3D 模型。其中UV 展开(UV Unwrap)是让模型"穿衣服"的关键一步:把三维网格表面展开成二维平面,得到一组 (U, V) 坐标,后续的纹理烘焙器再依据这组坐标把颜色"贴"回去。本文带你完整读懂 Modly 内置的 uv_unwrapper 展开器:从 Box Mapping 六面立方体投影,到重叠检测,再到 3×2 Atlas 图集打包的全流程。

UV 展开是什么?为什么需要 Atlas

可以把 UV 展开想象成把地球仪表面摊平到纸上:

  • Box Mapping(盒式映射):不用复杂的切割缝算法,而是把模型投到包围盒的 6 个面上,像"拍立体照片"一样,每个面得到一张二维贴图切片;
  • Atlas(图集):6 个切片不能重叠摆放,Modly 把它们排成3 列 × 2 行的网格,最终拼成一张 0~1 范围内的完整 UV 图。

这样纹理烘焙器(texture_baker)只需一张贴图就能覆盖整个模型。

完整流程总览:5 步流水线

整个展开逻辑集中在 Unwrapper 类的forward方法中(unwrap.py#L615-L669),依次执行:

步骤方法作用
1_align_mesh_with_main_axisPCA 对齐模型主轴
2_box_assign_vertex_to_cube_face六面投影,生成每面 UV
3_rotate_uv_slices_consistent_space统一 6 个切片的朝向
4_assign_faces_uv_to_atlas_indexBVH 检测重叠,分配图集位置
5_distribute_individual_uvs_in_atlas缩放、平移,打包进 3×2 网格

第 1 步:PCA 对齐模型主轴

模型生成后姿态可能是斜的,直接投影会造成六个面"各占一角"、空间浪费。_align_mesh_with_main_axis(unwrap.py#L537-L613)用**主成分分析(PCA)**找出模型的两个主方向,再叉乘出第三个轴,构建旋转矩阵把模型摆正——让它尽量贴合坐标轴,这样六面投影的利用率最高。

第 2 步:Box Mapping 六面投影(核心)

_box_assign_vertex_to_cube_face(unwrap.py#L14-L121)是整个展开器的心脏,分四小步:

  1. 归一化:把顶点坐标从包围盒范围映射到[-1, 1](unwrap.py#L41-L43);
  2. 定面:对每个三角形,取三个顶点法线的平均值作为面法线,然后与 6 个轴向(±1,0,0)、(0,±1,0)、(0,0,±1)做点积,取最大者决定该三角形属于立方体哪一面(unwrap.py#L58-L77);
  3. 投影:面向 +X/−X 的三角形取 (y, −z) 作为 (u, v);面向 ±Y 取 (x, −z);面向 ±Z 取 (x, ±y)——即"丢弃投影方向那个坐标,保留另外两个",这就是正交投影的盒式映射;
  4. 归一化到 [0,1]:按该面所有三角形的最大轴向分量统一缩放,保证六个切片纹理密度一致。

此时每个三角形都有了二维 UV,且被标记了"属于第几个面"(0~5)。

第 3 步:统一六个切片的朝向

六个面各自投影后,"上北下南"并不统一:+X 面朝上的方向和 +Z 面朝上的方向在三维空间中可能差 90°。若不一致,烘焙出来的贴图会出现"花纹方向错乱"。

_rotate_uv_slices_consistent_space(unwrap.py#L279-L354)的做法很巧妙:

  • 先用_calculate_tangents(unwrap.py#L211-L277)从位置与 UV 差分算出每个顶点的切线向量;
  • 再计算一个"期望切线"(绕 Y 轴的切向,即模型的自然"水平方向");
  • 对每个面的平均切线求夹角,得到该切片应旋转的角度,用 2D 旋转矩阵把整个切片旋转对齐,最后重新归一化回 [0,1]。

第 4 步:BVH 重叠检测,分配 Atlas 槽位

六面投影有个天然缺陷:斜朝向的三角形会投到不相邻的面上,和别的三角形在 2D 上重叠——重叠部分贴图信息就会被覆盖丢失。

Modly 的解决方案在 C++ 扩展 unwrapper.cpp 中:

  • 为六个面各自建BVH 包围盒树(bvh.h),并行检测三角形相交(unwrapper.cpp#L46-L88);
  • 发现重叠后,按三角形质心沿轴向排序,靠前的三角形保留原位,靠后的被"驱逐",移入图集的备用区域。

因此图集槽位编号(atlas index)分三档:

  • 0~5:六个主面切片(3×2 网格);
  • 6~11:第一轮重叠三角形(缩小一半塞进第二层 3×2 小网格);
  • 12+:残余随机重叠(放进底部 1/3 区域的长条里)。

第 5 步:3×2 网格打包成最终 Atlas

槽位分配好之后,_find_slice_offset_and_scale(unwrap.py#L149-L209)查表计算每片在 0~1 大图集中的偏移与缩放:

  • 主切片:offset = 1/3 × 网格坐标,div = 3,即经典3 列 2 行布局;
  • 重叠切片:offset基于1/6的更小网格,div = 6,以一半分辨率挤进主切片旁边;
  • 更多残余重叠:挤进底部 1/3 横条(unwrap.py#L200-L207)。

随后_handle_slice_uvs与_handle_remaining_uvs(unwrap.py#L356-L475)分别把两类切片归一化填满各自的小格子并加island_padding内边距(防止相邻切片纹理采样串色),最后_distribute_individual_uvs_in_atlas做uv / div + offset一步完成平移缩放。收尾的_get_unique_face_uv(unwrap.py#L517-L535)用torch.unique去重,输出最终顶点 UV 及顶点索引映射。

在实际应用中如何生效

展开器的产出(UV 坐标 + 顶点索引)会交给纹理烘焙器把 AI 生成的外观信息烘成贴图像素。在生成界面里,"Generate Texture"开关就是这一整条 UV 展开 + 烘焙管线的入口(GenerationOptions.tsx#L445),可自由设置 64~2048 的贴图分辨率。

小结

Modly UV 展开器用**"简单投影 + 冲突重排"**的思路,换掉了传统 UV 展开中复杂的切割缝求解:

  1. PCA 摆正模型,提高投影利用率;
  2. Box Mapping 六面正交投影,代码量小、速度快、无撕裂;
  3. 切线对齐保证六片朝向一致;
  4. BVH 加速重叠检测,冲突三角形降级到备用区;
  5. 3×2 网格 + 内边距完成 Atlas 打包。

代价是斜向表面存在重叠损失(靠 6/12 备用区缓解),但对 AI 生成模型的纹理烘焙场景,这种以速度优先的取舍非常务实——整套流程源码见 api/uv_unwrapper/,配合 api/texture_baker/ 即可完成从模型到贴图的全自动管线。

【免费下载链接】modlyDesktop app to generate 3D models from images or prompt using local AI — runs entirely on your GPU项目地址: https://gitcode.com/GitHub_Trending/mo/modly

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询