[Addon] Copy Vertex Order By UVs v0.6 (update 2013-01-31)

@CoDEmanX: thanks for the explanation. I have a lot to learn about python. “uv_loops[lstart:lend]” looked so innocent…

[Edit:] I cannot believe that python does not realize that:
(1) [uv.uv for uv in uv_loops1[lstart:lstart+F.loop_total]]
(2) [uv_loops1[i].uv for i in range(lstart, lstart+ F.loop_total)]
are the same thing, but still (1) is over 250 times slower. (2) is even faster than (3):
(3) [uv_loops1[i].uv for i in F.loop_indices]

for me with 66k quads (without rest of algorithm, just a loop over faces):
(1): 67.22099995613098 s
(2): 0.2200000286102295 s
(3): 0.24499988555908203 s

UPDATE: new release v0.6, twice as fast now. See first post.


Please try this release, the inner loop is now considering a single vertex instead of all vertices of all faces of a single vertex. That way the potential for the algorithm to get stuck in faces with same UV is smaller.

yeah, it should be smart enough to recognize what the [:] is used for, but on the other hand, [] somewhat forces a copy operation and could be desired in certain situations.

(2) vs. (3): Interesting find, i can only explain that like this: loop_indices is a convenience bpy api property (that’s for sure), and it gets updated whenever you access it (i assume), but it doesn’t really exist (internally, loop_start and loop_total are used, no need for loop_indices). If you read the real props and do the rest on pyside, it appears to be a little bit faster.

omg, life saver!

I tried the latest version (06), I tried randomizing the vertex order of the source mesh, decreased EPSILON , I checked if the UV is the same (and it seems to be, no matter how close I zoom in in the UV editor with both models visible).
Nothing works.

Here’s the model
I’m trying to copy the vertex order from leg_1_multires_apply to leg_1_import (I want to use it for the reshape option in the multires modifier later).

It’s not even extremely high poly (18k), but I have the same problem with higher subdivisions of the same model, and with other models. leg_1_import is imported from mudbox, leg_1_multires_apply is a lower subdivision imported from mudbox and subdivided with the multires modifier in blender.

Here’s the error:

Traceback (most recent call last):
File “C:\Users\ania\AppData\Roaming\Blender Foundation\Blender\2.65\scripts\addons
uke_copy_indices.py”, line 306, in execute
object_copy_indices(self, context)
File “C:\Users\ania\AppData\Roaming\Blender Foundation\Blender\2.65\scripts\addons
uke_copy_indices.py”, line 254, in object_copy_indices
mapByUv(mesh1, mesh2, [vnew1], [vnew2], VertexFaces1, VertexFaces2, uvcache1, uvcache2, mapping, invmapping, tmpMap)
File “C:\Users\ania\AppData\Roaming\Blender Foundation\Blender\2.65\scripts\addons
uke_copy_indices.py”, line 137, in mapByUv
raise Exception(“ERROR: found different mapping for vertex”)
Exception: ERROR: found different mapping for vertex

location: <unknown location>:-1

@ania: your UVs do not match:

UVs for face 3547: [[0.4108099937438965, 0.1966259926557541], [0.4086599349975586, 0.1993660032749176], [0.40619993209838867, 0.1972610056400299], [0.4077599048614502, 0.19447599351406097]]

UVs for face 3547: [[0.4062018394470215, 0.1972614973783493], [0.40775632858276367, 0.19447599351406097], [0.4108119010925293, 0.1966259926557541], [0.40865540504455566, 0.199366495013237]]

These are the first faces the addon is comparing, and by accident these would be the correct mapping (verified by hand with a new script, will clean it up and release it later). But as you see the UVs are not identical.

Note: I get another error than you: Exception: (‘ERROR: no match for face found:’, 3547) [ok, I see you get the other error if increasing EPSILON, that is to be expected because you have UVs that are very near each other]

Do you apply subdivide after export/import? Maybe that is the problem? I would export, edit, then import and map indices. If you subdivide inbetween those steps it maybe creates different UVs for the meshes.

Here the addon used to debug the issue:

Well one of the meshes is subdivided in Mudbox (and sculpted), the other one in Blender (and not sculpted). But both just divide each edge by 2 (no smoothing), same algorithm. Probably the rounding is different.

Vertex 1 and 2 seems swapped with 3 and 4 in this face, at least to the 4th digit, would the addon cope with this, or could that be the problem?

UVs for face 3547: [[0.4108099937438965, 0.1966259926557541], [0.4086599349975586, 0.1993660032749176], [0.40619993209838867, 0.1972610056400299], [0.4077599048614502, 0.19447599351406097]]

UVs for face 3547: [[0.4062018394470215, 0.1972614973783493], [0.40775632858276367, 0.19447599351406097], [0.4108119010925293, 0.1966259926557541], [0.40865540504455566, 0.199366495013237]]

