Jump to: navigation, search

Difference between revisions of "Pyhton Scripts"

(GlueVertices)
(BatchBonesModification)
 
(2 intermediate revisions by the same user not shown)
Line 99: Line 99:
 
  # name of the armature
 
  # name of the armature
 
  ARMATURE_NAME = 'armature_skeleton'
 
  ARMATURE_NAME = 'armature_skeleton'
  NAME_FILTER = 'spine'
+
  NAME_FILTER = [ 'arm', '_tail' ] # AND clause
 
   
 
   
 
  def doContinue( name ):
 
  def doContinue( name ):
 
     global NAME_FILTER
 
     global NAME_FILTER
     if NAME_FILTER == '':
+
     if len(NAME_FILTER) == 0:
 
         return True
 
         return True
     if name.find( NAME_FILTER ) != -1:
+
     allchecked = True
        return True
+
    for n in NAME_FILTER:
     return False
+
        if name.find( n ) == -1:
 +
            allchecked = False
 +
            break
 +
     return allchecked
 
   
 
   
 
  scn = bpy.context.scene
 
  scn = bpy.context.scene
Line 138: Line 141:
  
 
== GlueVertices ==
 
== 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
 
  # based on https://www.blender.org/api/blender_python_api_current/bpy.types.MeshVertex.html?highlight=meshvertex
Line 146: Line 153:
 
  from mathutils import Vector
 
  from mathutils import Vector
 
   
 
   
  # BEFORE launching script, SELECT the vertices to test
+
  # BEFORE launching script, SELECT the vertices form the region to test ( EDIT MODE, point select, rectangular selection for instance )
 
   
 
   
 
  # config
 
  # config

Latest revision as of 20:10, 9 April 2016

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