Table of Contents

House of Cards Blender Project

Wanting to make a huge virtual house of cards and placing a large picture, tiling across certain panels of the cards. Need to UV map to portion of a big graphic with Python scripting.

Initial proof of concept jittered. Fixed by changing Scene→Rigid Body World → Steps Per Second from 60 to 120.

My example c:\Projects\HouseOfCards\panelTest.blend has one object “Panel” which has two material slots,

In Python console, to look at the “Panel” dominoe:

dir (bpy.data.objects["Panel"]);

Returns lots of methods, values.

ob = bpy.data.objects["Panel"];
print (ob.active_material.name);
// -> Pink
>> type(ob.material_slots);
<class 'bpy_prop_collection'>
 
>>> len(ob.material_slots);
2
 
>>> list(ob.material_slots);
[bpy.data.objects['Panel'].material_slots[0], 
  bpy.data.objects['Panel'].material_slots[1]]

Show name of material slot (there are two in this example)

>> ob.material_slots[0].name
'Card Face'

Show vertices

ob = bpy.data.objects["Panel"];
mesh = ob.data;
for vertex in mesh.vertices:
   print(vertex.co)

Following need to be run in Object mode

Printing UVs for Object

UVs are stored in a UV layer, but still need to know which uv_layer goes with which face:

ob = bpy.data.objects["Panel"];
for uv_layer in ob.data.uv_layers:
    print("uv_layer: %s" % uv_layer.name)
 
for loop in ob.data.loops :
    uv_coords = ob.data.uv_layers[0].data[loop.index].uv
    print("Loop %d: %s" % (loop.index, uv_coords))

Get UVs per Face, Example from web

https://blenderartists.org/forum/showthread.php?254004-Accessing-UV-data-in-Python-script

import bpy
ob = bpy.data.objects["Panel"];
me = ob.data;
 
for f in me.polygons:
    print("Polygon", f.index, "from loop index", f.loop_start, "and length", f.loop_total)
    for i in f.loop_indices: # <-- python Range object with the proper indices already set
        l = me.loops[i] # The loop entry this polygon point refers to
        v = me.vertices[l.vertex_index] # The vertex data that loop entry refers to
        print("\tLoop index", l.index, "points to vertex index", l.vertex_index, \
            "at position", v.co)
        for j,ul in enumerate(me.uv_layers):
            print("\t\tUV Map", j, "has coordinates", ul.data[l.index].uv, \
                "for this loop index")

Noticing that the polygon where the vertex index set (2, 3, 6, 7, in my case) equals the set in the Vertex Group I defined, has the proper UV set.

Their explanation:

The me.loops object is really a lookup list, and each entry is NOT a loop in and of itself. The “loops” are really polygons and are stored in the me.polygons structure. Using me.polygons, you can slice the me.loops list into chunks.

Running this on the default cube shows that me.polygons has six entries (the six faces of the cube). Each polygon refers to four loop indexes, making the me.loops list 24 entries long.

Every UV layer in me.uv_layers has a “data” attribute that is a list that is the same length as the me.loops list. Every me.loops entry relates to the same index entry in the me.uv_layers[n].data list.

Printing Vertices Per Mesh

Vertices

ob = bpy.data.objects["Panel"];
mesh = ob.data;
for vertex in mesh.vertices:
   print(vertex.co)

Assigned vertices of card front and back to Vertex Groups:

Card FrontCard Rank/Suit
Card BackCard Back - Photo

Let's find the vertex groups, to print out their UVs:

ob = bpy.data.objects["Panel"];
vgCardBack = ob.vertex_groups['Card Back'];
print('Card Back');
for vertex in vgCardBack.vertices:
   print(vertex.co)
vgCardFront = ob.vertex_groups['Card Front'];
print('Card Front');
for vertex in vgCardFront.vertices:
   print(vertex.co)

Find vertices in Vertex Group

Original, from http://blenderartists.org/forum/showthread.php?252350-Selecting-vertices-of-a-vertex-group

import bpy
 
# find the index of the target group
for obj in bpy.data.objects:
  if type(obj.data) != bpy.types.Mesh:
    continue
 
  # This is an Object with a Mesh, see if it has the supported group name
  groupIndex = -1
  for i in range(0, len(obj.vertex_groups)):
    group = obj.vertex_groups[i]
    if group.name == "Test":
      groupIndex = i
 
  print("Checking %s for assigned vertices." % (obj.name))
 
  # Now access the vertices that are assigned to this group
  mesh = obj.data
  for v in mesh.vertices:
 
    for vertGroup in v.groups:
      if vertGroup.group == groupIndex:
 
        print("Vertex %d is part of group."%(v.index))

Non-BMesh, Working script

Modified to work with “Panel” example blend file:

import bpy
 
# find the index of the target group
ob = bpy.data.objects["Panel"];
 
