Jump to: navigation, search

Pyhton Scripts

Python scripts vault used during the project.

BoneMatrixCopy

import bpy, math
from mathutils import Vector, Matrix
# configuration ############
ARMATURE_NAME = 'makehuman'
BONE_NAME = 'RightArm'
# getting the right bone, no safety net...
scn = bpy.context.scene
armature = scn.objects[ ARMATURE_NAME ].data
bone = armature.bones[ BONE_NAME ]
# orientation of the bone is represented as a 4x4 matrix
# see https://www.blender.org/api/blender_python_api_2_59_0/bpy.types.Bone.html#bpy.types.Bone.matrix_local
bone_mat = bone.matrix_local
# getting the active object
target = scn.objects.active
# copy of the matrix ############
target.matrix_local = bone_mat
target.rotation_mode = 'QUATERNION'
target.rotation_mode = 'XYZ'
print( 'done, matrix of bone', armature.name, ':', bone.name, 'copied on',  target.name )

script on github

BonesAndVertexgroupsBulkRenaming

import bpy

# right and left markers
NEEDLE = "R_"
REPLACE = "L_"

# name of the armature and the related mesh
ARMATURE_NAME = 'armature_skeleton'
MESH_NAME = 'skeleton'

scn = bpy.context.scene
armature = scn.objects[ ARMATURE_NAME ].data
mesh = scn.objects[ MESH_NAME ]

# renaming all bones
print( "armature:", ARMATURE_NAME, armature )
for b in armature.bones:
   b.name = b.name.replace( NEEDLE, REPLACE )
   print( b.name )
   
# renaming all vertex groups
print( "mesh:", MESH_NAME, mesh )
for vg in mesh.vertex_groups:
   vg.name = vg.name.replace( NEEDLE, REPLACE )
   print( vg.name )

script on github

BonesVertexgroupsSync

import bpy

# name of the armature and the related mesh
ARMATURE_NAME = 'armature_skeleton'
MESH_NAME = 'skeleton'
REMOVE_VERTEXGROUPS = True

scn = bpy.context.scene
armature = scn.objects[ ARMATURE_NAME ].data
mesh = scn.objects[ MESH_NAME ]

print( mesh.vertex_groups )

# creation of missing vertex groups
for b in armature.bones:
   found = False
   for vg in mesh.vertex_groups:
       if vg.name == b.name:
           found = True
   if found == False:
       mesh.vertex_groups.new( b.name )
       print( b.name, "vertex group created" )

# deletion of vertex groups
if REMOVE_VERTEXGROUPS == True:
   for vg in mesh.vertex_groups:
       found = False
       for b in armature.bones:
           if vg.name == b.name:
               found = True
       if found == False:
           print( vg.name, "vertex group removed" )
           mesh.vertex_groups.remove( vg )

script on github

BatchBonesModification

import bpy

# name of the armature
ARMATURE_NAME = 'armature_skeleton'
NAME_FILTER = [ 'arm', '_tail' ] # AND clause

def doContinue( name ):
   global NAME_FILTER
   if len(NAME_FILTER) == 0:
       return True
   allchecked = True
   for n in NAME_FILTER:
       if name.find( n ) == -1:
           allchecked = False
           break
   return allchecked

scn = bpy.context.scene
armature = scn.objects[ ARMATURE_NAME ]

# modification on bones
# modifiable params are listed in doc
# https://www.blender.org/api/blender_python_api_2_77_release/bpy.types.Bone.html#bpy.types.Bone
print( '**** bones:', len(armature.pose.bones) )
for b in armature.data.bones:
   if not doContinue( b.name ):
       continue
   print( b.name )
   b.use_inherit_rotation = True
   b.use_inherit_scale = False

# modification on pose bones
# modifiable params are listed in doc 
# https://www.blender.org/api/blender_python_api_2_77_release/bpy.types.PoseBone.html
print( '**** pose bones:', len(armature.pose.bones) )
for pb in armature.pose.bones:
   if not doContinue( pb.name ):
       continue
   print( pb.name )
   pb.lock_location = (False,False,False)
   pb.lock_rotation = (False,False,False)
   pb.lock_scale = (False,False,False)

script on github

GlueVertices