could be a problem with the OBJ importer (do you use it?)

the original uv order is like 0123
and of your re-imported data 2301

in OBJ importer, we can find this hack:

                # BUG - Evil eekadoodle problem where faces that have vert index 0 location at 3 or 4 are shuffled.                if len(face_vert_loc_indices) == 4:
                    if face_vert_loc_indices[2] == 0 or face_vert_loc_indices[3] == 0:
                        face_vert_tex_indices = face_vert_tex_indices[2], face_vert_tex_indices[3], face_vert_tex_indices[0], face_vert_tex_indices[1]
                else:  # length of 3
                    if face_vert_loc_indices[2] == 0:
                        face_vert_tex_indices = face_vert_tex_indices[1], face_vert_tex_indices[2], face_vert_tex_indices[0]
                # END EEEKADOODLE FIX

so there is shuffling to fix a bug, not sure in which cases this is actually needed (maybe in conjunction with OBJs generated by a major 3d software package?)

for test purposes, comment out that code (or remove), re-import and retry index sorting.

Question is if UVs of new vertices are interpolated in the same way in both?

No, the current version assumes that the order of vertices in faces is identical in both meshes. I created a new version which has a switch to change that, but it does not solve the problem in your case. Will release this version later.

The problem is that the rounding/accuracy errors in your case are larger than the difference in UVs of certain faces. The new version of the addon would compare all vertices of 2 faces, but if more than one of those could be mapped to a vertex it will throw an error (so user can be sure that mapping is ok if he gets one). In your case the EPSILON has to be increased that much that there are faces where multiple vertices could be matched to each other.

Yes I use the obj importer. Commenting out that part did not help, however.

I thought so, in both cases it just cuts through half the edge, with no further interpolation (I always switch the “subdivide UVs” option off in Blender). But there could be different rounding in the programs.

Meanwhile I moreless solved the problem the other way around, by exporting the multires-subdivided mesh from blender into mudbox, doing a remesh operation there (which is also based on UV, but seems more robust), reimporting that version back to Blender, and doing a remesh in the multires modifier from the reimported mesh, which now has the right vertex order, onto the low poly.
There are still some artifacts, but at least it’s not such a wild mess as before.

fbar: couldn’t you add a check for the order of verts and correct it if shuffling is detected? Maybe all are shuffled by mudbox…

As written in my previous post, I created a version that does not care about vertex order. But I have not released it till now because I’m not sure how to let the user set that option, setting it in the script is easy for me but not so nice for users. I want to keep the original version too, because the old variant is more tolerant if multiple vertices in a face have very similar UVs (e.g. a face where all but one vertex cannot be mapped uniquely because UVs are too similar can still be mapped because a single vertex can be mapped because the order determines the other mappings).

I would like to let the user set options for the addon in the blender preferences addon screen, but I think this is not possible.

there are several ways to do this, user addon preferences doesn’t seem good though.

You could use a popup like “Move to layer” does, prompting for the mode. If you add the operator to a panel, it becomes easier: just add a checkbox (boolprop) above.

Not necessarily in mudbox, it is just a remesh operation there, no reorder (it transfers the absolute XYZ position of each vertex to the vertex of the other mesh which shares UV space), it could interpolate between vertices and tolerate when they are slightly off, it just needs to assign an XYZ vector to each UV vector. (parts of the target mesh can be deleted and it still works, which wouldn’t be possible if it would perform any vertex order operations)

Does this addon still work for Blender 2.66?

@ashasekayi: I just tried with 2.66a, seems to work.

Thanks for answering. :slight_smile:

Oy, I didn’t know 2.66a was out. I’ll give it another go.

does this still work with yiu guys in 2.73? i get this error;

Traceback (most recent call last):  File "/Users/romboutversluijs/Library/Application Support/Blender/2.72/scripts/addons/nuke_copy_indices.py", line 306, in execute
    object_copy_indices(self, context)
  File "/Users/romboutversluijs/Library/Application Support/Blender/2.72/scripts/addons/nuke_copy_indices.py", line 244, in object_copy_indices
    mapByUv(mesh1, mesh2, vList1, vList2, VertexFaces1, VertexFaces2, uvcache1, uvcache2, mapping, invmapping, newMaps)
  File "/Users/romboutversluijs/Library/Application Support/Blender/2.72/scripts/addons/nuke_copy_indices.py", line 162, in mapByUv
    raise Exception("ERROR: no match for face found:", f1)
Exception: ('ERROR: no match for face found:', 47)

location: &lt;unknown location&gt;:-1

Iv tried 2.72 as well. Even when i duplcate the mesh and than try it still gives that error. Ive tried a simple cube and this works. Also every step in 2.72

is there any one who still has this working