# Print all vertices
print("\nPrinting all vertices.")
mesh = ob.data;
for vertex in mesh.vertices:
   print(vertex.co)
 
 
# This is an Object with a Mesh, see if it has the supported group name
groupIndex = -1
groupName = "Card Back"
 
for i in range(0, len(ob.vertex_groups)):
   group = ob.vertex_groups[i]
   if group.name == groupName:
      groupIndex = i
 
print("Checking %s for assigned vertices, groupIndex is %f" % (ob.name, groupIndex))
 
# Now access the vertices that are assigned to this group
mesh = ob.data
for v in mesh.vertices:
 
   for vertGroup in v.groups:
      if vertGroup.group == groupIndex:
         print("Vertex %d is part of group %s."%(v.index, groupName))
 
# Find the UVs to go with these Vertices

Using BMesh

https://www.blender.org/api/blender_python_api_2_77_1/bmesh.html#module-bmesh

import bpy
import bmesh
 
ob = bpy.data.objects["Panel"];
 
# Get the active mesh
me = ob.data
 
# Get a BMesh representation
bm = bmesh.new()   # create an empty BMesh
bm.from_mesh(me)   # fill it in from a Mesh
 
# Modify the BMesh, can do anything here...
for v in bm.verts:
    v.co.x -= 1.0
 
# Finish up, write the bmesh back to the mesh
bm.to_mesh(me)
bm.free()  # free and prevent further access

Shows Vertexes and UVs

Per face.

import bpy
import bmesh
 
ob = bpy.data.objects["Panel"];
 
# Get the active mesh
me = ob.data
 
 
# Get a BMesh representation
bm = bmesh.new()   # create an empty BMesh
bm.from_mesh(me)   # fill it in from a Mesh
uv_lay = bm.loops.layers.uv.active
 
for face in bm.faces:
    print("face index %d" % face.index);
    for loop in face.loops:
        uv = loop[uv_lay].uv
        print("Loop UV: %f, %f" % uv[:])
        vert = loop.vert
        print("Loop Vertex: (%f,%f,%f)" % vert.co[:])
 

Let's try finding the face defined by the verts in the Vertex Group “Card Back”.

import bpy
import bmesh
 
ob = bpy.data.objects["Panel"];
me = ob.data
 
# Get a BMesh representation
bm = bmesh.new()   # create an empty BMesh
bm.from_mesh(me)   # fill it in from a Mesh
uv_lay = bm.loops.layers.uv.active
 
# Find the vertex group vertices
 
groupIndex = -1
 
# This is an Object with a Mesh, see if it has the supported group name
for i in range(0, len(ob.vertex_groups)):
   group = ob.vertex_groups[i]
   if group.name == "Card Back":
      groupIndex = i
 
 
# Now access the vertices that are assigned to this group
 
bmVertGroupMembers = []
 
for v in me.vertices:
   for vertGroup in v.groups:
      if vertGroup.group == groupIndex:
         print("Vertex %d is part of group."%(v.index))
         bmVertGroupMembers.new(v)
 
# Following doesn't work 
groupFace = bm.faces.get(bmVertGroupMembers);
 
print ("groupFace len: %d" % len(groupFace))

Going back to non-BMESH method. In BMesh, it is difficult to assemble the correct types.

Get Face from Mesh defined by Vertex Group

import bpy
ob = bpy.data.objects["Panel"];
 
 
def getFaceFromObjectContainingVertexGroup(ob, vertexGroupName):
 
  # First, get list of Vertexes in Vertex Group
 
  groupIndex = -1
 
  # This is an Object with a Mesh, see if it has the supported group name
  for i in range(0, len(ob.vertex_groups)):
    group = ob.vertex_groups[i]
    if group.name == vertexGroupName:
      groupIndex = i
 
  # if we didn't find it, exit
  if (groupIndex < 0):
    return null
 
  # Now access the vertices that are assigned to this group
 
  bmVertGroupMembers = []
 
  for v in ob.data.vertices:
    for vertGroup in v.groups:
      if vertGroup.group == groupIndex:
         print("Vertex %d is part of group."%(v.index))
         bmVertGroupMembers.append(v)
 
  # at this point, we have a list of vertices in bmVertGroupMembers
  # belonging to group vertexGroupName, with index groupIndex
 
for f in me.polygons:
    print("Polygon", f.index, "from loop index", f.loop_start, "and length", f.loop_total)
    for i in f.loop_indices: # <-- python Range object with the proper indices already set
        l = me.loops[i] # The loop entry this polygon point refers to
        v = me.vertices[l.vertex_index] # The vertex data that loop entry refers to
        print("\tLoop index", l.index, "points to vertex index", l.vertex_index, \
            "at position", v.co)
        for j,ul in enumerate(me.uv_layers):
            print("\t\tUV Map", j, "has coordinates", ul.data[l.index].uv, \
                "for this loop index")