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