3
$\begingroup$

How do I get a selected vertex and it's corresponding uv vertex?

A vertex I can get with

bpy.context.active_object.data.vertices[0]

A uv vertex I can get with

bpy.context.active_object.data.uv_layers['UVMap'].data[0]

But the index is not the same for uv and mesh vertex.

$\endgroup$
1
  • $\begingroup$ In your first line you retrieve a vertex from the active object's mesh, in the second line you retrieve the uv layer from the active object's mesh, and you don't need to add '.data[0]'. What you are refering to as the "index" of the uv map is its name itself, there is not way you will have a correlation between a mesh's vertices index and a mesh's UV_layer $\endgroup$
    – Yvain
    Mar 23, 2016 at 12:11

3 Answers 3

6
$\begingroup$

As madlaina says, A vertex doesn't have a 1:1 corraspondance with UV coordinates.

However using BMesh you can loop over a vertices connected face corners (loops), and find the UV's used by a vertex.

Heres a script that prints all vertices UV's in editmode.

Both the first-uv found (which is OK if you assume all UV's attached to a vertex will be the same).
And the mean average.

import bpy
import bmesh
from mathutils import Vector

obj = bpy.context.edit_object
me = obj.data
bm = bmesh.from_edit_mesh(me)


def uv_from_vert_first(uv_layer, v):
    for l in v.link_loops:
        uv_data = l[uv_layer]
        return uv_data.uv
    return None


def uv_from_vert_average(uv_layer, v):
    uv_average = Vector((0.0, 0.0))
    total = 0.0
    for loop in v.link_loops:
        uv_average += loop[uv_layer].uv
        total += 1.0

    if total != 0.0:
        return uv_average * (1.0 / total)
    else:
        return None

# Example using the functions above
uv_layer = bm.loops.layers.uv.active

for v in bm.verts:
    uv_first = uv_from_vert_first(uv_layer, v)
    uv_average = uv_from_vert_average(uv_layer, v)
    print("Vertex: %r, uv_first=%r, uv_average=%r" % (v, uv_first, uv_average))
$\endgroup$
1
  • $\begingroup$ exactly what I was looking for. Thank you! $\endgroup$
    – ndee
    Mar 23, 2016 at 13:33
3
$\begingroup$

The thing you need to consider is that a vertex can have multiple uv-coordinates (for example if you unwrap two faces then there are two uv coordinates for one vertex where the seams are)

The UV Coordinates are actually stored per face-loop and not per vertex. It is a good idea to read up on this here to understand the concept better:

https://wiki.blender.org/index.php/Dev:Source/Modeling/BMesh/Design

Maybe you can give us more information, what you would like to do with the uv coordinates.

$\endgroup$
0
$\begingroup$

As already said, a vertex can be associated to multiple UVs. That's because, from 3D authors' point of view, UV editing is done distributing polygons (not vertices) over the texture surface.

I propose here a snippet to scan the association between polygons, vertices and UV coordinates running in Object mode (no BMesh).

import bpy
import mathutils

src_obj: bpy.types.Object = bpy.context.active_object
assert src_obj.type == 'MESH'

# get reference to mesh
src_mesh: bpy.types.Mesh = src_obj.data

# Get basic UV info
active_uv_idx: int = src_mesh.uv_layers.active_index
active_uv: bpy.types.MeshUVLoopLayer = src_mesh.uv_layers[active_uv_idx]

print(f"Info for uvlayer {active_uv_idx} '{active_uv.name}' on object {src_obj.name}")

#
# Iterate over the polygons of the mesh    
for poly in src_mesh.polygons:
    assert type(poly) == bpy.types.MeshPolygon    
    assert len(poly.vertices) == len(poly.loop_indices)

    # For each vertex of the polygon, and uv loop indices
    for v_idx, loop_idx in zip(poly.vertices, poly.loop_indices):
        assert type(v_idx) == int
        assert type(loop_idx) == int
        
        # Get the UV coords
        # U increases on width (left to right), and V increases on height (bottom to top!)
        uv_coords: mathutils.Vector = active_uv.uv[loop_idx].vector
        assert 0.0 <= uv_coords.x <= 1.0
        assert 0.0 <= uv_coords.y <= 1.0
        
        print(f"UV in poly {poly.index} for vertex ID {v_idx} and loop ID {loop_idx}:", uv_coords)


print("All done.")

Discretely commented and heavily typed :-)

Output will be something like:

Info for uvlayer 0 'UVMapUVshpere' on object UVSphere
UV in poly 0 for vertex ID 4 and loop ID 0: <Vector (0.7500, 0.4375)>
UV in poly 0 for vertex ID 3 and loop ID 1: <Vector (0.7500, 0.5000)>
UV in poly 0 for vertex ID 13 and loop ID 2: <Vector (0.7188, 0.5000)>
UV in poly 0 for vertex ID 14 and loop ID 3: <Vector (0.7188, 0.4375)>
UV in poly 1 for vertex ID 474 and loop ID 4: <Vector (0.7500, 0.8750)>
UV in poly 1 for vertex ID 473 and loop ID 5: <Vector (0.7500, 0.9375)>
UV in poly 1 for vertex ID 6 and loop ID 6: <Vector (0.7188, 0.9375)>
UV in poly 1 for vertex ID 7 and loop ID 7: <Vector (0.7188, 0.8750)>
UV in poly 2 for vertex ID 477 and loop ID 8: <Vector (0.7500, 0.3750)>
UV in poly 2 for vertex ID 4 and loop ID 9: <Vector (0.7500, 0.4375)>
[...]
$\endgroup$

You must log in to answer this question.

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