使用【重心坐标】在模型上进行插值来获取纹理上每个像素对应的顶点坐标

文章描述了一个使用Blender的PythonAPI来处理3D模型的纹理坐标的过程,具体包括获取模型每个三角面的纹理坐标,遍历像素并判断其所属的纹理三角形,计算重心坐标,然后将这些信息存储到SQLite3数据库中。代码示例展示了如何操作数据库,创建表,以及处理四边形为两个三角形的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前提:

纹理在模型上贴好后,能使用blender python api直接获取的就是,这个模型的每个三角面片上顶点对应的纹理坐标。这其中每个三角面的顶点构成一个三角形(A),每个三角面的顶点对应的纹理坐标也构成一个三角形(B)。(注:实际上blender常用的是四边形,所以处理时要把四边形分成两个三角形)

计算步骤:
1、遍历每个像素(P)时,先判断这个像素属于一群B三角形中的哪个三角形。

2、然后结合这个像素坐标P以及三角形B算出这个像素对应的重心坐标
3、然后在结合重心坐标与这个像素P算出这个点在三角形A中的位置。
上述算法的默认条件是:认定三角形A与三角形B一致。然后在利用重心坐标进行差值计算

代码:

因为我需要存储到sqlite3的数据库,所以会用到sqlite3

import bpy
import sqlite3
import bmesh

dbpath = '/Users/wxzjr/file/uv_xyz.db'
# 链接数据库的句柄
db = sqlite3.connect(dbpath)
# cursor对象
cur = db.cursor()
# 存储要写入数据库的数据
sql_value = []
# 获取当前激活的对象:
obj = bpy.data.objects["nan_right"]
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
# 2. 获取对象的网格数据:
mesh = obj.data
# 3. 获取纹理图像数据,以及纹理图像的宽度和高度:
image = bpy.data.images["texture_20001.jpg"]
pixels = image.pixels
width, height = image.size
print(width,height)
uv_layers_data = obj.data.uv_layers.active.data

# 获取三角面数据
face_data = obj.data.polygons

# 获取模型的世界变换矩阵
world_mat = obj.matrix_world


# 清空表格
def clearData():
    print('开始清空表')
    sql = 'delete from pixelmap where 1 = 1'
    try:
        cur.execute(sql)
        print('清空表成功')
    except Exception as e:
        print(e)
        print('清空表失败')


def dissconnectDB():
    # 关闭游标
    cur.close()
    # 关闭连接
    db.close()
    print('断开数据库链接')


# 执行sql创建表
def createTable():
    print('开始创建表')
    # 执行sql创建表
    sql = 'create table pixelmap(id INTEGER PRIMARY KEY AUTOINCREMENT,texture string,u float,v float,canvas string,x float,y float,z float)'
    try:
        cur.execute(sql)
        print('创建表成功')
    except Exception as e:
        print(e)
        print('创建表失败')


def insertValueIntoTable(value):
    print('开始插入数据')
    try:
        # 执行sql创建表
        sql = 'insert into pixelmap(texture,u,v,canvas,x,y,z) values(?,?,?,?,?,?,?)'
        cur.executemany(sql, value)
        # 提交事务
        db.commit()
        print('插入成功')
    except Exception as e:
        print('插入失败')
        print(e)
        db.rollback()


# 计算点在三角形中的重心坐标
def calculate_barycenter(point, points):
    x, y = point[0], point[1]
    p1, p2, p3 = points[0], points[1], points[2]
    denominator = (p2[1] - p3[1]) * (p1[0] - p3[0]) + (p3[0] - p2[0]) * (p1[1] - p3[1])
    alpha = ((p2[1] - p3[1]) * (x - p3[0]) + (p3[0] - p2[0]) * (y - p3[1])) / denominator
    beta = ((p3[1] - p1[1]) * (x - p3[0]) + (p1[0] - p3[0]) * (y - p3[1])) / denominator
    gamma = 1.0 - alpha - beta
    return (alpha, beta, gamma)


