1
$\begingroup$

modelling noob here.

Problem: I am modifying a few meshes with the same number of vertices but different topology deformations. They were produced from the same base mesh but somewhere along the line the vertex indices diverged. I need the indices to allign so that I can transfer weight paint between the meshes. The objects have identical UV layouts as they were unwrapped before the topology was deformed.

Question: Is there a way to match vertex indices between objects by checking for proximal UV coordinates, sort of like the magic UV plugin but in reverse? Or perhaps a way of sorting the vertices of each object by UV coordinates so that they all match? Would the plugin copy_vert_ids be useful in this regard?

Thanks!

$\endgroup$
12
  • 1
    $\begingroup$ You could use Textools addon to make flattened versions of each mesh, which are ripped along seams and then flattened to UV. Then you can copy weights (data transfer) from one to the other, unflatten (textools makes a shapekey to do so), and copy weights back onto the proper, unflattened original. $\endgroup$
    – Nathan
    Jan 1, 2021 at 1:40
  • $\begingroup$ @Nathan That should be an answer? Could you also use the flattened shape-keys to Mesh>Sort Elements the vertex indices? $\endgroup$
    – Robin Betts
    Jan 1, 2021 at 9:43
  • $\begingroup$ I think this is not possible in general case, as several faces could share the exact same UV coordinates. So when testing uv co from one mesh that could match many vertices of the other mesh. Do you have any additional element in the context to take into account and so to get rid of that? $\endgroup$
    – lemon
    Jan 1, 2021 at 10:10
  • 1
    $\begingroup$ @RobinBetts You could sort the flattened meshes, but I don't see a way to get that onto the original-- the flattened meshes aren't the same, they're ripped along seams. It can achieve the end goal, but not the explicit question. $\endgroup$
    – Nathan
    Jan 1, 2021 at 16:28
  • $\begingroup$ @lemon & Nathan.. if the shapekey created by Textools splits the verts, then I thought maybe there's a hack .. sort in the flat > shape-key > merge by distance, happening to behave the same way for the 2 meshes.. I've never used Textools.. $\endgroup$
    – Robin Betts
    Jan 1, 2021 at 18:26

1 Answer 1

2
$\begingroup$

A caveat.. there are people on this site who are better at this than me.. I wouldn't have posted if one of them had done it first. (I've really had a go at it, to explore bmesh better for myself)

This script may be a starting point though.. it assumes the two meshes share identical UV maps, vertex counts, and that there are no overlapping / coincident vertices in the map(s).

To use it, you would insert the source and target object names, and the names of their matching UV maps. It creates a dictionary of the pairs of vertex indices, keyed by the UV coordinates.

import bpy
import bmesh
from collections import defaultdict

# Insert object names here
ob1 = bpy.data.objects['C1'] # Source object
ob2 = bpy.data.objects['C2'] # Target object
me1 = ob1.data 
me2 = ob2.data

# BMesh representations of both meshes
bm1 = bmesh.new()   
bm1.from_mesh(me1) 
bm2 = bmesh.new()   
bm2.from_mesh(me2)

  
# Insert UV map names here
uvm1 = bm1.loops.layers.uv['UVMap'] # Source's map
uvm2 = bm2.loops.layers.uv['UVMap'] # Target's map

#Create dict {(UV coordinate : [bm1 vert idx, bm2 vert idx]),...}
uvdict = defaultdict(lambda: [-1,-1])

for face in bm1.faces:
    for loop in face.loops:
        uvco = loop[uvm1].uv[:]
        vidx = loop.vert.index    
        uvdict[uvco][0] = vidx
        
for face in bm2.faces:
    for loop in face.loops:
        uvco = loop[uvm2].uv[:]
        vidx = loop.vert.index
        uvdict[uvco][1] = vidx 
               
#get rid of dupe loop -> vert refs
matchlist = list(set(tuple(x) for x in uvdict.values()))

bm2.verts.ensure_lookup_table()

#reassign target v indices
for pair in matchlist:
    bm2.verts [pair[1]].index = pair[0]
    
bm2.verts.sort()
bm2.to_mesh(me2)

bm1.free() 
bm2.free()

It's possible I've got the wrong end of the stick re. your problem.. I run the script in object mode, with nothing selected. Tightening / correction, by folks who know better, would be welcome.

$\endgroup$
3
  • 1
    $\begingroup$ I will try your script and see if I have any success with it. $\endgroup$
    – Frosferes
    Jan 1, 2021 at 20:47
  • 1
    $\begingroup$ Looks like that's done the trick! It turns out there were some overlapping and folded UV coordinates in my meshes. But this was solved by temporarily moving them, running the script and moving them back. I'm curious if this script would also work for objects with UV count > Vertex count as Nathan pointed out. This wasn't a problem for me since my meshes are UV ripped. Thank you for the help! $\endgroup$
    – Frosferes
    Jan 2, 2021 at 18:34
  • $\begingroup$ Great! Glad it worked for you. I tested it on [many UV Loop] -> [one Mesh Vertex] objects, with randomized vertex indices, so it should work. The script doesn't do anything clever, just bulldozes through the lot, then eliminates the dupes, where commented. So it should work, if all the UV loops (verts) have different UV coordinates, so those can be used as unique indices into the geometry vertex list. $\endgroup$
    – Robin Betts
    Jan 2, 2021 at 19:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .