############################################################################### ### ### ### jc ICE muscle system ### ### ### ############################################################################### ### ### ### created by juan correa ### ### www.sod4602.com ### ### sod4602@gmail.com ### ### version 1.0.0 ### ### ### ### This scripts creates a muscle system using ICE. ### ### It can be used as a muscle, spine or roll division. ### ### This script need the ICE_Kinematics work group to be connected. ### ### ### ### Run the script and select a base and tip object for your muscle. ### ### Input a muscle name that will be assigned to all components. ### ### Input number of divisions you want to have in your muscle. ### ### ### ### Thanks to Dipti Gandhi for object existance testing. ### ### Thanks to Patric Semple for suggestions. ### ### ### ############################################################################### ###################### globals ###################### #import libraries and set global varibles from win32com.client import constants as c import math xsi = Application oRoot = xsi.ActiveSceneRoot ###################### prick ###################### #pick setion for base and tip objects stored as oBone and oBone1 oPick = xsi.PickElement( c.siGenericObjectFilter, 'Pick a base bone', 'Pick a base bone') xsi.SelectObj(oPick(2)) oBone = xsi.Selection[0] oPick = xsi.PickElement( c.siGenericObjectFilter, 'Pick a tip bone', 'Pick a tip bone') xsi.Selection.Add( oPick(2), 0) oBone1 = xsi.Selection[1] xsi.DeselectAll() print ("chain selected, creating muscle...") ###################### model ###################### #find and define model where the muscle lives #if model is scene root skip #this so the muscle can be created in the scene root, or other model if necessary oModel = oBone.Model if oModel.name == "Scene_Root": oModelName = "" else: oModelName = oModel.name + "." ###################### oName ###################### #input a name for the muscle and add the model name oName oNameIn = xsi.XSIInputbox("enter a prefix for your muscle","muscle name") oName = oModelName + oNameIn ###################### distance ###################### #get and store the distance between oBone and oBone1 #function will calculate sqrt(pow(ax-bx,2)+pow(ay-by,2)+pow(ax-bx,2)) def bDistance( objA, objB ): Ax, Ay, Az = objA.Kinematics.Global.Transform.GetTranslationValues2() Bx, By, Bz = objB.Kinematics.Global.Transform.GetTranslationValues2() return math.sqrt( math.pow(Ax-Bx,2) + math.pow(Ay-By,2) + math.pow(Az-Bz,2) ) #function is called from oBone to oBone1 and printed fromObj, toObj = oBone , oBone1 dist = str( bDistance(fromObj, toObj) ) ###################### groups ###################### #groups are created for division objects and hidden objects #if the model is no the scene root the model is copyed to the proper model #!!!Application.CreateGroup("myGrp", "", oModel) will not create a model under oModel!!! oDivGrp = xsi.CreateGroup(oNameIn + "_div_grp", "", oModel) oDivGrpName = oDivGrp.fullName xsi.SetValue(oDivGrpName + ".selectability", 0, "") if oModel.name == "Sene_Root": print "model in place" else: xsi.CopyPaste(oDivGrpName, "", oModel, 1) xsi.DeselectAll() #same procedure for hidden object's group oHidGrp = xsi.CreateGroup(oNameIn + "_hidden_grp", "", oModel) oHidGrpName = oHidGrp.fullname xsi.ToggleVisibility(oHidGrpName, "", "") if oModel.name == "Sene_Root": print "model in place" else: xsi.CopyPaste(oHidGrpName, "", oModel, 1) xsi.DeselectAll() ###################### objects ###################### #my objects are created, transformed and display is set #oMusclePar is the main cointaner, lives under oBone1 oMusclePar = oBone.addnull(oNameIn + "_MusclePar") oMuscleParName = oMusclePar.fullName xsi.MatchTransform(oMusclePar, oBone, "siSRT", "") xsi.SIAddToGroup(oHidGrp, oMusclePar, "") #oICEcont is the ICE cointaner, lives under oMusclePar oICEcont = oMusclePar.addnull(oNameIn + "_ICEcont") oICEcontName = oICEcont.fullName #next line is commented out as it might be helpfull to relocate the ICEcont in some cases #xsi.MatchTransform(oICEcont, oMusclePar, "siSRT", "") xsi.SIAddToGroup(oHidGrp, oICEcont, "") #oBase is the base of the muscle, lives under oMusclePar #it is matched to oBone and temporarly aims at oBone1 oBase = oMusclePar.addnull(oNameIn + "_base") oBaseName = oBase.fullName xsi.SetValue(oBase.fullName + ".null.primary_icon", 2, "") xsi.SetValue(oBase.fullName + ".null.size", 1, "") xsi.MatchTransform(oBase, oBone, "siSRT", "") xsi.ApplyCns("Direction", oBase, oBone1, "") xsi.SetValue(oBase.fullName + ".kine.dircns.dirx", 0, "") xsi.SetValue(oBase.fullName + ".kine.dircns.diry", 1, "") xsi.SetValue(oBase.fullName + ".kine.dircns.dirz", 0, "") #oTip is the Tip of the muscle, lives under oBone1 #it is translation matched to oBone1 and it's rotation to oBase oTip = oBone1.addnull(oNameIn + "_tip") oTipName = oTip.fullName xsi.SetValue(oTip.fullName + ".null.primary_icon", 2, "") xsi.SetValue(oTip.fullName + ".null.size", 1, "") xsi.MatchTransform(oTip, oBone1, "siTrn", "") xsi.MatchTransform(oTip, oBase, "siRot", "") #oMidPar is the parent to the Mid of the muscle, it is 2 point constrained to oBase and oTip oMidPar = oMusclePar.addnull(oNameIn + "_mid_par") xsi.ApplyCns("TwoPoints", oMidPar, oBase.fullName + "," + oTip.fullName, "") xsi.SIAddToGroup(oHidGrp, oMidPar, "") #oMid is the Mid of the muscle, matched and parented to oMidPar oMid = oMidPar.addnull(oNameIn + "_mid") oMidName = oMid.fullName xsi.SetValue(oMid.fullName + ".null.primary_icon", 2, "") xsi.SetValue(oMid.fullName + ".null.size", 1, "") xsi.MatchTransform(oMid, oMidPar, "siSRT", "") ###################### divICE ###################### #createDivICEtree creates a the ICE tree for each of the division #id (number of the division) and trans (name of where the transforms live) are input def createDivICEtree(id,trans): xsi.ApplyOp("ICETree", "", "siNode", "", "", 0) #set global transforms xsi.AddICECompoundNode("Set Data", ".bone.ICETree") xsi.SetValue(".bone.ICETree.Set_Data.Reference", "this.kine.global", "") xsi.ConnectICENodes(".bone.ICETree.port1", ".bone.ICETree.Set_Data.Execute") #add array xsi.AddICENode("$XSI_DSPRESETS\\ICENodes\\SelectInArrayNode.Preset", ".bone.ICETree") xsi.ConnectICENodes(".bone.ICETree.Set_Data.Value", ".bone.ICETree.SelectInArrayNode.value") #select division id xsi.AddICENode("$XSI_DSPRESETS\\ICENodes\\GetDataNode.Preset", ".bone.ICETree") xsi.SetValue(".bone.ICETree.SceneReferenceNode.reference", id + ".ICEparms.ID", "") xsi.ConnectICENodes(".bone.ICETree.SelectInArrayNode.index", ".bone.ICETree.SceneReferenceNode.value") #get the BoneTransforms xsi.AddICENode("$XSI_DSPRESETS\\ICENodes\\GetDataNode.Preset", ".bone.ICETree") xsi.SetValue(".bone.ICETree.SceneReferenceNode[1].reference", trans + ".BoneTransforms", "") xsi.ConnectICENodes(".bone.ICETree.SelectInArrayNode.array", ".bone.ICETree.SceneReferenceNode[1].value") ###################### divs ###################### #define the creation of the divisions and iterate their name number def createDivisions(nDivs): for i in range(nDivs): oDiv = xsi.GetPrim("Bone", oNameIn + "_div" + str(i), oMusclePar, "") oDivName = oDiv.fullName xsi.SetValue(".bone.primary_icon", 6, "") #create a parameter with bone id, used by each ice tree xsi.AddProp("Custom_parameter_list", "", "", "ICEparms", "") xsi.SIAddCustomParameter(oDiv, "ID", "siInt4", i, 0, 100, "", 2053, 0, 100, "", "") #xsi.SIAddCustomParameter(oDiv, "parID", "siInt4", 0, 1, 100, "", 2053, 1, 100, "", "") #add to the division group from where the main ICE tree will access them xsi.SIAddToGroup(oDivGrp, "", "") #the length of each division is equals to the main lenth parameter xsi.SetExpr(oDivName + ".bone.length", oMuscleParName + ".ctrls.div_length", "") #apply the ICE tree createDivICEtree(oDivName, oICEcontName) #create the last division (has length 1) oDivTip = xsi.GetPrim("Bone", oNameIn + "_divTip", oMusclePar, "") oDivTipName = oDivTip.fullName xsi.SIAddToGroup(oDivGrp, "", "") xsi.SetValue(".bone.primary_icon", 6, "") xsi.AddProp("Custom_parameter_list", "", "", "ICEparms", "") xsi.SIAddCustomParameter(oDivTipName, "ID", "siInt4", nDivs, 0, 100, "", 2053, 0, 100, "", "") xsi.SIAddCustomParameter(oDivTipName, "parID", "siInt4", 0, 1, 100, "", 2053, 1, 100, "", "") createDivICEtree(oName + "_divTip", oICEcontName) ###################### mainICE ###################### #this is the main ICE tree applied to oICEcont #created in a function to have it as a self contained unit def createMainICEtree(name, base, tip, mid, grp): xsi.ApplyOp("ICETree", name, "siNode", "", "", 0) xsi.AddICECompoundNode("Bezier Spine", name + ".null.ICETree") xsi.ConnectICENodes(name + ".null.ICETree.port1", name + ".null.ICETree.Bezier_Spine.Execute_Debugging") #get the division's group xsi.AddICENode("$XSI_DSPRESETS\\ICENodes\\GetDataNode.Preset", name + ".null.ICETree") xsi.SetValue( name + ".null.ICETree.SceneReferenceNode.reference", oModelName + grp + ".bone.length", "") xsi.ConnectICENodes( name + ".null.ICETree.Bezier_Spine.Bone_Lengths", name + ".ICETree.SceneReferenceNode.value") #get the oBase transforms xsi.AddICENode("$XSI_DSPRESETS\\ICENodes\\GetDataNode.Preset", name + ".null.ICETree") xsi.SetValue(name + ".null.ICETree.SceneReferenceNode[1].reference", base + ".kine.global", "") xsi.ConnectICENodes(name + ".null.ICETree.Bezier_Spine.Base_Manip", name + ".null.ICETree.SceneReferenceNode[1].value") #get the oTip transforms xsi.AddICENode("$XSI_DSPRESETS\\ICENodes\\GetDataNode.Preset", name + ".null.ICETree") xsi.SetValue( name + ".null.ICETree.SceneReferenceNode[2].reference", tip + ".kine.global", "") xsi.ConnectICENodes( name + ".null.ICETree.Bezier_Spine.Tip_Manip", name + ".null.ICETree.SceneReferenceNode[2].value") #get the oMid transforms xsi.AddICENode("$XSI_DSPRESETS\\ICENodes\\GetDataNode.Preset", name + ".null.ICETree") xsi.SetValue(name + ".null.ICETree.SceneReferenceNode[3].reference", mid + ".kine.global", "") xsi.ConnectICENodes(name + ".null.ICETree.Bezier_Spine.Middle_Manip", name + ".null.ICETree.SceneReferenceNode[3].value") #set the BoneTransforms (this node will activate the divisions ICE trees) xsi.AddICECompoundNode("Set Data", name + ".null.ICETree") xsi.SetValue(name + ".null.ICETree.Set_Data.Reference", "self.BoneTransforms", "") xsi.ConnectICENodes(name + ".null.ICETree.Set_Data.Value", name + ".null.ICETree.Bezier_Spine.Transforms") xsi.AddPortToICENode(name + ".null.ICETree.port1", "siNodePortDataInsertionLocationAfter") xsi.ConnectICENodes(name + ".null.ICETree.port2", name + ".null.ICETree.Set_Data.Execute") #a few defaul values are set for the bezier spine xsi.SetValue(name + ".null.ICETree.Bezier_Spine.Base_Hdl_Offset_x", 0, "") xsi.SetValue(name + ".null.ICETree.Bezier_Spine.Base_Hdl_Offset_y", 1, "") xsi.SetValue(name + ".null.ICETree.Bezier_Spine.Tip_Hdl_Offset_x", 0, "") xsi.SetValue(name + ".null.ICETree.Bezier_Spine.Tip_Hdl_Offset_y", -1, "") xsi.SetValue(name + ".null.ICETree.Bezier_Spine.Squash_Limit", 0, "") xsi.SetValue(name + ".null.ICETree.Bezier_Spine.Stretch_Limit", 10, "") ###################### nurbs ###################### #create the nurbs surface for deformation (skinwrapping to the mesh or other) #created in a function to have it as a self contained unit def createNurbs(): oNurbs = xsi.CreatePrim("Cylinder", "NurbsSurface", oNameIn + "_musc", oMusclePar) oNurbsName = oNurbs.fullName xsi.SetValue(".surfmsh.geom.closevmax", False, "") xsi.SetValue(".surfmsh.geom.closevmin", False, "") #v subdivisions are set to number of divisions xsi.SetValue(".surfmsh.geom.subdivv", nDivsIn, "") #lenght is set to distance from oBone to oBone1 xsi.SetValue(".cylinder.height", dist, "") xsi.SetValue(".cylinder.radius", 0.5, "") xsi.MatchTransform(oNurbs, oBase, "siSRT", "") xsi.MatchTransform(oNurbs, oMid, "siTrn", "") #oNurbs is enveloped to all divisions xsi.SelectMembers(oDivGrp, "", "") oSel = xsi.Selection for i in range(oSel.count): oEnv = oSel[i] xsi.ApplyFlexEnv(oNurbsName + ";" + oEnv.fullName, True, 2) xsi.SetValue(oNurbsName + ".visibility.selectability", False, "") xsi.FreezeModeling(oNurbsName, "", "") ###################### divIn ###################### #input number of divisions desired and store nDivsIn = xsi.XSIInputbox("enter number of divisions", "divisions") #set length of each division == total lenth / number of divisions bLength = float(dist) / float(nDivsIn) ###################### customP ###################### #add custom parameter set and parameter where the lenght of the divisions is stored xsi.AddProp("Custom_parameter_list", oMusclePar, "", "ctrls", "") xsi.SIAddCustomParameter(oMuscleParName + ".ctrls", "div_length", "siDouble", bLength, 0, 100, "", 2053, 0, 100, "", "") ###################### freeoBase ###################### #oBase was constrained to oBone1, it can now be freed xsi.RemoveAllCns(oBase, "") ###################### calls ###################### #call the functions to create the remaining objects and ICE trees createDivisions(int(nDivsIn)) createMainICEtree(oICEcontName, oBaseName, oTipName, oMidName, oDivGrpName) createNurbs() print ( "distance between " + fromObj.FullName + " to " + toObj.FullName + " is: " + dist ) print ( "division length is " + str(bLength)) xsi.DeselectAll() #inspect the bezier spine container xsi.InspectObj(oICEcontName + ".null.ICETree.Bezier_Spine", "", "")