skinning and vertex filter in Blender

Last week, surfing to blenderartists.org forums, i have found some post speaking about influences of bones within Blender, and the way to limit them to a specific maximum number. This need is mainly due to the limits that some engines has: in this case, bone influences per vertex.
Some time ago i had the same problem exporting some characters to an external engine, and i wrote this little script to solve the problem.

The behavoir of the script is very simple. You can define the maximum number of weights modifying the global variable WEIGHT_MAX. You have to select the Mesh to be processed and execute the script. After the process, you are going to get the same number of influences in your vertex, but the influences with less weight would be set to 0,0. It doesn’t remove them. Then you’d have to apply the ‘Clean’ and ‘Normalize All’ inside Blender.

import bpy

WEIGHT_MAX = 4

def select_vertices(context, ob, max = 4):
  '''select vertices with more than max bone sinfluences'''
  mode_old = context.mode
  if context.mode != 'OBJECT':
    bpy.ops.object.mode_set(mode = 'OBJECT')
      
  for v in ob.data.vertices:
    if len(v.groups) > max:
      v.select = True
    else:
      v.select = False
    
  if mode_old == 'EDIT_MESH': mode_old = 'EDIT'
  if context.mode != mode_old:
    bpy.ops.object.mode_set(mode = mode_old)
        
def get_min_influence(v):
  '''get the min influence of a vertex'''
  min = 2e10
  min_group = -1
  for i in range(len(v.groups)):
    if ((v.groups[i].weight > 0) and (v.groups[i].weight < min)):
      min = v.groups[i].weight
      min_group = v.groups[i].group
    
  return min_group
    

def get_number_of_influences(v):
  '''get the number of influences non zero'''
  sum = 0
  for inf in v.groups:
    if inf.weight > 0.0: sum = sum + 1
    
  return (sum)
        
def remove_vertices_weights(context, ob, max = 4):
  '''if a vertex has more than max influences, remove the smallest ones'''
  mode_old = context.mode
    
  mode_old = context.mode
  if context.mode != 'OBJECT':
    bpy.ops.object.mode_set(mode = 'OBJECT')

  for v in ob.data.vertices:
    if (get_number_of_influences(v) > max):
      print ("ERASE - %i - %i" % (v.index, get_number_of_influences(v)))
      for i in range(len(v.groups) - max):
        min_group = get_min_influence(v)
        ob.vertex_groups[min_group].add([v.index], 0.0, 'REPLACE')
        
  if mode_old == 'EDIT_MESH': mode_old = 'EDIT'
  if context.mode != mode_old:
    bpy.ops.object.mode_set(mode = mode_old)

        
context = bpy.context
ob = context.object
select_vertices(context, ob, WEIGHT_MAX)
remove_vertices_weights(context, ob)

Esta última semana, he encontrado por los foros de blenderartists.org, un par de post hablando de las influencias de los huesos en Blender, y de como limitarlas. Esta necesidad se debe principalmente a que algunos motores tienen ciertos límites: en este caso, límite de influencias por vértice. Hace algún tiempo tuve un problema parecido al exportar ciertos personajes, y escribí este pequeño script para ayudarme en mi trabajo.

El comportamiento del script es muy sencillo. Puedes definir el número máximo de influences modificando la variable global WEIGHT_MAX al comienzo del script. Debes seleccionar la malla a procesar, y ejecutar el script. Tras el proceso, el número de influencias es el mismo, pero las influencias con menos peso son puestas a 0,0, por lo que solamente debes aplicar el ‘Clean’ y ‘Normalize All’ en Blender.

Leave a Reply

Your email address will not be published. Required fields are marked *