def barycentric_to_cartesian(uvw, xyz):
    # xyz是三角形的三个顶点坐标,uvw是目标点的重心坐标
    p = xyz[0] * uvw[0] + xyz[1] * uvw[1] + xyz[2] * uvw[2]
    return p


# 4. 对于每个像素点,找到它们所对应的三角形,并计算出该像素点在三角形中的重心坐标:
# 遍历每个像素点
createTable()
clearData()
total_load = 0
            
for y in range(height):
    for x in range(width):
        # 获取像素点的颜色值
        r = pixels[(y * width + x) * 4]
        g = pixels[(y * width + x) * 4 + 1]
        b = pixels[(y * width + x) * 4 + 2]
        # 如果像素点的颜色不是全黑,则表示它在纹理贴图上有对应的三角形
        if r != 0 or g != 0 or b != 0:
            # 获取纹理坐标
            u, v = float(x/width), float(y/height)
            # 遍历所有面
            poly = None
            for face in mesh.polygons:
                # 获取面的所有顶点
                vertices = []
                # 获取面的所有顶点对应的纹理坐标
                tex_coords = []
                loop_start = face.loop_start
                loop_end = face.loop_start + face.loop_total
                if face.loop_total == 4:
                    # 第一个三角面
                    vertices_0 = mesh.loops[face.loop_start].vertex_index
                    tex_coords.append(uv_layers_data[face.loop_start].uv)
                    vertices.append(world_mat @ mesh.vertices[vertices_0].co)
                    
                    vertices_1 = mesh.loops[face.loop_start+1].vertex_index
                    tex_coords.append(uv_layers_data[face.loop_start+1].uv)
                    vertices.append(world_mat @ mesh.vertices[vertices_1].co)
                    
                    vertices_2 = mesh.loops[face.loop_start+2].vertex_index
                    tex_coords.append(uv_layers_data[face.loop_start+2].uv)
                    vertices.append(world_mat @ mesh.vertices[vertices_2].co)
                    
                    vertices_3 = mesh.loops[face.loop_start+3].vertex_index
                    
                    # 计算重心坐标,判断该像素点是否在该三角面内
                    barycenter = calculate_barycenter((u, 1-v), tex_coords)
                    if (barycenter[0] >= 0.0 and barycenter[1] >= 0.0 and barycenter[2] >= 0.0):
                        poly = face
                        break
                    # 第二个三角面
                    vertices = []
                    tex_coords = []
                    
                    tex_coords.append(uv_layers_data[face.loop_start].uv)
                    vertices.append(world_mat @ mesh.vertices[vertices_0].co)
                    
                    tex_coords.append(uv_layers_data[face.loop_start+2].uv)
                    vertices.append(world_mat @ mesh.vertices[vertices_2].co)
                    
                    tex_coords.append(uv_layers_data[face.loop_start+3].uv)
                    vertices.append(world_mat @ mesh.vertices[vertices_3].co)
                    # 计算重心坐标,判断该像素点是否在该三角面内
                    barycenter = calculate_barycenter((u, 1-v), tex_coords)
                    if (barycenter[0] >= 0.0 and barycenter[1] >= 0.0 and barycenter[2] >= 0.0):
                        poly = face
                        break
                else:
                    for loop_index in range(loop_start, loop_end):
                        vertices_index = mesh.loops[loop_index].vertex_index
                        tex_coords.append(uv_layers_data[loop_index].uv)
                        vertices.append(world_mat @ mesh.vertices[vertices_index].co)
                        # 计算重心坐标,判断该像素点是否在该三角面内
                        barycenter = calculate_barycenter((u, 1-v), tex_coords)
                        if (barycenter[0] >= 0.0 and barycenter[1] >= 0.0 and barycenter[2] >= 0.0):
                            poly = face
            # 如果找到了三角形,则计算该像素点在三角形中的重心坐标
            if poly is not None:
                point = barycentric_to_cartesian(barycenter, vertices)
                sql_value.append(('wlzj_1_ipg', u, 1.0-v, "wlzj_1_mesh", point.x, point.y, point.z))
            else:
                print("Pixel {},{} not in face)".format(x,y))
insertValueIntoTable(sql_value)
dissconnectDB()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值