Skip to content

Instantly share code, notes, and snippets.

@Farfarer
Last active May 31, 2016 16:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Farfarer/cae8f6bdf4856ecb0cf85dc484a2dfb3 to your computer and use it in GitHub Desktop.
Save Farfarer/cae8f6bdf4856ecb0cf85dc484a2dfb3 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
# Transfer the selected weight maps from the primary (first selected) mesh to all other active (selected) meshes (map is created if required).
# Transfer happens via vertex index, if the two meshes have different vertex counts nothing will happen.
# If no weight maps are selected, all are transferred.
# Optional target map argument will cause the first selected weight map found on the primary mesh to be transferred to a weight map of the given name on the active mesh (map is created on the active mesh if required).
# NOTE: With the optional map argument given, only one map will be transferred.
import lx
import lxifc
import lxu.command
#_______________________________________________________________________________________________________________________ VISITORS
class ListMaps (lxifc.Visitor):
def __init__ (self, meshmap_from, meshmap_to):
self.meshmap_from = meshmap_from
self.meshmap_to = meshmap_to
self.meshmap_IDs_from = []
self.meshmap_IDs_to = []
def vis_Evaluate (self):
meshmap_name = self.meshmap_from.Name ()
try:
self.meshmap_to.SelectByName (lx.symbol.i_VMAP_WEIGHT, meshmap_name)
meshmap_to_ID = self.meshmap_to.ID ()
except:
meshmap_to_ID = self.meshmap_to.New (lx.symbol.i_VMAP_WEIGHT, meshmap_name)
self.meshmap_IDs_from.append (self.meshmap_from.ID ())
self.meshmap_IDs_to.append (meshmap_to_ID)
class TransferWeightByIndex_Cmd(lxu.command.BasicCommand):
#______________________________________________________________________________________________ SETUP AND INITIALISATION
def __init__(self):
lxu.command.BasicCommand.__init__(self)
self.dyna_Add ('target', lx.symbol.sTYPE_STRING)
self.basic_SetFlags (0, lx.symbol.fCMDARG_OPTIONAL)
def cmd_UserName(self):
return 'Transfer Weights by Index'
def cmd_Desc(self):
return 'Transfer all selected weight maps values from primary mesh to all other selected meshes based on vertex index.'
def cmd_Tooltip(self):
return 'Transfer all selected weight maps values from primary mesh to all other selected meshes based on vertex index.'
def cmd_Help(self):
return 'http://www.farfarer.com/'
def basic_ButtonName(self):
return 'Transfer Weights by Index'
def cmd_Flags(self):
return lx.symbol.fCMD_MODEL | lx.symbol.fCMD_UNDO | lx.symbol.fCMD_SELECT
def basic_Enable(self, msg):
return True
def cmd_Interact(self):
pass
#_______________________________________________________________________________________________ MAIN FUNCTION EXECUTION
def basic_Execute(self, msg, flags):
target_map = None
if self.dyna_IsSet (0):
target_map = self.dyna_String (0)
if len (target_map) == 0:
target_map = None
have_target_map = (target_map is not None)
# try:
# Grab the active and background layers.
layer_svc = lx.service.Layer ()
sel_svc = lx.service.Selection ()
# Get the two layers.
layer_scan = lx.object.LayerScan (layer_svc.ScanAllocate (lx.symbol.f_LAYERSCAN_EDIT))
if not layer_scan.test ():
return
layer_scan_count = layer_scan.Count ()
if layer_scan_count < 2:
return
sel_weightmaps = []
sel_type_vmap = sel_svc.LookupType (lx.symbol.sSELTYP_VERTEXMAP)
vmap_pkt_trans = lx.object.VMapPacketTranslation (sel_svc.Allocate (lx.symbol.sSELTYP_VERTEXMAP))
sel_vmap_count = sel_svc.Count (sel_type_vmap)
if sel_vmap_count > 0:
for vmap_idx in xrange (sel_vmap_count):
pkt = sel_svc.ByIndex (sel_type_vmap, vmap_idx)
vmap_type = vmap_pkt_trans.Type (pkt)
if vmap_type == lx.symbol.i_VMAP_WEIGHT:
sel_weightmaps.append (vmap_pkt_trans.Name (pkt))
maps_selected = (len (sel_weightmaps) > 0)
# Work out which is the primary active layer (destination) and which is the background layer (source).
primary_layer_index = -1
for layer in xrange (layer_scan_count):
if layer_scan.GetState (layer) == (lx.symbol.f_LAYERSCAN_PRIMARY | lx.symbol.f_LAYERSCAN_ACTIVE):
primary_layer_index = layer
# Early out if a primary layer has not been found.
if primary_layer_index == -1:
return
# Grab the mesh and accessors.
mesh_from = lx.object.Mesh (layer_scan.MeshBase (primary_layer_index))
point_from = lx.object.Point (mesh_from.PointAccessor ())
meshmap_from = lx.object.MeshMap (mesh_from.MeshMapAccessor ())
if not mesh_from.test () or not point_from.test () or not meshmap_from.test ():
return
point_count_from = mesh_from.PointCount ()
if point_count_from == 0:
return
for layer in xrange (layer_scan_count):
if layer == primary_layer_index:
continue
# Grab the mesh.
mesh_to = lx.object.Mesh (layer_scan.MeshEdit (layer))
if not mesh_to.test ():
continue
# Early out if either of the layers are empty.
point_count_to = mesh_to.PointCount ()
if point_count_to == 0:
continue
# Early out if the point count differs.
if point_count_to != point_count_from:
continue
# Grab the accessors needed.
point_to = lx.object.Point (mesh_to.PointAccessor ())
if not point_to.test ():
continue
meshmap_to = lx.object.MeshMap (mesh_to.MeshMapAccessor ())
if not meshmap_to.test ():
continue
# Get a list of the weight maps shared by the foreground and the background meshes.
meshmap_IDs_to = []
meshmap_IDs_from = []
if maps_selected:
# Do first selected map to specific map.
for sel_weightmap in sel_weightmaps:
try:
meshmap_from.SelectByName (lx.symbol.i_VMAP_WEIGHT, sel_weightmap)
except:
pass # Background mesh doesn't have this weight map keep trying until we find one.
else:
mapname = target_map if have_target_map else sel_weightmap
try:
meshmap_to.SelectByName (lx.symbol.i_VMAP_WEIGHT, mapname)
meshmap_ID_to = meshmap_to.ID ()
except:
meshmap_ID_to = meshmap_to.New (lx.symbol.i_VMAP_WEIGHT, mapname)
meshmap_IDs_to.append (meshmap_ID_to)
meshmap_IDs_from.append (meshmap_from.ID ())
if have_target_map:
break
elif not have_target_map:
# Do all maps.
visitor = ListMaps (meshmap_from, meshmap_to)
meshmap_from.FilterByType (lx.symbol.i_VMAP_WEIGHT)
meshmap_from.Enumerate (lx.symbol.iMARK_ANY, visitor, 0)
meshmap_IDs_from = visitor.meshmap_IDs_from
meshmap_IDs_to = visitor.meshmap_IDs_to
meshmap_from.FilterByType (0)
# Go through each point and copy the values of each weight map from the background mesh to the foreground mesh.
for p in xrange (point_count_from):
point_from.SelectByIndex (p)
point_to.SelectByIndex (p)
for from_ID, to_ID in zip(meshmap_IDs_from, meshmap_IDs_to):
weight = lx.object.storage ('f', 1)
try:
res = point_from.MapEvaluate (from_ID, weight)
except:
point_to.ClearMapValue (to_ID)
else:
if res:
point_to.SetMapValue (to_ID, weight)
else:
point_to.ClearMapValue (to_ID)
# Apply changes.
layer_scan.SetMeshChange (layer, lx.symbol.f_MESHEDIT_MAP_OTHER)
layer_scan.Apply ()
#________________________________________________________________________________________ BLESS FUNCTION AS MODO COMMAND
lx.bless (TransferWeightByIndex_Cmd, 'ffr.transferWeightByIndex')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment