Use [Center of Gravity Coordinates] to interpolate on the model to obtain the vertex coordinates corresponding to each pixel on the texture

premise:

After the texture is pasted on the model, what can be obtained directly using the blender python api is the texture coordinates corresponding to the vertices on each triangle of the model. The vertices of each triangular face constitute a triangle (A), and the texture coordinates corresponding to the vertices of each triangular face also constitute a triangle (B). (Note: In fact, blender usually uses quadrilaterals, so the quadrilaterals should be divided into two triangles when processing)

calculation steps:
1. When traversing each pixel (P), first determine which triangle in a group of B triangles this pixel belongs to.

2. Then combine the pixel coordinate P and the triangle B to calculate the corresponding centroid coordinates of this pixel.
3. Then calculate the position of this point in triangle A by combining Barycenter coordinates and this pixel P.
The default condition of the above algorithm is: it is determined that triangle A is consistent with triangle B. Then use the coordinates of the center of gravity to calculate the difference

code:

Because I need to store in the sqlite3 database, I will use sqlite3

import bpy
import sqlite3
import bmesh

dbpath = '/Users/wxzjr/file/uv_xyz.db'
# The handle to connect to the database
db = sqlite3. connect(dbpath)
# cursor object
cur = db. cursor()
# Store the data to be written to the database
sql_value = []
# Get the currently active object:
obj = bpy.data.objects["nan_right"]
obj. select_set(True)
bpy.context.view_layer.objects.active=obj
# 2. Get the mesh data of the object:
mesh = obj.data
# 3. Get the texture image data, as well as the width and height of the texture image:
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

# Get triangle data
face_data = obj.data.polygons

# Get the world transformation matrix of the model
world_mat = obj.matrix_world


# clear the table
def clearData():
    print('start emptying the table')
    sql = 'delete from pixelmap where 1 = 1'
    try:
        cur. execute(sql)
        print('Empty the table successfully')
    except Exception as e:
        print(e)
        print('Failed to clear table')


def dissconnectDB():
    # close the cursor
    cur. close()
    # close the connection
    db. close()
    print('Disconnect database link')


# Execute sql to create table
def createTable():
    print('start creating table')
    # Execute sql to create table
    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('Create table successfully')
    except Exception as e:
        print(e)
        print('Failed to create table')


def insertValueIntoTable(value):
    print('Start inserting data')
    try:
        # Execute sql to create table
        sql = 'insert into pixelmap(texture,u,v,canvas,x,y,z) values(?,?,?,?,?,?,?)'
        cur. executemany(sql, value)
        # Submit the transaction
        db. commit()
        print('insert successfully')
    except Exception as e:
        print('insert failed')
        print(e)
        db. rollback()


# Calculate the coordinates of the center of gravity of the point in the triangle
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 is the coordinates of the three vertices of the triangle, uvw is the coordinates of the center of gravity of the target point
    p = xyz[0] * uvw[0] + xyz[1] * uvw[1] + xyz[2] * uvw[2]
    return p


# 4. For each pixel point, find their corresponding triangle, and calculate the barycentric coordinates of the pixel point in the triangle:
# loop through each pixel
createTable()
clearData()
total_load = 0
            
for y in range(height):
    for x in range(width):
        # Get the color value of the pixel
        r = pixels[(y * width + x) * 4]
        g = pixels[(y * width + x) * 4 + 1]
        b = pixels[(y * width + x) * 4 + 2]
        # If the color of the pixel is not completely black, it means that it has a corresponding triangle on the texture map
        if r != 0 or g != 0 or b != 0:
            # Get texture coordinates
            u, v = float(x/width), float(y/height)
            # iterate over all faces
            poly = None
            for face in mesh. polygons:
                # Get all vertices of the face
                vertices = []
                # Get the texture coordinates corresponding to all vertices of the face
                tex_coords = []
                loop_start = face. loop_start
                loop_end = face.loop_start + face.loop_total
                if face. loop_total == 4:
                    # first triangle
                    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([email protected][vertices_2].co)
                    
                    vertices_3 = mesh.loops[face.loop_start + 3].vertex_index
                    
                    # Calculate the coordinates of the center of gravity to determine whether the pixel is within the triangle
                    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
                    # second triangle
                    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([email protected][vertices_2].co)
                    
                    tex_coords.append(uv_layers_data[face.loop_start + 3].uv)
                    vertices.append([email protected][vertices_3].co)
                    # Calculate the coordinates of the center of gravity to determine whether the pixel is within the triangle
                    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([email protected][vertices_index].co)
                        # Calculate the coordinates of the center of gravity to determine whether the pixel is within the triangle
                        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 a triangle is found, calculate the barycentric coordinates of the pixel in the triangle
            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()

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledgePython entry skill treeHomepageOverview 313218 people are studying systematically