Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Skin and bodygroups animation setup script
- # Written by DiFFtY (diffty@gmail.com)
- # Inspired by Miek's cloaking script (https://github.com/miek/sfm_scripts/tree/master/setup_cloaking)
- # Impulsed by doc_ock_rokc and VoxBombarde suggestions
- #
- # This script allows you to create a new channel in an Animation Set to control the skin number of a game model.
- #
- # Usage : Right click on a model Animation Set, go to Rig -> Load Rig Script, then open this .py
- #
- # Tested on SFM 0.9.7.6, 14/05/2013
- #
- # http://www.youtube.com/watch?v=cM0DW6jKCvs
- import vs
- def ControlGroupExists(controlGroupName):
- animSet = sfm.GetCurrentAnimationSet()
- return (animSet.FindControlGroup(controlGroupName) != None)
- def SetupSkin():
- # Get the currently selected animation set and shot, and the corresponding gamemodel
- shot = sfm.GetCurrentShot()
- animSet = sfm.GetCurrentAnimationSet()
- gameModel = animSet.gameModel
- BuildBodygroupSelectorExpression(gameModel)
- # Creating the control group
- controlGroup = animSet.FindOrAddControlGroup(animSet.GetRootControlGroup(), "Skin")
- # Creating the control in the animation set
- skinControl, skinValue = sfmUtils.CreateControlledValue("skin", "value", vs.AT_FLOAT, 0.0, animSet, shot)
- controlGroup.AddControl(skinControl)
- # Creating an operator/expression, to adapt the 0.0 -> 1.0 float information provided by the slider to a 0 -> number of skins in the gamemodel
- expression = sfmUtils.CreateExpression("skin_selector", "floor(lerp(value, lo, hi))", animSet)
- expression.AddAttribute("lo", vs.AT_FLOAT)
- expression.AddAttribute("hi", vs.AT_FLOAT)
- expression.SetValue("hi", gameModel.GetSkinCount()-1)
- expression.AddAttribute("value", vs.AT_FLOAT)
- # Connecting the normalized slider user-provided info to the expression
- skinControl.channel.SetOutput(expression, "value")
- # Creating the second channel, which take the result of the expression and assign it to the gamemodel skin info
- rescaleChannel = sfmUtils.CreateChannel("denormalized_skin_channel", vs.AT_FLOAT, 0., animSet, shot)
- rescaleChannel.SetInput(expression, "result")
- rescaleChannel.SetOutput(gameModel, "skin")
- # Removing keyframes from the second channel
- # (to avoid the default blank key (added in the CreateChannel() function) to override ones from the first channel, which are the ones set by the user)
- for i in range(0, rescaleChannel.log.GetKeyCount()):
- rescaleChannel.log.RemoveKey(0)
- return
- def BuildBodygroupSelectorExpression(gameModel):
- bodyParts = []
- nbModels = 0
- # Building body parts list array (with body part name and model count in each one)
- for i in range(0, gameModel.GetBodyPartCount()):
- if gameModel.GetBodyPart(i).nummodels > 1:
- bodyParts.append([gameModel.GetBodyPart(i).pszName(), gameModel.GetBodyPart(i).nummodels])
- nbModels += gameModel.GetBodyPart(i).nummodels-1
- expressions = {"strings":[""], "nbValues":[0]}
- currentRank = 0
- bodyPartCount = len(bodyParts)
- cumulatedBodyNumber = 1
- # Building the expression
- for idBodyPart in range(0, bodyPartCount):
- modelCount = bodyParts[idBodyPart][1]-1
- if idBodyPart == 0:
- #expression += "pow(2, (floor(value" + str(idBodyPart) + "*" + str(modelCount) + ") - 1)) * (floor(value" + str(idBodyPart) + "*" + str(modelCount) + ") > 0)"
- expressionNewPart = "floor(value" + str(idBodyPart) + " * " + str(modelCount) + ")"
- else:
- #expression += "pow(2, (" + str(currentRank) + " + floor(value" + str(idBodyPart) + "*" + str(modelCount) + ") - 1)) * (floor(value" + str(idBodyPart) + "*" + str(modelCount) + ") > 0)"
- expressionNewPart = "floor(value" + str(idBodyPart) + " * " + str(modelCount) + ") * " + str(cumulatedBodyNumber)
- if len(expressions['strings'][-1]+expressionNewPart) > 256:
- expressions['strings'].append(expressionNewPart)
- expressions['nbValues'].append(1)
- else:
- if idBodyPart > 0:
- expressions['strings'][-1] += " + "
- expressions['strings'][-1] += expressionNewPart
- expressions['nbValues'][-1] += 1
- print idBodyPart,bodyPartCount
- cumulatedBodyNumber += cumulatedBodyNumber*modelCount
- print expressions
- return expressions
- def SetupBodygroup():
- # Get the currently selected animation set and shot, and the corresponding gamemodel
- shot = sfm.GetCurrentShot()
- animSet = sfm.GetCurrentAnimationSet()
- gameModel = animSet.gameModel
- # Creating the expression, which will process every single bodygroup selector to one unique integer bodygroup number
- expressions = BuildBodygroupSelectorExpression(gameModel)
- # Creating the Bodygroup control group
- controlGroup = animSet.FindOrAddControlGroup(animSet.GetRootControlGroup(), "BodyGroups")
- # Listing every bodygroup, which have more than 1 model (basically, every bodygroup except the base one)
- usefulBodyparts = [i for i in range(0, gameModel.GetBodyPartCount()) if gameModel.GetBodyPart(i).nummodels > 1]
- # Initializing the control arrays
- bodyControl = [0]*len(usefulBodyparts)
- # Creating the controls in the animation set for each bodygroup
- for i, idBodypart in enumerate(usefulBodyparts):
- bodyControl[i], bodyValue = sfmUtils.CreateControlledValue(gameModel.GetBodyPart(idBodypart).pszName(), "value" + str(i), vs.AT_FLOAT, 0.0, animSet, shot)
- controlGroup.AddControl(bodyControl[i])
- resultExpression = sfmUtils.CreateExpression("bodygroup_selector_result", "", animSet)
- resultExpressionStr = ""
- startId = endId = 0
- # Creating an operator/expression, to adapt the 0.0 -> 1.0 float information provided by each slider to a 0 -> number of bodygroups in the gamemodel
- for exprId, currentExprStr in enumerate(expressions['strings']):
- resultExpression.AddAttribute("resultpart" + str(exprId+1), vs.AT_FLOAT)
- if exprId > 0:
- startId = endId
- resultExpressionStr += " + "
- resultExpressionStr += "resultpart" + str(exprId+1)
- endId = startId+expressions['nbValues'][exprId]
- expression = sfmUtils.CreateExpression("bodygroup_selector_part" + str(exprId+1), currentExprStr, animSet)
- for i in range(startId, endId):
- expression.AddAttribute("value"+str(i), vs.AT_FLOAT)
- # Connecting the normalized slider user-provided info to the expression
- bodyControl[i].channel.SetOutput(expression, "value" + str(i))
- processedChannel = sfmUtils.CreateChannel("computed_bodygroup_part" + str(exprId+1) + "_channel", vs.AT_FLOAT, 0., animSet, shot)
- processedChannel.SetInput(expression, "result")
- processedChannel.SetOutput(resultExpression, "resultpart" + str(exprId+1))
- for i in range(0, processedChannel.log.GetKeyCount()):
- processedChannel.log.RemoveKey(0)
- resultExpression.SetValue("expr", resultExpressionStr)
- # Creating the last channel, which take the result of the final sum and assign it to the gamemodel bodygroup info
- finalProcessedChannel = sfmUtils.CreateChannel("computed_bodygroup_channel", vs.AT_FLOAT, 0., animSet, shot)
- finalProcessedChannel.SetInput(resultExpression, "result")
- finalProcessedChannel.SetOutput(gameModel, "body")
- # Removing keyframes from the new channel
- # (to avoid the default blank key (added in the CreateChannel() function) to override ones from the first channel, which are the ones set by the user)
- for i in range(0, finalProcessedChannel.log.GetKeyCount()):
- finalProcessedChannel.log.RemoveKey(0)
- return
- #==================================================================================================
- # Script entry
- #==================================================================================================
- # Setup skin and bodygroup selector channels for the selected animation set
- if not ControlGroupExists("Skin"):
- SetupSkin()
- else:
- print "The control group for skins has already been built. Skipping."
- if not ControlGroupExists("BodyGroups"):
- SetupBodygroup()
- else:
- print "The control group for bodygroups has already been built. Skipping."
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement