4021 lines
125 KiB
Python
Executable File
4021 lines
125 KiB
Python
Executable File
'''
|
|
From https://github.com/Danlowlows/MobuCore
|
|
|
|
Adjustment Blending is a method for adjusting additive layer interpolation between keyframes, so that movement on the layer is shifted to areas where there is already movement on the base layer.
|
|
|
|
This helps to maintain the existing energy of the base layer motion, and helps to maintain contact points. For more information, see this talk from GDC 2016: https://youtu.be/eeWBlMJHR14?t=518
|
|
|
|
MobuCoreLibrary functions are required for this script.
|
|
____________________________________________________________________
|
|
|
|
This script was written by Dan Lowe as part of the MobuCore package. You can reach Dan Lowe on Twitter at https://twitter.com/danlowlows (at time of writing, direct messages are open).
|
|
|
|
MobuCore is made available under the following license terms:
|
|
|
|
Copyright (c) 2019 Dan Lowe
|
|
|
|
This software is provided 'as-is', without any express or implied warranty. In no event will the author be held liable for any damages arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
|
|
|
|
2. If you use this software, in source or binary form, an acknowledgment in the product documentation or credits would be appreciated but is not required. Example: "This product uses MobuCore (c) 2019 Dan Lowe."
|
|
|
|
3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
|
|
|
4. This notice may not be removed or altered from any source distribution.
|
|
'''
|
|
|
|
from pyfbsdk import *
|
|
|
|
|
|
# Gets all referened objects for a given character extension.
|
|
def GetObjectsFromExtension(ext):
|
|
extObjList = []
|
|
for i in range(ext.GetSrcCount()):
|
|
extObjList.append(ext.GetSrc(i))
|
|
if extObjList == []:
|
|
extObjList = None
|
|
return extObjList
|
|
|
|
|
|
# Gets all referenced character extension objects for a given character.
|
|
def GetCharacterExtensionObjects(character=None):
|
|
if not character:
|
|
character = FBApplication().CurrentCharacter
|
|
if character:
|
|
characterExtentionObjects = []
|
|
for ext in FBSystem().Scene.CharacterExtensions:
|
|
attachedChar = ext.PropertyList.Find("AttachedCharacter")
|
|
if len(attachedChar) > 0:
|
|
if attachedChar[0] == character:
|
|
extObjList = GetObjectsFromExtension(ext)
|
|
characterExtentionObjects = characterExtentionObjects + extObjList
|
|
if characterExtentionObjects == []:
|
|
characterExtentionObjects = None
|
|
else:
|
|
characterExtentionObjects = list(dict.fromkeys(characterExtentionObjects))
|
|
return characterExtentionObjects
|
|
|
|
|
|
# Gets the control rig for a given character.
|
|
def GetControlRigForCharacter(character=None):
|
|
if not character:
|
|
character = FBApplication().CurrentCharacter
|
|
if character:
|
|
ctrlRig = character.PropertyList.Find("ControlSet")
|
|
if len(ctrlRig) != 0:
|
|
ctrlRig = ctrlRig[0]
|
|
else:
|
|
ctrlRig = None
|
|
if ctrlRig:
|
|
return ctrlRig
|
|
|
|
|
|
# Get all character effectors and extensions.
|
|
def GetCharacterEffectorsAndExtensions(character=None):
|
|
if not character:
|
|
character = FBApplication().CurrentCharacter
|
|
if character:
|
|
effectors = GetControlRigEffectors(character)
|
|
extensions = GetCharacterExtensionObjects(character)
|
|
if not isinstance(effectors, list):
|
|
effectors = [effectors]
|
|
if not isinstance(extensions, list):
|
|
extensions = [extensions]
|
|
return effectors + extensions
|
|
|
|
|
|
# Gets the IK effectors for a given character.
|
|
def GetControlRigIKEffectors(character=None):
|
|
if not character:
|
|
character = FBApplication().CurrentCharacter
|
|
if character:
|
|
ctrlRig = GetControlRigForCharacter(character)
|
|
ikEffectors = []
|
|
for nodeId in FBEffectorId.values.itervalues():
|
|
if nodeId not in [FBEffectorId.kFBInvalidEffectorId, FBEffectorId.kFBLastEffectorId]:
|
|
effector = ctrlRig.GetIKEffectorModel(nodeId, 0)
|
|
if effector:
|
|
ikEffectors.append(effector)
|
|
if ikEffectors == []:
|
|
ikEffectors = None
|
|
return ikEffectors
|
|
|
|
|
|
# Gets the FK effectors for a given character.
|
|
def GetControlRigFKEffectors(character=None):
|
|
if not character:
|
|
character = FBApplication().CurrentCharacter
|
|
if character:
|
|
fkEffectors = []
|
|
for nodeId in FBBodyNodeId.values.itervalues():
|
|
if nodeId not in [FBBodyNodeId.kFBInvalidNodeId, FBBodyNodeId.kFBLastNodeId]:
|
|
effector = character.GetCtrlRigModel(nodeId)
|
|
if effector:
|
|
fkEffectors.append(effector)
|
|
if fkEffectors == []:
|
|
fkEffectors = None
|
|
return fkEffectors
|
|
|
|
|
|
# Gets both the FK and IK effectors for a given character.
|
|
def GetControlRigEffectors(character=None):
|
|
if not character:
|
|
character = FBApplication().CurrentCharacter
|
|
if character:
|
|
controlRigEffectors = GetControlRigFKEffectors(character) + GetControlRigIKEffectors(character)
|
|
return controlRigEffectors
|
|
|
|
|
|
# Groups pairs of keys from the layer fcurve, between which it will run an independent adjustment blend (allows adjustment blend to work with multiple key poses on the layer).
|
|
def GetKeyPairsFromFCurve(keys):
|
|
keyPairsList = []
|
|
for i in range(len(keys) - 1):
|
|
startKeyTime = keys[i].Time
|
|
startKeyValue = keys[i].Value
|
|
stopKeyTime = keys[i + 1].Time
|
|
stopKeyValue = keys[i + 1].Value
|
|
keyPairsList.append([startKeyTime, stopKeyTime, startKeyValue, stopKeyValue])
|
|
return keyPairsList
|
|
|
|
|
|
# Gets the transform nodes for an object.
|
|
def GetObjTransformNodes(obj):
|
|
transProp = obj.PropertyList.Find("Lcl Translation")
|
|
rotProp = obj.PropertyList.Find("Lcl Rotation")
|
|
if not transProp:
|
|
transProp.SetAnimated(True)
|
|
transProp = obj.PropertyList.Find("Lcl Translation")
|
|
if not rotProp:
|
|
rotProp.SetAnimated(True)
|
|
rotProp = obj.PropertyList.Find("Lcl Rotation")
|
|
transNodes = transProp.GetAnimationNode().Nodes
|
|
rotNodes = rotProp.GetAnimationNode().Nodes
|
|
nodes = list(transNodes) + list(rotNodes)
|
|
return nodes
|
|
|
|
|
|
# Gets the fcurves for an object from a specified layer.
|
|
def GetObjectFCurvesForLayer(obj, layerIndex):
|
|
FBSystem().CurrentTake.SetCurrentLayer(layerIndex)
|
|
try:
|
|
return [node.FCurve for node in GetObjTransformNodes(obj)]
|
|
except:
|
|
return []
|
|
|
|
|
|
# Reads the per frame values from an fcurve (doesn't require keys to be on those frames).
|
|
def EvaluateFCurveForKeyPairTimespan(fcurve, startTime, stopTime):
|
|
keyPairSpanValues = []
|
|
current = startTime
|
|
while not current > stopTime:
|
|
keyPairSpanValues.append([current, fcurve.Evaluate(current)])
|
|
current += FBTime(0, 0, 0, 1)
|
|
return keyPairSpanValues
|
|
|
|
|
|
# Finds the percentage of change that occured on the base layer curve, for the key pair.
|
|
def GetPercentageOfChangeValues(spanValues):
|
|
changeValues = [0.0]
|
|
for i in range(len(spanValues) - 1):
|
|
frameChangeValue = abs(spanValues[i + 1][1] - spanValues[i][1])
|
|
changeValues.append(frameChangeValue)
|
|
totalBaseLayerChange = sum(changeValues)
|
|
percentageValues = []
|
|
for i in range(len(changeValues)):
|
|
if totalBaseLayerChange != 0:
|
|
percentageValues.append([spanValues[i][0], (100.0 / totalBaseLayerChange) * changeValues[i]])
|
|
return percentageValues, totalBaseLayerChange
|
|
|
|
|
|
# The main adjustment blend function that does everything else. This is what you'd run if you were just adjustment blending a single object.
|
|
def AdjustmentBlendObject(obj):
|
|
take = FBSystem().CurrentTake
|
|
if take.GetLayerCount() > 1:
|
|
poseLayerFCurves = GetObjectFCurvesForLayer(obj, take.GetLayerCount() - 1)
|
|
baseLayerFCurves = GetObjectFCurvesForLayer(obj, 0)
|
|
for i in range(len(poseLayerFCurves)):
|
|
poseFCurve = poseLayerFCurves[i]
|
|
keys = poseFCurve.Keys
|
|
if len(keys) > 1:
|
|
keyPairsList = GetKeyPairsFromFCurve(keys)
|
|
for keyPair in keyPairsList:
|
|
startTime = keyPair[0]
|
|
stopTime = keyPair[1]
|
|
startValue = keyPair[2]
|
|
stopValue = keyPair[3]
|
|
spanValues = EvaluateFCurveForKeyPairTimespan(baseLayerFCurves[i], startTime, stopTime)
|
|
percentageValues, totalBaseLayerChange = GetPercentageOfChangeValues(spanValues)
|
|
totalPoseLayerChange = abs(stopValue - startValue)
|
|
previousValue = startValue
|
|
for value in percentageValues:
|
|
valueDelta = (totalPoseLayerChange / 100.0) * value[1]
|
|
if stopValue > startValue:
|
|
currentValue = previousValue + valueDelta
|
|
else:
|
|
currentValue = previousValue - valueDelta
|
|
poseLayerFCurves[i].KeyAdd(value[0], currentValue)
|
|
previousValue = currentValue
|
|
|
|
|
|
# The main adjustment blending function for running it on an entire character.
|
|
def AdjustmentBlendCharacter(character=None):
|
|
if not character:
|
|
character = FBApplication().CurrentCharacter
|
|
if character:
|
|
take = FBSystem().CurrentTake
|
|
if take.GetLayerCount() > 1:
|
|
characterObjs = GetCharacterEffectorsAndExtensions(character)
|
|
for obj in characterObjs:
|
|
if obj:
|
|
AdjustmentBlendObject(obj)
|
|
else:
|
|
FBMessageBox("Error...",
|
|
"No additive layer found for %s. Adjustment blending affects interpolation between keys on the the top most additive layer." % take.Name,
|
|
"OK")
|
|
else:
|
|
FBMessageBox("Error...",
|
|
"No additive layer found for %s. Adjustment blending affects interpolation between keys on the top most additive layer." % take.Name,
|
|
"OK")
|
|
|
|
|
|
def getNumberOfSelectedTakes():
|
|
number_of_selected_takes = 0
|
|
|
|
for take_index in range(len(FBSystem().Scene.Takes)):
|
|
if FBSystem().Scene.Takes[take_index].Selected == True:
|
|
number_of_selected_takes += 1
|
|
|
|
return number_of_selected_takes
|
|
|
|
|
|
def run():
|
|
# -- Get number of takes selected
|
|
number_of_selected_takes = getNumberOfSelectedTakes()
|
|
|
|
# if there is one selected take, still ignore it and use the current take
|
|
# it's a bit annoying when you have one take selected different from the current - chances are the user didn't mean to.
|
|
if number_of_selected_takes > 1:
|
|
for take_index in range(len(FBSystem().Scene.Takes)):
|
|
if FBSystem().Scene.Takes[take_index].Selected == True:
|
|
# go to take
|
|
FBSystem().CurrentTake = FBSystem().Scene.Takes[take_index]
|
|
AdjustmentBlendCharacter()
|
|
|
|
else:
|
|
AdjustmentBlendCharacter()
|
|
|
|
run()
|
|
import os
|
|
from RS import Perforce as P4
|
|
from pyfbsdk import *
|
|
import pythonidelib
|
|
|
|
|
|
def popUp(pUpTitle, pUpMessage, btn1="Continue", btn2="Cancel"):
|
|
input = FBMessageBox(pUpTitle,
|
|
pUpMessage,
|
|
btn1,
|
|
btn2
|
|
)
|
|
|
|
return input
|
|
|
|
def filename(path):
|
|
withext = str(path.split('\\')[-1])
|
|
withoutext = withext.split('.')[0]
|
|
|
|
return withoutext.upper()
|
|
|
|
|
|
|
|
def fileChecks(fbx):
|
|
fbxchecks = [False, False, False, False]
|
|
fbxinfo = P4.GetFileState(fbx)
|
|
|
|
if os.path.exists(fbx):
|
|
fbxchecks[0] = True
|
|
else:
|
|
popUp("Unable to Check Out", "Could not find the file locally")
|
|
|
|
if fbxchecks[0]:
|
|
if P4.DoesFileExist(fbx):
|
|
fbxchecks[1] = True
|
|
else:
|
|
if popUp("Unable to Check Out", "File does not exist in Perforce. Would you like to add it?") == 1:
|
|
CL = P4.CreateChangelist("[SOURCE] - " + filename(fbx))
|
|
P4.Add(fbx, CL.Number, True)
|
|
popUp("Checked Out", "FBX Added to CL %s" % CL.Number)
|
|
|
|
if fbxchecks[1]:
|
|
if not P4.IsOpenForEdit(fbxinfo):
|
|
fbxchecks[2] = True
|
|
else:
|
|
popUp("Unable to Check Out", "File is already Checked out")
|
|
|
|
if P4.IsLatest(fbxinfo):
|
|
fbxchecks[3] = True
|
|
else:
|
|
if popUp("Not Latest Revision", "You do not have the latest revision of this file. Get latest now?") == 1:
|
|
P4.Sync(fbx)
|
|
|
|
if all(fbxchecks) == True:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
|
|
if fileChecks(FBApplication().FBXFileName):
|
|
CL = P4.CreateChangelist("[SOURCE] - " + filename(FBApplication().FBXFileName))
|
|
P4.Edit(FBApplication().FBXFileName, CL.Number)
|
|
popUp("Checked Out", "FBX Checked out in CL %s" % CL.Number)
|
|
else:
|
|
print "Checks failed"
|
|
|
|
pythonidelib.FlushOutput()
|
|
#######################################################################
|
|
# -- Quickly reduce keys on all animated curves of selected models --
|
|
#######################################################################
|
|
from pyfbsdk import *
|
|
|
|
def reduceKeysOnSelected():
|
|
|
|
# Create a Key Reducing filter.
|
|
cleanFilter = FBFilterManager().CreateFilter('Key Reducing')
|
|
cleanFilter.PropertyList.Find('Precision').Data = 0.04
|
|
|
|
# -- Create an empty FBModelList
|
|
selectedModels = FBModelList()
|
|
|
|
topModel = None # -- Search all models, not just a particular branch
|
|
selectionState = True # -- Return models that are selected, not deselected
|
|
sortBySelectOrder = True # -- The last model in the list was selected most recently
|
|
FBGetSelectedModels(selectedModels, topModel, selectionState, sortBySelectOrder)
|
|
|
|
for model in selectedModels:
|
|
|
|
for lProp in model.PropertyList:
|
|
if lProp and lProp.IsAnimatable() and lProp.IsAnimated():
|
|
cleanFilter.Apply(lProp.GetAnimationNode(), True)
|
|
|
|
|
|
|
|
reduceKeysOnSelected()
|
|
|
|
|
|
|
|
|
|
|
|
#############################################################
|
|
# -- Quickly reduce all selected keys in the graph editor --
|
|
#############################################################
|
|
from pyfbsdk import *
|
|
import pythonidelib
|
|
pythonidelib.FlushOutput()
|
|
|
|
|
|
|
|
def getSelectedModels():
|
|
|
|
# -- Create an empty FBModelList
|
|
selectedModels = FBModelList()
|
|
|
|
topModel = None # -- Search all models, not just a particular branch
|
|
selectionState = True # -- Return models that are selected, not deselected
|
|
sortBySelectOrder = True # -- The last model in the list was selected most recently
|
|
FBGetSelectedModels(selectedModels, topModel, selectionState, sortBySelectOrder)
|
|
|
|
return selectedModels
|
|
|
|
|
|
|
|
def reduceSelectedKeys():
|
|
|
|
print "Starting Key Cleanup"
|
|
|
|
# -- Create a Key Reducing filter.
|
|
cleanFilter = FBFilterManager().CreateFilter( 'Key Reducing' )
|
|
cleanFilter.PropertyList.Find('Precision').Data = 0.04
|
|
|
|
# -- Create an empty list to be filled with nodes that have curves
|
|
nodesWithCurves = []
|
|
|
|
# -- Create an empty dictionary for storing keyframe times
|
|
selKeyTimes = {}
|
|
|
|
# -- Create an empty list of frame times
|
|
selKeyFrames = []
|
|
|
|
# -- For each model selected
|
|
for model in getSelectedModels():
|
|
|
|
# -- Find its properties
|
|
for lProp in model.PropertyList:
|
|
# -- For each property, find if it is animated
|
|
if lProp and lProp.IsAnimatable() and lProp.IsAnimated():
|
|
|
|
# ======== Finding Nodes capable of having FCurves =======
|
|
|
|
# -- If so, get the connected animation node
|
|
animNode = lProp.GetAnimationNode()
|
|
|
|
# -- Fine all children nodes of the connected animation node
|
|
nodes = animNode.Nodes
|
|
# -- If children nodes are found
|
|
if len(nodes) > 0:
|
|
# -- Add each one to our list
|
|
for node in nodes:
|
|
nodesWithCurves.append(node)
|
|
|
|
# -- Otherwise add the anim node to our list
|
|
else:
|
|
nodesWithCurves.append(animNode)
|
|
|
|
# ======== Finding Selected Keyframes ==========
|
|
|
|
# -- For every node in our list
|
|
for node in nodesWithCurves:
|
|
|
|
# -- reset the selected key times dictionary
|
|
selKeyTimes = {}
|
|
|
|
# -- If the node has an FCurve
|
|
if node.FCurve:
|
|
|
|
# -- For each keyframe on the FCurve
|
|
for key in node.FCurve.Keys:
|
|
# -- If that key is selected
|
|
if key.Selected == True:
|
|
|
|
# -- Add the keyframe's time to the dictionary
|
|
selKeyTimes[key.Time.GetFrame()] = key.Time
|
|
|
|
|
|
# -- If at least one keyframe was selected
|
|
if len(selKeyTimes) > 0:
|
|
|
|
# -- Fill the list with the frame data from the dictionary
|
|
for key in selKeyTimes:
|
|
selKeyFrames.append(key)
|
|
|
|
# -- Find the highest and lowest number in the frame list. This will be our filter range
|
|
startTime = min(selKeyFrames)
|
|
stopTime = max(selKeyFrames)
|
|
|
|
# -- Set the range of our filter using the range of selected keyframes
|
|
if startTime in selKeyTimes:
|
|
if stopTime in selKeyTimes:
|
|
cleanFilter.Start = selKeyTimes[startTime]
|
|
cleanFilter.Stop = selKeyTimes[stopTime]
|
|
|
|
# -- Apply the filter
|
|
cleanFilter.Apply(node.FCurve)
|
|
print "Cleaning keys on %s %s.%s from %r to %r" % (model.Name, animNode.Name, node.Name, startTime, stopTime)
|
|
|
|
# -- Cleanup
|
|
del (cleanFilter, nodesWithCurves, selKeyTimes, selKeyFrames)
|
|
print "Key Cleanup Complete"
|
|
|
|
reduceSelectedKeys()
|
|
|
|
|
|
|
|
|
|
|
|
################################################
|
|
# -- Lifted from Animal Tools created by Mangesh
|
|
################################################
|
|
from pyfbsdk import FBConstraintManager, FBModelList, FBGetSelectedModels
|
|
|
|
def renameConstraint(con):
|
|
|
|
if con.ReferenceGroupGetCount() in range(2,4):
|
|
child = con.ReferenceGet(0)
|
|
parent = con.ReferenceGet(1)
|
|
|
|
type = con.Description
|
|
if con.Description == 'Position From Positions':
|
|
type = 'Position'
|
|
elif con.Description == 'Rotation From Rotations':
|
|
type = 'Rotation'
|
|
elif con.Description == 'Scale From Scales':
|
|
type = 'Scale'
|
|
|
|
if child and parent:
|
|
newName = type + ' - ' + parent.Name + ' > ' + child.Name
|
|
con.Name = newName
|
|
else:
|
|
newName = type + ' - [EMPTY CONSTRAINT]'
|
|
con.Name = newName
|
|
|
|
|
|
def createConstraint():
|
|
|
|
selectedModels = FBModelList()
|
|
FBGetSelectedModels(selectedModels, None, True, True)
|
|
|
|
if len(selectedModels) <= 1 or len(selectedModels) > 2:
|
|
lMgr = FBConstraintManager()
|
|
lConst = lMgr.TypeCreateConstraint("Parent/Child")
|
|
return
|
|
|
|
lMgr = FBConstraintManager()
|
|
lConst = lMgr.TypeCreateConstraint("Parent/Child")
|
|
|
|
# get model & geometry
|
|
lMdls = FBModelList()
|
|
|
|
topModel = None
|
|
selectionState = True
|
|
sortBySelectOrder = True
|
|
FBGetSelectedModels(lMdls, topModel, selectionState, sortBySelectOrder)
|
|
|
|
mMdl = lMdls[1]
|
|
lGeo = lMdls[0]
|
|
|
|
# adding elements to the constraint slots
|
|
|
|
lConst.ReferenceAdd(0, mMdl)
|
|
lConst.ReferenceAdd(1, lGeo)
|
|
|
|
# weight of the constraint
|
|
|
|
lConst.Weight = 100
|
|
lConst.Active = False
|
|
lConst.Snap()
|
|
lConst.Lock = True
|
|
|
|
renameConstraint(lConst)
|
|
|
|
createConstraint()################################################
|
|
# -- Lifted from Animal Tools created by Mangesh
|
|
################################################
|
|
from pyfbsdk import FBConstraintManager, FBModelList, FBGetSelectedModels
|
|
|
|
def renameConstraint(con):
|
|
|
|
if con.ReferenceGroupGetCount() in range(2,4):
|
|
child = con.ReferenceGet(0)
|
|
parent = con.ReferenceGet(1)
|
|
|
|
type = con.Description
|
|
if con.Description == 'Position From Positions':
|
|
type = 'Position'
|
|
elif con.Description == 'Rotation From Rotations':
|
|
type = 'Rotation'
|
|
elif con.Description == 'Scale From Scales':
|
|
type = 'Scale'
|
|
|
|
if child and parent:
|
|
newName = type + ' - ' + parent.Name + ' > ' + child.Name
|
|
con.Name = newName
|
|
else:
|
|
newName = type + ' - [EMPTY CONSTRAINT]'
|
|
con.Name = newName
|
|
|
|
|
|
def createConstraint():
|
|
|
|
selectedModels = FBModelList()
|
|
FBGetSelectedModels(selectedModels, None, True, True)
|
|
|
|
if len(selectedModels) <= 1 or len(selectedModels) > 2:
|
|
lMgr = FBConstraintManager()
|
|
lConst = lMgr.TypeCreateConstraint("Parent/Child")
|
|
return
|
|
|
|
lMgr = FBConstraintManager()
|
|
lConst = lMgr.TypeCreateConstraint("Parent/Child")
|
|
|
|
# get model & geometry
|
|
lMdls = FBModelList()
|
|
|
|
topModel = None
|
|
selectionState = True
|
|
sortBySelectOrder = True
|
|
FBGetSelectedModels(lMdls, topModel, selectionState, sortBySelectOrder)
|
|
|
|
mMdl = lMdls[1]
|
|
lGeo = lMdls[0]
|
|
|
|
# adding elements to the constraint slots
|
|
|
|
lConst.ReferenceAdd(0, mMdl)
|
|
lConst.ReferenceAdd(1, lGeo)
|
|
|
|
# weight of the constraint
|
|
|
|
lConst.Weight = 100
|
|
lConst.Active = True
|
|
lConst.Lock = True
|
|
|
|
renameConstraint(lConst)
|
|
|
|
createConstraint()################################################
|
|
# -- Lifted from Animal Tools created by Mangesh
|
|
################################################
|
|
from pyfbsdk import FBConstraintManager, FBModelList, FBGetSelectedModels
|
|
|
|
def renameConstraint(con):
|
|
|
|
if con.ReferenceGroupGetCount() in range(2,4):
|
|
child = con.ReferenceGet(0)
|
|
parent = con.ReferenceGet(1)
|
|
|
|
type = con.Description
|
|
if con.Description == 'Position From Positions':
|
|
type = 'Position'
|
|
elif con.Description == 'Rotation From Rotations':
|
|
type = 'Rotation'
|
|
elif con.Description == 'Scale From Scales':
|
|
type = 'Scale'
|
|
|
|
if child and parent:
|
|
newName = type + ' - ' + parent.Name + ' > ' + child.Name
|
|
con.Name = newName
|
|
else:
|
|
newName = type + ' - [EMPTY CONSTRAINT]'
|
|
con.Name = newName
|
|
|
|
|
|
def createConstraint():
|
|
|
|
selectedModels = FBModelList()
|
|
FBGetSelectedModels(selectedModels, None, True, True)
|
|
|
|
if len(selectedModels) <= 1 or len(selectedModels) > 2:
|
|
lMgr = FBConstraintManager()
|
|
lConst = lMgr.TypeCreateConstraint("Position")
|
|
return
|
|
|
|
lMgr = FBConstraintManager()
|
|
lConst = lMgr.TypeCreateConstraint("Position")
|
|
|
|
# get model & geometry
|
|
lMdls = FBModelList()
|
|
|
|
topModel = None
|
|
selectionState = True
|
|
sortBySelectOrder = True
|
|
FBGetSelectedModels(lMdls, topModel, selectionState, sortBySelectOrder)
|
|
|
|
mMdl = lMdls[1]
|
|
lGeo = lMdls[0]
|
|
|
|
# adding elements to the constraint slots
|
|
|
|
lConst.ReferenceAdd(0, mMdl)
|
|
lConst.ReferenceAdd(1, lGeo)
|
|
|
|
# weight of the constraint
|
|
|
|
lConst.Weight = 100
|
|
lConst.Active = False
|
|
lConst.Snap()
|
|
lConst.Lock = True
|
|
|
|
renameConstraint(lConst)
|
|
|
|
createConstraint()################################################
|
|
# -- Lifted from Animal Tools created by Mangesh
|
|
################################################
|
|
from pyfbsdk import FBConstraintManager, FBModelList, FBGetSelectedModels
|
|
|
|
def renameConstraint(con):
|
|
|
|
if con.ReferenceGroupGetCount() in range(2,4):
|
|
child = con.ReferenceGet(0)
|
|
parent = con.ReferenceGet(1)
|
|
|
|
type = con.Description
|
|
if con.Description == 'Position From Positions':
|
|
type = 'Position'
|
|
elif con.Description == 'Rotation From Rotations':
|
|
type = 'Rotation'
|
|
elif con.Description == 'Scale From Scales':
|
|
type = 'Scale'
|
|
|
|
if child and parent:
|
|
newName = type + ' - ' + parent.Name + ' > ' + child.Name
|
|
con.Name = newName
|
|
else:
|
|
newName = type + ' - [EMPTY CONSTRAINT]'
|
|
con.Name = newName
|
|
|
|
|
|
def createConstraint():
|
|
|
|
selectedModels = FBModelList()
|
|
FBGetSelectedModels(selectedModels, None, True, True)
|
|
|
|
if len(selectedModels) <= 1 or len(selectedModels) > 2:
|
|
lMgr = FBConstraintManager()
|
|
lConst = lMgr.TypeCreateConstraint("Position")
|
|
return
|
|
|
|
lMgr = FBConstraintManager()
|
|
lConst = lMgr.TypeCreateConstraint("Position")
|
|
|
|
# get model & geometry
|
|
lMdls = FBModelList()
|
|
|
|
topModel = None
|
|
selectionState = True
|
|
sortBySelectOrder = True
|
|
FBGetSelectedModels(lMdls, topModel, selectionState, sortBySelectOrder)
|
|
|
|
mMdl = lMdls[1]
|
|
lGeo = lMdls[0]
|
|
|
|
# adding elements to the constraint slots
|
|
|
|
lConst.ReferenceAdd(0, mMdl)
|
|
lConst.ReferenceAdd(1, lGeo)
|
|
|
|
# weight of the constraint
|
|
|
|
lConst.Weight = 100
|
|
lConst.Active = True
|
|
lConst.Lock = True
|
|
|
|
renameConstraint(lConst)
|
|
|
|
createConstraint()################################################
|
|
# -- Lifted from Animal Tools created by Mangesh
|
|
################################################
|
|
from pyfbsdk import FBConstraintManager, FBModelList, FBGetSelectedModels
|
|
|
|
def renameConstraint(con):
|
|
|
|
if con.ReferenceGroupGetCount() in range(2,4):
|
|
child = con.ReferenceGet(0)
|
|
parent = con.ReferenceGet(1)
|
|
|
|
type = con.Description
|
|
if con.Description == 'Position From Positions':
|
|
type = 'Position'
|
|
elif con.Description == 'Rotation From Rotations':
|
|
type = 'Rotation'
|
|
elif con.Description == 'Scale From Scales':
|
|
type = 'Scale'
|
|
|
|
if child and parent:
|
|
newName = type + ' - ' + parent.Name + ' > ' + child.Name
|
|
con.Name = newName
|
|
else:
|
|
newName = type + ' - [EMPTY CONSTRAINT]'
|
|
con.Name = newName
|
|
|
|
|
|
def createConstraint():
|
|
|
|
selectedModels = FBModelList()
|
|
FBGetSelectedModels(selectedModels, None, True, True)
|
|
|
|
if len(selectedModels) <= 1 or len(selectedModels) > 2:
|
|
lMgr = FBConstraintManager()
|
|
lConst = lMgr.TypeCreateConstraint("Rotation")
|
|
return
|
|
|
|
lMgr = FBConstraintManager()
|
|
lConst = lMgr.TypeCreateConstraint("Rotation")
|
|
|
|
# get model & geometry
|
|
lMdls = FBModelList()
|
|
|
|
topModel = None
|
|
selectionState = True
|
|
sortBySelectOrder = True
|
|
FBGetSelectedModels(lMdls, topModel, selectionState, sortBySelectOrder)
|
|
|
|
mMdl = lMdls[1]
|
|
lGeo = lMdls[0]
|
|
|
|
# adding elements to the constraint slots
|
|
|
|
lConst.ReferenceAdd(0, mMdl)
|
|
lConst.ReferenceAdd(1, lGeo)
|
|
|
|
# weight of the constraint
|
|
|
|
lConst.Weight = 100
|
|
lConst.Active = False
|
|
lConst.Snap()
|
|
lConst.Lock = True
|
|
|
|
renameConstraint(lConst)
|
|
|
|
createConstraint()################################################
|
|
# -- Lifted from Animal Tools created by Mangesh
|
|
################################################
|
|
from pyfbsdk import FBConstraintManager, FBModelList, FBGetSelectedModels
|
|
|
|
def renameConstraint(con):
|
|
|
|
if con.ReferenceGroupGetCount() in range(2,4):
|
|
child = con.ReferenceGet(0)
|
|
parent = con.ReferenceGet(1)
|
|
|
|
type = con.Description
|
|
if con.Description == 'Position From Positions':
|
|
type = 'Position'
|
|
elif con.Description == 'Rotation From Rotations':
|
|
type = 'Rotation'
|
|
elif con.Description == 'Scale From Scales':
|
|
type = 'Scale'
|
|
|
|
if child and parent:
|
|
newName = type + ' - ' + parent.Name + ' > ' + child.Name
|
|
con.Name = newName
|
|
else:
|
|
newName = type + ' - [EMPTY CONSTRAINT]'
|
|
con.Name = newName
|
|
|
|
|
|
def createConstraint():
|
|
|
|
selectedModels = FBModelList()
|
|
FBGetSelectedModels(selectedModels, None, True, True)
|
|
|
|
if len(selectedModels) <= 1 or len(selectedModels) > 2:
|
|
lMgr = FBConstraintManager()
|
|
lConst = lMgr.TypeCreateConstraint("Rotation")
|
|
return
|
|
|
|
lMgr = FBConstraintManager()
|
|
lConst = lMgr.TypeCreateConstraint("Rotation")
|
|
|
|
# get model & geometry
|
|
lMdls = FBModelList()
|
|
|
|
topModel = None
|
|
selectionState = True
|
|
sortBySelectOrder = True
|
|
FBGetSelectedModels(lMdls, topModel, selectionState, sortBySelectOrder)
|
|
|
|
mMdl = lMdls[1]
|
|
lGeo = lMdls[0]
|
|
|
|
# adding elements to the constraint slots
|
|
|
|
lConst.ReferenceAdd(0, mMdl)
|
|
lConst.ReferenceAdd(1, lGeo)
|
|
|
|
# weight of the constraint
|
|
|
|
lConst.Weight = 100
|
|
lConst.Active = True
|
|
lConst.Lock = True
|
|
|
|
renameConstraint(lConst)
|
|
|
|
createConstraint()from pyfbsdk import *
|
|
|
|
|
|
def GetSelectedModels():
|
|
lModels = FBModelList()
|
|
FBGetSelectedModels(lModels)
|
|
return lModels
|
|
|
|
|
|
def CreateMarker(name='Marker', color=FBColor(1, 0, 0)):
|
|
marker = FBModelMarker(name)
|
|
|
|
marker.Show = True
|
|
marker.Look = FBMarkerLook.kFBMarkerLookHardCross
|
|
marker.PropertyList.Find("Size").Data = 500
|
|
marker.PropertyList.Find("Color RGB").Data = color
|
|
return marker
|
|
|
|
|
|
def Align(pModel, pAlignTo):
|
|
lAlignTransPos = FBVector3d();
|
|
lModelTransPos = FBVector3d();
|
|
lAlignRotPos = FBVector3d();
|
|
lModelRotPos = FBVector3d();
|
|
|
|
pAlignTo.GetVector(lAlignTransPos)
|
|
pModel.GetVector(lModelTransPos)
|
|
|
|
pAlignTo.GetVector(lAlignRotPos, FBModelTransformationType.kModelRotation)
|
|
pModel.GetVector(lModelRotPos, FBModelTransformationType.kModelRotation)
|
|
|
|
lModelTransPos[0] = lAlignTransPos[0]
|
|
lModelTransPos[1] = lAlignTransPos[1]
|
|
lModelTransPos[2] = lAlignTransPos[2]
|
|
|
|
lModelRotPos[0] = lAlignRotPos[0]
|
|
lModelRotPos[1] = lAlignRotPos[1]
|
|
lModelRotPos[2] = lAlignRotPos[2]
|
|
|
|
pModel.SetVector(lModelTransPos)
|
|
pModel.SetVector(lModelRotPos, FBModelTransformationType.kModelRotation)
|
|
|
|
del (lAlignRotPos, lAlignTransPos, lModelRotPos, lModelTransPos)
|
|
|
|
|
|
def Run():
|
|
models = GetSelectedModels()
|
|
|
|
if len(models) > 0:
|
|
for model in models:
|
|
color = FBColor(1, 0, 0)
|
|
if model.PropertyList.Find("Color RGB"):
|
|
color = model.Color
|
|
marker = CreateMarker(model.Name + "_Marker", color)
|
|
Align(marker, model)
|
|
del (color, marker)
|
|
else:
|
|
CreateMarker()
|
|
|
|
|
|
Run()
|
|
from pyfbsdk import *
|
|
import pythonidelib
|
|
from RS.Tools.FirstPersonController import Core as fpsCore
|
|
from RS import Globals
|
|
from RS.Utils import Scene
|
|
|
|
|
|
def getCharacterHeirarchyList(character):
|
|
characterNodeList = []
|
|
hips = character.GetModel(FBBodyNodeId.kFBHipsNodeId)
|
|
dummy = Scene.GetParent(hips)
|
|
Scene.GetChildren(dummy, characterNodeList, "", True)
|
|
return characterNodeList
|
|
|
|
|
|
def findNode(name):
|
|
foundNode = None
|
|
|
|
# -- Get list of all nodes of current character
|
|
currentCharacter = FBApplication().CurrentCharacter
|
|
characterNodeList = getCharacterHeirarchyList(currentCharacter)
|
|
|
|
# -- Check each node to see if it matches the desired name
|
|
for node in characterNodeList:
|
|
if node.Name == name:
|
|
foundNode = node
|
|
|
|
del (currentCharacter, characterNodeList)
|
|
return foundNode
|
|
|
|
|
|
def activateCamConstraint():
|
|
# -- Get the namespace of the current character
|
|
charNSpace = Scene.Component.GetNamespace(FBApplication().CurrentCharacter)
|
|
|
|
# -- Create empty variables to be filled
|
|
camConstraint = None
|
|
constraintFound = False
|
|
charConstraints = []
|
|
|
|
# -- For each constraint in the scene, check if it matches the character's namespace
|
|
for con in FBSystem().Scene.Constraints:
|
|
if Scene.Component.GetNamespace(con) == charNSpace:
|
|
charConstraints.append(con)
|
|
|
|
# -- Go through each constraint that matched the character namespace and find the FPS_Cam_Constraint
|
|
for con in charConstraints:
|
|
if 'FPS_Cam_Constraint'.lower() in con.Name.lower():
|
|
camConstraint = con
|
|
|
|
# -- If we found the FPS_Cam_Constraint, activate it
|
|
if camConstraint:
|
|
constraintFound = True
|
|
camConstraint.Active = True
|
|
|
|
# -- If we didn't, let the user know
|
|
else:
|
|
FBMessageBox("Quick Initialize CH Bones",
|
|
"WARNING:\n No FPS Constraint found for current character. ",
|
|
"Continue")
|
|
|
|
del (charNSpace, camConstraint, charConstraints)
|
|
return constraintFound
|
|
|
|
|
|
def activateCHConstraints(activate):
|
|
# -- Find the cone master
|
|
coneM = findNode("coneMaster")
|
|
# -- Create an empty list to fill with the constraint channels
|
|
chConstraints = []
|
|
|
|
# -- If we found the cone master
|
|
if coneM:
|
|
# -- For For each property of the cone master
|
|
# -- If it is one of the CH drivers
|
|
# -- Add it to our list
|
|
for prop in coneM.PropertyList:
|
|
|
|
if prop.Name == "activate_L_constraint":
|
|
chConstraints.append(prop)
|
|
|
|
if prop.Name == "activate_R_constraint":
|
|
chConstraints.append(prop)
|
|
|
|
# -- If both channels are found
|
|
if len(chConstraints) == 2:
|
|
# -- Switch them on/off depending on how the function was called
|
|
for constraint in chConstraints:
|
|
constraint.Data = activate
|
|
|
|
del (coneM, chConstraints)
|
|
return True
|
|
|
|
# -- If we didn't, let the user know
|
|
else:
|
|
FBMessageBox("Quick Initialize CH Bones",
|
|
"WARNING:\n No coneMaster found for current character.",
|
|
"Continue")
|
|
|
|
del (coneM, chConstraints)
|
|
return False
|
|
|
|
|
|
def getNumberOfSelectedTakes():
|
|
number_of_selected_takes = 0
|
|
|
|
for take_index in range(len(FBSystem().Scene.Takes)):
|
|
if FBSystem().Scene.Takes[take_index].Selected == True:
|
|
number_of_selected_takes += 1
|
|
|
|
return number_of_selected_takes
|
|
|
|
|
|
def plotOptions():
|
|
plot_options = FBPlotOptions()
|
|
plot_options.PlotAllTakes = False
|
|
plot_options.PlotOnFrame = True
|
|
plot_options.PlotPeriod = FBTime(0, 0, 0, 1)
|
|
plot_options.RotationFilterToApply = FBRotationFilter.kFBRotationFilterUnroll
|
|
plot_options.UseConstantKeyReducer = False
|
|
plot_options.ConstantKeyReducerKeepOneKey = True
|
|
plot_options.PlotTranslationOnRootOnly = False
|
|
|
|
return plot_options
|
|
|
|
|
|
def plotSelected():
|
|
opt = plotOptions()
|
|
FBSystem().CurrentTake.PlotTakeOnSelected(opt)
|
|
|
|
|
|
def initializeCH():
|
|
# -- Check for animation nodes. If we find them, display an error message
|
|
if keyedChannelCheck():
|
|
FBMessageBox("Quick Initialize CH Bones",
|
|
"WARNING:\n Please remove any keys from 'activate_L_constraint' and ''activate_R_constraint' on the coneMaster ",
|
|
"Continue")
|
|
|
|
else:
|
|
|
|
|
|
# -- Check to see if story mode is on
|
|
isStoryMuted = FBStory().Mute
|
|
|
|
# -- Then make sure its not muted and mute all the other tracks
|
|
FBStory().Mute = False
|
|
muteOtherCharTracks()
|
|
|
|
# -- Then make sure its muted
|
|
FBStory().Mute = True
|
|
|
|
# -- Find the FPS_Cam and CH bones for the current character
|
|
fpCam = findNode("FPS_Cam")
|
|
chBones = [findNode("CH_L_Hand"), findNode("CH_R_Hand")]
|
|
constraintFound = None
|
|
coneMFound = None
|
|
|
|
# -- If both ch bones are found
|
|
if chBones[0] and chBones[1]:
|
|
# -- And the first person camera is found
|
|
if fpCam:
|
|
# -- Switch on the cam constraint
|
|
constraintFound = activateCamConstraint()
|
|
|
|
# -- If the cam constraint was found
|
|
if constraintFound:
|
|
# --Switch on the CH Driver constraints
|
|
coneMFound = activateCHConstraints(True)
|
|
|
|
# -- If the cone master was found
|
|
if coneMFound:
|
|
# --Plot the CH bones to the selected takes
|
|
|
|
|
|
for comp in FBSystem().Scene.Components:
|
|
comp.Selected = False
|
|
|
|
for bone in chBones:
|
|
bone.Selected = True
|
|
|
|
plotSelected()
|
|
|
|
for bone in chBones:
|
|
bone.Selected = False
|
|
|
|
# --Switch off the CH Driver constraints
|
|
activateCHConstraints(False)
|
|
|
|
# -- If no ch bones were found let the user know
|
|
else:
|
|
FBMessageBox("Quick Initialize CH Bones",
|
|
"WARNING:\n No CH DOFs found for current character. ",
|
|
"Continue")
|
|
|
|
# -- Set story mode back to how it was
|
|
FBStory().Mute = isStoryMuted
|
|
del (fpCam, chBones, isStoryMuted, constraintFound, coneMFound)
|
|
|
|
|
|
def keyedChannelCheck():
|
|
# -- Find the cone master
|
|
coneM = findNode("coneMaster")
|
|
# -- Create an empty list to be filled with animation nodes
|
|
animNodes = []
|
|
|
|
if coneM:
|
|
# -- For each CH driver, see if it has an animation node. If so, add it to the list.
|
|
for prop in coneM.PropertyList:
|
|
if prop.Name == "activate_L_constraint":
|
|
animNodes.append(prop.GetAnimationNode())
|
|
|
|
if prop.Name == "activate_R_constraint":
|
|
animNodes.append(prop.GetAnimationNode())
|
|
|
|
# -- If any animation nodes ar found return true
|
|
if any(animNodes):
|
|
return True
|
|
|
|
# -- otherwise false
|
|
else:
|
|
return False
|
|
|
|
|
|
def ch_to_story():
|
|
chBones = [findNode("CH_L_Hand"), findNode("CH_R_Hand")]
|
|
|
|
# -- Create a story track and clip for the current character
|
|
track = FBStoryTrack(FBStoryTrackType.kFBStoryTrackAnimation, FBStory().RootFolder)
|
|
track.ChangeDetailsBegin()
|
|
for bone in chBones:
|
|
track.Details.append(bone)
|
|
track.ChangeDetailsEnd()
|
|
track.Label = FBSystem().CurrentTake.Name
|
|
clip = track.CopyTakeIntoTrack(FBSystem().CurrentTake.LocalTimeSpan, FBSystem().CurrentTake)
|
|
|
|
return track
|
|
|
|
|
|
def muteOtherCharTracks():
|
|
tracks = []
|
|
|
|
for lTrack in FBStory().RootFolder.Tracks:
|
|
lTrack.Mute = True
|
|
print lTrack.Name + " MUTED"
|
|
print lTrack.Mute
|
|
tracks.append(lTrack)
|
|
|
|
return tracks
|
|
|
|
|
|
def transfer():
|
|
FBSystem().Scene.Evaluate()
|
|
take = FBSystem().CurrentTake
|
|
chBones = [findNode("CH_L_Hand"), findNode("CH_R_Hand")]
|
|
|
|
if take.Name.endswith("_FirstPersonPreview"):
|
|
source_take_name = take.Name.rpartition("_")[0]
|
|
source_take = None
|
|
|
|
# switch to non preview take
|
|
for t in FBSystem().Scene.Takes:
|
|
if t.Name == source_take_name:
|
|
source_take = t
|
|
|
|
if source_take:
|
|
dup_take = take.CopyTake("TEMP_" + take.Name)
|
|
FBSystem().Scene.Evaluate()
|
|
initializeCH()
|
|
|
|
# add to story
|
|
isStoryMuted = FBStory().Mute
|
|
track = ch_to_story()
|
|
FBStory().Mute = False
|
|
|
|
FBSystem().CurrentTake = source_take
|
|
FBSystem().Scene.Evaluate()
|
|
|
|
for comp in FBSystem().Scene.Components:
|
|
comp.Selected = False
|
|
|
|
for bone in chBones:
|
|
bone.Selected = True
|
|
|
|
plotSelected()
|
|
|
|
for bone in chBones:
|
|
bone.Selected = False
|
|
|
|
# delete story and delete dup take
|
|
dup_take.FBDelete()
|
|
track.FBDelete()
|
|
FBStory().Mute = isStoryMuted
|
|
FBSystem().CurrentTake = take
|
|
|
|
else:
|
|
FBMessageBox("Quick Initialize CH Bones",
|
|
"WARNING:\n No source take found for: " + take.Name,
|
|
"Continue")
|
|
|
|
else:
|
|
FBMessageBox("Quick Initialize CH Bones",
|
|
"WARNING:\n" + take.Name + " is not a First Person Preview Take.",
|
|
"Continue")
|
|
|
|
|
|
def run():
|
|
# -- If more than 1 take is selected,
|
|
if getNumberOfSelectedTakes() > 1:
|
|
selected_takes = []
|
|
# -- go through each take
|
|
for take in FBSystem().Scene.Takes:
|
|
# -- If it is selected
|
|
if take.Selected:
|
|
selected_takes.append(take)
|
|
|
|
for take in selected_takes:
|
|
# -- Plot selected models to it
|
|
FBSystem().CurrentTake = take
|
|
transfer()
|
|
|
|
else:
|
|
transfer()
|
|
|
|
|
|
run()
|
|
pythonidelib.FlushOutput()
|
|
|
|
# For each selected take
|
|
# Duplicate it
|
|
# Initialize the CH bones on it
|
|
# Add the CH bones to story mode
|
|
# Go to the "non preview" take and plot the ch bones
|
|
# Delete the duplicate take
|
|
from pyfbsdk import *
|
|
|
|
|
|
def closest(list, Number):
|
|
aux = []
|
|
for valor in list:
|
|
aux.append(abs(Number - valor))
|
|
|
|
return aux.index(min(aux))
|
|
|
|
|
|
def ListMarkedTakes():
|
|
lSystem = FBSystem()
|
|
markedTakes = []
|
|
|
|
for lTakeIdx in range(len(lSystem.Scene.Takes)):
|
|
if lSystem.Scene.Takes[lTakeIdx].Name.startswith('>>>---'):
|
|
markedTakes.append(lTakeIdx)
|
|
|
|
return markedTakes
|
|
|
|
|
|
def NextMarkedTake():
|
|
lSystem = FBSystem()
|
|
lCurrentTakeName = lSystem.CurrentTake.Name
|
|
markedTakes = ListMarkedTakes()
|
|
|
|
# Look in the list until we find the index of the current take.
|
|
|
|
if len(markedTakes) > 0:
|
|
for lTakeIdx in range(len(lSystem.Scene.Takes)):
|
|
if lSystem.Scene.Takes[lTakeIdx].Name == lCurrentTakeName:
|
|
if lTakeIdx in markedTakes:
|
|
lMarkedIdx = markedTakes.index(lTakeIdx)
|
|
else:
|
|
lMarkedIdx = closest(markedTakes, lTakeIdx)
|
|
|
|
break;
|
|
|
|
# Increment the index to point to the next take.
|
|
lMarkedIdx = lMarkedIdx + 1
|
|
|
|
# Wrap around the end if the current take is the last.
|
|
if lMarkedIdx == len(markedTakes): lMarkedIdx = 0
|
|
|
|
# Set the current take using our new index.
|
|
lSystem.CurrentTake = lSystem.Scene.Takes[markedTakes[lMarkedIdx]]
|
|
|
|
# Cleanup of local variables.
|
|
del lMarkedIdx
|
|
|
|
del (lSystem, lCurrentTakeName, markedTakes)
|
|
|
|
|
|
NextMarkedTake()
|
|
################################################
|
|
# -- Lifted from Animal Tools created by Mangesh
|
|
################################################
|
|
|
|
from pyfbsdk import *
|
|
|
|
|
|
def NextTake():
|
|
lSystem = FBSystem()
|
|
lCurrentTakeName = lSystem.CurrentTake.Name
|
|
|
|
# Look in the list until we find the index of the current take.
|
|
for lTakeIdx in range( len( lSystem.Scene.Takes )):
|
|
if lSystem.Scene.Takes[lTakeIdx].Name == lCurrentTakeName:
|
|
break;
|
|
|
|
# Increment the index to point to the next take.
|
|
lTakeIdx = lTakeIdx + 1
|
|
|
|
# Wrap around the end if the current take is the last.
|
|
if lTakeIdx == len( lSystem.Scene.Takes ): lTakeIdx = 0
|
|
|
|
# Set the current take using our new index.
|
|
lSystem.CurrentTake = lSystem.Scene.Takes[lTakeIdx]
|
|
|
|
# Cleanup of local variables.
|
|
del( lSystem, lCurrentTakeName, lTakeIdx )
|
|
|
|
NextTake()
|
|
from pyfbsdk import *
|
|
|
|
|
|
def closest(list, Number):
|
|
aux = []
|
|
for valor in list:
|
|
aux.append(abs(Number - valor))
|
|
|
|
return aux.index(min(aux))
|
|
|
|
|
|
def ListMarkedTakes():
|
|
lSystem = FBSystem()
|
|
markedTakes = []
|
|
|
|
for lTakeIdx in range(len(lSystem.Scene.Takes)):
|
|
if lSystem.Scene.Takes[lTakeIdx].Name.startswith('>>>---'):
|
|
markedTakes.append(lTakeIdx)
|
|
|
|
return markedTakes
|
|
|
|
|
|
def PrevMarkedTake():
|
|
lSystem = FBSystem()
|
|
lCurrentTakeName = lSystem.CurrentTake.Name
|
|
markedTakes = ListMarkedTakes()
|
|
|
|
if len(markedTakes) > 0:
|
|
# Look in the list until we find the index of the current take.
|
|
for lTakeIdx in range(len(lSystem.Scene.Takes)):
|
|
if lSystem.Scene.Takes[lTakeIdx].Name == lCurrentTakeName:
|
|
if lTakeIdx in markedTakes:
|
|
lMarkedIdx = markedTakes.index(lTakeIdx)
|
|
else:
|
|
lMarkedIdx = closest(markedTakes, lTakeIdx)
|
|
|
|
break;
|
|
|
|
|
|
# Decrement the index to point to the next take.
|
|
# Here we take advantage of Python's subscripting access
|
|
# where -1 points to the last object in the list, which is
|
|
# where we want to be if the current take is the first in
|
|
# the list.
|
|
lMarkedIdx = lMarkedIdx - 1
|
|
|
|
|
|
# Set the current take using our new index.
|
|
lSystem.CurrentTake = lSystem.Scene.Takes[markedTakes[lMarkedIdx]]
|
|
|
|
# Cleanup of local variables.
|
|
del lMarkedIdx
|
|
|
|
del (lSystem, lCurrentTakeName, markedTakes)
|
|
|
|
|
|
PrevMarkedTake()
|
|
################################################
|
|
# -- Lifted from Animal Tools created by Mangesh
|
|
################################################
|
|
from pyfbsdk import *
|
|
|
|
def PrevTake():
|
|
lSystem = FBSystem()
|
|
lCurrentTakeName = lSystem.CurrentTake.Name
|
|
|
|
# Look in the list until we find the index of the current take.
|
|
for lTakeIdx in range( len( lSystem.Scene.Takes )):
|
|
if lSystem.Scene.Takes[lTakeIdx].Name == lCurrentTakeName:
|
|
break;
|
|
|
|
# Decrement the index to point to the next take.
|
|
# Here we take advantage of Python's subscripting access
|
|
# where -1 points to the last object in the list, which is
|
|
# where we want to be if the current take is the first in
|
|
# the list.
|
|
lTakeIdx = lTakeIdx - 1
|
|
|
|
# Set the current take using our new index.
|
|
lSystem.CurrentTake = lSystem.Scene.Takes[lTakeIdx]
|
|
|
|
# Cleanup of local variables.
|
|
del( lSystem, lCurrentTakeName, lTakeIdx )
|
|
|
|
PrevTake()
|
|
from pyfbsdk import *
|
|
from pyfbsdk_additions import *
|
|
import pythonidelib
|
|
from RS.Utils import Scene
|
|
from RS import Globals
|
|
from RS.Utils import Namespace, Creation
|
|
|
|
|
|
####################################################################
|
|
# Utility Functions
|
|
####################################################################
|
|
|
|
def PlotOptions(allTakes=False):
|
|
# -- Default Options for plotting
|
|
|
|
plot_options = FBPlotOptions()
|
|
plot_options.PlotAllTakes = allTakes
|
|
plot_options.PlotOnFrame = True
|
|
plot_options.PlotPeriod = FBTime(0, 0, 0, 1)
|
|
plot_options.RotationFilterToApply = FBRotationFilter.kFBRotationFilterUnroll
|
|
plot_options.UseConstantKeyReducer = False
|
|
plot_options.ConstantKeyReducerKeepOneKey = True
|
|
plot_options.PlotTranslationOnRootOnly = False
|
|
|
|
return plot_options
|
|
|
|
|
|
def PlotModelList(listOfModels, allTakes=False):
|
|
# -- Take a list of models and plot them
|
|
Scene.DeSelectAll()
|
|
|
|
for model in listOfModels:
|
|
model.Selected = True
|
|
|
|
FBSystem().CurrentTake.PlotTakeOnSelected(PlotOptions(allTakes))
|
|
Scene.DeSelectAll()
|
|
|
|
|
|
def GetCharacterHeirarchyList(character):
|
|
# -- Find all nodes for the current chatacyer
|
|
characterNodeList = []
|
|
hips = character.GetModel(FBBodyNodeId.kFBHipsNodeId)
|
|
dummy = Scene.GetParent(hips)
|
|
Scene.GetChildren(dummy, characterNodeList, "", True)
|
|
return characterNodeList
|
|
|
|
|
|
def CreateMarker(name='Marker', look='HardCross', size=500, color=FBColor(1, 0, 0)):
|
|
# -- Quick function for creating markers
|
|
marker = FBModelMarker(name)
|
|
|
|
looksDict = {
|
|
"Cube": FBMarkerLook.kFBMarkerLookCube,
|
|
"HardCross": FBMarkerLook.kFBMarkerLookHardCross,
|
|
"LightCross": FBMarkerLook.kFBMarkerLookLightCross,
|
|
"Sphere": FBMarkerLook.kFBMarkerLookSphere,
|
|
"Capsule": FBMarkerLook.kFBMarkerLookCapsule,
|
|
"Stick": FBMarkerLook.kFBMarkerLookStick,
|
|
"Bone": FBMarkerLook.kFBMarkerLookBone,
|
|
"None": FBMarkerLook.kFBMarkerLookNone
|
|
}
|
|
|
|
if look in looksDict.keys():
|
|
lookEnum = looksDict.get(look)
|
|
else:
|
|
lookEnum = FBMarkerLook.kFBMarkerLookHardCross
|
|
|
|
marker.Show = True
|
|
marker.Look = lookEnum
|
|
marker.PropertyList.Find("Size").Data = size
|
|
marker.PropertyList.Find("Color RGB").Data = color
|
|
return marker
|
|
|
|
|
|
def SwapConstraint(constraint):
|
|
# -- Take a constraint and switch the 'Source' and 'objects
|
|
|
|
child = constraint.ReferenceGet(0, 0)
|
|
parent = constraint.ReferenceGet(1, 0)
|
|
|
|
constraint.Active = False
|
|
constraint.Lock = False
|
|
|
|
constraint.ReferenceRemove(0, child)
|
|
constraint.ReferenceRemove(1, parent)
|
|
|
|
Globals.Scene.Evaluate()
|
|
|
|
constraint.ReferenceAdd(0, parent)
|
|
constraint.ReferenceAdd(1, child)
|
|
|
|
constraint.Snap()
|
|
constraint.Lock = True
|
|
|
|
Globals.Scene.Evaluate()
|
|
|
|
|
|
####################################################################
|
|
# UI Functions
|
|
####################################################################
|
|
|
|
def PopulateTool(t):
|
|
# -- Create a region for the main button
|
|
x = FBAddRegionParam(5, FBAttachType.kFBAttachTop, "")
|
|
y = FBAddRegionParam(5, FBAttachType.kFBAttachNone, "")
|
|
w = FBAddRegionParam(240, FBAttachType.kFBAttachNone, "")
|
|
h = FBAddRegionParam(30, FBAttachType.kFBAttachNone, "")
|
|
t.AddRegion("main_button_region", "main_button_region", x, y, w, h)
|
|
|
|
# -- Create the main button
|
|
t.create_button = FBButton()
|
|
t.SetControl("main_button_region", t.create_button)
|
|
t.create_button.Visible = True
|
|
t.create_button.ReadOnly = False
|
|
t.create_button.Enabled = True
|
|
t.create_button.Hint = ""
|
|
t.create_button.Caption = "Create Camera Space Setup"
|
|
t.create_button.State = 0
|
|
t.create_button.Style = FBButtonStyle.kFBPushButton
|
|
t.create_button.Justify = FBTextJustify.kFBTextJustifyCenter
|
|
t.create_button.Look = FBButtonLook.kFBLookNormal
|
|
t.create_button.OnClick.Add(MainButtonCallback)
|
|
|
|
# -- Set a bool to check if the setup has been created yet
|
|
t.created = False
|
|
|
|
ShowTool(t)
|
|
|
|
|
|
def AddDeleteButton(t):
|
|
# -- Add a second button the the UI
|
|
|
|
# -- Create a region for the delete button
|
|
x = FBAddRegionParam(5, FBAttachType.kFBAttachBottom, "")
|
|
y = FBAddRegionParam(40, FBAttachType.kFBAttachNone, "")
|
|
w = FBAddRegionParam(240, FBAttachType.kFBAttachNone, "")
|
|
h = FBAddRegionParam(30, FBAttachType.kFBAttachNone, "")
|
|
t.AddRegion("delete_button_region", "delete_button_region", x, y, w, h)
|
|
|
|
# -- Create the delete button
|
|
t.delete_button = FBButton()
|
|
t.SetControl("delete_button_region", t.delete_button)
|
|
t.delete_button.Visible = True
|
|
t.delete_button.ReadOnly = False
|
|
t.delete_button.Enabled = True
|
|
t.delete_button.Hint = ""
|
|
t.delete_button.Caption = "Delete Camera Space Setup"
|
|
t.delete_button.State = 0
|
|
t.delete_button.Style = FBButtonStyle.kFBPushButton
|
|
t.delete_button.Justify = FBTextJustify.kFBTextJustifyCenter
|
|
t.delete_button.Look = FBButtonLook.kFBLookNormal
|
|
t.delete_button.OnClick.Add(DeleteSetup)
|
|
|
|
|
|
def CloseCallback(control, event):
|
|
# -- Close the UI
|
|
CloseTool(t)
|
|
|
|
|
|
def CreateTool():
|
|
# -- Create the UI
|
|
global t
|
|
|
|
t = FBCreateUniqueTool("Hands To First Person Space")
|
|
x = 250
|
|
y = 40
|
|
|
|
t.StartSizeX = x
|
|
t.MinSizeX = x
|
|
t.MaxSizeX = x
|
|
|
|
t.StartSizeY = y
|
|
t.MinSizeY = y
|
|
t.MaxSizeY = y
|
|
|
|
PopulateTool(t)
|
|
|
|
|
|
####################################################################
|
|
# Setup Functions
|
|
####################################################################
|
|
|
|
|
|
def MainButtonCallback(control, event):
|
|
# -- Check to see if our setup has already been created
|
|
if t.created == False:
|
|
# -- If it hasn't, create one
|
|
CreateSetup()
|
|
else:
|
|
# -- If it has, plot and delete
|
|
PlotAndDeleteSetup()
|
|
|
|
|
|
def CreateSetup():
|
|
# -- Find the current character
|
|
character = FBApplication().CurrentCharacter
|
|
|
|
# -- If a character is found
|
|
if character:
|
|
|
|
# -- Check to see if the character has a control rig
|
|
if character.GetCurrentControlSet() == None:
|
|
|
|
# -- If it doesn't, create one and plot from skeleton
|
|
character.CreateControlRig(True)
|
|
character.Active = False
|
|
currentTake = FBSystem().CurrentTake
|
|
|
|
for take_index in range(len(FBSystem().Scene.Takes)):
|
|
# go to take
|
|
FBSystem().CurrentTake = FBSystem().Scene.Takes[take_index]
|
|
character.PlotAnimation(FBCharacterPlotWhere.kFBCharacterPlotOnControlRig, PlotOptions())
|
|
|
|
FBSystem().CurrentTake = currentTake
|
|
|
|
# -- Set the character's source to "Control Rig"
|
|
character.Active = True
|
|
|
|
# -- Get all the character's nodes
|
|
characterNodes = GetCharacterHeirarchyList(character)
|
|
|
|
# -- Create an empty variable to be changed if we find a camera
|
|
fpCam = None
|
|
|
|
# -- Search through all the character's nodes for the first person camera
|
|
for node in characterNodes:
|
|
if node.Name == "FPS_Cam":
|
|
# -- If it is found, change the empty variable
|
|
fpCam = node
|
|
|
|
# -- If a FPS camera was found
|
|
if fpCam:
|
|
# -- FInd the characters wrist effects
|
|
lWrist = character.GetEffectorModel(FBEffectorId.kFBLeftWristEffectorId)
|
|
rWrist = character.GetEffectorModel(FBEffectorId.kFBRightWristEffectorId)
|
|
|
|
# -- Set the wrist IK to 100 on both wrists
|
|
lWrist.PropertyList.Find("IK Reach Translation").Data = 100
|
|
lWrist.PropertyList.Find("IK Reach Rotation").Data = 100
|
|
rWrist.PropertyList.Find("IK Reach Translation").Data = 100
|
|
rWrist.PropertyList.Find("IK Reach Rotation").Data = 100
|
|
|
|
# -- Create a custom marker for our root
|
|
camParent = CreateMarker("Root", 'Bone', 50, FBColor(0.0, 0.9, 1.0))
|
|
camParent.ProcessObjectNamespace(FBNamespaceAction.kFBConcatNamespace, "FPSpace")
|
|
camParent.PropertyList.Find("Enable Transformation").Data = 0
|
|
camParent.PropertyList.Find("Enable Selection").Data = 0
|
|
|
|
# -- Create two markers for our custom hand controls
|
|
lHandMarker = CreateMarker("Ctrl_LeftHand", 'Bone', 550, FBColor(0.0, 0.9, 1.0))
|
|
lHandMarker.ProcessObjectNamespace(FBNamespaceAction.kFBConcatNamespace, "FPSpace")
|
|
rHandMarker = CreateMarker("Ctrl_RightHand", 'Bone', 550, FBColor(0.0, 0.9, 1.0))
|
|
rHandMarker.ProcessObjectNamespace(FBNamespaceAction.kFBConcatNamespace, "FPSpace")
|
|
|
|
# -- Parent the hand controls to the root
|
|
lHandMarker.Parent = camParent
|
|
rHandMarker.Parent = camParent
|
|
|
|
# -- Create a new constraint folder
|
|
constraintFolder = Creation.rs_CreateFolder("Constraints", "FBConstraint")
|
|
constraintFolder.ProcessObjectNamespace(FBNamespaceAction.kFBConcatNamespace, "FPSpace")
|
|
|
|
# -- zero constrain the parent marker to the align point. Add a namespace
|
|
rootCon = Scene.Constraint.Constraint(
|
|
Scene.Constraint.PARENT_CHILD,
|
|
"FPS_Cam > Root",
|
|
camParent,
|
|
fpCam,
|
|
Active=True,
|
|
Lock=True
|
|
)
|
|
|
|
# -- Add the constraint to the constraint folder and add a namespace
|
|
constraintFolder.Items.append(rootCon)
|
|
rootCon.ProcessObjectNamespace(FBNamespaceAction.kFBConcatNamespace, "FPSpace")
|
|
|
|
# -- zero constrain the left hand marker to the left hand. Add a namespace
|
|
lHandCon = Scene.Constraint.Constraint(
|
|
Scene.Constraint.PARENT_CHILD,
|
|
"Ctrl_LeftHand > LeftWristEffector",
|
|
lHandMarker,
|
|
lWrist,
|
|
Active=True,
|
|
Lock=True
|
|
)
|
|
|
|
# -- Add the constraint to the constraint folder and add a namespace
|
|
constraintFolder.Items.append(lHandCon)
|
|
lHandCon.ProcessObjectNamespace(FBNamespaceAction.kFBConcatNamespace, "FPSpace")
|
|
|
|
# -- zero constrain the left hand marker to the left hand. Add a namespace
|
|
rHandCon = Scene.Constraint.Constraint(
|
|
Scene.Constraint.PARENT_CHILD,
|
|
"Ctrl_RightHand > RightWristEffector",
|
|
rHandMarker,
|
|
rWrist,
|
|
Active=True,
|
|
Lock=True
|
|
)
|
|
|
|
# -- Add the constraint to the constraint folder and add a namespace
|
|
constraintFolder.Items.append(rHandCon)
|
|
rHandCon.ProcessObjectNamespace(FBNamespaceAction.kFBConcatNamespace, "FPSpace")
|
|
|
|
Globals.Scene.Evaluate()
|
|
|
|
# -- Plot the custom hand controls and flip the constraints
|
|
PlotModelList([lHandMarker, rHandMarker], allTakes=True)
|
|
Globals.Scene.Evaluate()
|
|
SwapConstraint(lHandCon)
|
|
SwapConstraint(rHandCon)
|
|
|
|
# -- Change the main button's caption
|
|
t.create_button.Caption = "Plot and Delete Camera Space Setup"
|
|
|
|
# -- Set a bool to check if the setup has been created yet
|
|
t.created = True
|
|
t.create_button.OnClick.Add(PlotAndDeleteSetup)
|
|
|
|
# -- Run function that adds a new button
|
|
AddDeleteButton(t)
|
|
|
|
# -- Add some length to the UI to make room for the new button
|
|
y = 75
|
|
t.MinSizeY = y
|
|
t.MaxSizeY = y
|
|
|
|
|
|
def PlotAndDeleteSetup(control=None, event=None):
|
|
# -- Find the current Character
|
|
character = FBApplication().CurrentCharacter
|
|
|
|
# -- If a character was found
|
|
if character:
|
|
|
|
# -- Find the character's wrist effectors
|
|
lWrist = character.GetEffectorModel(FBEffectorId.kFBLeftWristEffectorId)
|
|
rWrist = character.GetEffectorModel(FBEffectorId.kFBRightWristEffectorId)
|
|
|
|
# -- If both wrists were found
|
|
if lWrist and rWrist:
|
|
# -- Plot them on all takes
|
|
PlotModelList([lWrist, rWrist], allTakes=True)
|
|
|
|
# -- Delete the entire setup
|
|
Globals.Scene.Evaluate()
|
|
DeleteSetup()
|
|
|
|
|
|
def DeleteSetup(control=None, event=None):
|
|
# -- We gave all of objects and constraints in the setup a namespace
|
|
# -- Get this namespace
|
|
nameSpace = Namespace.GetFBNamespace("FPSpace")
|
|
|
|
if nameSpace:
|
|
# -- Delete all of the namespace's contents
|
|
for item in Namespace.GetContents(nameSpace):
|
|
item.FBDelete()
|
|
Globals.Scene.Evaluate()
|
|
|
|
# -- Delete the namespace
|
|
nameSpace.FBDelete()
|
|
del (nameSpace)
|
|
|
|
# -- Close the UI
|
|
CloseCallback(None, None)
|
|
|
|
|
|
CreateTool()
|
|
from pyfbsdk import *
|
|
import pythonidelib
|
|
from RS import Globals
|
|
from RS.Utils.Scene import Component, Groups, GetParent, GetChildren
|
|
|
|
def getCharacterHeirarchyList(character):
|
|
characterNodeList = []
|
|
hips = character.GetModel(FBBodyNodeId.kFBHipsNodeId)
|
|
dummy = GetParent(hips)
|
|
GetChildren(dummy, characterNodeList, "", True)
|
|
return characterNodeList
|
|
|
|
def findNode(name):
|
|
|
|
foundNode = None
|
|
|
|
# -- Get list of all nodes of current character
|
|
currentCharacter = FBApplication().CurrentCharacter
|
|
characterNodeList = getCharacterHeirarchyList(currentCharacter)
|
|
|
|
|
|
# -- Check each node to see if it matches the desired name
|
|
for node in characterNodeList:
|
|
if node.Name == name:
|
|
foundNode = node
|
|
|
|
del (currentCharacter, characterNodeList)
|
|
return foundNode
|
|
|
|
# -- Make a lest of meshes to add to group
|
|
hideMeshes = [
|
|
findNode('player_zero_head_000'),
|
|
findNode('player_zero_eyes_000'),
|
|
findNode('player_zero_eyebrows_000'),
|
|
findNode('player_zero_teeth_000'),
|
|
]
|
|
|
|
|
|
groupnames = []
|
|
|
|
for group in Globals.Groups:
|
|
groupnames.append(group.Name)
|
|
|
|
# -- If any animation nodes ar found return true
|
|
if "HeadMeshes" in groupnames:
|
|
for group in Globals.Groups:
|
|
if group.Name == "HeadMeshes":
|
|
headGroup = group
|
|
else:
|
|
headGroup = FBGroup ("HeadMeshes")
|
|
|
|
|
|
# -- If those meshes were found, select them them
|
|
for mesh in hideMeshes:
|
|
if mesh:
|
|
# Adding the objects to the group
|
|
headGroup.ConnectSrc(mesh)
|
|
|
|
headGroup.Pickable = False
|
|
|
|
|
|
if headGroup.Show == True:
|
|
headGroup.Show = False
|
|
else:
|
|
headGroup.Show = Truefrom pyfbsdk import *
|
|
from RS.Utils.Scene import Component, Groups, GetParent, GetChildren
|
|
|
|
def getCharacterHeirarchyList(character):
|
|
characterNodeList = []
|
|
hips = character.GetModel(FBBodyNodeId.kFBHipsNodeId)
|
|
dummy = GetParent(hips)
|
|
GetChildren(dummy, characterNodeList, "", True)
|
|
return characterNodeList
|
|
|
|
def findNode(name):
|
|
|
|
foundNode = None
|
|
|
|
# -- Get list of all nodes of current character
|
|
currentCharacter = FBApplication().CurrentCharacter
|
|
characterNodeList = getCharacterHeirarchyList(currentCharacter)
|
|
|
|
|
|
# -- Check each node to see if it matches the desired name
|
|
for node in characterNodeList:
|
|
if node.Name == name:
|
|
foundNode = node
|
|
|
|
del (currentCharacter, characterNodeList)
|
|
return foundNode
|
|
|
|
# -- Get the namespace of the current character
|
|
charNSpace = Component.GetNamespace(FBApplication().CurrentCharacter)
|
|
|
|
# -- Get all groups associated with this namespace
|
|
groups = Groups.GetGroupsFromNamespace(charNSpace)
|
|
|
|
# -- Switch off the werables groups
|
|
for group in groups:
|
|
if group.Name == 'Wearables_Other' \
|
|
or group.Name == 'Wearables_Outfit' \
|
|
or group.Name == 'Sliders' \
|
|
or group.Name == 'FPSCamera':
|
|
group.Show = False
|
|
|
|
if group.Name == 'Geometry':
|
|
group.Pickable = False
|
|
|
|
# -- Make a lest of meshes to hide
|
|
hideMeshes = [
|
|
findNode('player_zero_hair_000'),
|
|
findNode('player_zero_scarf_002'),
|
|
findNode('player_zero_scarf_002'),
|
|
findNode('player_zero_satchel_strap_000'),
|
|
findNode('CameraBasePivotOffset_Controller')
|
|
]
|
|
|
|
# -- If those meshes were found, hiden them
|
|
for mesh in hideMeshes:
|
|
if mesh:
|
|
mesh.Show = False####################################
|
|
# -- Quickly plot selected models --
|
|
####################################
|
|
from pyfbsdk import *
|
|
import pythonidelib
|
|
|
|
|
|
def getSelectedModels():
|
|
# -- Create an empty FBModelList
|
|
selectedModels = FBModelList()
|
|
|
|
topModel = None # -- Search all models, not just a particular branch
|
|
selectionState = True # -- Return models that are selected, not deselected
|
|
sortBySelectOrder = True # -- The last model in the list was selected most recently
|
|
FBGetSelectedModels(selectedModels, topModel, selectionState, sortBySelectOrder)
|
|
|
|
return selectedModels
|
|
|
|
|
|
def getNumberOfSelectedTakes():
|
|
number_of_selected_takes = 0
|
|
|
|
for take_index in range(len(FBSystem().Scene.Takes)):
|
|
if FBSystem().Scene.Takes[take_index].Selected == True:
|
|
number_of_selected_takes += 1
|
|
|
|
return number_of_selected_takes
|
|
|
|
|
|
def holdFirstFrame():
|
|
# -- Create an empty list to be filled with nodes that have curves
|
|
nodesWithCurves = []
|
|
|
|
# -- Create an empty dictionary for storing keyframe times
|
|
keyTimes = {}
|
|
|
|
# -- Create an empty list of frame times
|
|
keyFrames = []
|
|
|
|
# -- For each model selected
|
|
for model in getSelectedModels():
|
|
|
|
# -- Find its properties
|
|
for lProp in model.PropertyList:
|
|
# -- For each property, find if it is animated
|
|
if lProp and lProp.IsAnimatable() and lProp.IsAnimated():
|
|
|
|
# ======== Finding Nodes capable of having FCurves =======
|
|
|
|
# -- If so, get the connected animation node
|
|
animNode = lProp.GetAnimationNode()
|
|
|
|
# -- Find all children nodes of the connected animation node
|
|
nodes = animNode.Nodes
|
|
# -- If children nodes are found
|
|
if len(nodes) > 0:
|
|
# -- Add each one to our list
|
|
for node in nodes:
|
|
nodesWithCurves.append(node)
|
|
|
|
# -- Otherwise add the anim node to our list
|
|
else:
|
|
nodesWithCurves.append(animNode)
|
|
|
|
# ======== Finding Selected Keyframes ==========
|
|
|
|
# -- For every node in our list
|
|
for node in nodesWithCurves:
|
|
|
|
# -- reset the selected key times dictionary
|
|
curveKeys = node.FCurve.Keys
|
|
keyTimes = {}
|
|
|
|
# -- If the node has an FCurve
|
|
if node.FCurve:
|
|
|
|
# -- For each keyframe on the FCurve
|
|
for key in curveKeys:
|
|
print key
|
|
pythonidelib.FlushOutput()
|
|
# -- Add the keyframe's time to the dictionary
|
|
keyTimes[key.Time.GetFrame()] = key.Time
|
|
|
|
# -- Fill the list with the frame data from the dictionary
|
|
for key in keyTimes:
|
|
print key
|
|
pythonidelib.FlushOutput()
|
|
keyFrames.append(key)
|
|
|
|
# -- Find the lowest number in the frame list. This will be our starting frame
|
|
firstKey = min(keyFrames)
|
|
secondKeyTime = FBTime(0, 0, 0, firstKey+1)
|
|
lastKey = max(keyFrames)
|
|
lastKeyTime = FBTime(0, 0, 0, lastKey)
|
|
|
|
print firstKey
|
|
print lastKey
|
|
pythonidelib.FlushOutput()
|
|
|
|
node.FCurve.KeyDeleteByTimeRange(secondKeyTime, lastKeyTime)
|
|
|
|
# -- Cleanup
|
|
del (nodesWithCurves, keyTimes, keyFrames)
|
|
|
|
|
|
def Run():
|
|
# -- If at least one model is selected
|
|
if len(getSelectedModels()) > 0:
|
|
|
|
# -- If more than 1 take is selected,
|
|
if getNumberOfSelectedTakes() > 1:
|
|
# -- go through each take
|
|
for take in FBSystem().Scene.Takes:
|
|
# -- If it is selected
|
|
if take.Selected == True:
|
|
# -- Plot selected models to it
|
|
FBSystem().CurrentTake = take
|
|
holdFirstFrame()
|
|
|
|
|
|
|
|
# -- annoying when you have one take selected different from the current - chances are the user didn't mean to.
|
|
else:
|
|
# -- Plot selected to current taKE
|
|
holdFirstFrame()
|
|
|
|
print "Plotting Complete"
|
|
else:
|
|
print "No Objects selected"
|
|
|
|
|
|
Run()
|
|
from pyfbsdk import *
|
|
from pyfbsdk_additions import *
|
|
import pythonidelib
|
|
|
|
|
|
# -- For each constraint in the scene
|
|
for con in FBSystem().Scene.Constraints:
|
|
|
|
# -- For each constraint that is selected
|
|
if con.Selected == True:
|
|
|
|
# -- Set the weight channel as animated
|
|
con.Weight.SetAnimated(True)
|
|
|
|
# -- Apply the animation node and curve to variable
|
|
weightNode = con.Weight.GetAnimationNode()
|
|
weightCurve = weightNode.FCurve
|
|
|
|
# -- Create a key with value 0 at the current frame
|
|
key = weightCurve.KeyAdd(FBSystem().LocalTime, 0)
|
|
|
|
# -- Assign the key to a variable
|
|
weightKey = weightCurve.Keys[key]
|
|
|
|
# -- Set the key to Auto and Clamped
|
|
weightKey.TangentMode = FBTangentMode(2)
|
|
weightKey.TangentClampMode = FBTangentClampMode(1)
|
|
|
|
pythonidelib.FlushOutput()
|
|
|
|
from pyfbsdk import *
|
|
from pyfbsdk_additions import *
|
|
import pythonidelib
|
|
|
|
# -- For each constraint in the scene
|
|
for con in FBSystem().Scene.Constraints:
|
|
|
|
# -- For each constraint that is selected
|
|
if con.Selected == True:
|
|
# -- Set the weight channel as animated
|
|
con.Weight.SetAnimated(True)
|
|
|
|
# -- Apply the animation node and curve to variable
|
|
weightNode = con.Weight.GetAnimationNode()
|
|
weightCurve = weightNode.FCurve
|
|
|
|
# -- Create a key with value 100 at the current frame
|
|
key = weightCurve.KeyAdd(FBSystem().LocalTime, 100)
|
|
|
|
# -- Assign the key to a variable
|
|
weightKey = weightCurve.Keys[key]
|
|
|
|
# -- Set the key to Auto and Clamped
|
|
weightKey.TangentMode = FBTangentMode(2)
|
|
weightKey.TangentClampMode = FBTangentClampMode(1)
|
|
|
|
pythonidelib.FlushOutput()
|
|
|
|
from pyfbsdk import *
|
|
from pyfbsdk_additions import *
|
|
|
|
def getSelectedModels():
|
|
|
|
# -- Create an empty FBModelList
|
|
selectedModels = FBModelList()
|
|
|
|
topModel = None # -- Search all models, not just a particular branch
|
|
selectionState = True # -- Return models that are selected, not deselected
|
|
sortBySelectOrder = True # -- The last model in the list was selected most recently
|
|
FBGetSelectedModels(selectedModels, topModel, selectionState, sortBySelectOrder)
|
|
|
|
return selectedModels
|
|
|
|
def keySelectedIKOn(selected):
|
|
|
|
for model in selected:
|
|
ik_T = model.PropertyList.Find('IK Reach Translation')
|
|
ik_R = model.PropertyList.Find('IK Reach Rotation')
|
|
|
|
IKChannels = [ik_T, ik_R]
|
|
|
|
for channel in IKChannels:
|
|
|
|
if channel:
|
|
# -- Set the channel as animated
|
|
channel.SetAnimated(True)
|
|
|
|
# -- Apply the animation node and curve to variable
|
|
channelNode = channel.GetAnimationNode()
|
|
channelCurve = channelNode.FCurve
|
|
|
|
# -- Create a key with value 100 at the current frame
|
|
key = channelCurve.KeyAdd(FBSystem().LocalTime, 0)
|
|
|
|
# -- Assign the key to a variable
|
|
channelKey = channelCurve.Keys[key]
|
|
|
|
# -- Set the key to Auto and Clamped
|
|
channelKey.TangentMode = FBTangentMode(2)
|
|
channelKey.TangentClampMode = FBTangentClampMode(1)
|
|
|
|
|
|
keySelectedIKOn(getSelectedModels())
|
|
|
|
|
|
|
|
|
|
from pyfbsdk import *
|
|
from pyfbsdk_additions import *
|
|
|
|
def getSelectedModels():
|
|
|
|
# -- Create an empty FBModelList
|
|
selectedModels = FBModelList()
|
|
|
|
topModel = None # -- Search all models, not just a particular branch
|
|
selectionState = True # -- Return models that are selected, not deselected
|
|
sortBySelectOrder = True # -- The last model in the list was selected most recently
|
|
FBGetSelectedModels(selectedModels, topModel, selectionState, sortBySelectOrder)
|
|
|
|
return selectedModels
|
|
|
|
def keySelectedIKOn(selected):
|
|
|
|
for model in selected:
|
|
ik_T = model.PropertyList.Find('IK Reach Translation')
|
|
ik_R = model.PropertyList.Find('IK Reach Rotation')
|
|
|
|
IKChannels = [ik_T, ik_R]
|
|
|
|
for channel in IKChannels:
|
|
|
|
if channel:
|
|
# -- Set the channel as animated
|
|
channel.SetAnimated(True)
|
|
|
|
# -- Apply the animation node and curve to variable
|
|
channelNode = channel.GetAnimationNode()
|
|
channelCurve = channelNode.FCurve
|
|
|
|
# -- Create a key with value 100 at the current frame
|
|
key = channelCurve.KeyAdd(FBSystem().LocalTime, 100)
|
|
|
|
# -- Assign the key to a variable
|
|
channelKey = channelCurve.Keys[key]
|
|
|
|
# -- Set the key to Auto and Clamped
|
|
channelKey.TangentMode = FBTangentMode(2)
|
|
channelKey.TangentClampMode = FBTangentClampMode(1)
|
|
|
|
|
|
keySelectedIKOn(getSelectedModels())
|
|
|
|
|
|
|
|
|
|
from pyfbsdk import *
|
|
|
|
takes = FBSystem().Scene.Takes
|
|
|
|
|
|
def getNumberOfSelectedTakes():
|
|
number_of_selected_takes = 0
|
|
|
|
for take_index in range(len(FBSystem().Scene.Takes)):
|
|
if FBSystem().Scene.Takes[take_index].Selected == True:
|
|
number_of_selected_takes += 1
|
|
|
|
return number_of_selected_takes
|
|
|
|
|
|
if getNumberOfSelectedTakes() > 0:
|
|
for take in takes:
|
|
if take.Selected:
|
|
|
|
newName = '>>>---' + take.Name
|
|
take.Name = newName
|
|
else:
|
|
newName = '>>>---' + FBSystem().CurrentTake.Name
|
|
FBSystem().CurrentTake.Name = newName
|
|
|
|
####################################################
|
|
# Uses story mode to move the current take to zero
|
|
####################################################
|
|
from pyfbsdk import *
|
|
import pythonidelib
|
|
|
|
|
|
# =================== Taken from Mike's mj_QuickPlot script ========================
|
|
|
|
def plotOptions():
|
|
plot_options = FBPlotOptions()
|
|
plot_options.PlotAllTakes = False
|
|
plot_options.PlotOnFrame = True
|
|
plot_options.PlotPeriod = FBTime(0, 0, 0, 1)
|
|
plot_options.RotationFilterToApply = FBRotationFilter.kFBRotationFilterUnroll
|
|
plot_options.UseConstantKeyReducer = False
|
|
plot_options.ConstantKeyReducerKeepOneKey = True
|
|
plot_options.PlotTranslationOnRootOnly = False
|
|
|
|
return plot_options
|
|
|
|
|
|
def getNumberOfSelectedTakes():
|
|
number_of_selected_takes = 0
|
|
|
|
for take_index in range(len(FBSystem().Scene.Takes)):
|
|
if FBSystem().Scene.Takes[take_index].Selected == True:
|
|
number_of_selected_takes += 1
|
|
|
|
return number_of_selected_takes
|
|
|
|
|
|
def plotToRig(character):
|
|
character.PlotAnimation(FBCharacterPlotWhere.kFBCharacterPlotOnControlRig, plotOptions())
|
|
|
|
|
|
def plotToSkeleton(character):
|
|
character.PlotAnimation(FBCharacterPlotWhere.kFBCharacterPlotOnSkeleton, plotOptions())
|
|
|
|
|
|
# =====================================================================================
|
|
|
|
def muteOtherCharTracks():
|
|
|
|
currChar = FBApplication().CurrentCharacter
|
|
|
|
charTracks = []
|
|
|
|
for lTrack in FBStory().RootFolder.Tracks:
|
|
|
|
lChar = lTrack.PropertyList.Find('Character')
|
|
|
|
if lChar is not None:
|
|
for d in lTrack.Details:
|
|
if d == currChar:
|
|
if lTrack.Mute == False:
|
|
lTrack.Mute = True
|
|
charTracks.append(lTrack)
|
|
print "Story Track: %s temporarily muted" % lTrack.Name
|
|
|
|
return charTracks
|
|
|
|
def enableMutedTracks(charTracks):
|
|
|
|
for lTrack in charTracks:
|
|
lTrack.Mute = False
|
|
print "Story Track: %s unmuted" % lTrack.Name
|
|
|
|
def zeroStoryAndPlot(to_skeleton = True):
|
|
|
|
|
|
# -- Assign important stuff to variables
|
|
app = FBApplication()
|
|
system = FBSystem()
|
|
story = FBStory()
|
|
take = system.CurrentTake
|
|
char = FBApplication().CurrentCharacter
|
|
|
|
# -- Create a story track and clip for the current character
|
|
track = FBStoryTrack(FBStoryTrackType.kFBStoryTrackCharacter, story.RootFolder)
|
|
track.Details.append(char)
|
|
track.Label = system.CurrentTake.Name
|
|
clip = track.CopyTakeIntoTrack(system.CurrentTake.LocalTimeSpan, system.CurrentTake)
|
|
|
|
# -- Set the start of the clip to zero
|
|
clip.PropertyList.Find('Start').Data = FBTime(0)
|
|
|
|
# -- Assign the new end of the clip to a variable
|
|
end = clip.PropertyList.Find('Stop').Data
|
|
|
|
# -- Set the start and end of the current take to match the story clip
|
|
take.LocalTimeSpan = FBTimeSpan(
|
|
FBTime(0),
|
|
end
|
|
)
|
|
|
|
# -- If the character rig is active, plot it to the skeleton and plot to it back to the rig
|
|
if to_skeleton == True:
|
|
plotToSkeleton(char)
|
|
plotToRig(char)
|
|
# -- Otherwise just plot it straight to the skeleton
|
|
else:
|
|
plotToSkeleton(char)
|
|
|
|
print "%s Moved to Zero" % (take.Name)
|
|
|
|
clip.FBDelete()
|
|
track.FBDelete()
|
|
|
|
def moveTakesToZero():
|
|
|
|
|
|
# -- Get the current character
|
|
current_character = FBApplication().CurrentCharacter
|
|
|
|
# -- Need to create control rig first?
|
|
if current_character.GetCurrentControlSet() == None:
|
|
current_character.CreateControlRig(True)
|
|
|
|
# -- Check if the current character is active
|
|
if current_character.Active == True:
|
|
to_skeleton = True
|
|
else:
|
|
to_skeleton = False
|
|
|
|
# -- Get number of takes selected
|
|
number_of_selected_takes = getNumberOfSelectedTakes()
|
|
|
|
# if there is one selected take, still ignore it and use the current take
|
|
# it's a bit annoying when you have one take selected different from the current - chances are the user didn't mean to.
|
|
|
|
if number_of_selected_takes > 1:
|
|
for take_index in range(len(FBSystem().Scene.Takes)):
|
|
if FBSystem().Scene.Takes[take_index].Selected == True:
|
|
# go to take
|
|
FBSystem().CurrentTake = FBSystem().Scene.Takes[take_index]
|
|
plotToSkeleton(current_character)
|
|
zeroStoryAndPlot(to_skeleton)
|
|
|
|
else:
|
|
plotToSkeleton(current_character)
|
|
zeroStoryAndPlot(to_skeleton)
|
|
|
|
def Run():
|
|
|
|
if FBMessageBox("Move Take to Zero",
|
|
"WARNING:\n This will plot the current character on all selected takes and cannot be undone.",
|
|
"Continue", "Cancel"
|
|
) == 1:
|
|
|
|
storymute = FBStory().Mute
|
|
alreadymuted = False
|
|
|
|
if storymute:
|
|
alreadymuted = True
|
|
FBStory().Mute = False
|
|
|
|
mutedTracks = muteOtherCharTracks()
|
|
moveTakesToZero()
|
|
enableMutedTracks(mutedTracks)
|
|
|
|
if alreadymuted == True:
|
|
FBStory().Mute = True
|
|
|
|
else:
|
|
print "User cancelled"
|
|
|
|
|
|
|
|
|
|
|
|
Run()
|
|
pythonidelib.FlushOutput()from pyfbsdk import *
|
|
from pyfbsdk_additions import *
|
|
import pythonidelib
|
|
|
|
# -- Create an empty list
|
|
children = []
|
|
|
|
# -- For each selected constraint in the scene, add each child to the list
|
|
for con in FBSystem().Scene.Constraints:
|
|
if con.Selected == True:
|
|
children.append(con.ReferenceGet(0))
|
|
|
|
# -- For each child in the list, set selection to true
|
|
for c in children:
|
|
c.Selected = True
|
|
print str(c.Name) + " Selected"
|
|
|
|
pythonidelib.FlushOutput()from pyfbsdk import *
|
|
from pyfbsdk_additions import *
|
|
import pythonidelib
|
|
|
|
# -- Create an empty list
|
|
parents = []
|
|
|
|
# -- For each selected constraint in the scene, add each child to the list
|
|
for con in FBSystem().Scene.Constraints:
|
|
if con.Selected == True:
|
|
parents.append(con.ReferenceGet(1))
|
|
|
|
# -- For each parent in the list, set selection to true
|
|
for p in parents:
|
|
p.Selected = True
|
|
print str(p.Name) + " Selected"
|
|
|
|
pythonidelib.FlushOutput()from pyfbsdk import *
|
|
from RS.Utils import Scene
|
|
from RS import Globals
|
|
|
|
|
|
def CreateConstraint(parent, child):
|
|
con = Scene.Constraint.Constraint(
|
|
Scene.Constraint.PARENT_CHILD,
|
|
"Constraint",
|
|
child,
|
|
parent,
|
|
Active=True,
|
|
Lock=True
|
|
)
|
|
return con
|
|
|
|
|
|
def PlotOptions():
|
|
plot_options = FBPlotOptions()
|
|
plot_options.PlotAllTakes = True
|
|
plot_options.PlotOnFrame = True
|
|
plot_options.PlotPeriod = FBTime(0, 0, 0, 1)
|
|
plot_options.RotationFilterToApply = FBRotationFilter.kFBRotationFilterUnroll
|
|
plot_options.UseConstantKeyReducer = False
|
|
plot_options.ConstantKeyReducerKeepOneKey = True
|
|
plot_options.PlotTranslationOnRootOnly = False
|
|
|
|
return plot_options
|
|
|
|
def PlotModelList(listOfModels):
|
|
print listOfModels
|
|
|
|
Scene.DeSelectAll()
|
|
|
|
for model in listOfModels:
|
|
model.Selected = True
|
|
|
|
Globals.Scene.Evaluate()
|
|
FBSystem().CurrentTake.PlotTakeOnSelected(PlotOptions())
|
|
|
|
Scene.DeSelectAll()
|
|
|
|
|
|
def GetSelectedModels():
|
|
lModels = FBModelList()
|
|
FBGetSelectedModels(lModels)
|
|
return lModels
|
|
|
|
|
|
def CreateMarker(name='Marker', color=FBColor(1, 0, 0)):
|
|
marker = FBModelMarker(name)
|
|
|
|
marker.Show = True
|
|
marker.Look = FBMarkerLook.kFBMarkerLookHardCross
|
|
marker.PropertyList.Find("Size").Data = 500
|
|
marker.PropertyList.Find("Color RGB").Data = color
|
|
return marker
|
|
|
|
|
|
def SwapConstraint(constraint):
|
|
# -- Take a constraint and switch the 'Source' and 'objects
|
|
|
|
child = constraint.ReferenceGet(0, 0)
|
|
parent = constraint.ReferenceGet(1, 0)
|
|
|
|
constraint.Active = False
|
|
constraint.Lock = False
|
|
|
|
constraint.ReferenceRemove(0, child)
|
|
constraint.ReferenceRemove(1, parent)
|
|
|
|
Globals.Scene.Evaluate()
|
|
|
|
constraint.ReferenceAdd(0, parent)
|
|
constraint.ReferenceAdd(1, child)
|
|
|
|
constraint.Snap()
|
|
constraint.Lock = True
|
|
|
|
Globals.Scene.Evaluate()
|
|
|
|
|
|
def Run():
|
|
models = GetSelectedModels()
|
|
|
|
if len(models) > 0:
|
|
constraints = []
|
|
markers = []
|
|
|
|
for model in models:
|
|
color = FBColor(1, 0, 0)
|
|
|
|
if model.PropertyList.Find("Color RGB"):
|
|
color = model.Color
|
|
|
|
marker = CreateMarker("PinToMarker - " + model.Name, color)
|
|
markers.append(marker)
|
|
|
|
con = CreateConstraint(model, marker)
|
|
con.Name = "PinToMarker - " + model.Name
|
|
constraints.append(con)
|
|
|
|
if markers:
|
|
PlotModelList(markers)
|
|
|
|
Globals.Scene.Evaluate()
|
|
|
|
if constraints:
|
|
for con in constraints:
|
|
SwapConstraint(con)
|
|
|
|
Globals.Scene.Evaluate()
|
|
|
|
|
|
Run()
|
|
from pyfbsdk import *
|
|
from RS.Utils import Scene
|
|
from RS import Globals
|
|
|
|
|
|
def CreateConstraint(parent, child):
|
|
con = Scene.Constraint.Constraint(
|
|
Scene.Constraint.PARENT_CHILD,
|
|
"Constraint",
|
|
child,
|
|
parent,
|
|
Active=True,
|
|
Lock=True
|
|
)
|
|
return con
|
|
|
|
|
|
def PlotOptions():
|
|
plot_options = FBPlotOptions()
|
|
plot_options.PlotAllTakes = True
|
|
plot_options.PlotOnFrame = True
|
|
plot_options.PlotPeriod = FBTime(0, 0, 0, 1)
|
|
plot_options.RotationFilterToApply = FBRotationFilter.kFBRotationFilterUnroll
|
|
plot_options.UseConstantKeyReducer = False
|
|
plot_options.ConstantKeyReducerKeepOneKey = True
|
|
plot_options.PlotTranslationOnRootOnly = False
|
|
|
|
return plot_options
|
|
|
|
|
|
def PlotModelList(listOfModels):
|
|
print listOfModels
|
|
|
|
Scene.DeSelectAll()
|
|
|
|
for model in listOfModels:
|
|
model.Selected = True
|
|
|
|
Globals.Scene.Evaluate()
|
|
FBSystem().CurrentTake.PlotTakeOnSelected(PlotOptions())
|
|
|
|
Scene.DeSelectAll()
|
|
|
|
|
|
def GetSelectedModels():
|
|
lModels = FBModelList()
|
|
FBGetSelectedModels(lModels)
|
|
return lModels
|
|
|
|
|
|
def CreateMarker(name='Marker', color=FBColor(1, 0, 0)):
|
|
marker = FBModelMarker(name)
|
|
|
|
marker.Show = True
|
|
marker.Look = FBMarkerLook.kFBMarkerLookHardCross
|
|
marker.PropertyList.Find("Size").Data = 500
|
|
marker.PropertyList.Find("Color RGB").Data = color
|
|
return marker
|
|
|
|
|
|
def Run():
|
|
models = GetSelectedModels()
|
|
|
|
if len(models) > 0:
|
|
constraints = []
|
|
markers = []
|
|
|
|
for model in models:
|
|
color = FBColor(1, 0, 0)
|
|
|
|
if model.PropertyList.Find("Color RGB"):
|
|
color = model.Color
|
|
|
|
marker = CreateMarker("PlotToMarker - " + model.Name, color)
|
|
markers.append(marker)
|
|
|
|
con = CreateConstraint(model, marker)
|
|
con.Name = "PlotToMarker - " + model.Name
|
|
constraints.append(con)
|
|
|
|
if markers:
|
|
PlotModelList(markers)
|
|
|
|
if constraints:
|
|
for constraint in constraints:
|
|
constraint.FBDelete()
|
|
|
|
Globals.Scene.Evaluate()
|
|
|
|
|
|
Run()
|
|
from pyfbsdk import *
|
|
from RS import Globals
|
|
from RS.Utils import Scene
|
|
import pythonidelib
|
|
|
|
|
|
def getCharacterHeirarchyList(character):
|
|
characterNodeList = []
|
|
hips = character.GetModel(FBBodyNodeId.kFBHipsNodeId)
|
|
dummy = Scene.GetParent(hips)
|
|
Scene.GetChildren(dummy, characterNodeList, "", True)
|
|
return characterNodeList
|
|
|
|
def findNode(name):
|
|
|
|
foundNode = None
|
|
|
|
# -- Get list of all nodes of current character
|
|
currentCharacter = FBApplication().CurrentCharacter
|
|
characterNodeList = getCharacterHeirarchyList(currentCharacter)
|
|
|
|
|
|
# -- Check each node to see if it matches the desired name
|
|
for node in characterNodeList:
|
|
if node.Name == name:
|
|
foundNode = node
|
|
|
|
del (currentCharacter, characterNodeList)
|
|
return foundNode
|
|
|
|
def activateCamConstraint():
|
|
|
|
# -- Get the namespace of the current character
|
|
charNSpace = Scene.Component.GetNamespace(FBApplication().CurrentCharacter)
|
|
|
|
# -- Create empty variables to be filled
|
|
camConstraint = None
|
|
constraintFound = False
|
|
charConstraints = []
|
|
|
|
# -- For each constraint in the scene, check if it matches the character's namespace
|
|
for con in FBSystem().Scene.Constraints:
|
|
if Scene.Component.GetNamespace(con) == charNSpace:
|
|
charConstraints.append(con)
|
|
|
|
# -- Go through each constraint that matched the character namespace and find the FPS_Cam_Constraint
|
|
for con in charConstraints:
|
|
if 'FPS_Cam_Constraint'.lower() in con.Name.lower():
|
|
camConstraint = con
|
|
|
|
# -- If we found the FPS_Cam_Constraint, activate it
|
|
if camConstraint:
|
|
constraintFound = True
|
|
camConstraint.Active = True
|
|
|
|
# -- If we didn't, let the user know
|
|
else:
|
|
FBMessageBox("Quick Initialize CH Bones",
|
|
"WARNING:\n No FPS Constraint found for current character. ",
|
|
"Continue")
|
|
|
|
del (charNSpace, camConstraint, charConstraints)
|
|
return constraintFound
|
|
|
|
def activateCHConstraints(activate):
|
|
|
|
|
|
# -- Find the cone master
|
|
coneM = findNode("coneMaster")
|
|
# -- Create an empty list to fill with the constraint channels
|
|
chConstraints = []
|
|
|
|
# -- If we found the cone master
|
|
if coneM:
|
|
# -- For For each property of the cone master
|
|
# -- If it is one of the CH drivers
|
|
# -- Add it to our list
|
|
for prop in coneM.PropertyList:
|
|
|
|
if prop.Name == "activate_L_constraint":
|
|
chConstraints.append(prop)
|
|
|
|
if prop.Name == "activate_R_constraint":
|
|
chConstraints.append(prop)
|
|
|
|
# -- If both channels are found
|
|
if len(chConstraints) == 2:
|
|
# -- Switch them on/off depending on how the function was called
|
|
for constraint in chConstraints:
|
|
constraint.Data = activate
|
|
|
|
del (coneM, chConstraints)
|
|
return True
|
|
|
|
# -- If we didn't, let the user know
|
|
else:
|
|
FBMessageBox("Quick Initialize CH Bones",
|
|
"WARNING:\n No coneMaster found for current character.",
|
|
"Continue")
|
|
|
|
del (coneM, chConstraints)
|
|
return False
|
|
|
|
def getNumberOfSelectedTakes():
|
|
number_of_selected_takes = 0
|
|
|
|
for take_index in range(len(FBSystem().Scene.Takes)):
|
|
if FBSystem().Scene.Takes[take_index].Selected == True:
|
|
number_of_selected_takes += 1
|
|
|
|
return number_of_selected_takes
|
|
|
|
def plotOptions():
|
|
plot_options = FBPlotOptions()
|
|
plot_options.PlotAllTakes = False
|
|
plot_options.PlotOnFrame = True
|
|
plot_options.PlotPeriod = FBTime(0, 0, 0, 1)
|
|
plot_options.RotationFilterToApply = FBRotationFilter.kFBRotationFilterUnroll
|
|
plot_options.UseConstantKeyReducer = False
|
|
plot_options.ConstantKeyReducerKeepOneKey = True
|
|
plot_options.PlotTranslationOnRootOnly = False
|
|
|
|
return plot_options
|
|
|
|
def plotSelected(take):
|
|
|
|
opt = plotOptions()
|
|
take.PlotTakeOnSelected(opt)
|
|
|
|
def plotOnSelectedTakes(bones):
|
|
selection = []
|
|
|
|
# -- If more than 1 take is selected,
|
|
if getNumberOfSelectedTakes() > 1:
|
|
|
|
takesToPlot = []
|
|
|
|
# -- Store the takes the user has selected
|
|
for take in FBSystem().Scene.Takes:
|
|
if take.Selected == True:
|
|
takesToPlot.append(take)
|
|
|
|
# -- Store the user selection and deselect everything
|
|
for comp in FBSystem().Scene.Components:
|
|
if comp.Selected == True:
|
|
selection.append(comp)
|
|
comp.Selected = False
|
|
|
|
# -- Select the ch bones
|
|
for bone in bones:
|
|
bone.Selected = True
|
|
|
|
# -- Go through each selected take
|
|
for take in takesToPlot:
|
|
# -- Plot selected models to it
|
|
plotSelected(take)
|
|
print "CH Bones Initialized for take: " + str(take.Name)
|
|
|
|
# -- Deselect the bones
|
|
for bones in bones:
|
|
bones.Selected = False
|
|
|
|
# -- Reselect the user selection
|
|
for object in selection:
|
|
object.Selected = True
|
|
|
|
del (selection, takesToPlot)
|
|
|
|
# -- annoying when you have one take selected different from the current - chances are the user didn't mean to.
|
|
else:
|
|
|
|
# -- Store the user selection and deselect everything
|
|
for comp in FBSystem().Scene.Components:
|
|
if comp.Selected == True:
|
|
selection.append(comp)
|
|
comp.Selected = False
|
|
|
|
# -- Select the ch bones
|
|
for bone in bones:
|
|
bone.Selected = True
|
|
|
|
# -- Plot selected to current take
|
|
take = FBSystem().CurrentTake
|
|
plotSelected(take)
|
|
print "CH Bones Initialized for current take"
|
|
|
|
# -- Deselect the bones
|
|
for bones in bones:
|
|
bones.Selected = False
|
|
|
|
# -- Reselect the user selection
|
|
for object in selection:
|
|
object.Selected = True
|
|
|
|
del selection
|
|
|
|
def initializeCH():
|
|
|
|
# -- Check for animation nodes. If we find them, display an error message
|
|
if keyedChannelCheck():
|
|
FBMessageBox("Quick Initialize CH Bones",
|
|
"WARNING:\n Please remove any keys from 'activate_L_constraint' and ''activate_R_constraint' on the coneMaster ",
|
|
"Continue")
|
|
|
|
else:
|
|
# -- Check to see if story mode is on
|
|
isStoryMuted = FBStory().Mute
|
|
|
|
# -- Then make sure its off
|
|
FBStory().Mute = True
|
|
|
|
# -- Find the FPS_Cam and CH bones for the current character
|
|
fpCam = findNode("FPS_Cam")
|
|
chBones = [findNode("CH_L_Hand"), findNode("CH_R_Hand")]
|
|
constraintFound = None
|
|
coneMFound = None
|
|
|
|
# -- If both ch bones are found
|
|
if chBones[0] and chBones[1]:
|
|
# -- And the first person camera is found
|
|
if fpCam:
|
|
# -- Switch on the cam constraint
|
|
constraintFound = activateCamConstraint()
|
|
|
|
# -- If the cam constraint was found
|
|
if constraintFound:
|
|
# --Switch on the CH Driver constraints
|
|
coneMFound = activateCHConstraints(True)
|
|
|
|
# -- If the cone master was found
|
|
if coneMFound:
|
|
# --Plot the CH bones to the selected takes
|
|
plotOnSelectedTakes(chBones)
|
|
|
|
# --Switch off the CH Driver constraints
|
|
activateCHConstraints(False)
|
|
|
|
# -- If no ch bones were found let the user know
|
|
else:
|
|
FBMessageBox("Quick Initialize CH Bones",
|
|
"WARNING:\n No CH DOFs found for current character. ",
|
|
"Continue")
|
|
|
|
|
|
# -- Set story mode back to how it was
|
|
FBStory().Mute = isStoryMuted
|
|
del (fpCam, chBones, isStoryMuted, constraintFound, coneMFound)
|
|
|
|
def keyedChannelCheck():
|
|
|
|
# -- Find the cone master
|
|
coneM = findNode("coneMaster")
|
|
# -- Create an empty list to be filled with animation nodes
|
|
animNodes = []
|
|
|
|
if coneM:
|
|
# -- For each CH driver, see if it has an animation node. If so, add it to the list.
|
|
for prop in coneM.PropertyList:
|
|
if prop.Name == "activate_L_constraint":
|
|
animNodes.append(prop.GetAnimationNode())
|
|
|
|
if prop.Name == "activate_R_constraint":
|
|
animNodes.append(prop.GetAnimationNode())
|
|
|
|
# -- If any animation nodes ar found return true
|
|
if any(animNodes):
|
|
return True
|
|
|
|
# -- otherwise false
|
|
else:
|
|
return False
|
|
|
|
|
|
initializeCH()
|
|
Globals.Scene.Evaluate()
|
|
pythonidelib.FlushOutput()from pyfbsdk import *
|
|
from RS import Globals
|
|
from RS.Utils import Scene
|
|
import pythonidelib
|
|
|
|
|
|
def getCharacterHeirarchyList(character):
|
|
characterNodeList = []
|
|
hips = character.GetModel(FBBodyNodeId.kFBHipsNodeId)
|
|
dummy = Scene.GetParent(hips)
|
|
Scene.GetChildren(dummy, characterNodeList, "", True)
|
|
return characterNodeList
|
|
|
|
def findNode(name):
|
|
|
|
foundNode = None
|
|
|
|
# -- Get list of all nodes of current character
|
|
currentCharacter = FBApplication().CurrentCharacter
|
|
characterNodeList = getCharacterHeirarchyList(currentCharacter)
|
|
|
|
|
|
# -- Check each node to see if it matches the desired name
|
|
for node in characterNodeList:
|
|
if node.Name == name:
|
|
foundNode = node
|
|
|
|
del (currentCharacter, characterNodeList)
|
|
return foundNode
|
|
|
|
def activateCamConstraint():
|
|
|
|
# -- Get the namespace of the current character
|
|
charNSpace = Scene.Component.GetNamespace(FBApplication().CurrentCharacter)
|
|
|
|
# -- Create empty variables to be filled
|
|
camConstraint = None
|
|
constraintFound = False
|
|
charConstraints = []
|
|
|
|
# -- For each constraint in the scene, check if it matches the character's namespace
|
|
for con in FBSystem().Scene.Constraints:
|
|
if Scene.Component.GetNamespace(con) == charNSpace:
|
|
charConstraints.append(con)
|
|
|
|
# -- Go through each constraint that matched the character namespace and find the FPS_Cam_Constraint
|
|
for con in charConstraints:
|
|
if 'FPS_Cam_Constraint'.lower() in con.Name.lower():
|
|
camConstraint = con
|
|
|
|
# -- If we found the FPS_Cam_Constraint, activate it
|
|
if camConstraint:
|
|
constraintFound = True
|
|
camConstraint.Active = True
|
|
|
|
# -- If we didn't, let the user know
|
|
else:
|
|
FBMessageBox("Quick Initialize CH Bones",
|
|
"WARNING:\n No FPS Constraint found for current character. ",
|
|
"Continue")
|
|
|
|
del (charNSpace, camConstraint, charConstraints)
|
|
return constraintFound
|
|
|
|
def activateCHConstraints(activate):
|
|
|
|
|
|
# -- Find the cone master
|
|
coneM = findNode("coneMaster")
|
|
# -- Create an empty list to fill with the constraint channels
|
|
chConstraints = []
|
|
|
|
# -- If the conemaster was found:
|
|
if coneM:
|
|
# -- For For each property of the cone master
|
|
# -- If it is one of the CH drivers
|
|
# -- Add it to our list
|
|
for prop in coneM.PropertyList:
|
|
|
|
if prop.Name == "activate_L_constraint":
|
|
chConstraints.append(prop)
|
|
|
|
if prop.Name == "activate_R_constraint":
|
|
chConstraints.append(prop)
|
|
|
|
# -- If both channels are found
|
|
if len(chConstraints) == 2:
|
|
# -- Switch them on/off depending on how the function was called
|
|
for constraint in chConstraints:
|
|
constraint.Data = activate
|
|
|
|
del (coneM, chConstraints)
|
|
return True
|
|
|
|
# -- If we didn't, let the user know
|
|
else:
|
|
FBMessageBox("Quick Initialize CH Bones",
|
|
"WARNING:\n No coneMaster found for current character.",
|
|
"Continue")
|
|
|
|
del (coneM, chConstraints)
|
|
return False
|
|
|
|
def getNumberOfSelectedTakes():
|
|
number_of_selected_takes = 0
|
|
|
|
for take_index in range(len(FBSystem().Scene.Takes)):
|
|
if FBSystem().Scene.Takes[take_index].Selected == True:
|
|
number_of_selected_takes += 1
|
|
|
|
return number_of_selected_takes
|
|
|
|
def plotOptions():
|
|
plot_options = FBPlotOptions()
|
|
plot_options.PlotAllTakes = False
|
|
plot_options.PlotOnFrame = True
|
|
plot_options.PlotPeriod = FBTime(0, 0, 0, 1)
|
|
plot_options.RotationFilterToApply = FBRotationFilter.kFBRotationFilterUnroll
|
|
plot_options.UseConstantKeyReducer = False
|
|
plot_options.ConstantKeyReducerKeepOneKey = True
|
|
plot_options.PlotTranslationOnRootOnly = False
|
|
|
|
return plot_options
|
|
|
|
def plotSelected(take):
|
|
|
|
opt = plotOptions()
|
|
take.PlotTakeOnSelected(opt)
|
|
|
|
def plotOnAllTakes(bones):
|
|
selection = []
|
|
takesToPlot = []
|
|
|
|
# -- Get every take in the scene
|
|
for take in FBSystem().Scene.Takes:
|
|
takesToPlot.append(take)
|
|
|
|
# -- Store the user selection and deselect everything
|
|
for comp in FBSystem().Scene.Components:
|
|
if comp.Selected == True:
|
|
selection.append(comp)
|
|
comp.Selected = False
|
|
|
|
# -- Select the ch bones
|
|
for bone in bones:
|
|
bone.Selected = True
|
|
|
|
# -- Go through each take
|
|
for take in takesToPlot:
|
|
# -- Plot selected models to it
|
|
plotSelected(take)
|
|
print "CH Bones Initialized for take: " + str(take.Name)
|
|
|
|
# -- Deselect the bones
|
|
for bones in bones:
|
|
bones.Selected = False
|
|
|
|
# -- Reselect the user selection
|
|
for object in selection:
|
|
object.Selected = True
|
|
|
|
del (selection, takesToPlot)
|
|
|
|
def initializeCH():
|
|
# -- Check for animation nodes. If we find them, display an error message
|
|
if keyedChannelCheck():
|
|
FBMessageBox("Quick Initialize CH Bones",
|
|
"WARNING:\n Please remove any keys from 'activate_L_constraint' and ''activate_R_constraint' on the coneMaster ",
|
|
"Continue")
|
|
|
|
else:
|
|
# -- Check to see if story mode is on
|
|
isStoryMuted = FBStory().Mute
|
|
|
|
# -- Then make sure its off
|
|
FBStory().Mute = True
|
|
|
|
# -- Find the FPS_Cam and CH bones for the current character
|
|
fpCam = findNode("FPS_Cam")
|
|
chBones = [findNode("CH_L_Hand"), findNode("CH_R_Hand")]
|
|
constraintFound = None
|
|
coneMFound = None
|
|
|
|
# -- If both ch bones are found
|
|
if chBones[0] and chBones[1]:
|
|
# -- And the first person camera is found
|
|
if fpCam:
|
|
# -- Switch on the cam constraint
|
|
constraintFound = activateCamConstraint()
|
|
|
|
# --If the cam constraint was found
|
|
if constraintFound:
|
|
# --Switch on the CH Driver constraints
|
|
coneMFound = activateCHConstraints(True)
|
|
|
|
# -- If the cne master was found
|
|
if coneMFound:
|
|
# --Plot the CH bones to the selected takes
|
|
plotOnAllTakes(chBones)
|
|
|
|
# --Switch off the CH Driver constraints
|
|
activateCHConstraints(False)
|
|
|
|
# -- If no ch bones were found let the user know
|
|
else:
|
|
FBMessageBox("Quick Initialize CH Bones",
|
|
"WARNING:\n No CH DOFs found for current character. ",
|
|
"Continue")
|
|
|
|
|
|
# -- Set story mode back to how it was
|
|
FBStory().Mute = isStoryMuted
|
|
del (fpCam, chBones, isStoryMuted, constraintFound, coneMFound)
|
|
|
|
def keyedChannelCheck():
|
|
|
|
# -- Find the cone master
|
|
coneM = findNode("coneMaster")
|
|
# -- Create an empty list to be filled with animation nodes
|
|
animNodes = []
|
|
|
|
# -- If the cone master was found
|
|
if coneM:
|
|
# -- For each CH driver, see if it has an animation node. If so, add it to the list.
|
|
for prop in coneM.PropertyList:
|
|
if prop.Name == "activate_L_constraint":
|
|
animNodes.append(prop.GetAnimationNode())
|
|
|
|
if prop.Name == "activate_R_constraint":
|
|
animNodes.append(prop.GetAnimationNode())
|
|
|
|
# -- If any animation nodes ar found return true
|
|
if any(animNodes):
|
|
return True
|
|
|
|
# -- otherwise false
|
|
else:
|
|
return False
|
|
|
|
|
|
initializeCH()
|
|
Globals.Scene.Evaluate()
|
|
pythonidelib.FlushOutput()####################################################################
|
|
# Quickly Plot either down to skeleton or vice versa depending on current state
|
|
####################################################################
|
|
|
|
from pyfbsdk import *
|
|
import RS.Globals
|
|
import RS.Core as Core
|
|
|
|
|
|
def plotOptions():
|
|
plot_options = FBPlotOptions()
|
|
plot_options.PlotAllTakes = False
|
|
plot_options.PlotOnFrame = True
|
|
plot_options.PlotPeriod = FBTime(0, 0, 0, 1)
|
|
plot_options.RotationFilterToApply = FBRotationFilter.kFBRotationFilterUnroll
|
|
plot_options.UseConstantKeyReducer = False
|
|
plot_options.ConstantKeyReducerKeepOneKey = True
|
|
plot_options.PlotTranslationOnRootOnly = False
|
|
|
|
return plot_options
|
|
|
|
|
|
def getNumberOfSelectedTakes():
|
|
number_of_selected_takes = 0
|
|
|
|
for take_index in range(len(FBSystem().Scene.Takes)):
|
|
if FBSystem().Scene.Takes[take_index].Selected == True:
|
|
number_of_selected_takes += 1
|
|
|
|
return number_of_selected_takes
|
|
|
|
|
|
def plotToRig(character):
|
|
character.PlotAnimation(FBCharacterPlotWhere.kFBCharacterPlotOnControlRig, plotOptions())
|
|
|
|
|
|
def plotToSkeleton(character):
|
|
character.PlotAnimation(FBCharacterPlotWhere.kFBCharacterPlotOnSkeleton, plotOptions())
|
|
|
|
|
|
def ToggleDevices():
|
|
for device in FBSystem().Scene.Devices:
|
|
device.Online = not device.Online
|
|
|
|
|
|
def QuickPlot():
|
|
# ToggleDevices()
|
|
current_character = FBApplication().CurrentCharacter
|
|
|
|
# need to create control rig first?
|
|
if current_character.GetCurrentControlSet() == None:
|
|
current_character.CreateControlRig(True)
|
|
|
|
if current_character.Active == True:
|
|
to_skeleton = True
|
|
else:
|
|
to_skeleton = False
|
|
|
|
number_of_selected_takes = getNumberOfSelectedTakes()
|
|
|
|
# if there is one selected take, still ignore it and use the current take
|
|
# it's a bit annoying when you have one take selected different from the current - chances are the user didn't mean to.
|
|
|
|
if number_of_selected_takes > 1:
|
|
for take_index in range(len(FBSystem().Scene.Takes)):
|
|
if FBSystem().Scene.Takes[take_index].Selected == True:
|
|
# go to take
|
|
FBSystem().CurrentTake = FBSystem().Scene.Takes[take_index]
|
|
|
|
if to_skeleton == True:
|
|
plotToSkeleton(current_character)
|
|
else:
|
|
plotToRig(current_character)
|
|
else:
|
|
if to_skeleton == True:
|
|
for character in Core.System.Scene.Characters:
|
|
plotToSkeleton(character)
|
|
else:
|
|
for character in Core.System.Scene.Characters:
|
|
plotToRig(character)
|
|
|
|
# ToggleDevices()
|
|
|
|
print "Plotting Complete"
|
|
|
|
|
|
####################################################################
|
|
# Main
|
|
####################################################################
|
|
|
|
QuickPlot()####################################
|
|
# -- Quickly plot selected models --
|
|
####################################
|
|
from pyfbsdk import *
|
|
from pyfbsdk_additions import *
|
|
|
|
|
|
def getSelectedModels():
|
|
|
|
# -- Create an empty FBModelList
|
|
selectedModels = FBModelList()
|
|
|
|
topModel = None # -- Search all models, not just a particular branch
|
|
selectionState = True # -- Return models that are selected, not deselected
|
|
sortBySelectOrder = True # -- The last model in the list was selected most recently
|
|
FBGetSelectedModels(selectedModels, topModel, selectionState, sortBySelectOrder)
|
|
|
|
return selectedModels
|
|
|
|
def getNumberOfSelectedTakes():
|
|
number_of_selected_takes = 0
|
|
|
|
for take_index in range(len(FBSystem().Scene.Takes)):
|
|
if FBSystem().Scene.Takes[take_index].Selected == True:
|
|
number_of_selected_takes += 1
|
|
|
|
return number_of_selected_takes
|
|
|
|
def plotOptions():
|
|
plot_options = FBPlotOptions()
|
|
plot_options.PlotAllTakes = False
|
|
plot_options.PlotOnFrame = True
|
|
plot_options.PlotPeriod = FBTime(0, 0, 0, 1)
|
|
plot_options.RotationFilterToApply = FBRotationFilter.kFBRotationFilterUnroll
|
|
plot_options.UseConstantKeyReducer = False
|
|
plot_options.ConstantKeyReducerKeepOneKey = True
|
|
plot_options.PlotTranslationOnRootOnly = False
|
|
|
|
return plot_options
|
|
|
|
def plotSelected(take):
|
|
|
|
opt = plotOptions()
|
|
take.PlotTakeOnSelected(opt)
|
|
|
|
def QuickPlot():
|
|
|
|
# -- Get selected models
|
|
sel = getSelectedModels()
|
|
# -- If at least one model is selected
|
|
if len(sel) > 0:
|
|
|
|
# -- If more than 1 take is selected,
|
|
if getNumberOfSelectedTakes() > 1:
|
|
# -- go through each take
|
|
for take in FBSystem().Scene.Takes:
|
|
# -- If it is selected
|
|
if take.Selected == True:
|
|
# -- Plot selected models to it
|
|
plotSelected(take)
|
|
print "Selected Objects plotted to " + str(take.Name)
|
|
|
|
|
|
# -- annoying when you have one take selected different from the current - chances are the user didn't mean to.
|
|
else:
|
|
# -- Plot selected to current taKE
|
|
take = FBSystem().CurrentTake
|
|
plotSelected(take)
|
|
print "Selected Objects plotted to current take"
|
|
|
|
print "Plotting Complete"
|
|
else:
|
|
print "No Objects selected"
|
|
|
|
QuickPlot()####################################################
|
|
# Uses story mode to move the current take to zero
|
|
####################################################
|
|
from pyfbsdk import *
|
|
import pythonidelib
|
|
|
|
|
|
# =================== Taken from Mike's mj_QuickPlot script ========================
|
|
|
|
def plotOptions():
|
|
plot_options = FBPlotOptions()
|
|
plot_options.PlotAllTakes = False
|
|
plot_options.PlotOnFrame = True
|
|
plot_options.PlotPeriod = FBTime(0, 0, 0, 1)
|
|
plot_options.RotationFilterToApply = FBRotationFilter.kFBRotationFilterUnroll
|
|
plot_options.UseConstantKeyReducer = False
|
|
plot_options.ConstantKeyReducerKeepOneKey = True
|
|
plot_options.PlotTranslationOnRootOnly = False
|
|
|
|
return plot_options
|
|
|
|
|
|
def getNumberOfSelectedTakes():
|
|
number_of_selected_takes = 0
|
|
|
|
for take_index in range(len(FBSystem().Scene.Takes)):
|
|
if FBSystem().Scene.Takes[take_index].Selected == True:
|
|
number_of_selected_takes += 1
|
|
|
|
return number_of_selected_takes
|
|
|
|
|
|
def plotToRig(character):
|
|
character.PlotAnimation(FBCharacterPlotWhere.kFBCharacterPlotOnControlRig, plotOptions())
|
|
|
|
|
|
def plotToSkeleton(character):
|
|
character.PlotAnimation(FBCharacterPlotWhere.kFBCharacterPlotOnSkeleton, plotOptions())
|
|
|
|
|
|
# =====================================================================================
|
|
|
|
def muteOtherCharTracks():
|
|
|
|
currChar = FBApplication().CurrentCharacter
|
|
|
|
charTracks = []
|
|
|
|
for lTrack in FBStory().RootFolder.Tracks:
|
|
|
|
lChar = lTrack.PropertyList.Find('Character')
|
|
|
|
if lChar is not None:
|
|
for d in lTrack.Details:
|
|
if d == currChar:
|
|
if lTrack.Mute == False:
|
|
lTrack.Mute = True
|
|
charTracks.append(lTrack)
|
|
# print "Story Track: %s temporarily muted" % lTrack.Name
|
|
|
|
return charTracks
|
|
|
|
def enableMutedTracks(charTracks):
|
|
|
|
for lTrack in charTracks:
|
|
lTrack.Mute = False
|
|
# print "Story Track: %s unmuted" % lTrack.Name
|
|
|
|
def scaleStoryAndPlot(ratescale, to_skeleton = True):
|
|
|
|
|
|
# -- Assign important stuff to variables
|
|
app = FBApplication()
|
|
system = FBSystem()
|
|
story = FBStory()
|
|
take = system.CurrentTake
|
|
char = FBApplication().CurrentCharacter
|
|
|
|
# -- Create a story track and clip for the current character
|
|
track = FBStoryTrack(FBStoryTrackType.kFBStoryTrackCharacter, story.RootFolder)
|
|
track.Details.append(char)
|
|
track.Label = system.CurrentTake.Name
|
|
clip = track.CopyTakeIntoTrack(system.CurrentTake.LocalTimeSpan, system.CurrentTake)
|
|
|
|
# -- Get some time information about the clip we created
|
|
lSpeed = clip.PropertyList.Find('Speed')
|
|
lStart = clip.PropertyList.Find('Start')
|
|
lStop = clip.PropertyList.Find('Stop')
|
|
|
|
# -- Use the start and end of the clip to determine the length
|
|
oldLength = lStop.Data.GetFrame() - lStart.Data.GetFrame()
|
|
# -- Calculate a new length based on the ratescale
|
|
fScaledLength = float(oldLength / ratescale)
|
|
|
|
# -- Convert length to an integer (and round up)
|
|
iScaledLength = int(fScaledLength)
|
|
|
|
# -- Set the speed of the clip to the desired ratescale
|
|
lSpeed.Data = ratescale
|
|
# -- Use the new length, added to the current start time, to assign a new stop time
|
|
lStop.Data = FBTime(0, 0, 0, lStart.Data.GetFrame() + iScaledLength, 0)
|
|
|
|
# -- Assign the new end of the clip to a variable
|
|
end = clip.PropertyList.Find('Stop').Data
|
|
|
|
# -- Set the start and end of the current take to match the story clip
|
|
take.LocalTimeSpan = FBTimeSpan(
|
|
lStart.Data,
|
|
end
|
|
)
|
|
|
|
# -- Add 1 frame to the end of the clip as padding
|
|
lStop.Data = FBTime(0, 0, 0, lStop.Data.GetFrame() + 1, 0)
|
|
|
|
# -- If the character rig is active, plot it to the skeleton and plot to it back to the rig
|
|
if to_skeleton == True:
|
|
plotToSkeleton(char)
|
|
plotToRig(char)
|
|
# -- Otherwise just plot it straight to the skeleton
|
|
else:
|
|
plotToSkeleton(char)
|
|
|
|
print "%s rate scaled to %s" % (take.Name, round(ratescale,1))
|
|
|
|
clip.FBDelete()
|
|
track.FBDelete()
|
|
|
|
def ratescaleTakes(ratescale):
|
|
|
|
|
|
# -- Get the current character
|
|
current_character = FBApplication().CurrentCharacter
|
|
|
|
# -- Need to create control rig first?
|
|
if current_character.GetCurrentControlSet() == None:
|
|
current_character.CreateControlRig(True)
|
|
|
|
# -- Check if the current character is active
|
|
if current_character.Active == True:
|
|
to_skeleton = True
|
|
else:
|
|
to_skeleton = False
|
|
|
|
# -- Get number of takes selected
|
|
number_of_selected_takes = getNumberOfSelectedTakes()
|
|
|
|
# if there is one selected take, still ignore it and use the current take
|
|
# it's a bit annoying when you have one take selected different from the current - chances are the user didn't mean to.
|
|
|
|
if number_of_selected_takes > 1:
|
|
for take_index in range(len(FBSystem().Scene.Takes)):
|
|
if FBSystem().Scene.Takes[take_index].Selected == True:
|
|
# go to take
|
|
FBSystem().CurrentTake = FBSystem().Scene.Takes[take_index]
|
|
plotToSkeleton(current_character)
|
|
scaleStoryAndPlot(ratescale, to_skeleton)
|
|
|
|
else:
|
|
plotToSkeleton(current_character)
|
|
scaleStoryAndPlot(ratescale, to_skeleton)
|
|
|
|
def Run():
|
|
|
|
# -- Get the amount that the user wants to scale and let them confirm they want to plot all selected takes
|
|
|
|
pUpTitle = "Rate Scale Takes"
|
|
pUpMessage = """WARNING:\n This will plot the current character on all selected takes and cannot be undone.\n\nRate Scale Amount:"""
|
|
|
|
input = FBMessageBoxGetUserValue( pUpTitle,
|
|
pUpMessage,
|
|
1.0,
|
|
FBPopupInputType.kFBPopupFloat,
|
|
"Continue",
|
|
"Cancel"
|
|
)
|
|
|
|
if input[0] == 1:
|
|
|
|
storymute = FBStory().Mute
|
|
alreadymuted = False
|
|
|
|
if storymute:
|
|
alreadymuted = True
|
|
FBStory().Mute = False
|
|
|
|
mutedTracks = muteOtherCharTracks()
|
|
ratescaleTakes(input[1])
|
|
enableMutedTracks(mutedTracks)
|
|
|
|
if alreadymuted == True:
|
|
FBStory().Mute = True
|
|
|
|
else:
|
|
print "User cancelled"
|
|
|
|
|
|
|
|
|
|
|
|
Run()
|
|
pythonidelib.FlushOutput()from pyfbsdk import *
|
|
from pyfbsdk_additions import *
|
|
|
|
|
|
def renameConstraint(con):
|
|
|
|
if con.ReferenceGroupGetCount() in range(2,4):
|
|
child = con.ReferenceGet(0)
|
|
parent = con.ReferenceGet(1)
|
|
|
|
type = con.Description
|
|
if con.Description == 'Position From Positions':
|
|
type = 'Position'
|
|
elif con.Description == 'Rotation From Rotations':
|
|
type = 'Rotation'
|
|
elif con.Description == 'Scale From Scales':
|
|
type = 'Scale'
|
|
|
|
if child and parent:
|
|
newName = type + ' - ' + parent.Name + ' > ' + child.Name
|
|
con.Name = newName
|
|
else:
|
|
newName = type + ' - [EMPTY CONSTRAINT]'
|
|
con.Name = newName
|
|
|
|
# -- For each constraint in the scene
|
|
for con in FBSystem().Scene.Constraints:
|
|
|
|
# -- If the constraint is selected
|
|
if con.Selected == True:
|
|
renameConstraint(con)
|
|
|
|
|
|
|
|
|
|
|
|
from pyfbsdk import *
|
|
import pythonidelib
|
|
from RS.Tools.FirstPersonController import Core as fpsCore
|
|
from RS import Globals
|
|
from RS.Utils import Scene
|
|
|
|
def getCharacterHeirarchyList(character):
|
|
characterNodeList = []
|
|
hips = character.GetModel(FBBodyNodeId.kFBHipsNodeId)
|
|
dummy = Scene.GetParent(hips)
|
|
Scene.GetChildren(dummy, characterNodeList, "", True)
|
|
return characterNodeList
|
|
|
|
def findNode(name):
|
|
|
|
foundNode = None
|
|
|
|
# -- Get list of all nodes of current character
|
|
currentCharacter = FBApplication().CurrentCharacter
|
|
characterNodeList = getCharacterHeirarchyList(currentCharacter)
|
|
|
|
|
|
# -- Check each node to see if it matches the desired name
|
|
for node in characterNodeList:
|
|
if node.Name == name:
|
|
foundNode = node
|
|
|
|
del (currentCharacter, characterNodeList)
|
|
return foundNode
|
|
|
|
|
|
def getNumberOfSelectedTakes():
|
|
number_of_selected_takes = 0
|
|
|
|
for take_index in range(len(FBSystem().Scene.Takes)):
|
|
if FBSystem().Scene.Takes[take_index].Selected == True:
|
|
number_of_selected_takes += 1
|
|
|
|
return number_of_selected_takes
|
|
|
|
|
|
def bakeRot():
|
|
currentCharacter = FBApplication().CurrentCharacter
|
|
|
|
# -- If more than 1 take is selected,
|
|
if getNumberOfSelectedTakes() > 1:
|
|
# -- go through each take
|
|
for take in FBSystem().Scene.Takes:
|
|
# -- If it is selected
|
|
if take.Selected:
|
|
# -- Plot selected models to it
|
|
FBSystem().CurrentTake = take
|
|
Globals.Scene.Evaluate()
|
|
startTime = FBSystem().CurrentTake.LocalTimeSpan.GetStart()
|
|
endTime = FBSystem().CurrentTake.LocalTimeSpan.GetStop()
|
|
fpsCore.TransferConeMasterAnimationToMoverSpace(currentCharacter, startTime, endTime)
|
|
Globals.Scene.Evaluate()
|
|
cleanCurves()
|
|
|
|
# -- annoying when you have one take selected different from the current - chances are the user didn't mean to.
|
|
else:
|
|
startTime = FBSystem().CurrentTake.LocalTimeSpan.GetStart()
|
|
endTime = FBSystem().CurrentTake.LocalTimeSpan.GetStop()
|
|
fpsCore.TransferConeMasterAnimationToMoverSpace(currentCharacter, startTime, endTime)
|
|
Globals.Scene.Evaluate()
|
|
|
|
def plotOptions():
|
|
plot_options = FBPlotOptions()
|
|
plot_options.PlotAllTakes = False
|
|
plot_options.PlotOnFrame = True
|
|
plot_options.PlotPeriod = FBTime(0, 0, 0, 1)
|
|
plot_options.RotationFilterToApply = FBRotationFilter.kFBRotationFilterUnroll
|
|
plot_options.UseConstantKeyReducer = False
|
|
plot_options.ConstantKeyReducerKeepOneKey = True
|
|
plot_options.PlotTranslationOnRootOnly = False
|
|
|
|
return plot_options
|
|
|
|
|
|
def plotSelected():
|
|
opt = plotOptions()
|
|
FBSystem().CurrentTake.PlotTakeOnSelected(opt)
|
|
|
|
def cleanCurves():
|
|
# -- Find the cone master
|
|
coneM = findNode("coneMaster")
|
|
|
|
for comp in FBSystem().Scene.Components:
|
|
comp.Selected = False
|
|
|
|
coneM.Selected = True
|
|
plotSelected()
|
|
|
|
|
|
bakeRot()
|
|
Globals.Scene.Evaluate()
|
|
pythonidelib.FlushOutput()
|
|
|
|
###########################################
|
|
# -- Quickly pick the IK Hand Extentions --
|
|
###########################################
|
|
from pyfbsdk import *
|
|
from pyfbsdk import *
|
|
from RS.Utils import Scene
|
|
|
|
|
|
|
|
|
|
def getCharacterHeirarchyList(character):
|
|
characterNodeList = []
|
|
hips = character.GetModel(FBBodyNodeId.kFBHipsNodeId)
|
|
dummy = Scene.GetParent(hips)
|
|
Scene.GetChildren(dummy, characterNodeList, "", True)
|
|
return characterNodeList
|
|
|
|
def findNodesForCurrentCharacter(name):
|
|
|
|
foundNode = None
|
|
foundNodes = []
|
|
|
|
# -- Get list of all nodes of current character
|
|
currentCharacter = FBApplication().CurrentCharacter
|
|
characterNodeList = getCharacterHeirarchyList(currentCharacter)
|
|
|
|
|
|
# -- Check each node to see if it matches the desired name
|
|
for node in characterNodeList:
|
|
if node.Name == name:
|
|
foundNode = node
|
|
foundNodes.append(foundNode)
|
|
|
|
del (currentCharacter, characterNodeList)
|
|
return foundNodes
|
|
|
|
def findNodesForEntireScene(name):
|
|
|
|
foundComponents = FBComponentList()
|
|
|
|
includeNamespace = True
|
|
modelsOnly = True
|
|
FBFindObjectsByName('*' + name, foundComponents, includeNamespace, modelsOnly)
|
|
|
|
return foundComponents
|
|
|
|
def selectNode(input, character = True):
|
|
|
|
|
|
nodes = []
|
|
names = [x.strip() for x in input.split(',')]
|
|
|
|
if character == True:
|
|
for name in names:
|
|
for node in findNodesForCurrentCharacter(name):
|
|
nodes.append(node)
|
|
else:
|
|
for name in names:
|
|
for node in findNodesForEntireScene(name):
|
|
nodes.append(node)
|
|
|
|
|
|
if len(nodes) > 0:
|
|
|
|
clearSelection()
|
|
for node in nodes:
|
|
if node:
|
|
if node.PropertyList.Find('Look'):
|
|
node.PropertyList.Find('Look').Data = 1
|
|
if node.PropertyList.Find('Size'):
|
|
node.PropertyList.Find('Size').Data = 5.0
|
|
if node.PropertyList.Find('Pickable'):
|
|
node.PropertyList.Find('Pickable').Data = True
|
|
if node.PropertyList.Find('Transformable'):
|
|
node.PropertyList.Find('Transformable').Data = True
|
|
if node.PropertyList.Find('Show'):
|
|
node.PropertyList.Find('Show').Data = True
|
|
|
|
node.Selected = True
|
|
|
|
return nodes
|
|
|
|
|
|
def TestMessageBox(pVal):
|
|
# The result from the call will be a tuple containing the index of the
|
|
# button pressed (or -1 in case of error). The second element will be
|
|
# the value entered.
|
|
lRes = FBMessageBoxGetUserValue("Search and Select", "Search For: ", pVal, FBPopupInputType.kFBPopupString, "Character", "Scene", "Cancel")
|
|
|
|
# Did the user press 'Ok'?
|
|
if lRes[0] == 1:
|
|
found = selectNode(lRes[1], True)
|
|
if len(found) > 0:
|
|
FBMessageBox("Result", "%s object found for current character" % len(found), "Ok")
|
|
else:
|
|
FBMessageBox("Result", "No objects found for current character", "Ok")
|
|
if lRes[0] == 2:
|
|
found = selectNode(lRes[1], False)
|
|
if len(found) > 0:
|
|
FBMessageBox("Result", "%s objects found in scene" % len(found), "Ok")
|
|
else:
|
|
FBMessageBox("Result", "No objects found in scene", "Ok")
|
|
|
|
del (lRes)
|
|
|
|
def clearSelection():
|
|
for comp in FBSystem().Scene.Components:
|
|
comp.Selected = False
|
|
|
|
|
|
|
|
TestMessageBox("")
|
|
|
|
###########################################
|
|
# -- Quickly pick the IK Hand Extentions --
|
|
###########################################
|
|
from pyfbsdk import *
|
|
from pyfbsdk import *
|
|
from RS.Utils import Scene
|
|
|
|
|
|
def getCharacterHeirarchyList(character):
|
|
characterNodeList = []
|
|
hips = character.GetModel(FBBodyNodeId.kFBHipsNodeId)
|
|
dummy = Scene.GetParent(hips)
|
|
Scene.GetChildren(dummy, characterNodeList, "", True)
|
|
return characterNodeList
|
|
|
|
def findNode(name):
|
|
|
|
foundNode = None
|
|
|
|
# -- Get list of all nodes of current character
|
|
currentCharacter = FBApplication().CurrentCharacter
|
|
characterNodeList = getCharacterHeirarchyList(currentCharacter)
|
|
|
|
|
|
# -- Check each node to see if it matches the desired name
|
|
for node in characterNodeList:
|
|
if node.Name == name:
|
|
foundNode = node
|
|
|
|
del (currentCharacter, characterNodeList)
|
|
return foundNode
|
|
|
|
def selectFromList(names):
|
|
|
|
for name in names:
|
|
|
|
node = findNode(name)
|
|
|
|
if node:
|
|
node.PropertyList.Find('Look').Data = 1
|
|
node.Look = 1
|
|
node.Size = 5.0
|
|
node.Pickable = True
|
|
node.Transformable = True
|
|
node.Show = True
|
|
node.Selected = True
|
|
|
|
selectList = [
|
|
"CH_L_Hand",
|
|
"CH_R_Hand"
|
|
]
|
|
|
|
selectFromList(selectList)
|
|
###########################################
|
|
# -- Quickly pick the IK Hand Extentions --
|
|
###########################################
|
|
from pyfbsdk import *
|
|
from pyfbsdk import *
|
|
from RS.Utils import Scene
|
|
|
|
|
|
def getCharacterHeirarchyList(character):
|
|
characterNodeList = []
|
|
hips = character.GetModel(FBBodyNodeId.kFBHipsNodeId)
|
|
dummy = Scene.GetParent(hips)
|
|
Scene.GetChildren(dummy, characterNodeList, "", True)
|
|
return characterNodeList
|
|
|
|
def findNode(name):
|
|
|
|
foundNode = None
|
|
|
|
# -- Get list of all nodes of current character
|
|
currentCharacter = FBApplication().CurrentCharacter
|
|
characterNodeList = getCharacterHeirarchyList(currentCharacter)
|
|
|
|
|
|
# -- Check each node to see if it matches the desired name
|
|
for node in characterNodeList:
|
|
if node.Name == name:
|
|
foundNode = node
|
|
|
|
del (currentCharacter, characterNodeList)
|
|
return foundNode
|
|
|
|
def selectFromList(names):
|
|
|
|
for name in names:
|
|
|
|
node = findNode(name)
|
|
|
|
if node:
|
|
node.PropertyList.Find('Look').Data = 1
|
|
node.Look = 1
|
|
node.Size = 5.0
|
|
node.Pickable = True
|
|
node.Transformable = True
|
|
node.Show = True
|
|
node.Selected = True
|
|
|
|
selectList = [
|
|
"IK_L_Hand",
|
|
"IK_R_Hand"
|
|
]
|
|
|
|
selectFromList(selectList)
|
|
###########################################
|
|
# -- Quickly pick the IK Hand Extentions --
|
|
###########################################
|
|
from pyfbsdk import *
|
|
from pyfbsdk import *
|
|
from RS.Utils import Scene
|
|
|
|
|
|
def getCharacterHeirarchyList(character):
|
|
characterNodeList = []
|
|
hips = character.GetModel(FBBodyNodeId.kFBHipsNodeId)
|
|
dummy = Scene.GetParent(hips)
|
|
Scene.GetChildren(dummy, characterNodeList, "", True)
|
|
return characterNodeList
|
|
|
|
def findNode(name):
|
|
|
|
foundNode = None
|
|
|
|
# -- Get list of all nodes of current character
|
|
currentCharacter = FBApplication().CurrentCharacter
|
|
characterNodeList = getCharacterHeirarchyList(currentCharacter)
|
|
|
|
|
|
# -- Check each node to see if it matches the desired name
|
|
for node in characterNodeList:
|
|
if node.Name == name:
|
|
foundNode = node
|
|
|
|
del (currentCharacter, characterNodeList)
|
|
return foundNode
|
|
|
|
def selectFromList(names):
|
|
|
|
for name in names:
|
|
|
|
node = findNode(name)
|
|
|
|
if node:
|
|
node.PropertyList.Find('Look').Data = 1
|
|
node.Look = 1
|
|
node.Size = 5.0
|
|
node.Pickable = True
|
|
node.Transformable = True
|
|
node.Show = True
|
|
node.Selected = True
|
|
|
|
selectList = [
|
|
"PH_L_Hand",
|
|
"PH_R_Hand"
|
|
]
|
|
|
|
selectFromList(selectList)
|
|
from pyfbsdk import *
|
|
import pythonidelib
|
|
|
|
def SelectMarkedTakes():
|
|
lSystem = FBSystem()
|
|
|
|
print "\nMarked Takes:\n"
|
|
|
|
for lTakeIdx in range(len(lSystem.Scene.Takes)):
|
|
take = lSystem.Scene.Takes[lTakeIdx]
|
|
take.Selected = False
|
|
|
|
if take.Name.startswith('>>>---'):
|
|
take.Selected = True
|
|
print take.Name[6:]
|
|
pythonidelib.FlushOutput()
|
|
|
|
SelectMarkedTakes()
|
|
from pyfbsdk import *
|
|
from pyfbsdk_additions import *
|
|
|
|
# -- For each constraint in the scene
|
|
for con in FBSystem().Scene.Constraints:
|
|
if con.Selected == True:
|
|
|
|
newName = con.Name + ' [ANIMATED]'
|
|
con.Name = newName
|
|
|
|
|
|
####################################################################
|
|
# Adds current character as a story track with current take added
|
|
####################################################################
|
|
from pyfbsdk import *
|
|
import pythonidelib
|
|
|
|
|
|
def addCharacterTrack():
|
|
track = FBStoryTrack(FBStoryTrackType.kFBStoryTrackCharacter, story.RootFolder)
|
|
track.Details.append(app.CurrentCharacter)
|
|
track.Label = system.CurrentTake.Name
|
|
|
|
|
|
clip = track.CopyTakeIntoTrack(system.CurrentTake.LocalTimeSpan, system.CurrentTake)
|
|
|
|
clip.Selected = True
|
|
interp = clip.PropertyList.Find('Timewarp Interpolation')
|
|
interp.Data = 0
|
|
|
|
FBStory().Mute = False
|
|
|
|
|
|
|
|
|
|
|
|
app = FBApplication()
|
|
system = FBSystem()
|
|
story = FBStory()
|
|
scene = system.Scene
|
|
|
|
addCharacterTrack()
|
|
pythonidelib.FlushOutput()
|
|
from pyfbsdk import *
|
|
|
|
takes = FBSystem().Scene.Takes
|
|
|
|
|
|
def getNumberOfSelectedTakes():
|
|
number_of_selected_takes = 0
|
|
|
|
for take_index in range(len(FBSystem().Scene.Takes)):
|
|
if FBSystem().Scene.Takes[take_index].Selected == True:
|
|
number_of_selected_takes += 1
|
|
|
|
return number_of_selected_takes
|
|
|
|
|
|
if getNumberOfSelectedTakes() > 0:
|
|
for take in takes:
|
|
if take.Selected:
|
|
if take.Name.startswith('>>>---'):
|
|
take.Name = take.Name[6:]
|
|
else:
|
|
if FBSystem().CurrentTake.Name.startswith('>>>---'):
|
|
FBSystem().CurrentTake.Name = FBSystem().CurrentTake.Name[6:] |