# Demon Project - Enveloping Nulls Script # By Peter Agg # peteragg@googlemail.com / peteragg.co.uk #(kudos also goes to Nicole Bouchard and Ian Thompson for their help) """ The idea of this tool is to create a series of nulls which are going to be used to envelope geometry to. This is particularly useful if your're exporting to another program which doesn't support XSI rigs (like a game engine). When you run this script you will be promted to select your model. Once it's done you should have a null made for nd constrained to every required object, organised into a hierarchy and put into a group. Note that, at the moment, the hierarchy sorting won't work for Bone structures built outside of the COG/Hips (like IK feet) so you'll have to sort these manually afterwards. I've also commented out all the logmessage checks, but feels free to add them back - they've all been commented with the code: #"# This script presumes a few things: 1) That you've followed a certain naming convention (i.e controls end in "_controls", effectors with "_eff" etc.) 2) To create an IK Bone chain you use a Position (or Pose) constraint to attach an effector to a root (if you use another method then comment out the "findikbones()" function call on line 103, you can use my Compensate Null Script to pick which ones to change)) 3) You have a group in your rig called "Bones" which holds all the objects which need an envelope null being created 4) Your rig doesn't contain a null called "env" as we'll be creating one to put all the created nulls under 5) You don't have a group called "env_nulls" already, again we'll be making one in the script. """ import win32com.client from win32com.client import constants as c def Pickmodel(): global Picked # Pick the model to work with Picked = Application.PickElement(c.siModelFilter, "Pick model", "Pick model" ) # Right-Click bomb out if Picked[0] == 0: Application.logmessage("ERROR: Right button clicked, returning") return else: #"# Application.logmessage(str(Picked(2)) +" was chosen") #"# Application.logmessage(str(len(str(Picked(2))))) createENVnulls() def createENVnulls(): # select all the bones (via pre-made model group) # make sure it exists first... try: Application.SelectObj( str(Picked(2)) + ".Bones", "", "") except: Application.logmessage("ERROR: No Bones group in selected model") return selection = Application.SelectMembers( str(Picked(2)) + ".Bones", "", "") #"# Application.logmessage("selection is "+ str(len(selection)) + " long") # create a null in the model to nest the nulls in ( again, if it doesn't already exist) try: Application.SelectMembers(str(Picked(2)) + ".env", "", "") except: nullparent = Application.GetPrim("Null", "env", Picked(2)) # create a group for all the nulls we're about to create try: Application.SelectObj( str(Picked(2)) + ".env_nulls", "", "") except: Application.DeselectAll() ENVgroup = Application.CreateGroup("env_nulls", "", str(Picked(2))) Application.CopyPaste(str(ENVgroup), "", Picked(2), 1) for x in selection: # the returned name will include the model's name. For the sake of neatness we'll take it off: oldname = str(x) #"# Application.logmessage("old name = " + oldname) # get the string length of the Model's name, add one to it to include the "." ModNameLen = (len(str(Picked(2)))) + 1 # reduce the string by the model name's length newname = oldname[ModNameLen:] ####Application.logmessage("new name = " + str(newname)) # create a null for each selected bone MakeENV = Application.GetPrim("Null", str(newname) + "_env", str(nullparent)) #"# Application.logmessage(str(MakeENV) +" was created") # pose constrain null to appropriate bone Application.ApplyCns("Pose", MakeENV, x, "") #"# Application.logmessage(str(MakeENV) +" was constrained to " + str(newname)) # move to envelope group Application.CopyPaste(str(MakeENV), "", str(ENVgroup), 1) # find any IK Bones findikbones() # sort the created nulls sortnulls() return Application.logmessage("ERROR: env_null group already exists in model") return Application.logmessage("ERROR: env null already exists in model") def findikbones(): selection = Picked(2).FindChildren("") #Application.logmessage(selection.count) for i in range (0, selection.count-1): #check to see whether the object has a contraint const = selection(i).Kinematics.Constraints if const.count > 0: #"# Application.logmessage(selection(i)) #"# Application.logmessage(const.count) # get the object which the object is constrained to selected = selection(i) constraints = selected.Kinematics.Constraints for k in constraints: for l in k.constraining: constraining = l #"# Application.logmessage(str(selection(i)) + " is constrained by a " + k.Type + " to: " + str(constraining)) # see whether the constraining object is also an effector if str(constraining.Type) == "eff": # make sure that the constraint is a Pose or Pos if str(k.Type) == "posecns" or str(k.Type) == "poscns": #"# Application.logmessage("selection is constraining an effector") # Get the parent of the constraining object PickedParent = constraining.Parent #"# Application.logmessage ("Parent of contstraining: " + str(PickedParent)) # Get it's children Children = PickedParent.FindChildren("") #"# Application.logmessage (len(Children)) for j in range (0, len(Children)-1): #"# Application.logmessage("IK Bone: "+ str(Children(j))) """ # Uncomment block for TEST - IK nulls should turn yellow Application.logmessage(str(Children(j)) + "_env.display") Application.MakeLocal(str(Children(j)) + "_env.display", "siNodePropagation") Application.SetValue(str(Children(j)) + "_env.display.wirecolorr", 0.878, "") Application.SetValue(str(Children(j)) + "_env.display.wirecolorg", 0.878, "") Application.SetValue(str(Children(j)) + "_env.display.wirecolorb", 0, "") """ # compensate the constraint by the length of the bone bonelength = Application.GetValue(str(Children(j)) + ".bone.length") #"# Application.logmessage(bonelength) Application.SetValue(str(Children(j)) + "_env.kine.posecns.posx", bonelength , "") else: Application.logmessage("Not a pose constraint") else: Application.logmessage("selection isn't constraining an effector") else: Application.logmessage("no constraints") def sortnulls(): # Select all nulls in env_nulls group selection = Application.SelectMembers( str(Picked(2)) + ".env_nulls", "", "") for i in selection: #"# Application.logmessage(i) selected = str(i) #Find the Reference Bone by taking off the "_env" RefBone = Application.GetValue(str(selected[0:-4])) # Find the Reference Bone's Parent RefBoneParent = RefBone.Parent #"# Application.logmessage("RefBoneParent = " + str(RefBoneParent)) if str(RefBoneParent.Type) == "bone": # If the parent is a Bone, parent them #"# Application.logmessage("Parented to " + str(RefBoneParent) + "_env") Application.ParentObj(str(RefBoneParent) + "_env", selected) elif str(RefBoneParent.Type) == "root": # or, if it's a root then we need to find the next bone up the chain NewParent = RefBoneParent.Parent NewParentSTR = str(NewParent) # But first check that it isn't a control object (like the hips) if str(NewParentSTR[-7:]) == "control": # Make sure that the control object has an _env null for g in selection: if str(g) == NewParentSTR + "_env": #"# Application.logmessage(str(selected) + " Parented to " + str(NewParent)) Application.ParentObj(str(NewParent) + "_env", selected) else: # Otherwise cycle up the chain until we find the next root up while str(NewParent.Type) != "root": NewParent = NewParent.Parent Application.logmessage("Looking at: " + str(NewParent)) # Stop the loop at the Model (for things like the Hips of IK feet) if str(NewParent) == str(Picked(2)): #"# Application.logmessage(str(selected) + " won't be parented") break else: # Once we've got to the next root, we need to go back down the chain to find the last bone children = NewParent.FindChildren("", c.siChainBonePrimType, "", False) for h in children: # Application.logmessage("HELLO " + str(h)) # If the next bone doesn't have a child, then we can parent it to that if str(h.FindChild("", c.siChainBonePrimType, "", False)) == "None": #"# Application.logmessage("HELLO " + str(h.FindChild("", c.siChainBonePrimType, "", False))) #"# Application.logmessage(str(selected) + " Parented to " + str(h)) Application.ParentObj(str(h) + "_env", selected) # But if it does have a child, we have to go down the chain until we find one that doesn't else: currentchild = h childcheck = h.FindChild("", c.siChainBonePrimType, "", False) while str(childcheck) != "None": currentchild = currentchild.FindChild("", c.siChainBonePrimType, "", False) childcheck = currentchild.FindChild("", c.siChainBonePrimType, "", False) else: #"# Application.logmessage(str(selected) + " Parented to " + str(currentchild)) Application.ParentObj(str(currentchild) + "_env", selected) break Pickmodel()