You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过编程(如Python)实现不同UV展开间的纹理颜色迁移?

基于UV坐标反向映射的纹理迁移方案(Python实现)

核心思路

跳过顶点颜色的中间插值步骤,直接建立UV-2与UV-1的像素级精准映射:对目标纹理(UV-2对应的纹理画布)的每个像素,先找到其在3D模型表面对应的位置,再获取该位置的UV-1坐标,直接采样原纹理(纹理1)的颜色值填充到目标像素。这种方法能完整保留原纹理的细节,不会因顶点插值丢失精度。

实现步骤(依赖Python库:OpenCV、NumPy、trimesh)

1. 加载模型与UV数据

读取包含两组UV的3D模型(如.obj格式),提取顶点位置、两组UV坐标及面索引数据:

import trimesh
import numpy as np
import cv2

# 加载模型,禁用自动处理以保留原始UV数据
mesh = trimesh.load("your_model.obj", process=False)
# 提取两组UV(需根据模型实际存储结构调整,部分模型会将多组UV存在不同字段)
uv1 = mesh.visual.uv  # UV-1坐标组
uv2 = mesh.visual.uv_second  # UV-2坐标组
faces = mesh.faces  # 模型面的顶点索引
face_uv1_idx = mesh.visual.face_uvs  # 每个面对应的UV-1索引
face_uv2_idx = mesh.visual.face_uvs_second  # 每个面对应的UV-2索引

2. 初始化纹理画布

以原纹理的分辨率创建目标纹理画布:

# 加载原纹理贴图1
src_texture = cv2.imread("texture1.png")
h, w = src_texture.shape[:2]
# 初始化目标纹理(UV-2对应)
dst_texture = np.zeros_like(src_texture)

3. 逐像素映射纹理颜色

遍历目标纹理的每个像素,完成UV-2到UV-1的反向映射与颜色采样:

for y in range(h):
    for x in range(w):
        # 将像素坐标转换为UV-2坐标(UV范围通常为[0,1])
        uv2_coord = np.array([x / (w-1), y / (h-1)])
        # 找到该UV-2坐标所属的三角面
        face_idx = find_face_for_uv(uv2_coord, faces, face_uv2_idx, uv2)
        if face_idx is None:
            continue  # 跳过模型UV外的空白区域
        # 获取当前面的三个UV-2顶点
        uv2_face = uv2[face_uv2_idx[face_idx]]
        # 计算UV点在三角面内的重心坐标
        barycentric = compute_barycentric(uv2_coord, uv2_face)
        # 通过重心坐标计算对应的3D空间点
        face_vertices = mesh.vertices[faces[face_idx]]
        point_3d = barycentric[0]*face_vertices[0] + barycentric[1]*face_vertices[1] + barycentric[2]*face_vertices[2]
        # 用同一重心坐标计算对应的UV-1坐标
        uv1_face = uv1[face_uv1_idx[face_idx]]
        uv1_coord = barycentric[0]*uv1_face[0] + barycentric[1]*uv1_face[1] + barycentric[2]*uv1_face[2]
        # 采样原纹理颜色(适配OpenCV的y轴向下的图像坐标系)
        src_x = int(uv1_coord[0] * (w-1))
        src_y = int((1 - uv1_coord[1]) * (h-1))
        dst_texture[y, x] = src_texture[src_y, src_x]

# 保存最终的UV-2纹理
cv2.imwrite("texture_uv2.png", dst_texture)

4. 辅助函数实现

查找UV所属的三角面

def find_face_for_uv(uv_coord, faces, face_uv_idx, uv_data):
    for i, face_uvs in enumerate(face_uv_idx):
        uv_tri = uv_data[face_uvs]
        if point_in_triangle(uv_coord, uv_tri[0], uv_tri[1], uv_tri[2]):
            return i
    return None

判断点是否在三角面内(基于重心坐标)

def point_in_triangle(p, a, b, c):
    v0 = c - a
    v1 = b - a
    v2 = p - a
    dot00 = np.dot(v0, v0)
    dot01 = np.dot(v0, v1)
    dot02 = np.dot(v0, v2)
    dot11 = np.dot(v1, v1)
    dot12 = np.dot(v1, v2)
    denom = dot00 * dot11 - dot01 * dot01
    if denom == 0:
        return False
    u = (dot11 * dot02 - dot01 * dot12) / denom
    v = (dot00 * dot12 - dot01 * dot02) / denom
    return (u >= 0) and (v >= 0) and (u + v <= 1)

计算三角面内点的重心坐标

def compute_barycentric(p, a, b, c):
    v0 = b - a
    v1 = c - a
    v2 = p - a
    d00 = np.dot(v0, v0)
    d01 = np.dot(v0, v1)
    d11 = np.dot(v1, v1)
    d20 = np.dot(v2, v0)
    d21 = np.dot(v2, v1)
    denom = d00 * d11 - d01 * d01
    v = (d11 * d20 - d01 * d21) / denom
    w = (d00 * d21 - d01 * d20) / denom
    u = 1.0 - v - w
    return np.array([u, v, w])

优化方向

  • 并行加速:用NumPy向量化操作或multiprocessing库替代双重循环,提升处理大纹理的效率
  • 纹理过滤:将最近邻采样替换为双线性插值,优化纹理边缘的平滑度
  • 重叠UV处理:若UV-2存在重叠区域,可通过加权平均采样结果解决冲突

内容的提问来源于stack exchange,提问作者XiaoJin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 05:30:42