It seems simple when started, but if the script is applied on a mesh having 10K vertices, comparing all vertices on all vertices becomes quite heavy. The optimisation is to select a bunch of vertices in EDIT mode. This indicates to the script where to search and compare positions. The second trick is that you can't hold references to vertices when you swicth modes! This is a huge drawback when you need to do things like this...

Anyway, the first pass of the script is very slow. I suggest to open a console and follow the execution.

# based on https://www.blender.org/api/blender_python_api_current/bpy.types.MeshVertex.html?highlight=meshvertex
# and http://blender.stackexchange.com/questions/7144/how-to-get-the-distance-between-two-objects-in-the-game-engine
import bpy
from bpy import context
from math import sqrt
from mathutils import Vector

# BEFORE launching script, SELECT the vertices form the region to test ( EDIT MODE, point select, rectangular selection for instance )

# config
TOLERANCE = 0.00001

# globals
MERGED_COUNT = 0
LAST_INDEX = 0
VSELECTED = []
VMERGES = {}
VMERGEPOS = []

def getDistance( v1, v2 ):
   distance = sqrt( (v1.co[0] - v2.co[0])**2 + (v1.co[1] - v2.co[1])**2 + (v1.co[2] - v2.co[2])**2)
   #print(distance)
   return distance

def getDistance2Vector( vertex, vector ):
   distance = sqrt( (vertex.co[0] - vector.x)**2 + (vertex.co[1] - vector.y)**2 + (vertex.co[2] - vector.z)**2)
   #print(distance)
   return distance

obj = context.active_object
print( "scanning", obj.data.vertices, "vertices" )

bpy.ops.object.mode_set(mode="OBJECT")

vall = obj.data.vertices
for v in vall:
   if v.select:
       VSELECTED.append( v )

print( "***********", len( VSELECTED ), "vertices to verify" )

# making merge groups
vselnum = len( VSELECTED )
i = 0
for v in VSELECTED:
   #print( v.co, i )
   for j in range( i + 1, vselnum ):
       if j >= vselnum:
           break
       vo = VSELECTED[ j ]
       d = getDistance( v, vo )
       if d < TOLERANCE:
           # retro seeking: v may have to be merged with a previous one!
           index = i
           for m in VMERGES:
               mlist = VMERGES[ m ]
               mcontinue = True
               for mc in mlist:
                   if mc == v:
                       index = m
                       mcontinue = False
                       #print( "retro-seek is successful", i, m )
                       break
               if not mcontinue:
                   break
           
           if i not in VMERGES:
               VMERGES[ index ] = [ v ]
           VMERGES[ index ].append( vo )
           
   i += 1

# rendering position of merge
for k in VMERGES:
   mlist = VMERGES[ k ]
   pos = Vector( (0,0,0) )
   for mc in mlist:
       pos.x += mc.co[0]
       pos.y += mc.co[1]
       pos.z += mc.co[2]
   pos.x /= len( mlist )
   pos.y /= len( mlist )
   pos.z /= len( mlist )
   #print( len(VMERGEPOS), ">>", len(mlist), ">>", pos )
   VMERGEPOS.append( pos )

print( "VMERGEPOS:",  len( VMERGEPOS ) )

bpy.ops.object.mode_set(mode="EDIT")
bpy.ops.mesh.select_all(action="DESELECT")
bpy.context.tool_settings.mesh_select_mode = (True , False , False)
bpy.ops.object.mode_set(mode="OBJECT")

mcount = 0
for p in VMERGEPOS:
   vall = obj.data.vertices
   velected = 0
   for v in vall:
       d = getDistance2Vector( v, p )
       if d < TOLERANCE:
           v.select = True
           velected += 1
   if velected != 0:
       bpy.ops.object.mode_set(mode="EDIT")
       bpy.ops.mesh.merge(type='CENTER')
       bpy.ops.mesh.select_all(action="DESELECT")
       bpy.ops.object.mode_set(mode="OBJECT")
       print( "merge done at", p.x, p.y, p.z, "vertex:", velected, "count:", mcount, "/", len(VMERGEPOS) )
   MERGED_COUNT += velected
   mcount += 1

print( "total:",  MERGED_COUNT, "vertices have been merged" )

script on github