Files
gtav-src/tools_ng/techart/sandboxmotionbuilder/Shared/mj_select_MOVER.py
T
2025-09-29 00:52:08 +02:00

13283 lines
508 KiB
Python
Executable File

PNG
####################################################################
# Adds current character as a story track with current take added
####################################################################
from pyfbsdk import *
def addCharacterTrack():
track = FBStoryTrack(FBStoryTrackType.kFBStoryTrackCharacter, story.RootFolder)
track.Details.append(app.CurrentCharacter)
track.Label = system.CurrentTake.Name
try:
clip = track.CopyTakeIntoTrack(system.CurrentTake.LocalTimeSpan, system.CurrentTake)
clip.Selected = True
except AttributeError:
FBMessageBox("Error", "Other Layer have keys", "Ok")
track.FBDelete()
pass
app = FBApplication()
system = FBSystem()
story = FBStory()
scene = system.Scene
addCharacterTrack()
PNG
####################################################################
# Find Clip Dictionaries in ClipDictionaryMetadatas which have custom substring in name and add new Flags attribute to them
# Print out entire modified ClipDictionaryMetadatas xml element to allow user to copy and paste back into clip set file
####################################################################
from pyfbsdk import *
import xml.etree.ElementTree as ET
import tempfile
import os
import RS.Config
def prettyPrint(elem, level=0):
i = "\n" + level * "\t"
if len( elem ):
if not elem.text or not elem.text.strip():
elem.text = i + "\t"
if not elem.tail or not elem.tail.strip():
elem.tail = i
for elem in elem:
prettyPrint(elem, level+1)
if not elem.tail or not elem.tail.strip():
elem.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
def getSubString():
value = None
result = FBMessageBoxGetUserValue( "Add Flags to ClipDictionaryMetadatas", "Enter partial folder path (e.g. MECH_LOCO_M@GENERIC@)", value , FBPopupInputType.kFBPopupString, "Go" )
return result[1]
def chooseClipSet():
# Create the popup and set necessary initial values.
lFp = FBFilePopup()
lFp.Caption = "Choose ClipSet to import"
lFp.Style = FBFilePopupStyle.kFBFilePopupOpen
# BUG: If we do not set the filter, we will have an exception.
lFp.Filter = "*.meta"
# Set the default path.
lFp.Path = RS.Config.Project.Path.Assets + "\\export\\data\\anim\\clip_sets\\clip_sets_groups\\"
# Get the GUI to show.
lRes = lFp.Execute()
# If we select files, show them, otherwise indicate that the selection was canceled.
if lRes:
return lFp
else:
return False
####################################################################
# custom class so we can find line numbers
# from: http://stackoverflow.com/questions/6949395/is-there-a-way-to-get-a-line-number-from-an-elementtree-element
####################################################################
class LineNumberingParser(ET.XMLParser):
def _start_list(self, *args, **kwargs):
# Here we assume the default XML parser which is expat
# and copy its element position attributes into output Elements
element = super(self.__class__, self)._start_list(*args, **kwargs)
element._start_line_number = self.parser.CurrentLineNumber
element._start_column_number = self.parser.CurrentColumnNumber
element._start_byte_index = self.parser.CurrentByteIndex
return element
def _end(self, *args, **kwargs):
element = super(self.__class__, self)._end(*args, **kwargs)
element._end_line_number = self.parser.CurrentLineNumber
element._end_column_number = self.parser.CurrentColumnNumber
element._end_byte_index = self.parser.CurrentByteIndex
return element
####################################################################
# main
####################################################################
search_substring = getSubString()
result = chooseClipSet()
if result:
xml_file = ( result.Path + "\\" + result.FileName )
tree = ET.parse( xml_file, parser=LineNumberingParser() )
root = tree.getroot()
search_tag = 'key'
#search_substring = 'MECH_LOCO_F@GENERIC'
##############################################################
# only search in the children section of each meta file
##############################################################
clipDictionaryMetadataElement = root.find('ClipDictionaryMetadatas')
if clipDictionaryMetadataElement:
children = clipDictionaryMetadataElement.getchildren()
for element in children:
if element.tag == 'Item':
##############################################################
# find items which match 'search_tag' and 'search_substring'
##############################################################
if search_tag in element.attrib:
if search_substring in element.attrib[ search_tag ]:
##############################################################
# add Flags attribute with DMF_ExcludeFromPopulationBudget
##############################################################
new_sub_entry = ET.SubElement( element, 'Flags')
new_sub_entry.text = 'DMF_ExcludeFromPopulationBudget'
prettyPrint( clipDictionaryMetadataElement )
##############################################################
# Save out results and open file
##############################################################
output_file_path = tempfile.gettempdir() + '\\mj_LocoMetaSearch_output.txt'
with open(output_file_path,'w') as f:
output = ET.tostring( clipDictionaryMetadataElement )
f.write( output )
f.closed
os.startfile( output_file_path )PNG
####################################################################
# Adds current character as a story track with current take added
####################################################################
from pyfbsdk import *
def addOverrideToStory():
track = FBStoryTrack(FBStoryTrackType.kFBStoryTrackCharacter, story.RootFolder)
track.Details.append(app.CurrentCharacter)
track.Label = system.CurrentTake.Name
subtrack = track.CreateSubTrack( FBStoryTrackType.kFBStoryTrackCharacter, FBStoryTrackRefMode.kFBStoryTrackOverride )
#subtrack = FBStoryTrack(FBStoryTrackType.kFBStoryTrackCharacter, story.RootFolder)
subtrack.Label = "(Override)"
subtrack.ReferenceMode = FBStoryTrackRefMode.kFBStoryTrackOverride
subtrack.PassThrough = True
subtrack.AcceptKey = False
app = FBApplication()
system = FBSystem()
story = FBStory()
scene = system.Scene
addOverrideToStory()
PNG
from pyfbsdk import *
from pyfbsdk_additions import *
from RS.Utils import Scene
def clamp(n, minn, maxn):
return max( min(maxn, n), minn )
def clearSelection():
''' Clear selection function '''
# Get selected models
modelList = FBModelList ()
FBGetSelectedModels (modelList, None, True)
# Deselect models
for model in modelList:
model.Selected = False
def getCharacterHeirarchyList(character):
characterNodeList = []
hips = character.GetModel( FBBodyNodeId.kFBHipsNodeId )
dummy = Scene.GetParent( hips )
Scene.GetChildren( dummy, characterNodeList, "", True )
return characterNodeList
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 RemoveXandYRotationKeys( object ):
for key in object.Rotation.GetAnimationNode().Nodes[0].FCurve.Keys:
key.Value = 0.0
for key in object.Rotation.GetAnimationNode().Nodes[1].FCurve.Keys:
key.Value = 0.0
# enforce Time Independent Tangent mode on Z rotation keys
for key in object.Rotation.GetAnimationNode().Nodes[2].FCurve.Keys:
key.TangentMode = FBTangentMode.kFBTangentModeTimeIndependent
def ResampleFilterRotationKeys( object, desired_density ):
###############################################################################################################
# process z rotation fcurve and remove all keys except for:
# * the start and end keys
# * any keys which fall at frame_step intervals
# Note: we use a cached fcurve to evaluate since we are deleting the keys as we go and it destroys our index
###############################################################################################################
take_start_frame = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
take_end_frame = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()
take_frame_range = float( take_end_frame - take_start_frame )
frame_step = int( take_frame_range / desired_density )
# z rotation key fcurve
fcurve = object.Rotation.GetAnimationNode().Nodes[2].FCurve
# make a copy of fcurve for reference
fcurve_cache = FBFCurve()
fcurve_cache.KeyReplaceBy( fcurve )
# loop backwards through fcurve keys
for i in range( len( fcurve.Keys ) - 1, -1, -1 ):
if frame_step != 0:
time_step_modulo = ( fcurve_cache.Keys[ i ].Time - fcurve_cache.Keys[ 0 ].Time ).GetFrame() % frame_step
else:
time_step_modulo = 0
if fcurve_cache.Keys[ i ].Time != FBTime( 0,0,0, take_start_frame ) \
and fcurve_cache.Keys[ i ].Time != FBTime( 0,0,0, take_end_frame ) \
and time_step_modulo != 0:
fcurve.KeyDelete( i, i )
def getSceneObject( name, characterNodeList ):
for node in characterNodeList:
if node.Name.lower() == name:
return node
# Error node not found in scene!
FBMessageBox( "Error", "Error: '" + name + "' object not found in scene!", "OK" )
raise Exception( "Error: " + name + " not found in scene!" )
def goButtonCallBack(control, event):
constraints = FBSystem().Scene.Constraints
#####################################################################################################
# Get Character Nodes
#####################################################################################################
currentCharacter = FBApplication().CurrentCharacter
characterNodeList = getCharacterHeirarchyList(currentCharacter)
# Find required nodes for constraints
OH_UpperFixup = getSceneObject( 'oh_upperfixupdirection', characterNodeList )
OH_Facing = getSceneObject( 'oh_facingdirection', characterNodeList )
OH_Torso = getSceneObject( 'oh_torsodirection', characterNodeList )
OH_Independent = getSceneObject( 'oh_independentmoverdirection', characterNodeList )
OH_MoverOffset = getSceneObject( 'oh_moveroffset', characterNodeList )
skel_torso = getSceneObject( 'skel_spine3', characterNodeList )
skel_head = getSceneObject( 'skel_head', characterNodeList )
skel_shoulders = getSceneObject( 'skel_spine5', characterNodeList )
mover_node = getSceneObject( 'mover', characterNodeList )
skel_root = getSceneObject( 'skel_root', characterNodeList )
lMgr = FBConstraintManager()
#####################################################################################################
# Create Facing Constraint
#####################################################################################################
if t.facing_enable_button.State:
# get index to rotation constraint
lIndex = None
for i in range(0, lMgr.TypeGetCount()):
if lMgr.TypeGetName(i) == 'Rotation':
lIndex = i
break
# create constraint
oh_facing_constraint = lMgr.TypeCreateConstraint(lIndex)
oh_facing_constraint.Name = 'OH_Facing_Direction_Constraint'
# add ref objects
for i in range(0, oh_facing_constraint.ReferenceGroupGetCount()):
if oh_facing_constraint.ReferenceGroupGetName(i) == 'Constrained Object':
oh_facing_constraint.ReferenceAdd(i, OH_Facing )
elif oh_facing_constraint.ReferenceGroupGetName(i) == 'Source':
oh_facing_constraint.ReferenceAdd(i, skel_head )
# snap/activate constraint
oh_facing_constraint.Active = True
oh_facing_constraint.PropertyList.Find("Rotation").Data = FBVector3d( 0.0, 90.0, 0.0 )
#####################################################################################################
# Create Upper Fixup Constraint
#####################################################################################################
if t.fixup_enable_button.State:
# get index to rotation constraint
lIndex = None
for i in range(0, lMgr.TypeGetCount()):
if lMgr.TypeGetName(i) == 'Rotation':
lIndex = i
break
# create constraint
oh_upperfixup_constraint = lMgr.TypeCreateConstraint(lIndex)
oh_upperfixup_constraint.Name = 'OH_Upperfixup_Constraint'
# add ref objects
for i in range(0, oh_upperfixup_constraint.ReferenceGroupGetCount()):
if oh_upperfixup_constraint.ReferenceGroupGetName(i) == 'Constrained Object':
oh_upperfixup_constraint.ReferenceAdd(i, OH_UpperFixup )
elif oh_upperfixup_constraint.ReferenceGroupGetName(i) == 'Source':
if t.hips_mode_button.State:
oh_upperfixup_constraint.ReferenceAdd(i, skel_root )
else:
oh_upperfixup_constraint.ReferenceAdd(i, mover_node )
# snap/activate constraint
oh_upperfixup_constraint.Active = True
oh_upperfixup_constraint.PropertyList.Find("Rotation").Data = FBVector3d( 0.0, 0.0, 0.0 )
#####################################################################################################
# Create Torso Constraint
#####################################################################################################
if t.torso_enable_button.State:
# get index to rotation constraint
lIndex = None
for i in range(0, lMgr.TypeGetCount()):
if lMgr.TypeGetName(i) == 'Rotation':
lIndex = i
break
# create constraint
oh_torso_constraint = lMgr.TypeCreateConstraint(lIndex)
oh_torso_constraint.Name = 'OH_Torso_Constraint'
# add ref objects
for i in range(0, oh_torso_constraint.ReferenceGroupGetCount()):
if oh_torso_constraint.ReferenceGroupGetName(i) == 'Constrained Object':
oh_torso_constraint.ReferenceAdd(i, OH_Torso )
elif oh_torso_constraint.ReferenceGroupGetName(i) == 'Source':
oh_torso_constraint.ReferenceAdd(i, skel_torso )
# snap/activate constraint
oh_torso_constraint.Active = True
oh_torso_constraint.PropertyList.Find("Rotation").Data = FBVector3d( 0.0, 90.0, 0.0 )
#####################################################################################################
# Create Independent Constraint
#####################################################################################################
if t.independent_enable_button.State:
# get index to rotation constraint
lIndex = None
for i in range(0, lMgr.TypeGetCount()):
if lMgr.TypeGetName(i) == 'Rotation':
lIndex = i
break
# create constraint
oh_independent_constraint = lMgr.TypeCreateConstraint(lIndex)
oh_independent_constraint.Name = 'oh_independent_constraint'
# add ref objects
for i in range(0, oh_independent_constraint.ReferenceGroupGetCount()):
if oh_independent_constraint.ReferenceGroupGetName(i) == 'Constrained Object':
oh_independent_constraint.ReferenceAdd(i, OH_Independent )
elif oh_independent_constraint.ReferenceGroupGetName(i) == 'Source':
oh_independent_constraint.ReferenceAdd(i, mover_node )
# snap/activate constraint
oh_independent_constraint.Active = True
oh_independent_constraint.PropertyList.Find("Rotation").Data = FBVector3d( 0.0, 0.0, 0.0 )
#####################################################################################################
# Create Mover Offset Constraint
#####################################################################################################
if t.mover_offset_enable_button.State:
#---------------------------------------------------------------------------------------------------
# Rotation Constraint
# --------------------------------------------------------------------------------------------------
lIndex = None
for i in range(0, lMgr.TypeGetCount()):
if lMgr.TypeGetName(i) == 'Rotation':
lIndex = i
break
# create constraint
oh_mover_offset_rot_constraint = lMgr.TypeCreateConstraint(lIndex)
oh_mover_offset_rot_constraint.Name = 'oh_mover_offset_rot_constraint'
# add ref objects
for i in range(0, oh_mover_offset_rot_constraint.ReferenceGroupGetCount()):
if oh_mover_offset_rot_constraint.ReferenceGroupGetName(i) == 'Constrained Object':
oh_mover_offset_rot_constraint.ReferenceAdd(i, OH_MoverOffset)
elif oh_mover_offset_rot_constraint.ReferenceGroupGetName(i) == 'Source':
oh_mover_offset_rot_constraint.ReferenceAdd(i, mover_node)
# snap/activate constraint
oh_mover_offset_rot_constraint.Active = True
if t.mover_offset_hips_mode_button.State == 1:
oh_mover_offset_rot_constraint.PropertyList.Find("Rotation").Data = FBVector3d(0.0, 0.0, -180.0)
else:
oh_mover_offset_rot_constraint.PropertyList.Find("Rotation").Data = FBVector3d(0.0, 0.0, 0.0)
#---------------------------------------------------------------------------------------------------
# Position Constraint
# --------------------------------------------------------------------------------------------------
for i in range(0, lMgr.TypeGetCount()):
if lMgr.TypeGetName(i) == 'Position':
lIndex = i
break
# create constraint
oh_mover_offset_pos_constraint = lMgr.TypeCreateConstraint(lIndex)
oh_mover_offset_pos_constraint.Name = 'oh_mover_offset_pos_constraint'
# add ref objects
for i in range(0, oh_mover_offset_pos_constraint.ReferenceGroupGetCount()):
if oh_mover_offset_pos_constraint.ReferenceGroupGetName(i) == 'Constrained Object':
oh_mover_offset_pos_constraint.ReferenceAdd(i, OH_MoverOffset)
elif oh_mover_offset_pos_constraint.ReferenceGroupGetName(i) == 'Source':
oh_mover_offset_pos_constraint.ReferenceAdd(i, mover_node)
# snap/activate constraint
oh_mover_offset_pos_constraint.Active = True
if t.mover_offset_hips_mode_button.State == 1:
oh_mover_offset_pos_constraint.PropertyList.Find("Translation").Data = FBVector3d(0.0, 0.0, 0.0)
else:
oh_mover_offset_pos_constraint.PropertyList.Find("Translation").Data = FBVector3d(0.0, -100.0, 0.0)
#####################################################################################################
# Plot and delete constraint
#####################################################################################################
selected_takes_list = []
# how many takes has user selected?
for iTake in FBSystem().Scene.Takes:
if ( iTake.Selected == True ):
selected_takes_list.append(iTake)
clearSelection()
OH_Facing.Selected = t.facing_enable_button.State
OH_UpperFixup.Selected = t.fixup_enable_button.State
OH_Torso.Selected = t.torso_enable_button.State
OH_Independent.Selected = t.independent_enable_button.State
OH_MoverOffset.Selected = t.mover_offset_enable_button.State
# if user hasn't selected any takes then just use the current one
if len( selected_takes_list ) == 0:
# make sure system in on base layer
FBSystem().CurrentTake.SetCurrentLayer(0)
FBSystem().CurrentTake.PlotTakeOnSelected( plotOptions() )
# flatten torso contraint by zeroing keys on X and Y axes
if t.facing_enable_button.State:
RemoveXandYRotationKeys( OH_Facing )
ResampleFilterRotationKeys( OH_Facing, t.desired_oh_facing_key_density )
if t.torso_enable_button.State:
RemoveXandYRotationKeys( OH_Torso )
ResampleFilterRotationKeys( OH_Torso, t.desired_oh_torso_key_density )
if t.fixup_enable_button.State:
RemoveXandYRotationKeys( OH_UpperFixup )
ResampleFilterRotationKeys( OH_UpperFixup, t.desired_oh_fixup_key_density )
if t.independent_enable_button.State:
RemoveXandYRotationKeys( OH_Independent )
ResampleFilterRotationKeys( OH_Independent, t.desired_oh_fixup_key_density )
if t.mover_offset_enable_button.State:
RemoveXandYRotationKeys(OH_MoverOffset)
ResampleFilterRotationKeys(OH_MoverOffset, t.desired_oh_fixup_key_density)
# else plot each selected take
else:
for take in selected_takes_list:
FBSystem().CurrentTake = take
# make sure system in on base layer
FBSystem().CurrentTake.SetCurrentLayer(0)
FBSystem().CurrentTake.PlotTakeOnSelected( plotOptions() )
# flatten torso contraint by zeroing keys on X and Y axes
if t.facing_enable_button.State:
RemoveXandYRotationKeys( OH_Facing )
ResampleFilterRotationKeys( OH_Facing, t.desired_oh_facing_key_density )
if t.torso_enable_button.State:
RemoveXandYRotationKeys( OH_Torso )
ResampleFilterRotationKeys( OH_Torso, t.desired_oh_torso_key_density )
if t.fixup_enable_button.State:
RemoveXandYRotationKeys( OH_UpperFixup )
ResampleFilterRotationKeys( OH_UpperFixup, t.desired_oh_fixup_key_density )
if t.independent_enable_button.State:
RemoveXandYRotationKeys( OH_Independent )
ResampleFilterRotationKeys( OH_Independent, t.desired_oh_fixup_key_density )
if t.mover_offset_enable_button.State:
RemoveXandYRotationKeys(OH_MoverOffset)
ResampleFilterRotationKeys(OH_MoverOffset, t.desired_oh_fixup_key_density)
clearSelection()
# delete constraints
if t.facing_enable_button.State:
oh_facing_constraint.FBDelete()
if t.fixup_enable_button.State:
oh_upperfixup_constraint.FBDelete()
if t.torso_enable_button.State:
oh_torso_constraint.FBDelete()
if t.independent_enable_button.State:
oh_independent_constraint.FBDelete()
if t.mover_offset_enable_button.State:
oh_mover_offset_rot_constraint.FBDelete()
oh_mover_offset_pos_constraint.FBDelete()
####################################################################
# UI definition and callbacks
####################################################################
def oh_facing_key_density_sliderUpdated(control, event):
take_start_frame = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
take_end_frame = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()
take_frame_range = take_end_frame - take_start_frame
density_value = int( control.Value * t.max_key_density )
density_value = clamp( density_value, 1 , t.max_key_density )
t.oh_facing_key_density_label.Caption = str ( density_value )
t.desired_oh_facing_key_density = density_value
def oh_torso_key_density_sliderUpdated(control, event):
take_start_frame = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
take_end_frame = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()
take_frame_range = take_end_frame - take_start_frame
density_value = int( control.Value * t.max_key_density )
density_value = clamp( density_value, 1 , t.max_key_density )
t.oh_torso_key_density_label.Caption = str ( density_value )
t.desired_oh_torso_key_density = density_value
def oh_fixup_key_density_sliderUpdated(control, event):
take_start_frame = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
take_end_frame = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()
take_frame_range = take_end_frame - take_start_frame
density_value = int( control.Value * t.max_key_density )
density_value = clamp( density_value, 1 , t.max_key_density )
t.oh_fixup_key_density_label.Caption = str ( density_value )
t.desired_oh_fixup_key_density = density_value
def modeButtonsCallback(control, event):
if t.mover_mode_button.State:
t.oh_fixup_key_density_slider.Enabled = False
if t.hips_mode_button.State:
t.oh_fixup_key_density_slider.Enabled = True
def EnableButtonCallback(control, event):
t.oh_facing_key_density_slider.Enabled = t.facing_enable_button.State
t.oh_facing_key_density_label.Enabled = t.facing_enable_button.State
t.oh_torso_key_density_slider.Enabled = t.torso_enable_button.State
t.oh_torso_key_density_label.Enabled = t.torso_enable_button.State
t.oh_fixup_key_density_slider.Enabled = t.fixup_enable_button.State
t.oh_fixup_key_density_label.Enabled = t.fixup_enable_button.State
t.hips_mode_button.Enabled = t.fixup_enable_button.State
t.mover_mode_button.Enabled = t.fixup_enable_button.State
#t.independent_hips_mode_button.Enabled = t.independent_enable_button.State
t.independent_mover_mode_button.Enabled = t.independent_enable_button.State
t.mover_offset_mover_mode_button.Enabled = t.mover_offset_enable_button.State
t.mover_offset_hips_mode_button.Enabled = t.mover_offset_enable_button.State
def PopulateTool(t):
ui_x_offset = 5
ui_y_offset = 5
ui_x_width = 250
ui_y_height = 70
ui_button_height = 30
ui_button_width = 40
ui_column_a = 50
ui_column_b = 130
ui_column_c = 180
##########################################################################################
# Mode Border and Controls
##########################################################################################
ui_y_offset += 5
#########################################################################################
# SLIDER DEFAULTS
##########################################################################################
t.min_key_density = 0
t.max_key_density = 20
t.oh_facing_key_density_default = 12
t.oh_torso_key_density_default = 18
t.oh_fixup_key_density_default = 4
##########################################################################################
# OH Facing Sample Label & oh_torso_key_density_slider
##########################################################################################
x = FBAddRegionParam(ui_x_offset,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_y_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("oh_facing_key_density_slider_border","OH Facing Key Density", x, y, w, h)
t.SetBorder("oh_facing_key_density_slider_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_y_offset += 25
x = FBAddRegionParam(ui_x_offset + 10,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 20,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(15,FBAttachType.kFBAttachNone,"")
t.AddRegion("oh_facing_density_label","oh_facing_density_label", x, y, w, h)
t.desired_oh_facing_key_density = t.oh_facing_key_density_default
t.oh_facing_key_density_label = FBLabel()
t.SetControl("oh_facing_density_label", t.oh_facing_key_density_label)
t.oh_facing_key_density_label.Justify = FBTextJustify.kFBTextJustifyCenter
t.oh_facing_key_density_label.Visible = True
t.oh_facing_key_density_label.ReadOnly = False
t.oh_facing_key_density_label.Enabled = True
t.oh_facing_key_density_label.Caption = str( t.desired_oh_facing_key_density )
ui_y_offset += 20
x = FBAddRegionParam(ui_x_offset + 10,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 20,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(15,FBAttachType.kFBAttachNone,"")
t.AddRegion("oh_facing_key_density_slider","oh_facing_key_density_slider", x, y, w, h)
t.oh_facing_key_density_slider = FBSlider()
t.oh_facing_key_density_slider.Value = ( 1.0 / t.max_key_density ) * t.desired_oh_facing_key_density
t.oh_facing_key_density_slider.Orientation = FBOrientation.kFBHorizontal
t.oh_facing_key_density_slider.OnTransaction.Add( oh_facing_key_density_sliderUpdated )
t.SetControl("oh_facing_key_density_slider", t.oh_facing_key_density_slider)
#------------------------------------------------------------------------------------
# Enable Button
ui_y_offset -= 35
x = FBAddRegionParam(ui_x_offset + 5,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset + 5,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(15,FBAttachType.kFBAttachNone,"")
t.AddRegion("facing_enable_button","facing_enable_button", x, y, w, h)
t.facing_enable_button = FBButton()
t.SetControl("facing_enable_button", t.facing_enable_button)
t.facing_enable_button.Visible = True
t.facing_enable_button.ReadOnly = False
t.facing_enable_button.Enabled = True
t.facing_enable_button.Hint = "Animate OH_FacingDirection?"
t.facing_enable_button.Caption = ""
t.facing_enable_button.State = 1
t.facing_enable_button.Style = FBButtonStyle.kFBCheckbox
t.facing_enable_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.facing_enable_button.Look = FBButtonLook.kFBLookNormal
t.facing_enable_button.OnClick.Add( EnableButtonCallback )
ui_y_offset += 35
#------------------------------------------------------------------------------------
##########################################################################################
# OH Torso Sample Label & oh_torso_key_density_slider
##########################################################################################
ui_y_offset += 35
x = FBAddRegionParam(ui_x_offset,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_y_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("oh_torso_key_density_slider_border","OH Torso Key Density", x, y, w, h)
t.SetBorder("oh_torso_key_density_slider_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_y_offset += 30
x = FBAddRegionParam(ui_x_offset + 10,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 20,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(15,FBAttachType.kFBAttachNone,"")
t.AddRegion("oh_torso_density_label","oh_torso_density_label", x, y, w, h)
t.desired_oh_torso_key_density = t.oh_torso_key_density_default
t.oh_torso_key_density_label = FBLabel()
t.SetControl("oh_torso_density_label", t.oh_torso_key_density_label)
t.oh_torso_key_density_label.Justify = FBTextJustify.kFBTextJustifyCenter
t.oh_torso_key_density_label.Visible = True
t.oh_torso_key_density_label.ReadOnly = False
t.oh_torso_key_density_label.Enabled = True
t.oh_torso_key_density_label.Caption = str( t.desired_oh_torso_key_density )
ui_y_offset += 20
x = FBAddRegionParam(ui_x_offset + 10,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 20,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(15,FBAttachType.kFBAttachNone,"")
t.AddRegion("oh_torso_key_density_slider","oh_torso_key_density_slider", x, y, w, h)
t.oh_torso_key_density_slider = FBSlider()
t.oh_torso_key_density_slider.Value = ( 1.0 / t.max_key_density ) * t.desired_oh_torso_key_density
t.oh_torso_key_density_slider.Orientation = FBOrientation.kFBHorizontal
t.oh_torso_key_density_slider.OnTransaction.Add( oh_torso_key_density_sliderUpdated )
t.SetControl("oh_torso_key_density_slider", t.oh_torso_key_density_slider)
#------------------------------------------------------------------------------------
# Enable Button
ui_y_offset -= 35
x = FBAddRegionParam(ui_x_offset + 5,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset + 5,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(15,FBAttachType.kFBAttachNone,"")
t.AddRegion("torso_enable_button","torso_enable_button", x, y, w, h)
t.torso_enable_button = FBButton()
t.SetControl("torso_enable_button", t.torso_enable_button)
t.torso_enable_button.Visible = True
t.torso_enable_button.ReadOnly = False
t.torso_enable_button.Enabled = True
t.torso_enable_button.Hint = "Animate OH_TorsoDirection?"
t.torso_enable_button.Caption = ""
t.torso_enable_button.State = 1
t.torso_enable_button.Style = FBButtonStyle.kFBCheckbox
t.torso_enable_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.torso_enable_button.Look = FBButtonLook.kFBLookNormal
t.torso_enable_button.OnClick.Add( EnableButtonCallback )
ui_y_offset += 35
#------------------------------------------------------------------------------------
##########################################################################################
# OH Fixup Sample Label & oh_torso_key_density_slider
##########################################################################################
ui_y_offset += 30
x = FBAddRegionParam(ui_x_offset,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_y_height + 30,FBAttachType.kFBAttachNone,"")
t.AddRegion("oh_fixup_key_density_slider_border","OH Fixup Follow Mode & Key Density", x, y, w, h)
t.SetBorder("oh_fixup_key_density_slider_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_y_offset += 30
#Buttons
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"mover_mode_button")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(95,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("mover_mode_button","mover_mode_button", x, y, w, h)
t.mover_mode_button = FBButton()
t.SetControl("mover_mode_button", t.mover_mode_button)
t.mover_mode_button.Visible = True
t.mover_mode_button.ReadOnly = False
t.mover_mode_button.Enabled = True
t.mover_mode_button.Hint = "Simply match mover direction"
t.mover_mode_button.Caption = "Mover"
t.mover_mode_button.State = 1
t.mover_mode_button.Style = FBButtonStyle.kFBRadioButton
t.mover_mode_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.mover_mode_button.Look = FBButtonLook.kFBLookNormal
t.mover_mode_button.OnClick.Add( modeButtonsCallback )
x = FBAddRegionParam(ui_column_b,FBAttachType.kFBAttachTop,"hips_mode_button")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(90,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("hips_mode_button","hips_mode_button", x, y, w, h)
t.hips_mode_button = FBButton()
t.SetControl("hips_mode_button", t.hips_mode_button)
t.hips_mode_button.Visible = True
t.hips_mode_button.ReadOnly = False
t.hips_mode_button.Enabled = True
t.hips_mode_button.Hint = "Follow hip direction using key density options"
t.hips_mode_button.Caption = "Hips"
t.hips_mode_button.State = 0
t.hips_mode_button.Style = FBButtonStyle.kFBRadioButton
t.hips_mode_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.hips_mode_button.Look = FBButtonLook.kFBLookNormal
t.hips_mode_button.OnClick.Add( modeButtonsCallback )
t.fixup_mode_radio_buttons = FBButtonGroup()
t.fixup_mode_radio_buttons.Add(t.mover_mode_button)
t.fixup_mode_radio_buttons.Add(t.hips_mode_button)
ui_y_offset += 30
x = FBAddRegionParam(ui_x_offset + 10,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 20,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(15,FBAttachType.kFBAttachNone,"")
t.AddRegion("oh_fixup_density_label","oh_fixup_density_label", x, y, w, h)
t.desired_oh_fixup_key_density = t.oh_fixup_key_density_default
t.oh_fixup_key_density_label = FBLabel()
t.SetControl("oh_fixup_density_label", t.oh_fixup_key_density_label)
t.oh_fixup_key_density_label.Justify = FBTextJustify.kFBTextJustifyCenter
t.oh_fixup_key_density_label.Visible = True
t.oh_fixup_key_density_label.ReadOnly = False
t.oh_fixup_key_density_label.Enabled = True
t.oh_fixup_key_density_label.Caption = str( t.desired_oh_fixup_key_density )
ui_y_offset += 20
x = FBAddRegionParam(ui_x_offset + 10,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 20,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(15,FBAttachType.kFBAttachNone,"")
t.AddRegion("oh_fixup_key_density_slider","oh_fixup_key_density_slider", x, y, w, h)
t.oh_fixup_key_density_slider = FBSlider()
t.oh_fixup_key_density_slider.Value = ( 1.0 / t.max_key_density ) * t.desired_oh_fixup_key_density
t.oh_fixup_key_density_slider.Orientation = FBOrientation.kFBHorizontal
t.oh_fixup_key_density_slider.OnTransaction.Add( oh_fixup_key_density_sliderUpdated )
t.SetControl("oh_fixup_key_density_slider", t.oh_fixup_key_density_slider)
#------------------------------------------------------------------------------------
# Enable Button
ui_y_offset -= 70
x = FBAddRegionParam(ui_x_offset + 5,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset + 5,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(15,FBAttachType.kFBAttachNone,"")
t.AddRegion("fixup_enable_button","fixup_enable_button", x, y, w, h)
t.fixup_enable_button = FBButton()
t.SetControl("fixup_enable_button", t.fixup_enable_button)
t.fixup_enable_button.Visible = True
t.fixup_enable_button.ReadOnly = False
t.fixup_enable_button.Enabled = True
t.fixup_enable_button.Hint = "Animate OH_FixupDirection?"
t.fixup_enable_button.Caption = ""
t.fixup_enable_button.State = 1
t.fixup_enable_button.Style = FBButtonStyle.kFBCheckbox
t.fixup_enable_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.fixup_enable_button.Look = FBButtonLook.kFBLookNormal
t.fixup_enable_button.OnClick.Add( EnableButtonCallback )
ui_y_offset += 70
#------------------------------------------------------------------------------------
##########################################################################################
# OH Independent Mover Direction
##########################################################################################
ui_y_offset += 30
x = FBAddRegionParam(ui_x_offset,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_y_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("oh_independent_mover_border","OH Independent Follow Mode", x, y, w, h)
t.SetBorder("oh_independent_mover_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_y_offset += 30
#Buttons
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"independent_mover_mode_button")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(95,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("independent_mover_mode_button","independent_mover_mode_button", x, y, w, h)
t.independent_mover_mode_button = FBButton()
t.SetControl("independent_mover_mode_button", t.independent_mover_mode_button)
t.independent_mover_mode_button.Visible = True
t.independent_mover_mode_button.ReadOnly = False
t.independent_mover_mode_button.Enabled = True
t.independent_mover_mode_button.Hint = "Simply match mover direction"
t.independent_mover_mode_button.Caption = "Mover"
t.independent_mover_mode_button.State = 1
t.independent_mover_mode_button.Style = FBButtonStyle.kFBRadioButton
t.independent_mover_mode_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.independent_mover_mode_button.Look = FBButtonLook.kFBLookNormal
t.independent_mover_mode_button.OnClick.Add( modeButtonsCallback )
x = FBAddRegionParam(ui_column_b,FBAttachType.kFBAttachTop,"independent_hips_mode_button")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(90,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("independent_hips_mode_button","independent_hips_mode_button", x, y, w, h)
t.independent_hips_mode_button = FBButton()
t.SetControl("independent_hips_mode_button", t.independent_hips_mode_button)
t.independent_hips_mode_button.Visible = True
t.independent_hips_mode_button.ReadOnly = True
t.independent_hips_mode_button.Enabled = False
t.independent_hips_mode_button.Hint = "Follow hip direction using key density options"
t.independent_hips_mode_button.Caption = "Hips"
t.independent_hips_mode_button.State = 0
t.independent_hips_mode_button.Style = FBButtonStyle.kFBRadioButton
t.independent_hips_mode_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.independent_hips_mode_button.Look = FBButtonLook.kFBLookNormal
t.independent_hips_mode_button.OnClick.Add( modeButtonsCallback )
t.independent_mode_radio_buttons = FBButtonGroup()
t.independent_mode_radio_buttons.Add(t.independent_mover_mode_button)
t.independent_mode_radio_buttons.Add(t.independent_hips_mode_button)
# Enable Button
ui_y_offset -= 20
x = FBAddRegionParam(ui_x_offset + 5, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset + 5, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(20, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(15, FBAttachType.kFBAttachNone, "")
t.AddRegion("independent_enable_button", "independent_enable_button", x, y, w, h)
t.independent_enable_button = FBButton()
t.SetControl("independent_enable_button", t.independent_enable_button)
t.independent_enable_button.Visible = True
t.independent_enable_button.ReadOnly = False
t.independent_enable_button.Enabled = True
t.independent_enable_button.Hint = "Animate OH_IndependentDirection?"
t.independent_enable_button.Caption = ""
t.independent_enable_button.State = 1
t.independent_enable_button.Style = FBButtonStyle.kFBCheckbox
t.independent_enable_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.independent_enable_button.Look = FBButtonLook.kFBLookNormal
t.independent_enable_button.OnClick.Add(EnableButtonCallback)
ui_y_offset += 70
# ------------------------------------------------------------------------------------
##########################################################################################
# OH Mover Offset Direction
##########################################################################################
ui_y_offset += 0
x = FBAddRegionParam(ui_x_offset, FBAttachType.kFBAttachNone, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_y_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("oh_mover_offset_border", "OH Mover Offset Follow Mode", x, y, w, h)
t.SetBorder("oh_mover_offset_border", FBBorderStyle.kFBEmbossBorder, True, True, 2, 0, 90.0, 0)
ui_y_offset += 30
# Buttons
x = FBAddRegionParam(ui_column_a, FBAttachType.kFBAttachTop, "mover_offset_mover_mode_button")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(95, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("mover_offset_mover_mode_button", "mover_offset_mover_mode_button", x, y, w, h)
t.mover_offset_mover_mode_button = FBButton()
t.SetControl("mover_offset_mover_mode_button", t.mover_offset_mover_mode_button)
t.mover_offset_mover_mode_button.Visible = True
t.mover_offset_mover_mode_button.ReadOnly = False
t.mover_offset_mover_mode_button.Enabled = True
t.mover_offset_mover_mode_button.Hint = "Match bottom of mover"
t.mover_offset_mover_mode_button.Caption = "Mover"
t.mover_offset_mover_mode_button.State = 0
t.mover_offset_mover_mode_button.Style = FBButtonStyle.kFBRadioButton
t.mover_offset_mover_mode_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.mover_offset_mover_mode_button.Look = FBButtonLook.kFBLookNormal
#t.mover_offset_mover_mode_button.OnClick.Add(modeButtonsCallback)
x = FBAddRegionParam(ui_column_b, FBAttachType.kFBAttachTop, "mover_offset_hips_mode_button")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(90, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("mover_offset_hips_mode_button", "mover_offset_hips_mode_button", x, y, w, h)
t.mover_offset_hips_mode_button = FBButton()
t.SetControl("mover_offset_hips_mode_button", t.mover_offset_hips_mode_button)
t.mover_offset_hips_mode_button.Visible = True
t.mover_offset_hips_mode_button.ReadOnly = False
t.mover_offset_hips_mode_button.Enabled = True
t.mover_offset_hips_mode_button.Hint = "Follow the reverse of mover direction (default)"
t.mover_offset_hips_mode_button.Caption = "Default"
t.mover_offset_hips_mode_button.State = 1
t.mover_offset_hips_mode_button.Style = FBButtonStyle.kFBRadioButton
t.mover_offset_hips_mode_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.mover_offset_hips_mode_button.Look = FBButtonLook.kFBLookNormal
#t.mover_offset_hips_mode_button.OnClick.Add(modeButtonsCallback)
t.mover_offset_mode_radio_buttons = FBButtonGroup()
t.mover_offset_mode_radio_buttons.Add(t.mover_offset_mover_mode_button)
t.mover_offset_mode_radio_buttons.Add(t.mover_offset_hips_mode_button)
# Enable Button
ui_y_offset -= 20
x = FBAddRegionParam(ui_x_offset + 5, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset + 5, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(20, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(15, FBAttachType.kFBAttachNone, "")
t.AddRegion("mover_offset_enable_button", "mover_offset_enable_button", x, y, w, h)
t.mover_offset_enable_button = FBButton()
t.SetControl("mover_offset_enable_button", t.mover_offset_enable_button)
t.mover_offset_enable_button.Visible = True
t.mover_offset_enable_button.ReadOnly = False
t.mover_offset_enable_button.Enabled = True
t.mover_offset_enable_button.Hint = "Animate OH_MoverOffset?"
t.mover_offset_enable_button.Caption = ""
t.mover_offset_enable_button.State = 1
t.mover_offset_enable_button.Style = FBButtonStyle.kFBCheckbox
t.mover_offset_enable_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.mover_offset_enable_button.Look = FBButtonLook.kFBLookNormal
t.mover_offset_enable_button.OnClick.Add(EnableButtonCallback)
ui_y_offset += 70
#------------------------------------------------------------------------------------
##########################################################################################
# Go button
##########################################################################################
x = FBAddRegionParam(ui_x_offset,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("go_button_region","go_button_region", x, y, w, h)
t.go_button = FBButton()
t.SetControl("go_button_region", t.go_button)
t.go_button.Visible = True
t.go_button.ReadOnly = False
t.go_button.Enabled = True
t.go_button.Hint = ""
t.go_button.Caption = "Animate OH Bones"
t.go_button.State = 0
t.go_button.Style = FBButtonStyle.kFBPushButton
t.go_button.Justify = FBTextJustify.kFBTextJustifyCenter
t.go_button.Look = FBButtonLook.kFBLookNormal
t.go_button.OnClick.Add(goButtonCallBack)
##########################################################################################
# Calculate Tool Window Size and Draw
##########################################################################################
t.StartSizeX = ui_x_width + 27
t.StartSizeY = ui_y_offset + 75
ShowTool(t)
####################################################################
# Main
####################################################################
def CreateTool():
global t
version = 1.0
t = FBCreateUniqueTool("AnimateOHBones v" + str( version ) )
PopulateTool( t )
CreateTool()PNG
from fbx import *
from FbxCommon import *
from pyfbsdk_additions import *
from pyfbsdk import *
import RS.Globals
import RS.Config
import fbx
global SKEL_NODES_LIST
def GetSkelNodes():
SKEL_NODES_LIST = []
HUMAN_NODES_LIST = ( RS.Globals.gSkelArray )
ANIMAL_NODES_LIST = ( RS.Globals.gAnimalSkelArray )
# construct master SKEL_NODES_LIST from human and animals
# first add mover and badly named horse tail ( url:bugstar:2594825 - 2014 RS.Globals.gAnimalSkelTailArray is incorrect )
SKEL_NODES_LIST.append( 'mover' )
SKEL_NODES_LIST.append( 'SKEL_Tail1' )
SKEL_NODES_LIST.append( 'SKEL_Tail2' )
SKEL_NODES_LIST.append( 'SKEL_Tail3' )
SKEL_NODES_LIST.append( 'SKEL_Tail4' )
SKEL_NODES_LIST.append( 'PH_R_Hand' )
SKEL_NODES_LIST.append( 'PH_L_Hand' )
for entry in HUMAN_NODES_LIST:
SKEL_NODES_LIST.append( entry )
for entry in ANIMAL_NODES_LIST:
SKEL_NODES_LIST.append( RS.Globals.gAnimalPrefixSkel + entry )
return SKEL_NODES_LIST
def GetFBXCharacterNamespace( name ):
try:
namespace = str( name ).split( ':' )[ 0 ]
# Multiple ':' in the namespace, so deal with that situation.
except ValueError:
namespaces = str( name ).split( ':' )[ :-1 ]
namespace = ''
for i in namespaces:
namespace += '{0}:'.format( i )
namespace = self.namespace.rstrip( ':' )
return namespace
def findAnimationNode( pName, pNode ):
lResult = None
lName = pName.split( '/' )
for lNode in pNode.Nodes:
if lNode.Name == lName[0]:
if len( lName ) > 1:
lResult = findAnimationNode( pName.replace( '%s/' % lName[0], '' ), lNode )
else:
lResult = lNode
return lResult
def copyAnimationFromCurve( curve, animationNode ):
'''
copies all animation from fbx curve, to MB animation node
'''
num_of_keys = curve.KeyGetCount()
fcurve = animationNode.FCurve
# Clear existing animation on model.
fcurve.EditClear()
# Begin adding the new keys.
fcurve.EditBegin()
for key_index in range( num_of_keys ):
value = curve.KeyGetValue( key_index )
time = curve.KeyGetTime( key_index ).Get()
fcurve.KeyAdd( FBTime( time ), value )
fcurve.EditEnd()
def fbxGetMatchingAnimationFromLayer( animLayer, node ):
'''
Description:
Inspects the supplied fbx animation layer, and finds the animation for each model on the layer.
Author:
Jason Hayes <jason.hayes@rockstarsandiego.com>
Arguments:
animLayer: The fbx animation layer object.
node: The fbx object to inspect.
'''
# Iterate over each node and only look at meshes.
for modelId in range( node.GetChildCount() ):
model = node.GetChild( modelId )
#if model.GetTypeName() == 'LimbNode':
if True:
model_name = str( model.GetName() )
try:
namespace, name = model_name.split( ':' )
# Hit multiple : in the name. For now, it isn't what we
except ValueError:
namespaces = model_name.split( ':' )[ :-1 ]
namespace = ''
for i in namespaces:
namespace += '{0}:'.format( i )
namespace = namespace.rstrip( ':' )
name = model_name.split( ':' )[ -1 ]
desired_source_namespace = GetFBXCharacterNamespace( t.source_char_list.Items[ t.source_char_list.ItemIndex ] )
#print "model_name is " + str( model_name )
#print "name is " + str( name )
#print "namespace is " + str( namespace )
#print "desired_source_namespace is " + str( desired_source_namespace )
if name in SKEL_NODES_LIST and namespace == desired_source_namespace:
#print "processing source curve for " + str(namespace) + ":" + str(name)
desired_model_long_name = t.selected_dest_char_namespace + ":" + name
destinationModel = FBFindModelByLabelName( str( desired_model_long_name ) )
# If the model exists in the scene...
if destinationModel:
# transfer the fcurve data.
# Translation
xPosCurve = model.LclTranslation.GetCurve( animLayer, 'X' )
yPosCurve = model.LclTranslation.GetCurve( animLayer, 'Y' )
zPosCurve = model.LclTranslation.GetCurve( animLayer, 'Z' )
if xPosCurve:
animationNode = findAnimationNode( 'Lcl Translation/X', destinationModel.AnimationNode )
if animationNode:
copyAnimationFromCurve( xPosCurve, animationNode )
if yPosCurve:
animationNode = findAnimationNode( 'Lcl Translation/Y', destinationModel.AnimationNode )
if animationNode:
copyAnimationFromCurve( yPosCurve, animationNode )
if zPosCurve:
animationNode = findAnimationNode( 'Lcl Translation/Z', destinationModel.AnimationNode )
if animationNode:
copyAnimationFromCurve( zPosCurve, animationNode )
# Rotation
xRotCurve = model.LclRotation.GetCurve( animLayer, 'X' )
yRotCurve = model.LclRotation.GetCurve( animLayer, 'Y' )
zRotCurve = model.LclRotation.GetCurve( animLayer, 'Z' )
if xRotCurve:
animationNode = findAnimationNode( 'Lcl Rotation/X', destinationModel.AnimationNode )
if animationNode:
copyAnimationFromCurve( xRotCurve, animationNode )
if yRotCurve:
animationNode = findAnimationNode( 'Lcl Rotation/Y', destinationModel.AnimationNode )
if animationNode:
copyAnimationFromCurve( yRotCurve, animationNode )
if zRotCurve:
animationNode = findAnimationNode( 'Lcl Rotation/Z', destinationModel.AnimationNode )
if animationNode:
copyAnimationFromCurve( zRotCurve, animationNode )
fbxGetMatchingAnimationFromLayer( animLayer, model )
def loadFBXIntoMemory( filepath ):
# Initialize the fbx sdk.
t.sdkManager, t.fbxScene = InitializeSdkObjects()
# Load the fbx file into memory.
result = LoadScene( t.sdkManager, t.fbxScene, filepath )
return result
def fbxGetCharactersFromFBX( fbxScene ):
num_characters = fbxScene.GetCharacterCount()
characters = []
for char_index in range( num_characters ):
character = fbxScene.GetCharacter( char_index )
characters.append( character.GetName() )
return characters
def importCharacterAnimation():
'''
'''
# fetch list of selected takes
selected_takes = []
for item in range( len(t.takeSelectionUI.list.Items) ):
if( t.takeSelectionUI.list.IsSelected( item ) ):
selected_takes.append( t.takeSelectionUI.list.Items[ item ] )
system = FBSystem()
numTakes = t.fbxScene.GetSrcObjectCount( FbxAnimStack.ClassId )
for takeId in range( numTakes ):
take = t.fbxScene.GetSrcObject( FbxAnimStack.ClassId, takeId )
take_name = str( take.GetName() )
if take_name in selected_takes:
# create take
FBSystem().CurrentTake.CopyTake("copy")
# go to new take
FBSystem().CurrentTake = FBSystem().Scene.Takes[-1]
# clear all the animation on the new take
FBSystem().CurrentTake.ClearAllProperties( False )
# rename take
currentTake = system.CurrentTake
currentTake.Name = take_name
timespan = FbxAnimStack.GetLocalTimeSpan( take )
# set correct time range
start = FBTime(
timespan.GetStart().GetTime()[1],
timespan.GetStart().GetTime()[2],
timespan.GetStart().GetTime()[3],
timespan.GetStart().GetTime()[4],
0 )
stop = FBTime(
timespan.GetStop().GetTime()[1],
timespan.GetStop().GetTime()[2],
timespan.GetStop().GetTime()[3],
timespan.GetStop().GetTime()[4],
0 )
FBSystem().CurrentTake.LocalTimeSpan = FBTimeSpan( start, stop )
# Get the number of animation layers for this take.
num_layers = take.GetSrcObjectCount( FbxAnimLayer.ClassId )
for layer_index in range( num_layers ):
# Get the animation layer object.
layer = take.GetSrcObject( FbxAnimLayer.ClassId, layer_index )
layer_name = str ( layer.GetName() ).split( ':' )[ -1 ]
scene_num_layers = currentTake.GetLayerCount()
matchingLayer = None
# run through layers and see if there are any missing matches
for scene_layer_index in range( scene_num_layers ):
scene_layer = currentTake.GetLayer( scene_layer_index )
if scene_layer.Name == layer_name:
# TODO: Ask to make sure the user wants to override existing animation on this layer.
currentTake.SetCurrentLayer( scene_layer_index )
matchingLayer = layer
break
# No layer using the name found, so create a new one.
if not matchingLayer:
currentTake.CreateNewLayer()
scene_num_layers = currentTake.GetLayerCount()
currentLayer = currentTake.GetLayer( scene_num_layers - 1 )
currentLayer.Name = layer_name
currentTake.SetCurrentLayer( scene_num_layers - 1 )
# Iterate over each model in the animation file.
# get matching models for each layer
fbxGetMatchingAnimationFromLayer( layer, t.fbxScene.GetRootNode() )
takeId += 1
# close take selection UI
FBDestroyToolByName("Select Takes")
#---------------------------------------------------------------------------------------------------------------------------------------------------------------
# UI
#---------------------------------------------------------------------------------------------------------------------------------------------------------------
def takeSelectionButtonCallback(control, event):
global SKEL_NODES_LIST
SKEL_NODES_LIST = GetSkelNodes()
t.takeSelectionUI = FBCreateUniqueTool("Select Takes")
PopulateTakeSelectionUI( t.takeSelectionUI )
def sourceListCallback(control, event):
#Enable UI in response to user input
t.source_char_label.Caption = "Source Selected"
t.source_char_label.Enabled = True
if t.source_char_label.Enabled and t.dest_char_label.Enabled:
# enable > label
t.target_label.Caption = ">>"
t.target_label.Enabled = True
# enable transfer button
t.takeSelectionButton.Enabled = True
def destListCallback(control, event):
#Enable UI in response to user input
t.dest_char_label.Caption = "Destination Selected"
t.dest_char_label.Enabled = True
#determine target namespace from selection
t.selected_dest_char_namespace = control.Items[control.ItemIndex].split( ':' )[ 0 ]
if t.source_char_label.Enabled and t.dest_char_label.Enabled:
t.target_label.Caption = ">>"
t.target_label.Enabled = True
# enable transfer button
t.takeSelectionButton.Enabled = True
def loadButtonCallBack(control, event):
# get fbx file path from user
fbx = chooseFBX()
if fbx:
t.load_button.Caption = "Loading FBX..."
filepath = ( fbx.Path + "\\" + fbx.FileName )
#load fbx into memory through SDK
loadFBXIntoMemory( filepath )
characters = fbxGetCharactersFromFBX( t.fbxScene )
#add characters in source fbx to UI
for char in characters:
t.source_char_list.Items.append( str(char) )
t.load_button.Caption = "Load Complete. Select Source and Destination."
t.load_button.Enabled = False
else:
print "Fbx selection cancelled."
def PopulateListWithCharacters( uiList ):
for char in RS.Globals.Characters:
uiList.Items.append( char.LongName )
def chooseFBX():
# Create the popup and set necessary initial values.
lFp = FBFilePopup()
lFp.Caption = "Choose FBX to import from"
lFp.Style = FBFilePopupStyle.kFBFilePopupOpen
# BUG: If we do not set the filter, we will have an exception.
lFp.Filter = "*.fbx"
# Set the default path.
lFp.Path = RS.Config.Project.Path.Art + "\\animation\\ingame\\source\\"
# Get the GUI to show.
lRes = lFp.Execute()
# If we select files, show them, otherwise indicate that the selection was canceled.
if lRes:
return lFp
else:
return False
def PopulateLayout(t):
# ui modifiers for easier element positioning
ui_tool_width = 250
ui_gap = 5
ui_list_width = ui_tool_width - ui_gap * 10
ui_list_height = 200
ui_targetlabel_width = 20
ui_label_height = 20
ui_button_height = 30
ui_window_edge = 18 # magic number to add on width of UI edge
#init positions
ui_offset_width = ui_gap
ui_offset_height = ui_gap
#----------------------------------------------------------------------------
# Source Character Label
#----------------------------------------------------------------------------
t.source_char_label = FBLabel()
x = FBAddRegionParam(ui_offset_width,FBAttachType.kFBAttachTop,"status_region")
y = FBAddRegionParam(ui_offset_height,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_list_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_label_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("sourceLabel_region","sourceLabel_region", x, y, w, h)
t.SetControl("sourceLabel_region", t.source_char_label)
t.source_char_label.Visible = True
t.source_char_label.ReadOnly = False
t.source_char_label.Enabled = False
t.source_char_label.Justify = FBTextJustify.kFBTextJustifyCenter
t.source_char_label.Caption = "Select Source"
#----------------------------------------------------------------------------
# Destination Character Label
#----------------------------------------------------------------------------
ui_offset_width += ui_list_width + ui_targetlabel_width
t.dest_char_label = FBLabel()
x = FBAddRegionParam(ui_offset_width,FBAttachType.kFBAttachTop,"status_region")
y = FBAddRegionParam(ui_offset_height,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_list_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_label_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("destLabel_region","destLabel_region", x, y, w, h)
t.SetControl("destLabel_region", t.dest_char_label)
t.dest_char_label.Visible = True
t.dest_char_label.ReadOnly = False
t.dest_char_label.Enabled = False
t.dest_char_label.Justify = FBTextJustify.kFBTextJustifyCenter
t.dest_char_label.Caption = "Select Destination"
#----------------------------------------------------------------------------
# Source Character List
#----------------------------------------------------------------------------
ui_offset_width = ui_gap
ui_offset_height += ui_label_height + ui_gap
x = FBAddRegionParam(ui_offset_width,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_offset_height,FBAttachType.kFBAttachTop,"")
w = FBAddRegionParam(ui_list_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_list_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("source_char_list","source_char_list", x,y,w,h)
t.source_char_list = FBList()
t.SetControl("source_char_list", t.source_char_list)
t.source_char_list.Style = FBListStyle.kFBVerticalList
#add list call back
t.source_char_list.OnChange.Add(sourceListCallback)
#----------------------------------------------------------------------------
# > Label
#----------------------------------------------------------------------------
ui_offset_width += ui_list_width
t.target_label = FBLabel()
x = FBAddRegionParam(ui_offset_width,FBAttachType.kFBAttachTop,"status_region")
y = FBAddRegionParam(ui_offset_height,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_targetlabel_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_list_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("targetLabel_region","targetLabel_region", x, y, w, h)
t.SetControl("targetLabel_region", t.target_label)
t.target_label.Visible = True
t.target_label.ReadOnly = False
t.target_label.Enabled = False
t.target_label.Justify = FBTextJustify.kFBTextJustifyCenter
t.target_label.Caption = ">"
#----------------------------------------------------------------------------
# Destination Character List
#----------------------------------------------------------------------------
ui_offset_width += ui_targetlabel_width
x = FBAddRegionParam(ui_offset_width,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_offset_height,FBAttachType.kFBAttachTop,"")
w = FBAddRegionParam(ui_list_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_list_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("dest_char_list","dest_char_list", x,y,w,h)
t.dest_char_list = FBList()
t.SetControl("dest_char_list", t.dest_char_list)
t.dest_char_list.Style = FBListStyle.kFBVerticalList
PopulateListWithCharacters( t.dest_char_list )
t.dest_char_list.OnChange.Add(destListCallback)
#----------------------------------------------------------------------------
# FBX load button
#----------------------------------------------------------------------------
ui_offset_width = ui_gap
ui_offset_height += ui_list_height + ui_gap
x = FBAddRegionParam(ui_offset_width,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_offset_height,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam((ui_list_width * 2) + ui_targetlabel_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("load_button_region","load_button_region", x, y, w, h)
t.load_button = FBButton()
t.SetControl("load_button_region", t.load_button)
t.load_button.Visible = True
t.load_button.ReadOnly = False
t.load_button.Enabled = True
t.load_button.Hint = ""
t.load_button.Caption = "Choose Source FBX"
t.load_button.State = 0
t.load_button.Style = FBButtonStyle.kFBPushButton
t.load_button.Justify = FBTextJustify.kFBTextJustifyCenter
t.load_button.Look = FBButtonLook.kFBLookNormal
t.load_button.OnClick.Add(loadButtonCallBack)
#----------------------------------------------------------------------------
# takeSlection Button
#----------------------------------------------------------------------------
ui_offset_height += ui_button_height + ui_gap
x = FBAddRegionParam(ui_offset_width,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_offset_height,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam((ui_list_width * 2) + ui_targetlabel_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("takeSelection_button_region","takeSelection_button_region", x, y, w, h)
t.takeSelectionButton = FBButton()
t.SetControl("takeSelection_button_region", t.takeSelectionButton)
t.takeSelectionButton.Visible = True
t.takeSelectionButton.ReadOnly = False
t.takeSelectionButton.Enabled = False
t.takeSelectionButton.Hint = ""
t.takeSelectionButton.Caption = "Select Takes"
t.takeSelectionButton.State = 0
t.takeSelectionButton.Style = FBButtonStyle.kFBPushButton
t.takeSelectionButton.Justify = FBTextJustify.kFBTextJustifyCenter
t.takeSelectionButton.Look = FBButtonLook.kFBLookNormal
t.takeSelectionButton.OnClick.Add(takeSelectionButtonCallback)
#----------------------------------------------------------------
# show tool
#----------------------------------------------------------------
t.StartSizeX = ui_gap*2 + ui_list_width*2 + ui_targetlabel_width + ui_window_edge
t.StartSizeY = ui_list_height + ui_button_height * 2 + ui_label_height + ui_gap * 6 + ui_window_edge
ShowTool(t)
####################################################################
# Take Selection UI Callbacks
####################################################################
def AllTakesCallback(control, event):
for item in range( len(t.takeSelectionUI.list.Items) ):
t.takeSelectionUI.list.Selected( item, True )
def NoTakesCallback(control, event):
for item in range( len(t.takeSelectionUI.list.Items) ):
t.takeSelectionUI.list.Selected( item, False )
def takeButtonCallback(control, event):
print "Transferring Animation"
importCharacterAnimation()
####################################################################
# Take Selection UI
####################################################################
def PopulateTakeSelectionUI( takeSelectionUI ):
# ui variables for easier modification
ui_tool_width = 500
ui_gap = 5
ui_list_width = ui_tool_width - ui_gap * 10
ui_border_x = 10
ui_border_y = 10
ui_button_width = 50
ui_border_width = ui_tool_width - ui_gap * 7
ui_border_height = 100
ui_row_offset = 10
MAX_LIST_BOX_ENTRIES = 40
########################################################################
# All Takes Button
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_button_width ,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
takeSelectionUI.AddRegion("all_takes_button","all_takes_button", x, y, w, h)
takeSelectionUI.alltakesbutton = FBButton()
takeSelectionUI.alltakesbutton.Caption = "All"
takeSelectionUI.SetControl("all_takes_button", takeSelectionUI.alltakesbutton)
#callback
takeSelectionUI.alltakesbutton.OnClick.Add( AllTakesCallback )
########################################################################
# No Takes Button
x = FBAddRegionParam(ui_border_width - ui_button_width + ui_gap * 2,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_button_width ,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
takeSelectionUI.AddRegion("no_takes_button","no_takes_button", x, y, w, h)
takeSelectionUI.nonetakesbutton = FBButton()
takeSelectionUI.nonetakesbutton.Caption = "None"
takeSelectionUI.SetControl("no_takes_button", takeSelectionUI.nonetakesbutton)
#callback
takeSelectionUI.nonetakesbutton.OnClick.Add( NoTakesCallback )
########################################################################
ui_row_offset += 25
#Take List
takeSelectionUI.list = FBList()
takeSelectionUI.list.Style = FBListStyle.kFBVerticalList
takeSelectionUI.list.MultiSelect = True
takeSelectionUI.list.ExtendedSelect = True
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
# get take names and calculate size required for UI list at same time
num_of_takes = t.fbxScene.GetSrcObjectCount( FbxAnimStack.ClassId )
for take_id in range( num_of_takes ):
take = t.fbxScene.GetSrcObject( FbxAnimStack.ClassId, take_id )
take_name = take.GetName()
takeSelectionUI.list.Items.append( str(take_name ) )
# select by default
takeSelectionUI.list.Selected( take_id, True )
#limit UI size
if( len(takeSelectionUI.list.Items) < MAX_LIST_BOX_ENTRIES ):
ui_row_offset += 15
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
takeSelectionUI.AddRegion("takes","takes", x, y, w, h)
takeSelectionUI.SetControl("takes", takeSelectionUI.list)
########################################################################
#Go Button
ui_row_offset += 30
x = FBAddRegionParam(ui_border_x ,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(30,FBAttachType.kFBAttachNone,"")
takeSelectionUI.AddRegion("take_button","take_button", x, y, w, h)
takeSelectionUI.takeButton = FBButton()
takeSelectionUI.takeButton.Caption = "Transfer Selected"
takeSelectionUI.SetControl("take_button", takeSelectionUI.takeButton)
#callback
takeSelectionUI.takeButton.OnClick.Add( takeButtonCallback )
########################################################################
# draw tool
ui_row_offset += 70
# set tool ui size
takeSelectionUI.StartSizeX = ui_tool_width
takeSelectionUI.StartSizeY = ui_row_offset
ShowTool(takeSelectionUI)
####################################################################
# Main
####################################################################
def CreateTool():
global t
t = FBCreateUniqueTool("Character Animation Importer")
PopulateLayout(t)
CreateTool()
PNG
####################################################################
# Plot from a selection of Takes
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
import RS.Globals
# Global UI components
MAX_LIST_BOX_ENTRIES = 40
COMMONLY_USED_EXTS = ['mover','PH_R_Hand','OH_Pelvis','OH_FacingDirection','OH_UpperFixupDirection','OH_TorsoDirection']
def getUniqueCharacterExtensions():
exts = FBSystem().Scene.CharacterExtensions
UI_char_extension_objs = []
for e in exts:
components = e.Components
for c in components:
existing = False
for ext in UI_char_extension_objs:
if c.Name == ext.Name:
existing = True
if not existing:
UI_char_extension_objs.append( c )
return UI_char_extension_objs
def clearSelection():
''' Clear selection function '''
# Get selected models
modelList = FBModelList()
FBGetSelectedModels(modelList, None, True)
# Deselect models
for model in modelList:
model.Selected = False
def cleanSelectedExtensions( character, take ):
index = 0
for item in range( len(t.list.Items) ):
if( t.list.IsSelected( item ) ):
t.char_ext_objs[ index ].Selected = True
FBApplication().CurrentCharacter.KeyingMode = FBCharacterKeyingMode.kFBCharacterKeyingSelection
take.ClearAllProperties( True )
index +=1
####################################################################
# UI CallBacks
####################################################################
def AllExtsCallback(control, event):
for item in range( len(t.list.Items) ):
t.list.Selected( item, True )
def NoExtsCallback(control, event):
for item in range( len(t.list.Items) ):
t.list.Selected( item, False )
def cleanButtonCallBack(control, event):
################################################################################
# check user is sure
################################################################################
user_choice = FBMessageBox( "Message", "Delete all animation on selected character extensions?", "Yes", "No" )
if ( user_choice == 1 ):
character_list = []
if t.currentCharacterButton.State == True:
character_list.append( FBApplication().CurrentCharacter )
else:
for char in RS.Globals.Characters:
character_list.append( char )
for character in character_list:
################################################################################
# if current take only
################################################################################
if t.singleTakeModeButton.State:
take = FBSystem().CurrentTake
cleanSelectedExtensions( character, take )
################################################################################
# all takes
################################################################################
else:
for take in FBSystem().Scene.Takes:
FBSystem().CurrentTake = take
cleanSelectedExtensions( character, take )
clearSelection()
print "Cleaning Complete"
####################################################################
# UI
####################################################################
def PopulateTool(t):
# ui variables for easier modification
ui_border_x = 10
ui_border_y = 10
ui_border_width = 250
ui_border_height = 40
ui_column_a = 20
ui_column_b = ui_border_width / 2
ui_row_offset = 10
ui_button_width = 40
########################################################################
# All Exts Button
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width / 6 ,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("all_exts_button","all_exts_button", x, y, w, h)
t.allExtsButton = FBButton()
t.allExtsButton.Caption = "All"
t.SetControl("all_exts_button", t.allExtsButton)
#callback
t.allExtsButton.OnClick.Add( AllExtsCallback )
########################################################################
# No Takes Button
x = FBAddRegionParam(ui_border_width + 10 - ui_border_width / 4 ,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width / 4 ,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("no_exts_button","no_exts_button", x, y, w, h)
t.noExtsButton = FBButton()
t.noExtsButton.Caption = "None"
t.SetControl("no_exts_button", t.noExtsButton)
#callback
t.noExtsButton.OnClick.Add( NoExtsCallback )
########################################################################
ui_row_offset += 25
# Ext List
t.list = FBList()
t.list.Style = FBListStyle.kFBVerticalList
t.list.MultiSelect = True
t.list.ExtendedSelect = True
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
t.char_ext_objs = getUniqueCharacterExtensions()
# get take names and calculate size required for UI list at same time
for obj in t.char_ext_objs:
t.list.Items.append( obj.Name )
# select in list unless it's a commonly used item
if obj.Name not in COMMONLY_USED_EXTS:
t.list.Selected( len( t.list.Items) - 1, True )
#limit UI size
if( len(t.list.Items) < MAX_LIST_BOX_ENTRIES ):
ui_row_offset += 15
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
t.AddRegion("exts","exts", x, y, w, h)
t.SetControl("exts", t.list)
ui_row_offset = ui_row_offset + 10
########################################################################
ui_row_offset += 40
t.takesRadios = FBButtonGroup()
t.singleTakeModeButton = FBButton()
t.allTakesModeButton = FBButton()
t.takesRadios.Add( t.singleTakeModeButton )
t.takesRadios.Add( t.allTakesModeButton )
#Border
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_border_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("takes_border","Takes", x, y, w, h)
t.SetBorder("takes_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_row_offset += 10
#Buttons
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"single_takes_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width / 2,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_border_height / 2,FBAttachType.kFBAttachNone,"")
t.AddRegion("single_takes_region","single_takes_region", x, y, w, h)
t.SetControl("single_takes_region", t.singleTakeModeButton)
t.singleTakeModeButton.Visible = True
t.singleTakeModeButton.ReadOnly = False
t.singleTakeModeButton.Enabled = True
t.singleTakeModeButton.Hint = ""
t.singleTakeModeButton.Caption = "Current"
t.singleTakeModeButton.State = 0
t.singleTakeModeButton.Style = FBButtonStyle.kFBRadioButton
t.singleTakeModeButton.Justify = FBTextJustify.kFBTextJustifyLeft
t.singleTakeModeButton.Look = FBButtonLook.kFBLookNormal
x = FBAddRegionParam(ui_column_b,FBAttachType.kFBAttachTop,"all_takes_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width / 2,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_border_height / 2,FBAttachType.kFBAttachNone,"")
t.AddRegion("all_takes_region","all_takes_region", x, y, w, h)
t.SetControl("all_takes_region", t.allTakesModeButton )
t.allTakesModeButton.Visible = True
t.allTakesModeButton.ReadOnly = False
t.allTakesModeButton.Enabled = True
t.allTakesModeButton.Hint = ""
t.allTakesModeButton.Caption = "All"
t.allTakesModeButton.State = 1
t.allTakesModeButton.Style = FBButtonStyle.kFBRadioButton
t.allTakesModeButton.Justify = FBTextJustify.kFBTextJustifyLeft
t.allTakesModeButton.Look = FBButtonLook.kFBLookNormal
########################################################################
# Current Character or All?
########################################################################
ui_row_offset += 45
t.takesRadios = FBButtonGroup()
t.currentCharacterButton = FBButton()
t.allCharacterButton = FBButton()
t.takesRadios.Add( t.currentCharacterButton )
t.takesRadios.Add( t.allCharacterButton )
#Border
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_border_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("character_takes_border","Character?", x, y, w, h)
t.SetBorder("character_takes_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_row_offset += 10
#Buttons
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"current_mode_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width / 2,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_border_height / 2,FBAttachType.kFBAttachNone,"")
t.AddRegion("current_mode_region","current_mode_region", x, y, w, h)
t.SetControl("current_mode_region", t.currentCharacterButton)
t.currentCharacterButton.Visible = True
t.currentCharacterButton.ReadOnly = False
t.currentCharacterButton.Enabled = True
t.currentCharacterButton.Hint = ""
t.currentCharacterButton.Caption = "Current"
t.currentCharacterButton.State = 1
t.currentCharacterButton.Style = FBButtonStyle.kFBRadioButton
t.currentCharacterButton.Justify = FBTextJustify.kFBTextJustifyLeft
t.currentCharacterButton.Look = FBButtonLook.kFBLookNormal
x = FBAddRegionParam(ui_column_b,FBAttachType.kFBAttachTop,"all_mode_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width / 2,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_border_height / 2,FBAttachType.kFBAttachNone,"")
t.AddRegion("all_mode_region","all_mode_region", x, y, w, h)
t.SetControl("all_mode_region", t.allCharacterButton )
t.allCharacterButton.Visible = True
t.allCharacterButton.ReadOnly = False
t.allCharacterButton.Enabled = True
t.allCharacterButton.Hint = ""
t.allCharacterButton.Caption = "All"
t.allCharacterButton.State = 0
t.allCharacterButton.Style = FBButtonStyle.kFBRadioButton
t.allCharacterButton.Justify = FBTextJustify.kFBTextJustifyLeft
t.allCharacterButton.Look = FBButtonLook.kFBLookNormal
########################################################################
#Clean Extensions Button
ui_row_offset += 40
x = FBAddRegionParam(ui_border_x ,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(30,FBAttachType.kFBAttachNone,"")
t.AddRegion("clean_exts_button","clean_exts_button", x, y, w, h)
t.cleanButton = FBButton()
t.cleanButton.Caption = "Clean Extensions"
t.SetControl("clean_exts_button", t.cleanButton)
#callback
t.cleanButton.OnClick.Add( cleanButtonCallBack )
########################################################################
# draw tool
ui_row_offset += 70
# set tool ui size
t.StartSizeX = ui_border_width + 35
t.StartSizeY = ui_row_offset
####################################################################
# Main
####################################################################
def CreateTool():
global t
t = FBCreateUniqueTool("Clean Extensions")
PopulateTool(t)
ShowTool(t)
CreateTool()
####################################################################
# Allows user to clear character extension components of keys
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
# Global UI components
clear_button = FBButton()
#take control ui comps
take_radio_group = FBButtonGroup()
take_yes_button = FBButton()
take_no_button = FBButton()
take_radio_group.Add(take_yes_button)
take_radio_group.Add(take_no_button)
status = FBLabel()
button = []
UI_char_extension_objs = []
selected_character = ""
char_rollbone_objs = []
char_3lateral_objs = []
# Global UI components
MAX_LIST_BOX_ENTRIES = 40
def ClearAnim( pNode ):
# The FCurve property will not be null on a terminal node.
# i.e. the 'Lcl Translation' node will not have any animation on it
# directly... only the sub-nodes 'X', 'Y' or 'Z' may have animation.
if pNode.FCurve:
# Ah! there is a FCurve! Let's remove all the keys.
pNode.FCurve.EditClear()
else:
# Then we are dealing with a parent node. Let's look at it
# children nodes.
for lNode in pNode.Nodes:
# Recursively call ourselves to deal with sub-nodes.
ClearAnim( lNode )
# Cleanup
del( lNode )
def getSpecificCharacterExtension( obj ):
global selected_character
# get namespace of selected character
namespace = ( selected_character ).split(":")[0]
if namespace != "":
namespace += ":"
#print "namepsace is " + str(namespace)
exts = FBSystem().Scene.CharacterExtensions
for e in exts:
components = e.Components
for c in components:
#print "combined namespace and obj.Name is " + namespace + obj.Name
#print "c.LongName is " + c.LongName
if namespace + obj.Name == c.LongName:
#print "found match! with component " + c.LongName
return c
def getUniqueCharacterExtensions():
exts = FBSystem().Scene.CharacterExtensions
for e in exts:
components = e.Components
for c in components:
existing = False
for ext in UI_char_extension_objs:
if c.Name == ext.Name:
existing = True
if not existing:
pass
# UI_char_extension_objs.append( c )
def getCharacters():
return FBSystem().Scene.Characters
def setupPropertyList(tool):
global selected_character
tool.list.Items.removeAll()
tool.prop_list = []
character_list = getCharacters()
if len(character_list):
for char in character_list:
tool.list.Items.append( char.OwnerNamespace.Name )
else:
tool.list.Items.append('No characters found!')
selected_character = tool.list.Items[0]
####################################################################
# Clear Button CallBack
####################################################################
def clearButtonCallBack(control, event):
system = FBSystem()
if take_yes_button.State == 1:
currentTake = system.CurrentTake
for take in FBSystem().Scene.Takes:
system.CurrentTake = take
index = 0
for obj in UI_char_extension_objs:
if ( button[index].State == True ):
ext = getSpecificCharacterExtension( obj )
ClearAnim( ext.AnimationNode )
#animationNode = ext.PropertyList.Find("AnimationNode")
#if ( animationNode ):
# ClearAnim( animationNode )
index += 1
# restore take
system.CurrentTake = currentTake
else:
index = 0
for obj in UI_char_extension_objs:
if ( button[index].State == True ):
ext = getSpecificCharacterExtension( obj )
ClearAnim( ext.AnimationNode )
index += 1
print "Selected extensions cleared!"
status.Caption = "Extension keys cleared"
FBSystem().Scene.Evaluate()
####################################################################
# ListCallBack
####################################################################
def ListCallback(control, event):
global selected_character
selected_character = control.Items[control.ItemIndex]
####################################################################
# UI
####################################################################
def PopulateTool(t):
global selected_character
# ui variables for easier modification
ui_border_x = 10
ui_border_y = 2
ui_border_width = 140
ui_border_height = 100
ui_column_a = 20
ui_column_b = 60
ui_column_c = 100
ui_row_offset = 10
ui_button_width = 120
ui_button_height = 15
#Mover Selection----------------------------------------------
#Drop Down
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(25,FBAttachType.kFBAttachNone,"")
t.AddRegion("dropdown","dropdown", x, y, w, h)
t.list = FBList()
t.SetControl("dropdown", t.list)
setupPropertyList(t)
t.list.OnChange.Add(ListCallback)
#Extensions--------------------------------------------------
#get all scene character extension objects
getUniqueCharacterExtensions()
ui_row_offset += 40
#Border
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam( ( 20 * len(UI_char_extension_objs) ) + 15,FBAttachType.kFBAttachNone,"")
t.AddRegion("trans_border","Character Extensions", x, y, w, h)
t.SetBorder("trans_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_row_offset += 10
#Buttons
# create a button for each extension obj
for i in range( 0, len(UI_char_extension_objs) ):
region = "extButton" + str(i)
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop, region )
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_height,FBAttachType.kFBAttachNone,"")
t.AddRegion(region,region, x, y, w, h)
button.append( FBButton() )
t.SetControl(region, button[i] )
button[i].Visible = True
button[i].ReadOnly = False
button[i].Enabled = True
button[i].Hint = ""
button[i].Caption = UI_char_extension_objs[i].Name
# set certain options as off for ease of use
if ( "mover" in UI_char_extension_objs[i].Name ) or \
( "PH_R_Hand" in UI_char_extension_objs[i].Name ) or \
( "OH_FacingDirection" in UI_char_extension_objs[i].Name ) or \
( "OH_UpperFixupDirection" in UI_char_extension_objs[i].Name ) or \
( "PH_L_Hand" in UI_char_extension_objs[i].Name ):
button[i].State = 0
else:
button[i].State = 1
button[i].Style = FBButtonStyle.kFBCheckbox
button[i].Justify = FBTextJustify.kFBTextJustifyLeft
button[i].Look = FBButtonLook.kFBLookNormal
ui_row_offset += 20
#Takes--------------------------------------------------
#clear all takes?
ui_row_offset += 40
#Border
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam( 60 ,FBAttachType.kFBAttachNone,"")
t.AddRegion("takes","Clear All Takes?", x, y, w, h)
t.SetBorder("takes",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_row_offset += 10
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"take_yes_button")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(120,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("take_yes_button","take_yes_button", x, y, w, h)
t.SetControl("take_yes_button", take_yes_button )
take_yes_button.Visible = True
take_yes_button.ReadOnly = False
take_yes_button.Enabled = True
take_yes_button.Hint = ""
take_yes_button.Caption = "Yes"
take_yes_button.State = 1
take_yes_button.Style = FBButtonStyle.kFBRadioButton
take_yes_button.Justify = FBTextJustify.kFBTextJustifyLeft
take_yes_button.Look = FBButtonLook.kFBLookNormal
ui_row_offset += 20
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"take_no_button")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(120,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("take_no_button","take_no_button", x, y, w, h)
t.SetControl("take_no_button", take_no_button )
take_no_button.Visible = True
take_no_button.ReadOnly = False
take_no_button.Enabled = True
take_no_button.Hint = ""
take_no_button.Caption = "No"
take_no_button.State = 0
take_no_button.Style = FBButtonStyle.kFBRadioButton
take_no_button.Justify = FBTextJustify.kFBTextJustifyLeft
take_no_button.Look = FBButtonLook.kFBLookNormal
#Clear Button--------------------------------------------------
ui_row_offset = ui_row_offset + 10
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"clear_button_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(30,FBAttachType.kFBAttachNone,"")
t.AddRegion("clear_button_region","clear_button_region", x, y, w, h)
t.SetControl("clear_button_region", clear_button)
clear_button.Visible = True
clear_button.ReadOnly = False
clear_button.Enabled = True
clear_button.Hint = ""
clear_button.Caption = "Clear Keys on Selected"
clear_button.State = 0
clear_button.Style = FBButtonStyle.kFBPushButton
clear_button.Justify = FBTextJustify.kFBTextJustifyCenter
clear_button.Look = FBButtonLook.kFBLookNormal
clear_button.OnClick.Add(clearButtonCallBack)
#Status --------------------------------------------------
ui_row_offset = ui_row_offset + 35
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"status_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(30,FBAttachType.kFBAttachNone,"")
t.AddRegion("status_region","status_region", x, y, w, h)
t.SetControl("status_region", status)
status.Visible = True
status.ReadOnly = False
status.Enabled = True
status.Caption = ""
# set tool ui size
t.StartSizeX = 175
t.StartSizeY = ui_row_offset + 60
####################################################################
# Main
####################################################################
def CreateTool():
global t
t = FBCreateUniqueTool("Clean Extensions")
PopulateTool(t)
ShowTool(t)
CreateTool()
####################################################################
# Searches for references to clipsets in Loco and Meta files
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
import xml.etree.ElementTree as ET
import tempfile
import os
import RS.Config
class Clipset():
def __init__(self, name = '', start_line_number = 0, end_line_number = 0, referenced = False):
self.name = name
self.start_line_number = start_line_number
self.end_line_number = end_line_number
self.referenced = referenced
def Print(self):
print "###################"
print "clipset name is " + self.name
print "clipset starts on line number " + self.start_line_number
print "clipset ends on line number " + self.end_line_number
return
def generateClipsetsSearchArray(filepath, searchSubString):
clipsets = []
for subdir, dirs, files in os.walk(filepath):
for file in files:
filepath = subdir + os.sep + file
##############################################################
# only search in meta files
##############################################################
if filepath.endswith(".meta"):
tree = ET.parse(filepath, parser=LineNumberingParser())
root = tree.getroot()
clipsetroot = root.find('ClipSets')
attribute_tag = 'key'
children = clipsetroot.getchildren()
for child in children:
if (child.tag == 'Item'):
if attribute_tag in child.attrib:
# is the search substring contained within the clipset entry? If so add it to the list
if searchSubString in child.attrib[ attribute_tag ]:
#print "clipset " + child.attrib[ attribute_tag ] + " starts at line number " + str(child._start_line_number) + " and ends at liner number " + str(child._end_line_number) + "\n"
# create a clipset class, store the name and which line numbers it is stored at in the file
clipset = Clipset(child.attrib[ attribute_tag ], child._start_line_number, child._end_line_number)
clipsets.append(clipset)
#print "CONTENTS OF CLIPSETS\n"
#print "====================\n\n"
#for clipset in clipsets:
# print clipset.name
return clipsets
def findClipsetInMotions(parent, clipsets ):
children = parent.getchildren()
search_tag = 'Name'
for child in children:
if (child.tag == 'Item'):
subelements = child.getchildren()
for elem in subelements:
if elem.tag == search_tag:
# check name isn't left blank
if not elem.text == None:
# first strip off clip name from motion entry so we just have clipset
# typically motion entry contains something like "CLIPSET@MECH_LOCO_M@GENERIC@EMOTION@UNARMED@PANIC@RUN_FROM_CROUCH/START_FWD_45"
split_text = elem.text.split("/")[0]
# check each entry in clipsets for a match
i = 0
for clipset in clipsets:
if split_text.upper() == clipset.name.upper():
clipset.referenced = True
i = i + 1
return clipsets
def findClipsetInLoco( parent, clipsets, debug = False ):
children = parent.getchildren()
search_tag = 'ClipSet'
for child in children:
if (child.tag == 'Item'):
subelements = child.getchildren()
for elem in subelements:
if elem.tag == search_tag:
# check clipset isn't left blank
if not elem.text == None:
# check each entry in clipsets for a match
i = 0
for clipset in clipsets:
if elem.text.upper() == clipset.name:
clipset.referenced = True
i = i + 1
return clipsets
def SearchLoco(locoFilePath, clipsets):
for subdir, dirs, files in os.walk(locoFilePath):
for file in files:
filepath = subdir + os.sep + file
##############################################################
# only search in meta files
##############################################################
if filepath.endswith(".meta"):
tree = ET.parse(filepath, parser=LineNumberingParser())
root = tree.getroot()
if not root.tag == 'Motions':
root = root.find('Motions')
if root is not None:
##############################################################
# search in each file
##############################################################
clipsets = findClipsetInLoco( root, clipsets)
else:
#print "Motions Elements not found in file " + filepath
pass
return clipsets
def SearchMotions(motionsFilePath, clipsets):
for subdir, dirs, files in os.walk(motionsFilePath):
for file in files:
filepath = subdir + os.sep + file
##############################################################
# only search in motion files
##############################################################
if filepath.endswith(".motionxml"):
tree = ET.parse(filepath, parser=LineNumberingParser())
root = tree.getroot()
if not root.tag == 'Motion':
root = root.find('Motion')
root = root.find('Clips')
if root is not None:
##############################################################
# search in each file
##############################################################
clipsets = findClipsetInMotions(root, clipsets )
else:
print "Clips Elements not found in file " + filepath
return clipsets
####################################################################
# custom class so we can find line numbers
# from: http://stackoverflow.com/questions/6949395/is-there-a-way-to-get-a-line-number-from-an-elementtree-element
####################################################################
class LineNumberingParser(ET.XMLParser):
def _start_list(self, *args, **kwargs):
# Here we assume the default XML parser which is expat
# and copy its element position attributes into output Elements
element = super(self.__class__, self)._start_list(*args, **kwargs)
element._start_line_number = self.parser.CurrentLineNumber
element._start_column_number = self.parser.CurrentColumnNumber
element._start_byte_index = self.parser.CurrentByteIndex
return element
def _end(self, *args, **kwargs):
element = super(self.__class__, self)._end(*args, **kwargs)
element._end_line_number = self.parser.CurrentLineNumber
element._end_column_number = self.parser.CurrentColumnNumber
element._end_byte_index = self.parser.CurrentByteIndex
return element
def SearchClipsetsForReferences(clipsets, locoFilePath, motionsFilePath):
if len(clipsets) > 0:
##############################################################
# SEARCH LOCO FILES FOR CLIPSETS
##############################################################
clipsets = SearchLoco(locoFilePath, clipsets)
##############################################################
# SEARCH MOTIONS FILES FOR CLIPSETS
##############################################################
clipsets = SearchMotions(motionsFilePath, clipsets)
return clipsets
def PrintResultsToTextFile(clipsets, searchSubString ):
output = "\nSearching Loco and Motions files for usage of '" + searchSubString + "' and its variants\n\n"
if len(clipsets) > 0:
used_clipsets = [ ]
unused_clipsets = [ ]
for clipset in clipsets:
if clipset.referenced == True:
used_clipsets.append(clipset)
else:
unused_clipsets.append(clipset)
output += "############################################################################################################################\n"
output += "# Clipsets that are referenced in Loco or Motions \n"
output += "############################################################################################################################\n\n"
for used_clipset in used_clipsets:
output += used_clipset.name + "\n"
output += "\n############################################################################################################################\n"
output += "# Clipsets not referenced in Loco or Motions (Possibly safe to delete, but may be in use outside of these systems) \n"
output += "############################################################################################################################\n\n"
for unused_clipset in unused_clipsets:
output += unused_clipset.name + "\n"
else:
output += "############################################################################################################################\n"
output += "# No Clipsets could be found in selected Clipsets File! Aborting Search. Did you mean to select a different file?\n"
output += "############################################################################################################################\n\n"
output_file_path = tempfile.gettempdir() + '\\mj_ClipsetSearchAndDestroy_output.txt'
with open(output_file_path, 'w') as f:
f.write(output)
f.closed
os.startfile(output_file_path)
##############################################################################################################################################################
##############################################################################################################################################################
# UI CallBacks
##############################################################################################################################################################
##############################################################################################################################################################
def SearchCallback(control, event):
clipsetFilePath = RS.Config.Project.Path.Assets + "\\export\\data\\anim\\clip_sets\\clip_sets_groups\\"
locoFilePath = RS.Config.Project.Path.Assets + "\\export\\data\\loco\\types\\human\\"
motionsFilePath = RS.Config.Project.Path.Assets + "\\export\\anim\\motions\\@MECH_LOCO_M\\"
searchSubString = t.searchEdit.Text
clipsets = generateClipsetsSearchArray(clipsetFilePath, searchSubString)
clipsets = SearchClipsetsForReferences(clipsets, locoFilePath, motionsFilePath)
PrintResultsToTextFile(clipsets, searchSubString)
##############################################################################################################################################################
# UI
##############################################################################################################################################################
def PopulateTool(t):
# ui variables for easier modification
MAX_LIST_BOX_ENTRIES = 30
ui_border_x = 10
ui_border_width = 660
ui_border_height = 100
ui_row_offset = 10
########################################################################
# Border
x = FBAddRegionParam(ui_border_x, FBAttachType.kFBAttachNone, "")
y = FBAddRegionParam(ui_row_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_border_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_border_height - 5, FBAttachType.kFBAttachNone, "")
t.AddRegion("border_a", "", x, y, w, h)
t.SetBorder("border_a", FBBorderStyle.kFBEmbossBorder, True, True, 2, 0, 90.0, 0)
########################################################################
ui_row_offset += 5
# Search Label
x = FBAddRegionParam(ui_border_x + 5, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_row_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_border_width - 10, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(20, FBAttachType.kFBAttachNone, "")
t.AddRegion("search_region", "search_region", x, y, w, h)
t.searchLable = FBLabel()
t.SetControl("search_region", t.searchLable)
t.searchLable.Justify = FBTextJustify.kFBTextJustifyLeft
t.searchLable.Visible = True
t.searchLable.ReadOnly = False
t.searchLable.Enabled = True
t.searchLable.Caption = "Clipset Search Substring"
# Search Edit
ui_row_offset += 20
x = FBAddRegionParam(ui_border_x + 5, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_row_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_border_width - 10, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(20, FBAttachType.kFBAttachNone, "")
t.AddRegion("search_edit", "search_edit", x, y, w, h)
t.searchEdit = FBEdit()
t.searchEdit.Text = 'CLIPSET@MECH_LOCO_M@GENERIC@EMOTION@UNARMED@NERVOUS'
t.SetControl("search_edit", t.searchEdit)
########################################################################
# Search Button
ui_row_offset += 30
x = FBAddRegionParam(ui_border_x + 5, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_row_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_border_width - 10, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(30, FBAttachType.kFBAttachNone, "")
t.AddRegion("rename_button", "rename_button", x, y, w, h)
t.searchButton = FBButton()
t.searchButton.Caption = "Search Usage of Clipsets (and variants) in Loco and Motions files"
t.SetControl("rename_button", t.searchButton)
# callback
t.searchButton.OnClick.Add(SearchCallback)
########################################################################
# draw tool
########################################################################
ui_row_offset += 60
# set tool ui size
t.StartSizeX = 700
t.StartSizeY = ui_row_offset + 30
####################################################################
# Main
####################################################################
def CreateTool():
global t
t = FBCreateUniqueTool("Clipset Search Loco and Motions")
PopulateTool(t)
ShowTool(t)
CreateTool()
PNG
####################################################################
# Clipset utility script
#
# Initial function is to create a list of unreferenced clip dictionary metadatas
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
import xml.etree.ElementTree as ET
import tempfile
import os
import RS.Config
def prettyPrint(elem, level=0):
i = "\n" + level * "\t"
if len( elem ):
if not elem.text or not elem.text.strip():
elem.text = i + "\t"
if not elem.tail or not elem.tail.strip():
elem.tail = i
for elem in elem:
prettyPrint(elem, level+1)
if not elem.tail or not elem.tail.strip():
elem.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
def chooseClipSet():
# Create the popup and set necessary initial values.
lFp = FBFilePopup()
lFp.Caption = "Choose ClipSet to import"
lFp.Style = FBFilePopupStyle.kFBFilePopupOpen
# BUG: If we do not set the filter, we will have an exception.
lFp.Filter = "*.meta"
# Set the default path.
lFp.Path = RS.Config.Project.Path.Assets + "\\export\\data\\anim\\clip_sets\\clip_sets_groups\\"
# Get the GUI to show.
lRes = lFp.Execute()
# If we select files, show them, otherwise indicate that the selection was canceled.
if lRes:
return lFp
else:
return False
####################################################################
# UI & Callbacks
####################################################################
def addConditionButtonCallback(control, event):
pass
def clipsetButtonCallBack(control, event):
loadAndValidateClipSet()
def PopulateTool( t ):
##########################################################################################
# streaming and memory groups defines - ideally these should be loaded in from a meta file...
# but we'll hardcode them for now.
##########################################################################################
t.MAX_NUM_OF_CONDITIONS = 6
streaming_policy_list = [ 'SP_STREAMING', 'SP_SINGLEPLAYER_RESIDENT SP_MULTIPLAYER_RESIDENT' ]
streaming_policy_list_default = 0 # SP_STREAMING
memory_group_list = [
'MG_AmbientMovement', 'MG_CivilianReactions', 'MG_Climbs','MG_Combat', 'MG_CoreMovement', 'MG_Cover', 'MG_Creature',
'MG_CreatureHorse', 'MG_Dropdowns', 'MG_DoorInteraction','MG_EmotionalMovement', 'MG_Facial', 'MG_Falls','MG_Gesture', 'MG_Getups', 'MG_Jumps','MG_Loot', 'MG_Melee',
'MG_Misc', 'MG_None', 'MG_Parachuting', 'MG_PlayerMovement', 'MG_ScenariosBase', 'MG_ScenariosStreamed',
'MG_Script', 'MG_ShockingEventReactions', 'MG_Swimming', 'MG_VaultingClimbingJumping', 'MG_Vehicle', 'MG_Weapons'
]
memory_group_list_default = 13 # MG_Misc
streaming_priority_list = [ 'SP_LOW', 'SP_MEDIUM', 'SP_HIGH' ]
streaming_priority_list_default = 1 # SP_MEDIUM
##########################################################################################
# UI variables
##########################################################################################
# ui variables for easier modification
ui_border_x = 10
ui_border_y = 10
ui_border_width = 500
ui_border_height = 100
ui_x_offset = 10
ui_y_offset = 10
ui_x_width = 800
ui_button_width = 30
ui_entry_height = 30
ui_condition_gap = 5
ui_condition_width = 500
ui_condition_height = 20
ui_dropdown_width = 300
ui_memory_group_dropdown_width = 150
ui_clipset_button_width = ui_x_offset + ui_condition_gap * 5 + ui_condition_width + ui_dropdown_width + ui_memory_group_dropdown_width * 2
t.dictionaryEdit = []
t.streamingPolicy = []
t.memoryGroup = []
t.streamingPriority = []
for condition_index in range( t.MAX_NUM_OF_CONDITIONS ):
##########################################################################################
# Border
##########################################################################################
condition_index_str = str( condition_index )
x = FBAddRegionParam(ui_x_offset,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_offset + ui_condition_gap * 5 + ui_condition_width + ui_dropdown_width + ui_memory_group_dropdown_width * 2,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_entry_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("condition_border" + condition_index_str, "" , x, y, w, h)
t.SetBorder("condition_border" + condition_index_str,FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
##########################################################################################
# Dictionary Edit Box
##########################################################################################
x = FBAddRegionParam(ui_x_offset + ui_condition_gap,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_y_offset + ui_condition_gap,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_condition_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_condition_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("dictionary_editbox" + condition_index_str,"dictionary_editbox" + condition_index_str , x, y, w, h)
t.dictionaryEdit.append( FBEdit() )
t.dictionaryEdit[condition_index].Id = condition_index
t.dictionaryEdit[condition_index].Visible = True
t.dictionaryEdit[condition_index].ReadOnly = False
t.dictionaryEdit[condition_index].Enabled = True
t.dictionaryEdit[condition_index].Text = ''
t.SetControl("dictionary_editbox" + condition_index_str, t.dictionaryEdit[condition_index])
####################################################################
# streamingPolicy dropdown
####################################################################
x = FBAddRegionParam(ui_x_offset + ui_condition_gap * 2 + ui_condition_width,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_y_offset + ui_condition_gap,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_dropdown_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_condition_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("streamingpolicy_dropdown" + condition_index_str,"streamingpolicy_dropdown" + condition_index_str , x, y, w, h)
t.streamingPolicy.append( FBList() )
t.streamingPolicy[condition_index].Style = FBListStyle.kFBDropDownList
for policy in streaming_policy_list:
t.streamingPolicy[condition_index].Items.append( policy )
t.SetControl("streamingpolicy_dropdown" + condition_index_str, t.streamingPolicy[condition_index])
#### Default is SP_STREAMING ####
t.streamingPolicy[condition_index].ItemIndex = streaming_policy_list_default
####################################################################
# memorygroup dropdown
####################################################################
x = FBAddRegionParam(ui_x_offset + ui_condition_gap * 3 + ui_condition_width + ui_dropdown_width,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_y_offset + ui_condition_gap,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_memory_group_dropdown_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_condition_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("memorygroup_dropdown" + condition_index_str,"memorygroup_dropdown" + condition_index_str , x, y, w, h)
t.memoryGroup.append( FBList() )
t.memoryGroup[condition_index].Style = FBListStyle.kFBDropDownList
for group in memory_group_list:
t.memoryGroup[condition_index].Items.append( group )
t.SetControl("memorygroup_dropdown" + condition_index_str, t.memoryGroup[condition_index])
#### Default is ####
t.memoryGroup[condition_index].ItemIndex = memory_group_list_default
####################################################################
# streaming priority dropdown
####################################################################
x = FBAddRegionParam(ui_x_offset + ui_condition_gap * 4 + ui_condition_width + ui_dropdown_width + ui_memory_group_dropdown_width,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_y_offset + ui_condition_gap,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_memory_group_dropdown_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_condition_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("streamingpriority_dropdown" + condition_index_str,"streamingpriority_dropdown" + condition_index_str , x, y, w, h)
t.streamingPriority.append( FBList() )
t.streamingPriority[condition_index].Style = FBListStyle.kFBDropDownList
for priority in streaming_priority_list:
t.streamingPriority[condition_index].Items.append( priority )
t.SetControl("streamingpriority_dropdown" + condition_index_str, t.streamingPriority[condition_index])
#### Default is SP_MEDIUM ####
t.streamingPriority[condition_index].ItemIndex = streaming_priority_list_default
####################################################################
# increment UI condition
####################################################################
ui_y_offset += ui_entry_height + ui_condition_gap
####################################################################
# Choose Clipset and Validate Button
####################################################################
ui_y_offset += 5
x = FBAddRegionParam(ui_x_offset,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_clipset_button_width ,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_entry_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("choose_clipset_border", "" , x, y, w, h)
t.SetBorder("choose_clipset_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
t.clipset_button = FBButton()
t.SetControl("choose_clipset_border", t.clipset_button)
t.clipset_button.Visible = True
t.clipset_button.ReadOnly = False
t.clipset_button.Enabled = True
t.clipset_button.Hint = ""
t.clipset_button.Caption = "Choose Clipset File and Validate"
t.clipset_button.State = 0
t.clipset_button.Style = FBButtonStyle.kFBPushButton
t.clipset_button.Justify = FBTextJustify.kFBTextJustifyCenter
t.clipset_button.Look = FBButtonLook.kFBLookNormal
t.clipset_button.OnClick.Add( clipsetButtonCallBack )
####################################################################
# Enter some defaults (for male loco really)
####################################################################
t.dictionaryEdit[0].Text = 'MECH_LOCO_M@CHARACTER@ARTHUR@'
t.streamingPolicy[0].ItemIndex = 0
t.memoryGroup[0].ItemIndex = 16
t.streamingPriority[0].ItemIndex = 1
t.dictionaryEdit[1].Text = 'MECH_LOCO_M@CHARACTER@'
t.streamingPolicy[1].ItemIndex = 0
t.memoryGroup[1].ItemIndex = 0
t.streamingPriority[1].ItemIndex = 1
t.dictionaryEdit[2].Text = 'MECH_LOCO_M@GENERIC@EMOTION@'
t.streamingPolicy[2].ItemIndex = 0
t.memoryGroup[2].ItemIndex = 7
t.streamingPriority[2].ItemIndex = 1
t.dictionaryEdit[3].Text = 'MECH_LOCO_M@TYPE@'
t.streamingPolicy[3].ItemIndex = 0
t.memoryGroup[3].ItemIndex = 0
t.streamingPriority[3].ItemIndex = 1
t.dictionaryEdit[ t.MAX_NUM_OF_CONDITIONS - 1 ].Text = 'Default for any clip dictionaries not matching above rules.'
t.dictionaryEdit[ t.MAX_NUM_OF_CONDITIONS - 1 ].Enabled = False
t.streamingPolicy[t.MAX_NUM_OF_CONDITIONS - 1 ].ItemIndex = 0
t.memoryGroup[t.MAX_NUM_OF_CONDITIONS - 1 ].ItemIndex = 3
t.streamingPriority[t.MAX_NUM_OF_CONDITIONS - 1 ].ItemIndex = 1
####################################################################
# Show UI
####################################################################
ui_y_offset += ui_entry_height
t.StartSizeX = ui_x_offset + ui_condition_gap * 5 + ui_condition_width + ui_dropdown_width + ui_memory_group_dropdown_width * 2 + 35
t.StartSizeY = ui_y_offset + 45
ShowTool(t)
def loadAndValidateClipSet():
result = chooseClipSet()
####################################################################
# Open XML file
####################################################################
if result:
xml_file = ( result.Path + "\\" + result.FileName )
tree = ET.parse( xml_file )
root = tree.getroot()
clip_dictionary_names_list = {}
clip_dictionary_metadatas_list = {}
clipSetsElement = root.find('ClipSets')
clipDictionaryMetadatasElement = root.find('ClipDictionaryMetadatas')
####################################################################
# Populate existing entries into dictionaries
####################################################################
for clip_dictionary in clipSetsElement.iter('DictionaryIds'):
for item in clip_dictionary.iter('Item'):
# add to list if not already stored - not bothered about value
if item.text.upper() not in clip_dictionary_names_list:
clip_dictionary_names_list[item.text.upper()] = 0
for clip_dictionary_metadata in clipDictionaryMetadatasElement.iter('Item'):
# add to list if not already stored - not bothered about value
if clip_dictionary_metadata.attrib['key'].upper() not in clip_dictionary_metadatas_list:
clip_dictionary_metadatas_list[ clip_dictionary_metadata.attrib['key'].upper() ] = 0
####################################################################
# Compare clip dictionary list with clip dictionary metadatas
# anything missing requires a metadata definition
####################################################################
new_clip_dictionaries = ET.SubElement( root, 'These Clip Dictionaries are not referenced in clipDictionaryMetadatas. Paste the following into clipsets file.' )
for clip_dictionary in clip_dictionary_names_list:
if clip_dictionary not in clip_dictionary_metadatas_list:
# add clipdictionary element
new_entry = ET.SubElement( new_clip_dictionaries, 'Item')
new_entry.set('key', clip_dictionary)
####################################################################
# memoryGroup
# uses folder location to choose MG
####################################################################
new_sub_entry = ET.SubElement( new_entry, 'MemoryGroup')
string_found = False
matching_char_length = 0
for condition_index in range( t.MAX_NUM_OF_CONDITIONS - 1):
if not t.dictionaryEdit[condition_index].Text == '':
if t.dictionaryEdit[condition_index].Text in clip_dictionary:
if len( clip_dictionary ) > matching_char_length:
new_sub_entry.text = t.memoryGroup[condition_index].Items[ t.memoryGroup[condition_index].ItemIndex ]
string_found = True
matching_char_length = len( clip_dictionary )
if string_found == False:
new_sub_entry.text = t.memoryGroup[ t.MAX_NUM_OF_CONDITIONS - 1 ].Items[ t.memoryGroup[ t.MAX_NUM_OF_CONDITIONS - 1 ].ItemIndex ]
prettyPrint( new_clip_dictionaries )
####################################################################
# Compare clip metadata list with clip dictionaries
# anything unreferenced requires deleting
####################################################################
unused_metadata_dictionaries = ET.SubElement( root, 'These clipDictionaryMetadatas do not reference anything. Remove the following from the clipsets file.' )
unused_metadata = False
for clip_dictionary_metadata in clip_dictionary_metadatas_list:
if clip_dictionary_metadata not in clip_dictionary_names_list:
print "================= UNUSED METADATA FOUND ================="
print "name of clipset is " + str( clip_dictionary_metadata )
print "size of dictionary list is " + str( len( clip_dictionary_names_list ) )
for dictionary in clip_dictionary_names_list:
print str( dictionary )
# add clipdictionary element
new_entry = ET.SubElement( unused_metadata_dictionaries, 'Item')
new_entry.set('key', clip_dictionary_metadata)
unused_metadata = True
prettyPrint( unused_metadata_dictionaries )
####################################################################
# Write new metadatas file
####################################################################
output_file_path = tempfile.gettempdir() + '\\mj_ClipSetUtility_output.txt'
with open( output_file_path , 'w') as f:
output = ET.tostring( new_clip_dictionaries )
f.write( output )
if unused_metadata == True:
with open( output_file_path , 'a') as f:
output = '-----------------------------------------------------------------------------------------------------------\n'
f.write( output )
output = ET.tostring( unused_metadata_dictionaries )
f.write( output )
os.startfile( output_file_path )
print "Saved to " + output_file_path
else:
print "Error loading clipset."
####################################################################
# main
####################################################################
def CreateTool():
global t
t = FBCreateUniqueTool("ClipSet Utility")
PopulateTool(t)
CreateTool()from pyfbsdk import *
from pyfbsdk_additions import *
def clearSelection():
''' Clear selection function '''
# Get selected models
modelList = FBModelList ()
FBGetSelectedModels (modelList, None, True)
# Deselect models
for model in modelList:
model.Selected = False
####################################################################
# UI callbacks
####################################################################
def goButtonCallBack(control, event):
if t.pinned == False:
########################################
# Pin object
########################################
# create null
t.null = FBModelNull('constraint_null')
# get time span
current_start = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
current_end = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()
#----------------------------------------------------------------------------------
# loop for every frame - get pos/rot of selected object
#----------------------------------------------------------------------------------
# lists for storing object pos and rotations
trans_array = []
rot_array = []
for frame in range(current_start, current_end + 1):
# update slider
FBPlayerControl().Goto(FBTime(0,0,0,frame))
FBSystem().Scene.Evaluate()
# get selected translation and rotation for object
obj_trans = FBVector3d()
obj_rot = FBVector3d()
t.selected_obj.GetVector (obj_trans, FBModelTransformationType.kModelTranslation, True)
t.selected_obj.GetVector (obj_rot, FBModelTransformationType.kModelRotation, True)
FBSystem().Scene.Evaluate()
# store translation/rotation
trans_array.append(obj_trans)
rot_array.append(obj_rot)
# only select null
clearSelection()
t.null.Selected = True
#----------------------------------------------------------------------------------
# loop for every frame - set pos/rot on null
#----------------------------------------------------------------------------------
count = 0
for frame in range(current_start, current_end + 1):
# update slider
FBPlayerControl().Goto(FBTime(0,0,0,frame))
FBSystem().Scene.Evaluate()
# set selected translation and rotation for object
t.null.SetVector (trans_array[count], FBModelTransformationType.kModelTranslation, True)
t.null.SetVector (rot_array[count], FBModelTransformationType.kModelRotation, True)
FBSystem().Scene.Evaluate()
# key null
FBPlayerControl().Key()
FBSystem().Scene.Evaluate()
count += 1
####################################################################
# UI definition
####################################################################
def PopulateTool(t):
# get selected object
models = FBModelList()
FBGetSelectedModels( models )
if len(models) == 0:
FBMessageBox( "Message", "Nothing selected", "OK", None, None )
else:
t.selected_obj = models[0]
t.selected_obj_name = models[0].Name
#Pin button
x = FBAddRegionParam(5,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(5,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(240,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(30,FBAttachType.kFBAttachNone,"")
t.AddRegion("go_button_region","go_button_region", x, y, w, h)
t.pin_button = FBButton()
t.SetControl("go_button_region", t.pin_button)
t.pin_button.Visible = True
t.pin_button.ReadOnly = False
t.pin_button.Enabled = True
t.pin_button.Hint = ""
t.pin_button.Caption = "Plot & Pin '" + t.selected_obj_name + "'"
t.pin_button.State = 0
t.pin_button.Style = FBButtonStyle.kFBPushButton
t.pin_button.Justify = FBTextJustify.kFBTextJustifyCenter
t.pin_button.Look = FBButtonLook.kFBLookNormal
t.pin_button.OnClick.Add(goButtonCallBack)
# set pin state
t.pinned = False
ShowTool(t)
####################################################################
# Main
####################################################################
def CreateTool():
global t
t = FBCreateUniqueTool("Create Animated Null")
t.StartSizeX = 265
t.StartSizeY = 75
PopulateTool(t)
CreateTool()
PNG
from pyfbsdk import *
from pyfbsdk_additions import *
def clearSelection():
''' Clear selection function '''
# Get selected models
modelList = FBModelList ()
FBGetSelectedModels (modelList, None, True)
# Deselect models
for model in modelList:
model.Selected = False
def getSelectedAuxPivot():
''' goes through selected objects and returns first selected pivot '''
# Get selected models
modelList = FBModelList ()
FBGetSelectedModels ( modelList )
for model in modelList:
if model.Type is FBMarkerType.kFBMarkerTypeIKEffector:
return model
# clear all models
clearSelection()
# get current character and control set
character = FBApplication().CurrentCharacter
###########################################################################################
# left ankle effectors
###########################################################################################
'''
# create heel
result = character.CreateAuxiliary( FBEffectorId.kFBLeftAnkleEffectorId, True, 0.0, 0.0 )
if result:
auxPivot = getSelectedAuxPivot()
auxPivot.IKPivot = FBVector3d( 0.42, 9.44, 3.86)
auxPivot.Look = FBMarkerLook.kFBMarkerLookLightCross
auxPivot.Name = 'LeftAnkleHeelPivot'
auxPivot.Selected = False
'''
# create ball
result = character.CreateAuxiliary( FBEffectorId.kFBLeftAnkleEffectorId, True, 0.0, 0.0 )
if result:
auxPivot = getSelectedAuxPivot()
auxPivot.IKPivot = FBVector3d( 3.50, 10.53, -15.10)
auxPivot.Look = FBMarkerLook.kFBMarkerLookLightCross
auxPivot.Name = 'LeftAnkleBallPivot'
auxPivot.Selected = False
###########################################################################################
# left ball effectors
###########################################################################################
'''
# create ball
result = character.CreateAuxiliary( FBEffectorId.kFBLeftFootEffectorId, True, 0.0, 0.0 )
if result:
auxPivot = getSelectedAuxPivot()
auxPivot.IKPivot = FBVector3d( 3.50, 4.11, -1.61)
auxPivot.Look = FBMarkerLook.kFBMarkerLookLightCross
auxPivot.Color = FBColor(0.0, 255.0, 0.0)
auxPivot.Name = 'LeftFootBallPivot'
auxPivot.Selected = False
# create toe
result = character.CreateAuxiliary( FBEffectorId.kFBLeftFootEffectorId, True, 0.0, 0.0 )
if result:
auxPivot = getSelectedAuxPivot()
auxPivot.IKPivot = FBVector3d( 2.03, -0.52, -11.88)
auxPivot.Look = FBMarkerLook.kFBMarkerLookLightCross
auxPivot.Color = FBColor(0.0, 255.0, 0.0)
auxPivot.Name = 'LeftFootToePivot'
auxPivot.Selected = False
'''
###########################################################################################
# right ankle effectors
###########################################################################################
'''
# create heel
result = character.CreateAuxiliary( FBEffectorId.kFBRightAnkleEffectorId, True, 0.0, 0.0 )
if result:
auxPivot = getSelectedAuxPivot()
auxPivot.IKPivot = FBVector3d( -0.42, 9.44, 3.86)
auxPivot.Look = FBMarkerLook.kFBMarkerLookLightCross
auxPivot.Name = 'RightAnkleHeelPivot'
auxPivot.Selected = False
'''
# create ball
result = character.CreateAuxiliary( FBEffectorId.kFBRightAnkleEffectorId, True, 0.0, 0.0 )
if result:
auxPivot = getSelectedAuxPivot()
auxPivot.IKPivot = FBVector3d( -3.65, 10.53, -15.10)
auxPivot.Look = FBMarkerLook.kFBMarkerLookLightCross
auxPivot.Name = 'RightAnkleBallPivot'
auxPivot.Selected = False
###########################################################################################
# right ball effectors
###########################################################################################
'''
# create ball
result = character.CreateAuxiliary( FBEffectorId.kFBRightFootEffectorId, True, 0.0, 0.0 )
if result:
auxPivot = getSelectedAuxPivot()
auxPivot.IKPivot = FBVector3d( -3.50, 4.11, -1.61)
auxPivot.Look = FBMarkerLook.kFBMarkerLookLightCross
auxPivot.Color = FBColor(0.0, 255.0, 0.0)
auxPivot.Name = 'RightFootBallPivot'
auxPivot.Selected = False
# create toe
result = character.CreateAuxiliary( FBEffectorId.kFBRightFootEffectorId, True, 0.0, 0.0 )
if result:
auxPivot = getSelectedAuxPivot()
auxPivot.IKPivot = FBVector3d( -2.03, -0.52, -11.88)
auxPivot.Look = FBMarkerLook.kFBMarkerLookLightCross
auxPivot.Color = FBColor(0.0, 255.0, 0.0)
auxPivot.Name = 'RightFootToePivot'
auxPivot.Selected = False
'''PNG
####################################################################
# Create a tracking camera for the current character
####################################################################
from pyfbsdk import *
def createCharacterTrackingCamera():
app = FBApplication()
system = FBSystem()
# get current character and namespace
current_character = app.CurrentCharacter
if current_character is not None:
current_ns = current_character.OwnerNamespace.Name
# create camera
camera = FBCamera('Tracking Camera')
if current_ns is not None:
camera.ProcessObjectNamespace(FBNamespaceAction.kFBConcatNamespace, current_ns )
camera.Visible = True
camera.Show = True
# create parent null
cameraParent = FBModelNull('Tracking Camera Parent')
if current_ns is not None:
cameraParent.ProcessObjectNamespace(FBNamespaceAction.kFBConcatNamespace, current_ns)
camera.Parent = cameraParent
# create parent constraint
constraintManager = FBConstraintManager()
# get index to parent/child constraint
constraint_index = None
for i in range(0, constraintManager.TypeGetCount()):
if constraintManager.TypeGetName(i) == 'Position':
constraint_index = i
break
# create constraint
posConstraint = constraintManager.TypeCreateConstraint(constraint_index)
posConstraint.Name = 'Tracking Camera Position Constraint'
if current_ns is not None:
posConstraint.ProcessObjectNamespace(FBNamespaceAction.kFBConcatNamespace, current_ns)
moverObject = FBFindModelByLabelName(current_ns + ':mover')
if moverObject is not None:
# add ref objects
for i in range(0, posConstraint.ReferenceGroupGetCount()):
if posConstraint.ReferenceGroupGetName(i) == 'Source':
posConstraint.ReferenceAdd(i, moverObject )
elif posConstraint.ReferenceGroupGetName(i) == 'Constrained Object':
posConstraint.ReferenceAdd(i, cameraParent )
# snap constraint
posConstraint.Snap()
# switch camera to tracking cam
app.SwitchViewerCamera(camera)
createCharacterTrackingCamera()
PNG
from pyfbsdk import *
from pyfbsdk_additions import *
def DeleteAnimationOnSelectedObjects():
# get selected objects
selected_objs = FBModelList()
FBGetSelectedModels( selected_objs )
if len( selected_objs ) > 0:
user_choice = FBMessageBox( "Message", "Delete all animation on selected objects across all takes?", "Yes", "No" )
if ( user_choice == 1 ):
# make sure we're in selection mode not fullbody! Otherwise it will delete all animation on a character even if only one bone is selected
FBApplication().CurrentCharacter.KeyingMode = FBCharacterKeyingMode.kFBCharacterKeyingSelection
# for each take delete animation
for take in FBSystem().Scene.Takes:
FBSystem().CurrentTake = take
FBSystem().Scene.Evaluate()
take.ClearAllProperties( True )
print "All animation deleted on selected objects"
else:
FBMessageBox( "Message", "No objects selected", "OK" )
DeleteAnimationOnSelectedObjects()PNG
from pyfbsdk import *
from pyfbsdk_additions import *
# Clear all auxiliary on given effector
def ClearAuxEffectors(pCharacter, pEffectorId):
lAuxToClear = []
for lSetId in FBEffectorSetID.values.values():
# Default set should not be deleted.
if lSetId == FBEffectorSetID.FBEffectorSetDefault: continue
lAuxEffector = pCharacter.GetEffectorModel(pEffectorId,lSetId)
if lAuxEffector:
lAuxToClear.append(lAuxEffector)
else: break
# Clear the list
for lModel in reversed(lAuxToClear):
lModel.FBDelete()
user_response = FBMessageBox( "Warning", "Are you sure you want to delete all aux foot pivots?", "Yes", "No" )
if user_response == 1:
character = FBApplication().CurrentCharacter
ClearAuxEffectors( character, FBEffectorId.kFBLeftAnkleEffectorId )
ClearAuxEffectors( character, FBEffectorId.kFBLeftFootEffectorId )
ClearAuxEffectors( character, FBEffectorId.kFBRightAnkleEffectorId )
ClearAuxEffectors( character, FBEffectorId.kFBRightFootEffectorId )
print "All aux pivots deleted!"
else:
print "Cancelled!"
PNG
####################################################################
# searches for bad xml formatting with respect to conditions
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
import xml.etree.ElementTree as ET
import tempfile
import os
import RS.Config
def checkForBadConditions(filepath, output, parent):
children = parent.getchildren()
for child in children:
if (child.tag == 'Condition') and (parent.tag =='Conditions'):
output += ">> " + filepath + " at line number " + str(child._start_line_number) + "\n"
#print output
# does child contain more elements?
if len(child.getchildren()) > 0:
output = checkForBadConditions(filepath, output, child)
return output
####################################################################
# custom class so we can find line numbers
# from: http://stackoverflow.com/questions/6949395/is-there-a-way-to-get-a-line-number-from-an-elementtree-element
####################################################################
class LineNumberingParser(ET.XMLParser):
def _start_list(self, *args, **kwargs):
# Here we assume the default XML parser which is expat
# and copy its element position attributes into output Elements
element = super(self.__class__, self)._start_list(*args, **kwargs)
element._start_line_number = self.parser.CurrentLineNumber
element._start_column_number = self.parser.CurrentColumnNumber
element._start_byte_index = self.parser.CurrentByteIndex
return element
def _end(self, *args, **kwargs):
element = super(self.__class__, self)._end(*args, **kwargs)
element._end_line_number = self.parser.CurrentLineNumber
element._end_column_number = self.parser.CurrentColumnNumber
element._end_byte_index = self.parser.CurrentByteIndex
return element
####################################################################
# main
####################################################################
# loco meta path
rootdir = RS.Config.Project.Path.Assets + "\\export\\data\\loco\\"
# output string
output = "############################################################################################################################\n"
output += "# Bad Conditions xml formatting results\n"
output += "############################################################################################################################\n\n"
##############################################################
# Loop through each nested file in the locoelement meta structure
##############################################################
for subdir, dirs, files in os.walk(rootdir):
for file in files:
filepath = subdir + os.sep + file
##############################################################
# only search in meta files
##############################################################
if filepath.endswith(".meta"):
tree = ET.parse( filepath, parser=LineNumberingParser() )
root = tree.getroot()
##############################################################
# search in <Condition> in each file
##############################################################
conditionElement = root.find('Condition')
if conditionElement:
output = checkForBadConditions(filepath, output, conditionElement)
##############################################################
# search in <Motions> in each file
##############################################################
conditionElement = root.find('Motions')
if conditionElement:
output = checkForBadConditions(filepath, output, conditionElement)
##############################################################
# Save out results and open file
##############################################################
output_file_path = tempfile.gettempdir() + '\\mj_LocoMetaSearch_output.txt'
with open(output_file_path,'w') as f:
f.write( output )
f.closed
os.startfile( output_file_path )
PNG
####################################################################
# searches for bad xml formatting with respect to conditions
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
import xml.etree.ElementTree as ET
import tempfile
import os
import RS.Config
def isFileAMotionType( root ):
if root.tag == 'Item':
for attribute_tag in root.attrib:
if root.attrib[ attribute_tag ] == 'Loco__MotionType':
return True
return False
def findMissingController(filepath, output, parent ):
children = parent.getchildren()
isControllerFound = False
for child in children:
if (child.tag == 'UsesController'):
isControllerFound = True
if not isControllerFound:
output += ">> " + filepath + "\n"
return output
def findNonMotionLoco(filepath, output, parent, loco_motion_type):
children = parent.getchildren()
attribute_tag = 'type'
search_tag = 'MotionSet'
for child in children:
if (child.tag == 'Item'):
if attribute_tag in child.attrib:
if child.attrib[ attribute_tag ] == loco_motion_type:
subelements = child.getchildren()
isTagFound = False
for elem in subelements:
if elem.tag == search_tag:
isTagFound = True
# does Motion contain a MotionSet attribute? if it doesn't it mustn't be on motions yet
if not isTagFound:
output += ">> " + filepath + " at line number " + str(child._start_line_number) + "\n"
return output
####################################################################
# custom class so we can find line numbers
# from: http://stackoverflow.com/questions/6949395/is-there-a-way-to-get-a-line-number-from-an-elementtree-element
####################################################################
class LineNumberingParser(ET.XMLParser):
def _start_list(self, *args, **kwargs):
# Here we assume the default XML parser which is expat
# and copy its element position attributes into output Elements
element = super(self.__class__, self)._start_list(*args, **kwargs)
element._start_line_number = self.parser.CurrentLineNumber
element._start_column_number = self.parser.CurrentColumnNumber
element._start_byte_index = self.parser.CurrentByteIndex
return element
def _end(self, *args, **kwargs):
element = super(self.__class__, self)._end(*args, **kwargs)
element._end_line_number = self.parser.CurrentLineNumber
element._end_column_number = self.parser.CurrentColumnNumber
element._end_byte_index = self.parser.CurrentByteIndex
return element
####################################################################
# main
####################################################################
# loco meta path
rootdir = RS.Config.Project.Path.Assets + "\\export\\data\\loco\\types\\human\\"
# output strings
missing_controller_output = "############################################################################################################################\n"
missing_controller_output += "# Motiontypes with no specified controller \n"
missing_controller_output += "############################################################################################################################\n\n"
loop_output = "############################################################################################################################\n"
loop_output += "# Loco Loops not on Motions \n"
loop_output += "############################################################################################################################\n\n"
idle_turn_output = "############################################################################################################################\n"
idle_turn_output += "# Loco Idle Turns not on Motions \n"
idle_turn_output += "############################################################################################################################\n\n"
stop_output = "############################################################################################################################\n"
stop_output += "# Loco Stops not on Motions \n"
stop_output += "############################################################################################################################\n\n"
start_output = "############################################################################################################################\n"
start_output += "# Loco Starts not on Motions \n"
start_output += "############################################################################################################################\n\n"
moving_turn_output = "############################################################################################################################\n"
moving_turn_output += "# Loco Moving Turns not on Motions \n"
moving_turn_output += "############################################################################################################################\n\n"
##############################################################
# Loop through each nested file in the locoelement meta structure
##############################################################
for subdir, dirs, files in os.walk(rootdir):
for file in files:
filepath = subdir + os.sep + file
##############################################################
# only search in meta files
##############################################################
if filepath.endswith(".meta"):
tree = ET.parse( filepath, parser=LineNumberingParser() )
root = tree.getroot()
##############################################################
# search in <Motions> in each file for missing motions
##############################################################
if isFileAMotionType( root ):
missing_controller_output = findMissingController(filepath, missing_controller_output, root )
##############################################################
# search in <Motions> in each file for missing motions
##############################################################
conditionElement = root.find('Motions')
if conditionElement:
loop_output = findNonMotionLoco(filepath, loop_output, conditionElement, 'Loco__MotionMoving')
idle_turn_output = findNonMotionLoco(filepath, idle_turn_output, conditionElement, 'Loco__MotionIdleTurn')
stop_output = findNonMotionLoco(filepath, stop_output, conditionElement, 'Loco__MotionStop')
start_output = findNonMotionLoco(filepath, start_output, conditionElement, 'Loco__MotionStart')
moving_turn_output = findNonMotionLoco(filepath, moving_turn_output, conditionElement, 'Loco__MotionMovingTurn')
##############################################################
# Save out results and open file
##############################################################
output = missing_controller_output + "\n" + loop_output + "\n" + idle_turn_output + "\n" + stop_output + "\n" + start_output + "\n" + moving_turn_output
output_file_path = tempfile.gettempdir() + '\\mj_LocoMetaSearch_output.txt'
with open(output_file_path,'w') as f:
f.write( output )
f.closed
os.startfile( output_file_path )
####################################################################
# searches for bad xml formatting with respect to conditions
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
import xml.etree.ElementTree as ET
import tempfile
import os
import RS.Config
def checkForBadIdleSyncs(filepath, output, parent):
children = parent.getchildren()
loco_motion_type = 'Loco__MotionUpperBodyLoop'
attribute_tag = 'type'
gait_search_tags = ['MinGait','MaxGait']
gait_search_value = 'LG_IDLE'
layer_search_tags = [ 'LayerSync' ]
layer_search_value = 'FOOTSYNC'
for child in children:
if (child.tag == 'Item'):
if attribute_tag in child.attrib:
if child.attrib[ attribute_tag ] == loco_motion_type:
# we have found a Loco__MotionUpperBodyLoop
# does it contain a min or max gait with LG_IDLE?
subelements = child.getchildren()
isGaitFound = False
for elem in subelements:
for gait_search_tag in gait_search_tags:
if elem.tag == gait_search_tag:
# does Loco__MotionUpperBodyLoop contain an LG_Idle Gait?
if elem.text.upper() == gait_search_value:
isGaitFound = True
if isGaitFound:
# yes does the upperbody contain a layersync?
isLayerSyncFound = False
isLayerFootSync = False
for elem in subelements:
for layer_search_tag in layer_search_tags:
if elem.tag == layer_search_tag:
# yes
isLayerSyncFound = True
# does it contain Footsync?
if elem.text.upper() == layer_search_value:
isLayerFootSync = True
# if Loco__MotionUpperBodyLoop doesn't specify a layersync OR has a footsync then it's bad!
if not isLayerSyncFound or isLayerFootSync:
output += ">> " + filepath + " at line number " + str(child._start_line_number) + "\n"
return output
####################################################################
# custom class so we can find line numbers
# from: http://stackoverflow.com/questions/6949395/is-there-a-way-to-get-a-line-number-from-an-elementtree-element
####################################################################
class LineNumberingParser(ET.XMLParser):
def _start_list(self, *args, **kwargs):
# Here we assume the default XML parser which is expat
# and copy its element position attributes into output Elements
element = super(self.__class__, self)._start_list(*args, **kwargs)
element._start_line_number = self.parser.CurrentLineNumber
element._start_column_number = self.parser.CurrentColumnNumber
element._start_byte_index = self.parser.CurrentByteIndex
return element
def _end(self, *args, **kwargs):
element = super(self.__class__, self)._end(*args, **kwargs)
element._end_line_number = self.parser.CurrentLineNumber
element._end_column_number = self.parser.CurrentColumnNumber
element._end_byte_index = self.parser.CurrentByteIndex
return element
####################################################################
# main
####################################################################
# loco meta path
rootdir = RS.Config.Project.Path.Assets + "\\export\\data\\loco\\types\\human\\"
# output string
output = "############################################################################################################################\n"
output += "# LG_IDLE LayerSync results\n"
output += "# \n"
output += "# These motions contain an upperbody loop which has an LG_Idle gait, and either specifies FootSync OR doesn't specify anything (which will default to FootSync)\n"
output += "############################################################################################################################\n\n"
##############################################################
# Loop through each nested file in the locoelement meta structure
##############################################################
for subdir, dirs, files in os.walk(rootdir):
for file in files:
filepath = subdir + os.sep + file
##############################################################
# only search in meta files
##############################################################
if filepath.endswith(".meta"):
tree = ET.parse( filepath, parser=LineNumberingParser() )
root = tree.getroot()
##############################################################
# search in <Motions> in each file
##############################################################
conditionElement = root.find('Motions')
if conditionElement:
output = checkForBadIdleSyncs(filepath, output, conditionElement)
##############################################################
# Save out results and open file
##############################################################
output_file_path = tempfile.gettempdir() + '\\mj_LocoMetaSearch_output.txt'
with open(output_file_path,'w') as f:
f.write( output )
f.closed
os.startfile( output_file_path )
PNG
from pyfbsdk import *
from pyfbsdk_additions import *
from ctypes import *
import os
import subprocess
def launchWithoutConsole(command):
CREATE_NO_WINDOW = 0x08000000
subprocess.call(command, creationflags=CREATE_NO_WINDOW)
def GetCharacterAsRexMBModel( character ):
current_character_root = character.GetModel(FBBodyNodeId.kFBHipsNodeId)
rexMBModels = RexMBRagePython.GetModels()
for rexMBModel in rexMBModels:
if current_character_root.LongName == rexMBModel.GetRootName():
return rexMBModel
def GetTakeAsRexMBTake( take_name ):
RexMBTakes = RexMBRagePython.GetTakes()
for i in range( len( FBSystem().Scene.Takes ) ):
if take_name == RexMBTakes[ i ].GetName():
return RexMBTakes[take_count]
def CalculateFootPlantFrames():
DEBUG = False
#############################################################################################
# Method runs through every frame of current take, stores pos and velocities of foot bones, then works out which frames we have a foot plant
# Returns two bool arrays in a tuple representing each frame for left foot and right foot respectively.
#############################################################################################
left_model = t.left_foot_container.Model
right_model = t.right_foot_container.Model
# frame range
take_start_frame = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
take_end_frame = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()
left_model_pos = []
right_model_pos = []
left_model_vel = []
right_model_vel = []
left_plant = []
right_plant = []
inputPos = FBVector3d()
frame_count = 0
#############################################################################################
# Store joint positions per frame
#############################################################################################
for frame in range(take_start_frame, take_end_frame + 1):
# update frame
FBPlayerControl().Goto(FBTime(0, 0, 0, frame))
FBSystem().Scene.Evaluate()
# get current foot transformations
left_model.GetVector(inputPos, FBModelTransformationType.kModelTranslation, True)
left_model_pos.append(FBVector3d(inputPos[0], inputPos[1], inputPos[2]))
right_model.GetVector(inputPos, FBModelTransformationType.kModelTranslation, True)
right_model_pos.append(FBVector3d(inputPos[0], inputPos[1], inputPos[2]))
frame_count += 1
#############################################################################################
# Calc joint velocities pre frame
#############################################################################################
for frame in range(frame_count):
if frame == 0:
# Initialise velocity arrays with zero on first frame
# and set plants as False.
left_model_vel.append( 0.0 )
right_model_vel.append( 0.0 )
left_plant.append(False)
right_plant.append(False)
else:
left_model_vel.append(( left_model_pos[ frame ] - left_model_pos[ frame - 1 ] ).Length())
if DEBUG:
print "left foot vel on frame " + str(frame) + " is " + str( left_model_vel[ frame ] )
right_model_vel.append(( right_model_pos[ frame ] - right_model_pos[ frame - 1 ] ).Length())
if DEBUG:
print "right foot vel on frame " + str(frame) + " is " + str(right_model_vel[ frame ])
# magic numbers - probably want to expose in UI
planting_velocity_threshold = 0.3
lifting_velocity_threshold = 0.6
left_foot_is_moving = False
right_foot_is_moving = False
# don't check first frame, we can't tell whether we've planted on frame zero
for frame in range(1, frame_count):
# check left foot
if left_model_vel[frame] < planting_velocity_threshold and left_foot_is_moving:
left_plant.append(True)
left_foot_is_moving = False
else:
left_plant.append(False)
if left_model_vel[frame] > lifting_velocity_threshold:
left_foot_is_moving = True
# check right foot
if right_model_vel[ frame ] < planting_velocity_threshold and right_foot_is_moving:
right_plant.append(True)
right_foot_is_moving = False
else:
right_plant.append(False)
if right_model_vel[ frame ] > lifting_velocity_threshold:
right_foot_is_moving = True
# return two bool arrays, access via tuple
return left_plant, right_plant
def AddFootTags( clip_path, footPlantFrames, clear_existing = True ):
tools_root = os.environ['RS_TOOLSROOT']
# delete any existing foot tracks
if clear_existing:
launchWithoutConsole(tools_root + '/bin/anim/clipedit.exe -clip ' + clip_path + ' -ops removetag,Foot -out ' + clip_path)
#############################################################################################
# left foot
#############################################################################################
# [0] tuple entry is left foot
count = 0
for frame in footPlantFrames[0]:
if frame:
phase = float( count ) / float( len(footPlantFrames[0]) )
launchWithoutConsole( tools_root + '/bin/anim/clipedit.exe -clip ' + clip_path + ' -ops addtag,Foot[].Heel=true;addtag,Foot[0].Right=false -out ' + clip_path )
launchWithoutConsole( tools_root + '/bin/anim/clipedit.exe -clip ' + clip_path + ' -ops edittag,Foot[0].startend=' + str( phase ) + ',' + str( phase ) + ' -out ' + clip_path )
count += 1
#############################################################################################
# right foot
#############################################################################################
# [1] tuple entry is right foot
count = 0
for frame in footPlantFrames[1]:
if frame:
phase = float( count ) / float( len(footPlantFrames[1]) )
launchWithoutConsole( tools_root + '/bin/anim/clipedit.exe -clip ' + clip_path + ' -ops addtag,Foot[].Heel=true;addtag,Foot[0].Right=true -out ' + clip_path)
launchWithoutConsole( tools_root + '/bin/anim/clipedit.exe -clip ' + clip_path + ' -ops edittag,Foot[0].startend=' + str(phase) + ',' + str(phase) + ' -out ' + clip_path)
count += 1
def IsFileWritable( path ):
return os.access( path, os.W_OK )
def DoesFilePathExist( path ):
return os.path.exists(path)
def GetExportClipFileName(take_name):
# first check for an alternate output name
cdll.rexmbrage.GetTakeAltName_Py.restype = c_char_p
output_name = cdll.rexmbrage.GetTakeAltName_Py( take_name )
# if no alternate is set then use take name
if output_name == '':
output_name = take_name
# add any prefix/suffixes
# current_character = FBApplication().CurrentCharacter
# rexMBModel = GetCharacterAsRexMBModel( current_character )
#output_name = rexMBModel.GetAnimPrefix() + output_name + rexMBModel.GetAnimSuffix()
return output_name
def ReturnExportPathForCurrentTake():
current_take_name = FBSystem().CurrentTake.Name
clip_path = ''
# only interested in takes if they are marked for export
if c_bool(cdll.rexMBRage.GetTakeExportSetting_Py( current_take_name )).value:
clip_name = GetExportClipFileName(current_take_name)
# if there's an alternate output path grab that, otherwise it will be using the default
if c_int(cdll.rexMBRage.GetTakeOutputPathCount_Py( current_take_name )).value > 0:
cdll.rexmbrage.GetTakeOutputPath_Py.restype = c_char_p
clip_path = cdll.rexmbrage.GetTakeOutputPath_Py( current_take_name, 0 )
else:
cdll.rexmbrage.GetExportPath_Py.restype = c_char_p
clip_path = cdll.rexmbrage.GetExportPath_Py()
if clip_path == '':
return clip_path
else:
# create final name
clip_path = clip_path + clip_name + '.clip'
return clip_path
def ValidatePath( path ):
if path != '':
if DoesFilePathExist( path ):
if IsFileWritable( path):
return True
else:
FBMessageBox("Error", "Clip file is not writable.", "Ok")
else:
FBMessageBox("Error", path + " does not appear on disk!", "Ok")
else:
FBMessageBox("Error","Export path has not been set in exporter for current take!", "Ok")
return False
def AutomateFootSteps():
path = ReturnExportPathForCurrentTake()
if ValidatePath( path ):
footPlantFrames = CalculateFootPlantFrames()
AddFootTags( path, footPlantFrames )
FBMessageBox("Success", "Foot tags added to " + path, "Ok")
####################################################################
# UI callbacks
####################################################################
def EventContainerDragAndDrop(control, event):
if event.State == FBDragAndDropState.kFBDragAndDropDrag:
event.Accept()
elif event.State == FBDragAndDropState.kFBDragAndDropDrop:
for e in event.Components:
# only allow certain types to be dropped
if type(e) is pyfbsdk.FBModelNull or type(e) is pyfbsdk.FBModelSkeleton or type(e) is pyfbsdk.FBModelMarker or type(e) is pyfbsdk.FBModel:
event.Accept()
# update UI and store dropped model
control.Items.removeAll()
control.Items.append(e.LongName)
control.Model = e
if t.left_foot_container.Model and t.right_foot_container.Model:
t.enabled = True
t.applyButton.Enabled = True
def applyButtonCallBack(control, event):
AutomateFootSteps()
####################################################################
# UI definition
####################################################################
def PopulateTool(t):
# UI constants
ui_x_offset = 10
ui_y_offset = 5
ui_x_width = 400
ui_button_height = 30
ui_button_width = 40
ui_column_a = 20
ui_column_b = 100
ui_column_c = 100
t.enabled = True
model = None
##########################################################################################
# Right Foot Effector
##########################################################################################
ui_y_offset += 10
x = FBAddRegionParam(ui_x_offset, FBAttachType.kFBAttachNone, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width - 20, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height + 10, FBAttachType.kFBAttachNone, "")
t.AddRegion("right_foot_border", "Right Foot Effector/Joint (Drag to change)", x, y, w, h)
t.SetBorder("right_foot_border", FBBorderStyle.kFBEmbossBorder, True, True, 2, 0, 90.0, 0)
ui_y_offset += 10
x = FBAddRegionParam(ui_x_offset + 10, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width - 40, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(20, FBAttachType.kFBAttachNone, "")
t.AddRegion("right_foot_model", "right_foot_model", x, y, w, h)
# set default model
character = FBApplication().CurrentCharacter
if character:
model = FBFindModelByLabelName(character.OwnerNamespace.Name + ':SKEL_R_Toe0')
t.right_foot_container = FBVisualContainer()
if model:
t.right_foot_container.Model = model
t.right_foot_container.Items.append(t.right_foot_container.Model.LongName)
else:
t.right_foot_container.Model = None
t.enabled = False
t.right_foot_container.OnDragAndDrop.Add(EventContainerDragAndDrop)
t.right_foot_container.ItemHeight = 20
t.right_foot_container.ItemWidth = ui_x_width - 45
t.SetControl("right_foot_model", t.right_foot_container)
ui_y_offset += ui_button_height + 10
##########################################################################################
# Left Foot effector
##########################################################################################
ui_y_offset += 10
x = FBAddRegionParam(ui_x_offset, FBAttachType.kFBAttachNone, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width - 20, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height + 10, FBAttachType.kFBAttachNone, "")
t.AddRegion("left_foot_border", "Left Foot Effector/Joint (Drag to change)", x, y, w, h)
t.SetBorder("left_foot_border", FBBorderStyle.kFBEmbossBorder, True, True, 2, 0, 90.0, 0)
ui_y_offset += 10
x = FBAddRegionParam(ui_x_offset + 10, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width - 40, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(20, FBAttachType.kFBAttachNone, "")
t.AddRegion("left_foot_model", "left_foot_model", x, y, w, h)
# set default model
character = FBApplication().CurrentCharacter
if character:
model = FBFindModelByLabelName(character.OwnerNamespace.Name + ':SKEL_L_Toe0')
t.left_foot_container = FBVisualContainer()
if model:
t.left_foot_container.Model = model
t.left_foot_container.Items.append(t.left_foot_container.Model.LongName)
else:
t.right_foot_container.Model = None
t.enabled = False
t.left_foot_container.OnDragAndDrop.Add(EventContainerDragAndDrop)
t.left_foot_container.ItemHeight = 20
t.left_foot_container.ItemWidth = ui_x_width - 45
t.SetControl("left_foot_model", t.left_foot_container)
##########################################################################################
# Apply Button
##########################################################################################
ui_y_offset += 40
x = FBAddRegionParam(ui_x_offset, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width - 20, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(25, FBAttachType.kFBAttachNone, "")
t.AddRegion("apply_button", "apply_button", x, y, w, h)
t.applyButton = FBButton()
t.SetControl("apply_button", t.applyButton)
t.applyButton.Visible = True
t.applyButton.ReadOnly = False
t.applyButton.Enabled = t.enabled
t.applyButton.Hint = ""
t.applyButton.Caption = "Apply"
t.applyButton.State = 0
t.applyButton.Style = FBButtonStyle.kFBPushButton
t.applyButton.Justify = FBTextJustify.kFBTextJustifyCenter
t.applyButton.Look = FBButtonLook.kFBLookNormal
t.applyButton.OnClick.Add(applyButtonCallBack)
ui_y_offset += ui_button_height + 30
##########################################################################################
# Calculate Tool Window Size and Draw
##########################################################################################
t.StartSizeX = ui_x_width + ui_x_offset * 2
t.StartSizeY = ui_y_offset + 10
ShowTool(t)
####################################################################
# Main
####################################################################
def CreateTool():
global t
t = FBCreateUniqueTool("AutomateFootSteps")
PopulateTool(t)
CreateTool()
PNG
####################################################################
# Allows user to lock selected character hat controller
####################################################################
from pyfbsdk import *
# get current character
current_character = FBApplication().CurrentCharacter
if current_character != None:
hat_ctrl = None
# get hat ctrl
for ext in current_character.CharacterExtensions:
if ext.Name == 'Hat_Rig':
hat_ctrl = ext.GetExtensionObjectWithLabelName('CTRL_PH_Hat_Loc')
break
if hat_ctrl is None:
print "Hat Ctrl Rig not found for current character!"
else:
# toggle translation/rotation dofs on or off
bTranslationDOF = hat_ctrl.PropertyList.Find("Enable Translation DOF").Data
bRotationDOF = hat_ctrl.PropertyList.Find("Enable Rotation DOF").Data
hat_ctrl.PropertyList.Find("Enable Translation DOF").Data = not bTranslationDOF
hat_ctrl.PropertyList.Find("Enable Rotation DOF").Data = not bRotationDOF
hat_ctrl.PropertyList.Find("TranslationMinX").Data = not bTranslationDOF
hat_ctrl.PropertyList.Find("TranslationMinY").Data = not bTranslationDOF
hat_ctrl.PropertyList.Find("TranslationMinZ").Data = not bTranslationDOF
hat_ctrl.PropertyList.Find("TranslationMaxX").Data = not bTranslationDOF
hat_ctrl.PropertyList.Find("TranslationMaxY").Data = not bTranslationDOF
hat_ctrl.PropertyList.Find("TranslationMaxZ").Data = not bTranslationDOF
hat_ctrl.PropertyList.Find("RotationMinX").Data = not bRotationDOF
hat_ctrl.PropertyList.Find("RotationMinY").Data = not bRotationDOF
hat_ctrl.PropertyList.Find("RotationMinZ").Data = not bRotationDOF
hat_ctrl.PropertyList.Find("RotationMaxX").Data = not bRotationDOF
hat_ctrl.PropertyList.Find("RotationMaxY").Data = not bRotationDOF
hat_ctrl.PropertyList.Find("RotationMaxZ").Data = not bRotationDOF
hat_ctrl.PropertyList.Find("TranslationMin").Data = FBVector3d()
hat_ctrl.PropertyList.Find("TranslationMax").Data = FBVector3d()
hat_ctrl.PropertyList.Find("RotationMin").Data = FBVector3d()
hat_ctrl.PropertyList.Find("RotationMax").Data = FBVector3d()
####################################################################
# Allows user to lock selected character extension components
# from receiving keyframes
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
# Global UI components
lock_button = FBButton()
unlock_button = FBButton()
radio_group = FBButtonGroup()
roll_yes_button = FBButton()
roll_no_button = FBButton()
radio_group.Add(roll_yes_button)
radio_group.Add(roll_no_button)
status = FBLabel()
button = []
char_extension_objs = []
char_rollbone_objs = []
def lockAllProperties( model ):
#get namespace of selected character in dropdown
chosenChar = t.list.Items[t.list.ItemIndex]
strList = chosenChar.split(':')
namespace = strList[0]
modelList = FBComponentList()
FBFindObjectsByName( namespace + ":" + model.Name, modelList, True, True )
if modelList:
for p in modelList[0].PropertyList:
if ( p.AllowsLocking() ):
p.SetLocked(True)
def unlockAllProperties( model ):
#get namespace of selected character in dropdown
chosenChar = t.list.Items[t.list.ItemIndex]
strList = chosenChar.split(':')
namespace = strList[0]
modelList = FBComponentList()
FBFindObjectsByName( namespace + ":" + model.Name, modelList, True, True )
if modelList:
for p in modelList[0].PropertyList:
if ( p.AllowsLocking() ):
p.SetLocked(False)
def getAllSceneCharacterRollBones( model ):
components = model.Components
for c in components:
rs_prop = c.PropertyList.Find("rs_Type")
if rs_prop:
# only look at bones
if rs_prop.Data == "rs_Bone":
# and ignore skel bones
if "SKEL" not in c.Name:
print c.Name
char_rollbone_objs.append( c )
#check down heirarchy
if hasattr(c, 'Children'):
for child in c.Children:
getAllSceneCharacterRollBones( child )
def getAllSceneCharacterExtensions():
exts = FBSystem().Scene.CharacterExtensions
for e in exts:
components = e.Components
for c in components:
existing = False
for ext in char_extension_objs:
if c.Name == ext.Name:
existing = True
if not existing:
char_extension_objs.append( c )
def getMoverNodes():
# get list of all models called 'mover'
mover_list = FBComponentList()
FBFindObjectsByName('mover', mover_list , False, True)
FBFindObjectsByName('Mover', mover_list , False, True)
FBFindObjectsByName('MOVER', mover_list , False, True)
filtered_mover_list = []
chars = FBSystem().Scene.Characters
# go through each model called mover and find which ones actually belong to characters
# so we get rid of vehicles etc.
# put result in new filtered_mover_list
for object in mover_list:
for char in chars:
extensions = char.CharacterExtensions
for e in extensions:
components = e.Components
for c in components:
if c.LongName == object.LongName:
filtered_mover_list.append(object)
return filtered_mover_list
def setupPropertyList(tool):
tool.list.Items.removeAll()
tool.prop_list = []
mover_list = getMoverNodes()
if len(mover_list):
for mover in mover_list:
tool.list.Items.append(mover.LongName)
else:
tool.list.Items.append('No mover node found!')
####################################################################
# Lock Button CallBack
####################################################################
def lockButtonCallBack(control, event):
index = 0
for obj in char_extension_objs:
if ( button[index].State == True ):
lockAllProperties( obj )
index += 1
if ( roll_yes_button.State == True ):
for rb in char_rollbone_objs:
lockAllProperties( rb )
print "Selected properties locked!"
status.Caption = "Properties locked"
FBSystem().Scene.Evaluate()
####################################################################
# Unlock Button CallBack
####################################################################
def unlockButtonCallBack(control, event):
index = 0
for obj in char_extension_objs:
if ( button[index].State == True ):
unlockAllProperties( obj )
index += 1
if ( roll_yes_button.State == True ):
for rb in char_rollbone_objs:
unlockAllProperties( rb )
print "Selected properties unlocked!"
status.Caption = "Properties unlocked"
FBSystem().Scene.Evaluate()
####################################################################
# UI
####################################################################
def PopulateTool(t):
# ui variables for easier modification
ui_border_x = 10
ui_border_y = 10
ui_border_width = 140
ui_border_height = 100
ui_column_a = 20
ui_column_b = 60
ui_column_c = 100
ui_row_offset = 10
ui_button_width = 120
ui_button_height = 15
#Mover Selection----------------------------------------------
#Drop Down
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(25,FBAttachType.kFBAttachNone,"")
t.AddRegion("dropdown","dropdown", x, y, w, h)
t.list = FBList()
t.SetControl("dropdown", t.list)
setupPropertyList(t)
#Extensions--------------------------------------------------
#get all scene character extension objects
getAllSceneCharacterExtensions()
ui_row_offset += 40
#Border
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam( ( 20 * len(char_extension_objs) ) + 15,FBAttachType.kFBAttachNone,"")
t.AddRegion("trans_border","Character Extensions", x, y, w, h)
t.SetBorder("trans_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_row_offset += 10
#Buttons
# create a button for each extension obj
for i in range( 0, len(char_extension_objs) ):
region = "extButton" + str(i)
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop, region )
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_height,FBAttachType.kFBAttachNone,"")
t.AddRegion(region,region, x, y, w, h)
button.append( FBButton() )
t.SetControl(region, button[i] )
button[i].Visible = True
button[i].ReadOnly = False
button[i].Enabled = True
button[i].Hint = ""
button[i].Caption = char_extension_objs[i].Name
# set certain options as off for ease of use
if ( "mover" in char_extension_objs[i].Name ) or \
( "PH_R_Hand" in char_extension_objs[i].Name ) or \
( "PH_L_Hand" in char_extension_objs[i].Name ):
button[i].State = 0
else:
button[i].State = 1
button[i].Style = FBButtonStyle.kFBCheckbox
button[i].Justify = FBTextJustify.kFBTextJustifyLeft
button[i].Look = FBButtonLook.kFBLookNormal
ui_row_offset += 20
#Rollbones--------------------------------------------------
#get all scene character rollbone objects
chosenChar = t.list.Items[t.list.ItemIndex]
obj = FBFindModelByLabelName(chosenChar)
if obj:
getAllSceneCharacterRollBones( obj )
ui_row_offset += 20
#Border
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam( 60 ,FBAttachType.kFBAttachNone,"")
t.AddRegion("roll_bones","Include Rollbones?", x, y, w, h)
t.SetBorder("roll_bones",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_row_offset += 10
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"roll_yes_button")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(120,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("roll_yes_button","roll_yes_button", x, y, w, h)
t.SetControl("roll_yes_button", roll_yes_button )
roll_yes_button.Visible = True
roll_yes_button.ReadOnly = False
roll_yes_button.Enabled = True
roll_yes_button.Hint = ""
roll_yes_button.Caption = "Yes"
roll_yes_button.State = 1
roll_yes_button.Style = FBButtonStyle.kFBRadioButton
roll_yes_button.Justify = FBTextJustify.kFBTextJustifyLeft
roll_yes_button.Look = FBButtonLook.kFBLookNormal
ui_row_offset += 20
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"roll_no_button")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(120,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("roll_no_button","roll_no_button", x, y, w, h)
t.SetControl("roll_no_button", roll_no_button )
roll_no_button.Visible = True
roll_no_button.ReadOnly = False
roll_no_button.Enabled = True
roll_no_button.Hint = ""
roll_no_button.Caption = "No"
roll_no_button.State = 0
roll_no_button.Style = FBButtonStyle.kFBRadioButton
roll_no_button.Justify = FBTextJustify.kFBTextJustifyLeft
roll_no_button.Look = FBButtonLook.kFBLookNormal
#Lock Button--------------------------------------------------
ui_row_offset = ui_row_offset + 40
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"lock_button_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(30,FBAttachType.kFBAttachNone,"")
t.AddRegion("lock_button_region","lock_button_region", x, y, w, h)
t.SetControl("lock_button_region", lock_button)
lock_button.Visible = True
lock_button.ReadOnly = False
lock_button.Enabled = True
lock_button.Hint = ""
lock_button.Caption = "Lock Selected"
lock_button.State = 0
lock_button.Style = FBButtonStyle.kFBPushButton
lock_button.Justify = FBTextJustify.kFBTextJustifyCenter
lock_button.Look = FBButtonLook.kFBLookNormal
lock_button.OnClick.Add(lockButtonCallBack)
#Unlock Button--------------------------------------------------
ui_row_offset = ui_row_offset + 35
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"unlock_button_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(30,FBAttachType.kFBAttachNone,"")
t.AddRegion("unlock_button_region","unlock_button_region", x, y, w, h)
t.SetControl("unlock_button_region", unlock_button)
unlock_button.Visible = True
unlock_button.ReadOnly = False
unlock_button.Enabled = True
unlock_button.Hint = ""
unlock_button.Caption = "Unlock Selected"
unlock_button.State = 0
unlock_button.Style = FBButtonStyle.kFBPushButton
unlock_button.Justify = FBTextJustify.kFBTextJustifyCenter
unlock_button.Look = FBButtonLook.kFBLookNormal
unlock_button.OnClick.Add(unlockButtonCallBack)
#Status --------------------------------------------------
ui_row_offset = ui_row_offset + 35
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"status_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(30,FBAttachType.kFBAttachNone,"")
t.AddRegion("status_region","status_region", x, y, w, h)
t.SetControl("status_region", status)
status.Visible = True
status.ReadOnly = False
status.Enabled = True
status.Caption = ""
####################################################################
# Main
####################################################################
def CreateTool():
global t
t = FBCreateUniqueTool("Key Locker")
t.StartSizeX = 175
t.StartSizeY = 575
PopulateTool(t)
ShowTool(t)
CreateTool()
####################################################################
# Allows user to lock selected character extension components
# from receiving keyframes
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
# Global UI components
lock_button = FBButton()
unlock_button = FBButton()
#roll bones ui comps
radio_group = FBButtonGroup()
roll_yes_button = FBButton()
roll_no_button = FBButton()
radio_group.Add(roll_yes_button)
radio_group.Add(roll_no_button)
#face control ui comps
fc_radio_group = FBButtonGroup()
face_yes_button = FBButton()
face_no_button = FBButton()
fc_radio_group.Add(face_yes_button)
fc_radio_group.Add(face_no_button)
status = FBLabel()
button = []
char_extension_objs = []
char_rollbone_objs = []
char_3lateral_objs = []
def lockAllProperties( obj ):
if obj:
for p in obj.PropertyList:
if ( p.AllowsLocking() ):
p.SetLocked(True)
def unlockAllProperties( obj ):
if obj:
for p in obj.PropertyList:
if ( p.AllowsLocking() ):
p.SetLocked(False)
def getAllSceneCharacterRollBones( model ):
chosenChar = t.list.Items[t.list.ItemIndex]
namespace = chosenChar.split(':')
pattern = namespace[0] + '*'
modelList = FBComponentList()
FBFindObjectsByName( pattern , modelList )
for c in modelList:
rs_prop = c.PropertyList.Find("rs_Type")
if rs_prop:
if rs_prop.Data == "rs_Bone":
# and ignore skel bones
if "SKEL" not in c.Name:
char_rollbone_objs.append( c )
def getAllSceneFaceControls( model ):
chosenChar = t.list.Items[t.list.ItemIndex]
namespace = chosenChar.split(':')
pattern = namespace[0] + '*'
modelList = FBComponentList()
FBFindObjectsByName( pattern , modelList )
for c in modelList:
rs_prop = c.PropertyList.Find("rs_Type")
if rs_prop:
# only look at bones
if "rs_3Lateral" in rs_prop.Data:
char_3lateral_objs.append( c )
def getAllSceneCharacterExtensions():
exts = FBSystem().Scene.CharacterExtensions
for e in exts:
components = e.Components
for c in components:
existing = False
for ext in char_extension_objs:
if c.Name == ext.Name:
existing = True
if not existing:
char_extension_objs.append( c )
def getMoverNodes():
# get list of all models called 'mover'
mover_list = FBComponentList()
FBFindObjectsByName('mover', mover_list , False, True)
FBFindObjectsByName('Mover', mover_list , False, True)
FBFindObjectsByName('MOVER', mover_list , False, True)
filtered_mover_list = []
chars = FBSystem().Scene.Characters
# go through each model called mover and find which ones actually belong to characters
# so we get rid of vehicles etc.
# put result in new filtered_mover_list
for object in mover_list:
for char in chars:
extensions = char.CharacterExtensions
for e in extensions:
components = e.Components
for c in components:
if c.LongName == object.LongName:
filtered_mover_list.append(object)
return filtered_mover_list
def setupPropertyList(tool):
tool.list.Items.removeAll()
tool.prop_list = []
mover_list = getMoverNodes()
if len(mover_list):
for mover in mover_list:
tool.list.Items.append(mover.LongName)
else:
tool.list.Items.append('No mover node found!')
####################################################################
# Lock Button CallBack
####################################################################
def lockButtonCallBack(control, event):
index = 0
for obj in char_extension_objs:
if ( button[index].State == True ):
lockAllProperties( obj )
index += 1
# if ( roll_yes_button.State == True ):
# for rb in char_rollbone_objs:
# lockAllProperties( rb )
if ( face_yes_button.State == True ):
for fc in char_3lateral_objs:
lockAllProperties( fc )
print "Selected properties locked!"
status.Caption = "Properties locked"
FBSystem().Scene.Evaluate()
####################################################################
# Unlock Button CallBack
####################################################################
def unlockButtonCallBack(control, event):
index = 0
for obj in char_extension_objs:
if ( button[index].State == True ):
unlockAllProperties( obj )
index += 1
if ( roll_yes_button.State == True ):
for rb in char_rollbone_objs:
unlockAllProperties( rb )
if ( face_yes_button.State == True ):
for fc in char_3lateral_objs:
lockAllProperties( fc )
print "Selected properties unlocked!"
status.Caption = "Properties unlocked"
FBSystem().Scene.Evaluate()
####################################################################
# UI
####################################################################
def PopulateTool(t):
# ui variables for easier modification
ui_border_x = 10
ui_border_y = 10
ui_border_width = 140
ui_border_height = 100
ui_column_a = 20
ui_column_b = 60
ui_column_c = 100
ui_row_offset = 10
ui_button_width = 120
ui_button_height = 15
#Mover Selection----------------------------------------------
#Drop Down
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(25,FBAttachType.kFBAttachNone,"")
t.AddRegion("dropdown","dropdown", x, y, w, h)
t.list = FBList()
t.SetControl("dropdown", t.list)
setupPropertyList(t)
#Extensions--------------------------------------------------
#get all scene character extension objects
getAllSceneCharacterExtensions()
ui_row_offset += 40
#Border
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam( ( 20 * len(char_extension_objs) ) + 15,FBAttachType.kFBAttachNone,"")
t.AddRegion("trans_border","Character Extensions", x, y, w, h)
t.SetBorder("trans_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_row_offset += 10
#Buttons
# create a button for each extension obj
for i in range( 0, len(char_extension_objs) ):
region = "extButton" + str(i)
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop, region )
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_height,FBAttachType.kFBAttachNone,"")
t.AddRegion(region,region, x, y, w, h)
button.append( FBButton() )
t.SetControl(region, button[i] )
button[i].Visible = True
button[i].ReadOnly = False
button[i].Enabled = True
button[i].Hint = ""
button[i].Caption = char_extension_objs[i].Name
# set certain options as off for ease of use
if ( "mover" in char_extension_objs[i].Name ) or \
( "PH_R_Hand" in char_extension_objs[i].Name ) or \
( "PH_L_Hand" in char_extension_objs[i].Name ):
button[i].State = 0
else:
button[i].State = 1
button[i].Style = FBButtonStyle.kFBCheckbox
button[i].Justify = FBTextJustify.kFBTextJustifyLeft
button[i].Look = FBButtonLook.kFBLookNormal
ui_row_offset += 20
#Rollbones--------------------------------------------------
#get all scene character rollbone objects
chosenChar = t.list.Items[t.list.ItemIndex]
obj = FBFindModelByLabelName(chosenChar)
if obj:
getAllSceneCharacterRollBones( obj )
ui_row_offset += 20
#Border
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam( 60 ,FBAttachType.kFBAttachNone,"")
t.AddRegion("roll_bones","Include Rollbones?", x, y, w, h)
t.SetBorder("roll_bones",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_row_offset += 10
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"roll_yes_button")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(120,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("roll_yes_button","roll_yes_button", x, y, w, h)
t.SetControl("roll_yes_button", roll_yes_button )
roll_yes_button.Visible = True
roll_yes_button.ReadOnly = False
roll_yes_button.Enabled = False
roll_yes_button.Hint = ""
roll_yes_button.Caption = "Yes"
roll_yes_button.State = 0
roll_yes_button.Style = FBButtonStyle.kFBRadioButton
roll_yes_button.Justify = FBTextJustify.kFBTextJustifyLeft
roll_yes_button.Look = FBButtonLook.kFBLookNormal
ui_row_offset += 20
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"roll_no_button")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(120,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("roll_no_button","roll_no_button", x, y, w, h)
t.SetControl("roll_no_button", roll_no_button )
roll_no_button.Visible = True
roll_no_button.ReadOnly = False
roll_no_button.Enabled = False
roll_no_button.Hint = ""
roll_no_button.Caption = "No"
roll_no_button.State = 1
roll_no_button.Style = FBButtonStyle.kFBRadioButton
roll_no_button.Justify = FBTextJustify.kFBTextJustifyLeft
roll_no_button.Look = FBButtonLook.kFBLookNormal
#3Lateral--------------------------------------------------
#get all scene character face controller objects
chosenChar = t.list.Items[t.list.ItemIndex]
namespace = chosenChar.split(":")
obj = FBFindModelByLabelName( namespace[0] + ':faceControls_OFF' )
if(obj):
getAllSceneFaceControls( obj )
ui_row_offset += 40
#Border
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam( 60 ,FBAttachType.kFBAttachNone,"")
t.AddRegion("face_controls","Include Face Controls?", x, y, w, h)
t.SetBorder("face_controls",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_row_offset += 10
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"face_yes_button")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(120,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("face_yes_button","face_yes_button", x, y, w, h)
t.SetControl("face_yes_button", face_yes_button )
face_yes_button.Visible = True
face_yes_button.ReadOnly = False
face_yes_button.Enabled = True
face_yes_button.Hint = ""
face_yes_button.Caption = "Yes"
face_yes_button.State = 1
face_yes_button.Style = FBButtonStyle.kFBRadioButton
face_yes_button.Justify = FBTextJustify.kFBTextJustifyLeft
face_yes_button.Look = FBButtonLook.kFBLookNormal
ui_row_offset += 20
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"face_no_button")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(120,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("face_no_button","face_no_button", x, y, w, h)
t.SetControl("face_no_button", face_no_button )
face_no_button.Visible = True
face_no_button.ReadOnly = False
face_no_button.Enabled = True
face_no_button.Hint = ""
face_no_button.Caption = "No"
face_no_button.State = 0
face_no_button.Style = FBButtonStyle.kFBRadioButton
face_no_button.Justify = FBTextJustify.kFBTextJustifyLeft
face_no_button.Look = FBButtonLook.kFBLookNormal
#Lock Button--------------------------------------------------
ui_row_offset = ui_row_offset + 40
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"lock_button_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(30,FBAttachType.kFBAttachNone,"")
t.AddRegion("lock_button_region","lock_button_region", x, y, w, h)
t.SetControl("lock_button_region", lock_button)
lock_button.Visible = True
lock_button.ReadOnly = False
lock_button.Enabled = True
lock_button.Hint = ""
lock_button.Caption = "Lock Selected"
lock_button.State = 0
lock_button.Style = FBButtonStyle.kFBPushButton
lock_button.Justify = FBTextJustify.kFBTextJustifyCenter
lock_button.Look = FBButtonLook.kFBLookNormal
lock_button.OnClick.Add(lockButtonCallBack)
#Unlock Button--------------------------------------------------
ui_row_offset = ui_row_offset + 35
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"unlock_button_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(30,FBAttachType.kFBAttachNone,"")
t.AddRegion("unlock_button_region","unlock_button_region", x, y, w, h)
t.SetControl("unlock_button_region", unlock_button)
unlock_button.Visible = True
unlock_button.ReadOnly = False
unlock_button.Enabled = True
unlock_button.Hint = ""
unlock_button.Caption = "Unlock Selected"
unlock_button.State = 0
unlock_button.Style = FBButtonStyle.kFBPushButton
unlock_button.Justify = FBTextJustify.kFBTextJustifyCenter
unlock_button.Look = FBButtonLook.kFBLookNormal
unlock_button.OnClick.Add(unlockButtonCallBack)
#Status --------------------------------------------------
ui_row_offset = ui_row_offset + 35
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"status_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(30,FBAttachType.kFBAttachNone,"")
t.AddRegion("status_region","status_region", x, y, w, h)
t.SetControl("status_region", status)
status.Visible = True
status.ReadOnly = False
status.Enabled = True
status.Caption = ""
####################################################################
# Main
####################################################################
def CreateTool():
global t
t = FBCreateUniqueTool("Key Locker")
t.StartSizeX = 175
t.StartSizeY = 610
PopulateTool(t)
ShowTool(t)
CreateTool()
####################################################################
# Loco Meta Search utility script
#
# Allows user to search through the loco meta files and search child elements of certain element types
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
import xml.etree.ElementTree as ET
import tempfile
import os
import RS.Config
####################################################################
# custom class so we can find line numbers
# from: http://stackoverflow.com/questions/6949395/is-there-a-way-to-get-a-line-number-from-an-elementtree-element
####################################################################
class LineNumberingParser(ET.XMLParser):
def _start_list(self, *args, **kwargs):
# Here we assume the default XML parser which is expat
# and copy its element position attributes into output Elements
element = super(self.__class__, self)._start_list(*args, **kwargs)
element._start_line_number = self.parser.CurrentLineNumber
element._start_column_number = self.parser.CurrentColumnNumber
element._start_byte_index = self.parser.CurrentByteIndex
return element
def _end(self, *args, **kwargs):
element = super(self.__class__, self)._end(*args, **kwargs)
element._end_line_number = self.parser.CurrentLineNumber
element._end_column_number = self.parser.CurrentColumnNumber
element._end_byte_index = self.parser.CurrentByteIndex
return element
####################################################################
# main
####################################################################
# outer scope to search
search_scope_tag = 'Motions'
# parent search
attribute_tag = 'type'
attribute_text = 'Loco__elementUpperBodyWeaponAiming'
# child search
child_tag = 'MoveNetwork'
child_text = 'TaskelementHumanLocoUpperBodyMovingAndFacing_UserDefined'
# loco meta path
rootdir = RS.Config.Project.Path.Assets + "\\export\\data\\loco\\"
# output string
output = "############################################################################################################################\n"
output += "# Search Results\n"
output += "############################################################################################################################\n\n"
##############################################################
# Loop through each nested file in the locoelement meta structure
##############################################################
for subdir, dirs, files in os.walk(rootdir):
for file in files:
#print os.path.join(subdir, file)
filepath = subdir + os.sep + file
##############################################################
# only search in meta files
##############################################################
if filepath.endswith(".meta"):
tree = ET.parse( filepath, parser=LineNumberingParser() )
root = tree.getroot()
##############################################################
# only search in the searchResults section of each meta file
##############################################################
searchScopesElement = root.find( search_scope_tag )
if searchScopesElement:
searchResults = searchScopesElement.getchildren()
for element in searchResults:
if element.tag == 'Item':
##############################################################
# find items which match 'attribute_tag' and 'attribute_text'
##############################################################
if attribute_tag in element.attrib:
if element.attrib[ attribute_tag ] == attribute_text:
##############################################################
# find child elements which match 'child_tag' and 'child_text'
##############################################################
for element_child in element.getchildren():
if element_child.tag == child_tag:
if element_child.text == child_text:
# add filename (maybe line number) to output file
output += ">> " + filepath + " at line number " + str( element_child._start_line_number ) + "\n"
##############################################################
# Save out results and open file
##############################################################
output_file_path = tempfile.gettempdir() + '\\mj_LocoMetaSearch_output.txt'
with open(output_file_path,'w') as f:
f.write( output )
f.closed
os.startfile( output_file_path )PNG
######################################################################################################
# Mask Locker
# Sets and prevents mask dofs from moving from their bind poses
######################################################################################################
from pyfbsdk import *
import csv
def getNodesByName( node_name ):
# find every node with give node name
object_list = FBComponentList()
FBFindObjectsByName( node_name, object_list, False )
#if no nodes are found we error
if len(object_list) == 0:
FBMessageBox("Error!", name_name + " mask dof not found in scene!", "OK", None, None)
else:
return object_list
def lockMaskDofs():
######################################################################################################
# Bind Poses
# Name, Local Translation, Local Rotation
######################################################################################################
mask_dofs = [
'MH_Mask_R_Low', -0.047735, -0.069731, 0.153070, -0.000775, -0.000790, 0.000033,
'MH_Mask_R_Mid', -0.061445, -0.013301, 0.167160, -0.000767, -0.000800, 0.000025,
'MH_Mask_LowRoot', 0.000000, 0.000000, 0.000000, 17.339338, -4.168191, -1.793406,
'MH_Mask_R_Upp', -0.059794, 0.052800, 0.164775, -0.000901, -6.620632, 0.003551,
'MH_Mask_C_Low', -0.000001, -0.101321, 0.196037, -0.242461, -1.506590, -7.084754,
'MH_Mask_C_Mid', 0.057864, -0.013299, 0.167161, -0.000767, -0.000800, 0.000025,
'MH_Mask_L_Low', 0.046939, -0.069730, 0.153071, -0.000775, -0.000790, 0.000033,
'MH_Mask_L_Mid', 0.057864, -0.013299, 0.167161, -0.000767, -0.000800, 0.000025,
'MH_Mask_C_Upp', -0.000003, 0.064241, 0.212310, -0.009491, -0.002771, 0.002094,
'MH_Mask_L_Upp', 0.057261, 0.052801, 0.164777, -0.000776, -0.000803, 0.000099,
'MH_MaskRoot', -0.038081, -0.088986, 0.000692, 179.774673, -89.566566, 90.226219,
'MH_Mask_MidRoot', 0.000000, 0.000000, 0.000000, 31.861649, -5.225916, -3.338191,
'MH_Mask_UpRoot', 0.000000, 0.000000, 0.000000, 45.831963, -4.224141, -4.543106
]
num_of_columns = 7
num_of_dofs = len( mask_dofs ) / num_of_columns
for index in range( 0, len( mask_dofs ), num_of_columns ):
# get objects from name(since there may be more than one)
node_list = getNodesByName( mask_dofs[index] )
# for each node set it to the desired translation/rotation and lock
for node in node_list:
# set min/max translation limits
node.PropertyList.Find("TranslationMinX").Data = True
node.PropertyList.Find("TranslationMinY").Data = True
node.PropertyList.Find("TranslationMinZ").Data = True
node.PropertyList.Find("TranslationMaxX").Data = True
node.PropertyList.Find("TranslationMaxY").Data = True
node.PropertyList.Find("TranslationMaxZ").Data = True
node.PropertyList.Find("RotationMinX").Data = True
node.PropertyList.Find("RotationMinY").Data = True
node.PropertyList.Find("RotationMinZ").Data = True
node.PropertyList.Find("RotationMaxX").Data = True
node.PropertyList.Find("RotationMaxY").Data = True
node.PropertyList.Find("RotationMaxZ").Data = True
node.PropertyList.Find("TranslationMin").Data = FBVector3d(
float(mask_dofs[index + 1]),
float(mask_dofs[index + 2]),
float(mask_dofs[index + 3])
)
node.PropertyList.Find("TranslationMax").Data = FBVector3d(
float(mask_dofs[index + 1]),
float(mask_dofs[index + 2]),
float(mask_dofs[index + 3])
)
node.PropertyList.Find("RotationMin").Data = FBVector3d(
float(mask_dofs[index + 4]),
float(mask_dofs[index + 5]),
float(mask_dofs[index + 6])
)
node.PropertyList.Find("RotationMax").Data = FBVector3d(
float(mask_dofs[index + 4]),
float(mask_dofs[index + 5]),
float(mask_dofs[index + 6])
)
print "All mask dofs locked."
lockMaskDofs()PNG
from pyfbsdk import *
# Merge all layers down to base
FBSystem().CurrentTake.MergeLayers( FBAnimationLayerMergeOptions.kFBAnimLayerMerge_AllLayers_CompleteScene, False, FBMergeLayerMode.kFBMergeLayerModeAutomatic, False )
# make sure keys are set on the base layer
FBSystem().CurrentTake.SetCurrentLayer(0)
print "All layers merged!"PNG
####################################################################
# Scales animation curves around the first frame on selected objects
# Allows the user to dampen or exaggerate motion
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
def applyScaleToNodeKeys( node, scale ):
fCurve = node.FCurve
num_of_keys = len( fCurve.Keys )
# get pivot value
pivot_value = fCurve.Keys[0].Value
for key_index in range( num_of_keys ):
difference_from_pivot = fCurve.Keys[key_index].Value - pivot_value
scaled_difference = difference_from_pivot * scale
fCurve.Keys[key_index].Value = pivot_value + scaled_difference
####################################################################
# UI callbacks
####################################################################
def applyButtonCallback(control, event):
if t.isCached == False:
t.transXCache = []
t.transYCache = []
t.transZCache = []
t.rotXCache = []
t.rotYCache = []
t.rotZCache = []
index = 0
for obj in t.selected_objects:
# get animation nodes
transX = obj.AnimationNode.Nodes[0].Nodes[0]
transY = obj.AnimationNode.Nodes[0].Nodes[1]
transZ = obj.AnimationNode.Nodes[0].Nodes[2]
rotX = obj.AnimationNode.Nodes[1].Nodes[0]
rotY = obj.AnimationNode.Nodes[1].Nodes[1]
rotZ = obj.AnimationNode.Nodes[1].Nodes[2]
# cache fcurves so we can reset if desired
if t.isCached == False:
t.transXCache.append(FBFCurve())
t.transYCache.append(FBFCurve())
t.transZCache.append(FBFCurve())
t.rotXCache.append(FBFCurve())
t.rotYCache.append(FBFCurve())
t.rotZCache.append(FBFCurve())
t.transXCache[index].KeyReplaceBy(transX.FCurve)
t.transYCache[index].KeyReplaceBy(transY.FCurve)
t.transZCache[index].KeyReplaceBy(transZ.FCurve)
t.rotXCache[index].KeyReplaceBy(rotX.FCurve)
t.rotYCache[index].KeyReplaceBy(rotY.FCurve)
t.rotZCache[index].KeyReplaceBy(rotZ.FCurve)
# scale
applyScaleToNodeKeys(transX, t.translation_scale.Value)
applyScaleToNodeKeys(transY, t.translation_scale.Value)
applyScaleToNodeKeys(transZ, t.translation_scale.Value)
applyScaleToNodeKeys(rotX, t.rotation_scale.Value)
applyScaleToNodeKeys(rotY, t.rotation_scale.Value)
applyScaleToNodeKeys(rotZ, t.rotation_scale.Value)
index += 1
# enable reset
t.isCached = True
t.reset_button.Enabled = True
FBSystem().Scene.Evaluate()
def resetButtonCallback(control, event):
index = 0
for obj in t.selected_objects:
# get animation nodes
transX = obj.AnimationNode.Nodes[0].Nodes[0]
transY = obj.AnimationNode.Nodes[0].Nodes[1]
transZ = obj.AnimationNode.Nodes[0].Nodes[2]
rotX = obj.AnimationNode.Nodes[1].Nodes[0]
rotY = obj.AnimationNode.Nodes[1].Nodes[1]
rotZ = obj.AnimationNode.Nodes[1].Nodes[2]
transX.FCurve.KeyReplaceBy(t.transXCache[index])
transY.FCurve.KeyReplaceBy(t.transYCache[index])
transZ.FCurve.KeyReplaceBy(t.transZCache[index])
rotX.FCurve.KeyReplaceBy(t.rotXCache[index])
rotY.FCurve.KeyReplaceBy(t.rotYCache[index])
rotZ.FCurve.KeyReplaceBy(t.rotZCache[index])
index += 1
t.translation_scale.Value = 1.0
t.rotation_scale.Value = 1.0
print "Reset FCurves"
#FBSystem().Scene.Evaluate()
####################################################################
# UI definition
####################################################################
def PopulateTool(t):
# ui defines
ui_tool_width = 200
ui_tool_height_offset = 15
ui_width_gap = 10
ui_border_height = 50
ui_edit_box_height = 30
ui_apply_button_height = 30
ui_reset_button_height = 30
# Translation Border
x = FBAddRegionParam(ui_width_gap, FBAttachType.kFBAttachNone, "")
y = FBAddRegionParam(ui_tool_height_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_tool_width - ui_width_gap * 4, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_border_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("trans_border", "Translation Scale", x, y, w, h)
t.SetBorder("trans_border", FBBorderStyle.kFBEmbossBorder, True, True, 2, 0, 90.0, 0)
# Translation Edit Box
ui_tool_height_offset += 15
x = FBAddRegionParam(ui_width_gap * 2, FBAttachType.kFBAttachNone, "")
y = FBAddRegionParam(ui_tool_height_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_tool_width - ui_width_gap * 6, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_edit_box_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("translation_scale", "translation_scale", x, y, w, h)
t.translation_scale = FBEditNumber()
t.SetControl("translation_scale", t.translation_scale)
t.translation_scale.Visible = True
t.translation_scale.ReadOnly = False
t.translation_scale.Enabled = True
t.translation_scale.Value = 1.0
t.translation_scale.Hint = "multiplier to increase or decrease translation curves"
t.translation_scale.SmallStep = 0.1
t.translation_scale.Min = 0.0
t.translation_scale.Max = 10.0
# Rotation Border
ui_tool_height_offset += ui_edit_box_height + 10
x = FBAddRegionParam(ui_width_gap, FBAttachType.kFBAttachNone, "")
y = FBAddRegionParam(ui_tool_height_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_tool_width - ui_width_gap * 4, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_border_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("rot_border", "Rotation Scale", x, y, w, h)
t.SetBorder("rot_border", FBBorderStyle.kFBEmbossBorder, True, True, 2, 0, 90.0, 0)
# Rotation Edit Box
ui_tool_height_offset += 15
x = FBAddRegionParam(ui_width_gap * 2, FBAttachType.kFBAttachNone, "")
y = FBAddRegionParam(ui_tool_height_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_tool_width - ui_width_gap * 6, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_edit_box_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("rotation_scale", "rotation_scale", x, y, w, h)
t.rotation_scale = FBEditNumber()
t.SetControl("rotation_scale", t.rotation_scale)
t.rotation_scale.Visible = True
t.rotation_scale.ReadOnly = False
t.rotation_scale.Enabled = True
t.rotation_scale.Value = 1.0
t.rotation_scale.Hint = "multiplier to increase or decrease rotation curves"
t.rotation_scale.SmallStep = 0.1
t.rotation_scale.Min = 0.0
t.rotation_scale.Max = 10.0
# Apply Button
ui_tool_height_offset += ui_edit_box_height + 15
x = FBAddRegionParam(ui_width_gap, FBAttachType.kFBAttachNone, "")
y = FBAddRegionParam(ui_tool_height_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_tool_width - ui_width_gap * 4, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_apply_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("apply_button", "apply_button", x, y, w, h)
t.apply_button = FBButton()
t.SetControl("apply_button", t.apply_button)
t.apply_button.Visible = True
t.apply_button.ReadOnly = False
t.apply_button.Enabled = True
t.apply_button.Hint = "Scale selected object's fcurves by % values above. First frame will be used as pivot point."
t.apply_button.Caption = "Apply"
t.apply_button.State = 0
t.apply_button.Style = FBButtonStyle.kFBPushButton
t.apply_button.Justify = FBTextJustify.kFBTextJustifyCenter
t.apply_button.Look = FBButtonLook.kFBLookNormal
t.apply_button.OnClick.Add(applyButtonCallback)
# Reset Button
ui_tool_height_offset += ui_apply_button_height + 5
x = FBAddRegionParam(ui_width_gap, FBAttachType.kFBAttachNone, "")
y = FBAddRegionParam(ui_tool_height_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_tool_width - ui_width_gap * 4, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_reset_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("reset_button", "reset_button", x, y, w, h)
t.reset_button = FBButton()
t.SetControl("reset_button", t.reset_button)
t.reset_button.Visible = True
t.reset_button.ReadOnly = False
t.reset_button.Enabled = False
t.reset_button.Hint = "Reset selected objects back to their starting animation."
t.reset_button.Caption = "Reset"
t.reset_button.State = 0
t.reset_button.Style = FBButtonStyle.kFBPushButton
t.reset_button.Justify = FBTextJustify.kFBTextJustifyCenter
t.reset_button.Look = FBButtonLook.kFBLookNormal
t.reset_button.OnClick.Add(resetButtonCallback)
# ----------------------------------------------------------------
# show tool
# ----------------------------------------------------------------
t.StartSizeX = ui_tool_width
t.StartSizeY = ui_tool_height_offset + 85
t.isCached = False
ShowTool(t)
####################################################################
# Main
####################################################################
def CreateTool():
global t
t = FBCreateUniqueTool("Motion Scale")
t.selected_objects = FBModelList()
FBGetSelectedModels(t.selected_objects)
if len(t.selected_objects) == 0:
FBMessageBox("Message", "Nothing selected", "OK", None, None)
else:
PopulateTool(t)
CreateTool()
PNG
from pyfbsdk import *
from pyfbsdk_additions import *
from RS.Utils.ContextManagers import SceneExpressionsDisabled
import xml.etree.ElementTree as ET
import math
import csv
import tempfile
import os.path
def plotToSkeleton( character ):
character.PlotAnimation( FBCharacterPlotWhere.kFBCharacterPlotOnSkeleton, plotOptions() )
def calcAV(AvVel, currentDropDownIndex):
multiplier = float(t.angularVelMultiplier[currentDropDownIndex])
y = float(t.y_addition[currentDropDownIndex])
if t.large_turn_button.State == 1:
return (multiplier * AvVel + y)/2
else:
return (multiplier * AvVel + y)
def FlattenKeys(fcurve):
for key in fcurve.Keys:
key.TangentMode = FBTangentMode.kFBTangentModeClampProgressive
key.LeftTangentWeight = 0.3333;
key.RightTangentWeight = 0.3333;
key.LeftDerivative = 0.0;
key.RightDerivative = 0.0;
def parseMotionWarpXML(t):
t.motionWarpPath = r"X:\wildwest\script\motionbuildersandbox\Mike\2014\MotionWarpData.xml"
print t.motionWarpPath
try:
t.tree = ET.ElementTree(file=t.motionWarpPath)
t.root = t.tree.getroot()
except:
t.XMLRead = False
return t.XMLRead
t.angularVelListNames = []
t.angularVelMultiplier = []
t.y_addition = []
t.minRadius = []
for child in t.root:
for x in child.iter("type"):
getRadius = child.find('minRadius').text
t.minRadius.append(getRadius)
getMultiplier = child.find('multiplier').text
t.angularVelMultiplier.append(getMultiplier)
getOffset = child.find('offset').text
t.y_addition.append(getOffset)
getName = x.get("name")
t.angularVelListNames.append(getName)
t.XMLRead = True
return t.XMLRead
def setupTurnParameterList(tool):
tool.dropDownList.Items.removeAll()
for x in t.angularVelListNames:
tool.dropDownList.Items.append(x)
def setupAdvancedSettingsList(tool):
tool.advanced_settings_dropdown.Items.removeAll()
tool.prop_list = []
tool.advanced_settings_dropdown.Items.append("Default (XZ)")
tool.advanced_settings_dropdown.Items.append("3D (XYZ)")
def setupPlotModeList(tool):
tool.plot_mode_dropdown.Items.removeAll()
tool.plot_mode_dropdown.Items.append("Plot Character")
tool.plot_mode_dropdown.Items.append("Plot Selected Nodes")
def ToggleDevices():
for device in FBSystem().Scene.Devices:
device.Online = not device.Online
def clamp(n, minn, maxn):
return max(min(maxn, n), minn)
def clean_cos(angle):
angle = min(1, max(angle, -1))
if (round(angle, 4) == 1.0):
angle = 0.0
return angle
def DoesSaveFileExist():
csvpath = tempfile.gettempdir() + '\\motionwarp_save_file.txt'
return os.path.isfile(csvpath)
def FindPropertyAnimationNode(property_name, model):
index = 0
# handle compound attributes
if '/' in property_name:
split_property_name = property_name.split('/')
if split_property_name[1] == 'X':
index = 0
if split_property_name[1] == 'Y':
index = 1
if split_property_name[1] == 'Z':
index = 2
property = model.PropertyList.Find(split_property_name[0])
if property:
animationNode = property.GetAnimationNode().Nodes[index]
return animationNode
else:
print "no property found for " + model.Name
# simple non-compound property type
else:
property = model.PropertyList.Find(property_name)
if property:
animationNode = property.GetAnimationNode()
return animationNode
else:
print "no property found for " + model.Name
def SerializeCurve(model_name, property_name, offset_angle, fcurve):
'''
Returns a list of dictionaries representing each of the keys in the given
FCurve.
'''
keyDataList = []
num_of_keys = len(fcurve.Keys)
for i in range(num_of_keys):
key = fcurve.Keys[i]
keyData = {
'model_name': model_name,
'property_name': property_name,
'time': key.Time.Get(),
'value': key.Value,
'interpolation': int(key.Interpolation),
'tangent-mode': int(key.TangentMode),
'constant-mode': int(key.TangentConstantMode),
'left-derivative': key.LeftDerivative,
'right-derivative': key.RightDerivative,
'left-weight': key.LeftTangentWeight,
'right-weight': key.RightTangentWeight,
'offset_angle': offset_angle
}
keyDataList.append(keyData)
return keyDataList
def storeZonalValues():
csvdata = []
csvpath = tempfile.gettempdir() + '\\motionwarp_save_file.txt'
properties = ['Yaw', 'Translation Offset']
offset_angle = t.angle_a.Value
for i in range(0, t.numOfObjects):
for j in range(0, len(properties)):
property = t.pathConstraint[i].PropertyList.Find(properties[j])
if property:
animationNode = property.GetAnimationNode()
if animationNode:
if len(animationNode.Nodes) > 0:
for node in animationNode.Nodes:
fcurve = node.FCurve
# create a list per key
keyDataList = SerializeCurve(t.selected_obj[i].Name, properties[j] + '/' + node.Name,
offset_angle, fcurve)
for key in keyDataList:
csvdata.append(key)
else:
fcurve = animationNode.FCurve
# create a list per key
keyDataList = SerializeCurve(t.selected_obj[i].Name, properties[j], offset_angle, fcurve)
for key in keyDataList:
csvdata.append(key)
# save out csv file
with open(csvpath, 'w') as csvfile:
fieldnames = ['model_name', 'property_name', 'time', 'value', 'interpolation', 'tangent-mode', 'constant-mode',
'left-derivative', 'right-derivative', 'left-weight', 'right-weight', 'offset_angle']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for element in csvdata:
writer.writerow(element)
def restoreZonalValues():
# reset min and max ranges
for slider_index in range(len(t.zonal.startSlider)):
t.zonal.startSlider[slider_index].range_min = 1000000000
t.zonal.endSlider[slider_index].range_max = -1000000000
csvdata = []
csvpath = tempfile.gettempdir() + '\\motionwarp_save_file.txt'
model_dictionary = CreateDictionaryFromModels(t.selected_obj)
properties = ['Yaw', 'Translation Offset/X', 'Translation Offset/Y', 'Translation Offset/Z']
# load from tmp file
with open(csvpath) as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
csvdata.append(row)
new_fcurve_cache = []
curr_fcurve_cache = []
for row in csvdata:
# only check against current selected models
if row['model_name'] in model_dictionary:
index = GetConstraintIndexFromModelName(row['model_name'])
animationNode = FindPropertyAnimationNode(row['property_name'], t.pathConstraint[index])
if animationNode:
fcurve = animationNode.FCurve
if fcurve:
propertykey = str(t.pathConstraint[index].Name + row['property_name'])
# is this a new curve?
if not IsCurveAlreadyCached(new_fcurve_cache, index, propertykey):
# create new tmp FCurve
new_fcurve_cache.append(FBFCurve())
new_fcurve_cache[-1].propertyname = row['property_name']
new_fcurve_cache[-1].propertykey = propertykey
new_fcurve_cache[-1].index = index
# load anim data
DeserializeCurve(new_fcurve_cache[-1], row)
# cache old fcurve pointer too
curr_fcurve_cache.append(fcurve)
else:
fcurve_from_cache = GetCurveFromCache(new_fcurve_cache, index, propertykey)
# load anim data
DeserializeCurve(fcurve_from_cache, row)
else:
print "no animation node found!!!!"
for i in range(len(new_fcurve_cache)):
ScaleCurveValues(new_fcurve_cache[i], curr_fcurve_cache[i])
##################################################
# check range extents of frame time
# used to update UI slider positions
##################################################
min_frame = curr_fcurve_cache[i].Keys[0].Time.GetFrame()
max_frame = curr_fcurve_cache[i].Keys[-1].Time.GetFrame()
if min_frame < t.zonal.startSlider[new_fcurve_cache[i].index].range_min:
t.zonal.startSlider[new_fcurve_cache[i].index].range_min = min_frame
if max_frame > t.zonal.endSlider[new_fcurve_cache[i].index].range_max:
t.zonal.endSlider[new_fcurve_cache[i].index].range_max = max_frame
def IsCurveAlreadyCached(new_fcurve_cache, index, propertykey):
for fcurve in new_fcurve_cache:
if fcurve.index == index:
if fcurve.propertykey == propertykey:
return True
return False
def GetCurveFromCache(new_fcurve_cache, index, propertykey):
for fcurve in new_fcurve_cache:
if fcurve.index == index:
if fcurve.propertykey == propertykey:
return fcurve
print "Warning! Curve was not found in cache when it should have been!"
def CreateDictionaryFromModels(models):
model_dictionary = {}
for model in models:
model_dictionary[model.Name] = model
return model_dictionary
def GetConstraintIndexFromModelName(model_name):
index = 0
for constraint in t.pathConstraint:
if constraint.ModelName == model_name:
return index
else:
index += 1
def TangentWeightIsDefault(tangentWeight):
'''
Returns whether the given tangent weight is equal to the default value of
1/3, taking floating-point precision into account.
'''
return tangentWeight > 0.3333 and tangentWeight < 0.3334
def DeserializeCurve(fcurve, row):
'''
Populates the given FCurve based on keyframe data listed in serialized
form. Expects key data to be ordered by time.
'''
keyIndex = fcurve.KeyAdd(FBTime(int(row['time'])), float(row['value']))
key = fcurve.Keys[keyIndex]
key.Interpolation = FBInterpolation.values[float(row['interpolation'])]
key.TangentMode = FBTangentMode.values[float(row['tangent-mode'])]
if key.TangentMode == FBTangentMode.kFBTangentModeTCB:
key.TangentMode = FBTangentMode.kFBTangentModeBreak
key.TangentConstantMode = FBTangentConstantMode.values[float(row['constant-mode'])]
key.LeftDerivative = float(row['left-derivative'])
key.RightDerivative = float(row['right-derivative'])
if not TangentWeightIsDefault(float(row['left-weight'])):
key.LeftTangentWeight = float(row['left-weight'])
if not TangentWeightIsDefault(float(row['right-weight'])):
key.RightTangentWeight = float(row['right-weight'])
def ScaleCurveValues(new_fcurve, curr_fcurve):
# scale new curve to match extents of old curve
new_curve_min = GetMinKeyValue(new_fcurve)
new_curve_max = GetMaxKeyValue(new_fcurve)
new_curve_min_time = new_fcurve.Keys[0].Time.GetFrame()
new_curve_max_time = new_fcurve.Keys[-1].Time.GetFrame()
new_curve_dir = GetDirectionOfFCurve(new_fcurve)
new_curve_range = abs(new_curve_min - new_curve_max)
new_curve_range_time = abs(new_curve_max_time - new_curve_min_time)
old_curve_min = GetMinKeyValue(curr_fcurve)
old_curve_max = GetMaxKeyValue(curr_fcurve)
old_curve_min_time = curr_fcurve.Keys[0].Time.GetFrame()
old_curve_max_time = curr_fcurve.Keys[-1].Time.GetFrame()
old_curve_dir = GetDirectionOfFCurve(curr_fcurve)
old_curve_range = abs(old_curve_min - old_curve_max)
old_curve_range_time = abs(old_curve_max_time - old_curve_min_time)
# if there is no value range then just scale time
if abs(new_curve_range) < 0.01:
scale_ratio = float(new_curve_range_time) / old_curve_range_time
offset = int(new_curve_min_time - old_curve_min_time)
ScaleFCurveTime(curr_fcurve, FBTime(0, 0, 0, old_curve_min_time), scale_ratio, offset)
return
else:
# then scale values of new fcurve to match existing curve value extents
for key in new_fcurve.Keys:
normalised_value = 1.0
if new_curve_dir * old_curve_dir > 0:
normalised_value = abs(key.Value - new_curve_min) / new_curve_range
else:
normalised_value = abs(key.Value - new_curve_max) / new_curve_range
key.Value = old_curve_min + (normalised_value * old_curve_range)
# copy fcurve
curr_fcurve.EditClear()
curr_fcurve.KeyReplaceBy(new_fcurve)
def GetMinKeyValue(fcurve):
min = 1000000000.0
for key in fcurve.Keys:
if key.Value < min:
min = key.Value
return min
def GetMaxKeyValue(fcurve):
max = -1000000000.0
for key in fcurve.Keys:
if key.Value > max:
max = key.Value
return max
def GetDirectionOfFCurve(fcurve):
if fcurve.Keys[0].Value <= fcurve.Keys[-1].Value:
return 1
else:
return -1
'''
def GetAbsMaxValueOfFCurve( fcurve, ref sign ):
abs_max_value = 0.0
for key in fcurve.Keys:
abs_value = abs( key.Value )
if abs_value > abs_max_value:
abs_max_value = key.Value
return abs_max_value
'''
def closeZonalHelperWindow():
FBDestroyToolByName("Zonal Key Helper")
def clearSelection():
''' Clear selection function '''
# Get selected models
modelList = FBModelList()
FBGetSelectedModels(modelList, None, True)
# Deselect models
for model in modelList:
model.Selected = False
# deselect constraints and unfocus any custom properties
for constraint in t.pathConstraint:
yaw_prop = constraint.PropertyList.Find("Yaw")
if yaw_prop:
# select custom property
yaw_prop.SetFocus(False)
translation_prop = constraint.PropertyList.Find("Translation Offset")
if translation_prop:
# select custom property
translation_prop.SetFocus(False)
constraint.Selected = False
def cleanupAndReset():
'''delete all constraints/paths and reset arrays to starting state'''
for j in range(0, t.numOfObjects):
# delete constraints
t.constraint[j].FBDelete()
t.pathConstraint[j].FBDelete()
# delete nulls
t.null[j].FBDelete()
t.pathNull[j].FBDelete()
# delete path
t.path[j].FBDelete()
# reset arrays
t.null = []
t.midNull = []
t.pathNull = []
t.path = []
t.pathConstraint = []
t.midNullConstraint = []
t.constraint = []
# delete keycontrols and reset
t.keyGroup.RemoveAllProperties()
t.keyGroup.FBDelete()
print 'constraints deleted'
# update UI
if t.numOfObjects == 1:
t.pin_button.Caption = "Apply MotionWarp to '" + t.selected_obj_name[0] + "'"
else:
t.pin_button.Caption = "Apply MotionWarp to " + str(t.numOfObjects) + " objects"
t.delete_button.Enabled = False
t.slider.Enabled = True
t.status.Enabled = True
t.pinned = False
t.zonalKeyHelper.Enabled = False
t.circle_button.Enabled = True
t.spline_button.Enabled = True
t.zonal_start_button.Enabled = True
t.zonal_stop_button.Enabled = True
####################################################################
# UI callbacks
####################################################################
def sliderUpdated(control, event):
t.status.Caption = str(int(control.Value * 10) + 2)
def modeButtonsCallback(control, event):
if t.circle_button.State:
t.radius.Enabled = True
t.radius.ReadOnly = False
t.counter_button.Enabled = True
t.clockwise_button.Enabled = True
t.slider.ReadOnly = True
t.slider.Enabled = False
t.status.Enabled = False
t.status.ReadOnly = True
t.angle_a.Enabled = False
t.angle_a.ReadOnly = True
t.angle_b.Enabled = False
t.angle_b.ReadOnly = True
t.zonalKeyHelper.Enabled = False
t.zonalKeyHelper.ReadOnly = True
t.radius_mode_button.Enabled = True
t.radius_mode_button.ReadOnly = False
t.manual_AV_mode_button.Enabled = True
t.manual_AV_mode_button.ReadOnly = False
t.auto_AV_mode_button.Enabled = True
t.auto_AV_mode_button.ReadOnly = False
t.advanced_settings_dropdown.Enabled = False
t.advanced_settings_dropdown.ReadOnly = True
t.advanced_settings_dropdown.ItemIndex = 0
if t.radius_mode_button.State == 1:
t.radius.Enabled = True
t.radius.ReadOnly = False
t.dropDownList.Enabled = False
t.dropDownList.ReadOnly = True
t.large_turn_button.Enabled = False
t.small_turn_button.Enabled = False
elif t.manual_AV_mode_button.State == 1:
t.radius.Enabled = True
t.radius.ReadOnly = False
t.dropDownList.Enabled = False
t.dropDownList.ReadOnly = True
t.large_turn_button.Enabled = False
t.small_turn_button.Enabled = False
else:
t.radius.Enabled = False
t.radius.ReadOnly = True
t.dropDownList.Enabled = True
t.dropDownList.ReadOnly = False
t.large_turn_button.Enabled = True
t.small_turn_button.Enabled = True
if t.spline_button.State:
t.radius.Enabled = False
t.radius.ReadOnly = True
t.counter_button.Enabled = False
t.clockwise_button.Enabled = False
t.large_turn_button.Enabled = False
t.small_turn_button.Enabled = False
t.slider.ReadOnly = False
t.slider.Enabled = True
t.status.Enabled = True
t.status.ReadOnly = False
t.angle_a.Enabled = False
t.angle_a.ReadOnly = True
t.angle_b.Enabled = False
t.angle_b.ReadOnly = True
t.zonalKeyHelper.Enabled = False
t.zonalKeyHelper.ReadOnly = True
t.radius_mode_button.Enabled = False
t.radius_mode_button.ReadOnly = True
t.manual_AV_mode_button.Enabled = False
t.manual_AV_mode_button.ReadOnly = True
t.auto_AV_mode_button.Enabled = False
t.auto_AV_mode_button.ReadOnly = True
t.dropDownList.Enabled = False
t.dropDownList.ReadOnly = True
t.advanced_settings_dropdown.Enabled = True
t.advanced_settings_dropdown.ReadOnly = False
if t.zonal_start_button.State or t.zonal_stop_button.State:
t.radius.Enabled = False
t.radius.ReadOnly = True
t.counter_button.Enabled = False
t.clockwise_button.Enabled = False
t.large_turn_button.Enabled = False
t.small_turn_button.Enabled = False
t.slider.ReadOnly = True
t.slider.Enabled = False
t.status.Enabled = False
t.status.ReadOnly = True
t.angle_a.Enabled = True
t.angle_a.ReadOnly = False
t.angle_b.Enabled = False
t.angle_b.ReadOnly = True
t.zonalKeyHelper.Enabled = False
t.zonalKeyHelper.ReadOnly = True
t.radius_mode_button.Enabled = False
t.radius_mode_button.ReadOnly = True
t.manual_AV_mode_button.Enabled = False
t.manual_AV_mode_button.ReadOnly = True
t.auto_AV_mode_button.Enabled = False
t.auto_AV_mode_button.ReadOnly = True
t.dropDownList.Enabled = False
t.dropDownList.ReadOnly = True
t.advanced_settings_dropdown.Enabled = True
t.advanced_settings_dropdown.ReadOnly = False
if t.zonal_advanced_button.State:
t.radius.Enabled = False
t.radius.ReadOnly = True
t.counter_button.Enabled = False
t.clockwise_button.Enabled = False
t.large_turn_button.Enabled = False
t.small_turn_button.Enabled = False
t.slider.ReadOnly = True
t.slider.Enabled = False
t.status.Enabled = False
t.status.ReadOnly = True
t.angle_a.Enabled = True
t.angle_a.ReadOnly = False
t.angle_b.Enabled = True
t.angle_b.ReadOnly = False
t.zonalKeyHelper.Enabled = False
t.zonalKeyHelper.ReadOnly = True
t.radius_mode_button.Enabled = False
t.radius_mode_button.ReadOnly = True
t.manual_AV_mode_button.Enabled = False
t.manual_AV_mode_button.ReadOnly = True
t.auto_AV_mode_button.Enabled = False
t.auto_AV_mode_button.ReadOnly = True
t.dropDownList.Enabled = False
t.dropDownList.ReadOnly = True
t.advanced_settings_dropdown.Enabled = True
t.advanced_settings_dropdown.ReadOnly = False
return
def radiusModeButtonsCallback(control, event):
if t.radius_mode_button.State:
t.radius.Hint = "Radius of circle in Metres"
else:
t.radius.Hint = "Inaccessable while not in Radius mode"
# Set Auto Angular Velocity Buttons to correct states
if t.auto_AV_mode_button.State:
t.radius.Enabled = False
t.radius.ReadOnly = True
t.radius_mode_button.Enabled = True
t.radius_mode_button.ReadOnly = False
t.manual_AV_mode_button.Enabled = True
t.manual_AV_mode_button.ReadOnly = False
t.auto_AV_mode_button.Enabled = True
t.auto_AV_mode_button.ReadOnly = False
t.dropDownList.Enabled = True
t.dropDownList.ReadOnly = False
t.large_turn_button.Enabled = True
t.small_turn_button.Enabled = True
# Set Manual Angular Velocity Buttons to correct states
elif t.manual_AV_mode_button.State:
t.large_turn_button.Enabled = False
t.small_turn_button.Enabled = False
t.radius.Enabled = True
t.radius.ReadOnly = False
t.radius_mode_button.Enabled = True
t.radius_mode_button.ReadOnly = False
t.manual_AV_mode_button.Enabled = True
t.manual_AV_mode_button.ReadOnly = False
t.auto_AV_mode_button.Enabled = True
t.auto_AV_mode_button.ReadOnly = False
t.dropDownList.Enabled = False
t.dropDownList.ReadOnly = True
# Set Manual Radius Buttons to correct states
elif t.radius_mode_button.State:
t.large_turn_button.Enabled = False
t.small_turn_button.Enabled = False
t.radius.Enabled = True
t.radius.ReadOnly = False
t.radius_mode_button.Enabled = True
t.radius_mode_button.ReadOnly = False
t.manual_AV_mode_button.Enabled = True
t.manual_AV_mode_button.ReadOnly = False
t.auto_AV_mode_button.Enabled = True
t.auto_AV_mode_button.ReadOnly = False
t.dropDownList.Enabled = False
t.dropDownList.ReadOnly = True
def deleteButtonCallBack(control, event):
if t.zonal_start_button.State or t.zonal_stop_button.State:
if hasattr(t, 'zonal'):
if not t.zonal.TypeInfo == 203:
closeZonalHelperWindow()
cleanupAndReset()
def zonalKeyHelperCallBack(control, event):
t.zonal = FBCreateUniqueTool("Zonal Key Helper")
PopulateZonalUI(t.zonal)
def goButtonCallBack(control, event):
# Disable all expressions for the duration of this event
with SceneExpressionsDisabled():
# get time span
t.take_start_frame = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
t.take_end_frame = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()
t.current_frame = FBSystem().LocalTime.GetFrame()
# HORRENDOUS HACK ALERT
# this fixes an issue with turns. Need to figure out why this fixes it when time permits :(
t.take_end_frame += 1
# update slider to startframe
FBPlayerControl().Goto(FBTime(0, 0, 0, t.take_start_frame))
FBSystem().Scene.Evaluate()
for i in range(0, t.numOfObjects):
########################################
# Initialise
########################################
if t.pinned == False:
clearSelection()
# create null
t.null.append(FBModelNull('constraint_null for ' + t.selected_obj_name[i]))
# create null
t.midNull.append(FBModelNull('mid_null'))
# create path null
t.pathNull.append(FBModelNull('path_null for ' + t.selected_obj_name[i]))
# create path curve
t.path.append(FBModelPath3D('MotionWarp 3d Curve for ' + t.selected_obj_name[i]))
# if it's the mover then make the 3D curve a different colour since we don't want to edit this one manually in most cases
if (t.selected_obj_name[i] == 'mover'):
# get curve color property
color_property = t.path[-1].PropertyList.Find('Curve Color')
if color_property:
color_property.Data = FBColor(0.0, 0.0, 1.0)
t.path[i].Show = True
#####################################################################################
# set keying group
# need to plot translation/rotation
#####################################################################################
ltran = t.null[i].PropertyList.Find('Translation (Lcl)')
lrot = t.null[i].PropertyList.Find('Rotation (Lcl)')
t.keyGroup = FBKeyingGroup("MotionWarpKeyGroup", FBKeyingGroupType.kFBKeyingGroupGlobal)
# Add Properties to Custom Key Group
t.keyGroup.AddProperty(ltran)
t.keyGroup.AddProperty(lrot)
# # SetActive, activate the keying group.
t.keyGroup.SetActive(True)
# # SetEnabled, will make available the keying group in keying group list of the key control UI.
t.keyGroup.SetEnabled(True)
# make sure system in on current layer
FBSystem().CurrentTake.SetCurrentLayer(0)
if t.pinned == False:
# turn off expressions for optimal performance
# ToggleDevices()
# lists for storing object pos and rotations
trans_array = []
trans_warp_weighting = []
path_start_position = []
rot_array = []
count = 0
# ----------------------------------------------------------------------------------
# Get Mover position of current character
# This will be used as a reference point for offsets
# if no Mover is found use initialised vector instead
# ----------------------------------------------------------------------------------
SEARCH_STRING = 'mover'
mover_start_position = FBVector3d()
mover_end_position = FBVector3d()
invMoverMx = FBMatrix()
moverWorldMx = FBMatrix()
mover_world_scaleV3 = FBSVector()
t.moverObject = ''
character = FBApplication().CurrentCharacter
if character is not None:
t.moverObject = FBFindModelByLabelName(character.OwnerNamespace.Name + ':' + SEARCH_STRING)
if t.moverObject is None:
print "WARNING! " + SEARCH_STRING + " not Found!"
# ----------------------------------------------------------------------------------
# loop for every frame - get pos/rot of selected object
# ----------------------------------------------------------------------------------
for frame in range(t.take_start_frame, t.take_end_frame + 1):
# update slider
FBPlayerControl().Goto(FBTime(0, 0, 0, frame))
FBSystem().Scene.Evaluate()
# get selected translation and rotation for object
for i in range(0, t.numOfObjects):
obj_trans = FBVector3d()
obj_rot = FBVector3d()
t.selected_obj[i].GetVector(obj_trans, FBModelTransformationType.kModelTranslation, True)
t.selected_obj[i].GetVector(obj_rot, FBModelTransformationType.kModelRotation, True)
##############################################################################################################################
# if we're on the last object also grab mover inv matrix and position
##############################################################################################################################
if (i == t.numOfObjects - 1):
if (frame == t.take_start_frame):
# get start position
t.moverObject.GetVector(mover_start_position, FBModelTransformationType.kModelTranslation,
True)
# get world and inverse matrices for Mover
t.moverObject.GetMatrix(invMoverMx, FBModelTransformationType.kModelInverse_Transformation,
True)
t.moverObject.GetMatrix(moverWorldMx, FBModelTransformationType.kModelTransformation, True)
FBMatrixToScaling(mover_world_scaleV3, moverWorldMx)
if (frame == t.take_end_frame):
t.moverObject.GetVector(mover_end_position, FBModelTransformationType.kModelTranslation,
True)
current_frame_mover_pos = FBVector3d()
current_frame_invMoverMx = FBMatrix()
t.moverObject.GetMatrix(current_frame_invMoverMx,
FBModelTransformationType.kModelInverse_Transformation, True)
t.moverObject.GetVector(current_frame_mover_pos, FBModelTransformationType.kModelTranslation,
True)
##############################################################################################################################
# store translation/rotation
trans_array.append(obj_trans)
rot_array.append(obj_rot)
t.midNull[i].Selected = True
if (frame == t.take_start_frame):
# store path position start
path_start_position.append(obj_trans)
count += 1
# ----------------------------------------------------------------------------------
# calculate path lengths
# ----------------------------------------------------------------------------------
path_length = []
frame_range = t.take_end_frame - t.take_start_frame
for i in range(0, t.numOfObjects):
if t.advanced_settings_dropdown.ItemIndex == 1:
path_length.append(
FBVector3d((trans_array[(frame_range - 1) * t.numOfObjects + i][0] - trans_array[i][0]),
(trans_array[(frame_range - 1) * t.numOfObjects + i][1] - trans_array[i][1]),
(trans_array[(frame_range - 1) * t.numOfObjects + i][2] - trans_array[i][2])
).Length()
)
else:
path_length.append(
FBVector3d((trans_array[(frame_range - 1) * t.numOfObjects + i][0] - trans_array[i][0]), 0,
(trans_array[(frame_range - 1) * t.numOfObjects + i][2] - trans_array[i][2])
).Length()
)
# ----------------------------------------------------------------------------------
# loop for every frame - set pos/rot on null
# ----------------------------------------------------------------------------------
count = 0
if t.circle_button.State:
curve_steps = 2
else:
curve_steps = int(t.slider.Value * 10) + 2
frame_step = float(frame_range / (curve_steps - 1.0))
frame_step_total = t.take_start_frame + frame_step
frame = t.take_start_frame
while frame <= t.take_end_frame:
# update slider
FBPlayerControl().Goto(FBTime(0, 0, 0, frame))
FBSystem().Scene.Evaluate()
for i in range(0, t.numOfObjects):
# set up path curve on first frame
if (frame == t.take_start_frame):
# path starts at each objects own starting frame
pathStart = FBVector4d(trans_array[count * t.numOfObjects + i][0],
trans_array[count * t.numOfObjects + i][1],
trans_array[count * t.numOfObjects + i][2], 0)
t.path[i].PathKeyStartAdd(pathStart)
# set pivot to be same as mover as default
pivot = t.path[i].PropertyList.Find('Scaling Pivot')
if pivot:
pivot.Data = mover_start_position
pivot = t.path[i].PropertyList.Find('Rotation Pivot')
if pivot:
pivot.Data = mover_start_position
# remove next three indices as they are created automatically and are unwanted
# each time we remove index1 the curve indices are recalculated so we need to do this three times
# looks odd!
t.path[i].PathKeyRemove(1)
t.path[i].PathKeyRemove(1)
t.path[i].PathKeyRemove(1)
trans_warp_weighting.append(0.0)
else:
# only if we're on a 'frame step' keyframe do we want to create a spline point (or end frame)
if (frame >= frame_step_total or frame == t.take_end_frame):
# Add path key. Fix the height to be the same as the starting height
if t.advanced_settings_dropdown.ItemIndex == 1:
t.path[i].PathKeyEndAdd(
FBVector4d(trans_array[count * t.numOfObjects + i][0],
trans_array[count * t.numOfObjects + i][1],
trans_array[count * t.numOfObjects + i][2], 0))
else:
t.path[i].PathKeyEndAdd(
FBVector4d(trans_array[count * t.numOfObjects + i][0], trans_array[i][1],
trans_array[count * t.numOfObjects + i][2], 0))
# Fix for bug. if the end frame is to close to the penultimate keyframe the tangent stretches out the curve.
# Reduce tangent length on penultimate key to zero
if (frame == t.take_end_frame and t.circle_button.State):
# linear tangent for penultimate key
keyIndex = t.path[i].PathKeyGetCount() - 2
keyPosition = t.path[i].PathKeyGet(keyIndex)
# set tangent to be the same position as the keyframe (creating a linear section between this and the last path key)
t.path[i].PathKeySetLeftTangent(keyIndex, keyPosition, True)
# if we're at the end of the object list *and* we're on a frame step then increment frame step total
if (i == t.numOfObjects - 1):
frame_step_total += frame_step
# trans warp weighting is an estimated percentage of the overall motionwarp path moved in this frame
# this will allow the motion warp path to more accurately follow the selected object
# calc % distance travelled this frame of overall path length (very approximate)
if t.advanced_settings_dropdown.ItemIndex == 1:
current_length = FBVector3d(
(trans_array[count * t.numOfObjects + i][0] - trans_array[i][0]),
(trans_array[count * t.numOfObjects + i][1] - trans_array[i][1]),
(trans_array[count * t.numOfObjects + i][2] - trans_array[i][2])
).Length()
else:
current_length = FBVector3d(
(trans_array[count * t.numOfObjects + i][0] - trans_array[i][0]), 0,
(trans_array[count * t.numOfObjects + i][2] - trans_array[i][2])
).Length()
if not path_length[i] == 0.0:
trans_warp_weighting.append((current_length / path_length[i]) * 100.0)
# if path length is zero use the frame progression to update the weighting percentage
else:
trans_warp_weighting.append((frame / frame_range) * 100.0)
# set selected translation and rotation for object
t.midNull[i].SetVector(trans_array[count * t.numOfObjects + i],
FBModelTransformationType.kModelTranslation, True)
t.midNull[i].SetVector(rot_array[count * t.numOfObjects + i],
FBModelTransformationType.kModelRotation, True)
FBSystem().Scene.Evaluate()
# key null
FBPlayerControl().Key()
if (frame == t.take_end_frame):
break
# increment frame and count
frame += 1
count += 1
# clamp frame range to end frame
if (frame > t.take_end_frame):
frame = t.take_end_frame
count = frame_range
for j in range(0, t.numOfObjects):
###################################################################################
# constrain path_null to path
###################################################################################
lMgr = FBConstraintManager()
# get index to parent/child constraint
lIndex = None
for i in range(0, lMgr.TypeGetCount()):
if lMgr.TypeGetName(i) == 'Path':
lIndex = i
break
# create constraint
path_constraint = lMgr.TypeCreateConstraint(lIndex)
path_constraint.Name = 'MotionWarp Path Constraint for ' + t.selected_obj_name[j]
# add ref objects
for i in range(0, path_constraint.ReferenceGroupGetCount()):
if path_constraint.ReferenceGroupGetName(i) == 'Path Source':
path_constraint.ReferenceAdd(i, t.path[j])
elif path_constraint.ReferenceGroupGetName(i) == 'Constrained Object':
path_constraint.ReferenceAdd(i, t.pathNull[j])
# snap/activate constraint
path_constraint.Active = True
# store ref to constraint objects
t.pathConstraint.append(path_constraint)
# store ref to the model related to the constraint
t.pathConstraint[len(t.pathConstraint) - 1].ModelName = t.selected_obj_name[j]
if t.circle_button.State:
path_constraint.PropertyList.Find("Follow Path").Data = False
else:
path_constraint.PropertyList.Find("Follow Path").Data = True
# path_constraint.PropertyList.Find("Follow Path").Data = True
path_constraint.PropertyList.Find("Up Vector").Data = 2
path_constraint.PropertyList.Find("Front Vector").Data = 0
###############################
# alter path warp to match object %
###############################
warpProperty = path_constraint.PropertyList.Find("Warp")
warpAn = warpProperty.GetAnimationNode()
warpFc = warpAn.FCurve
count = 0
for key in range(t.take_start_frame, t.take_end_frame):
warpFc.KeyAdd(FBTime(0, 0, 0, key), trans_warp_weighting[count * t.numOfObjects + j])
count += 1
###################################################################################
# constrain constraint_null to midd_null
###################################################################################
lMgr = FBConstraintManager()
# get index to parent/child constraint
lIndex = None
for i in range(0, lMgr.TypeGetCount()):
if lMgr.TypeGetName(i) == 'Parent/Child':
lIndex = i
break
# create constraint
lPosConst = lMgr.TypeCreateConstraint(lIndex)
# add ref objects
for i in range(0, lPosConst.ReferenceGroupGetCount()):
if lPosConst.ReferenceGroupGetName(i) == 'Source (Parent)':
lPosConst.ReferenceAdd(i, t.midNull[j])
elif lPosConst.ReferenceGroupGetName(i) == 'Constrained object (Child)':
lPosConst.ReferenceAdd(i, t.null[j])
# activate constraint
lPosConst.Active = True
# store ref to constraint objects
t.midNullConstraint.append(lPosConst)
###################################################################################
# parent constraint null
###################################################################################
# this is where the magic happens :)
# we've contrained the null to the midnull so it can't change but we change the heirarchy and plot
# so that the offset per frame now becomes a local transformation and we keep the existing world space transformation
# through this counter animation
t.null[j].Parent = t.pathNull[j]
###################################################################################
# plot and remove mid null
###################################################################################
clearSelection()
for i in range(0, t.numOfObjects):
t.null[i].Selected = True
# ToggleDevices()
FBSystem().CurrentTake.PlotTakeOnSelected(plotOptions())
# ToggleDevices()
FBSystem().Scene.Evaluate()
for i in range(0, t.numOfObjects):
# delete mid null
t.midNull[i].FBDelete()
# delete constraint
t.midNullConstraint[i].FBDelete()
###################################################################################
# finally constrain selected object to constraint null
###################################################################################
for j in range(0, t.numOfObjects):
lMgr = FBConstraintManager()
# get index to parent/child constraint
lIndex = None
for i in range(0, lMgr.TypeGetCount()):
if lMgr.TypeGetName(i) == 'Parent/Child':
lIndex = i
break
# create constraint
lPosConst = lMgr.TypeCreateConstraint(lIndex)
lPosConst.Name = ' Parent/Child Constraint to MotionWarp Path for ' + t.selected_obj_name[j]
# add ref objects
for i in range(0, lPosConst.ReferenceGroupGetCount()):
if lPosConst.ReferenceGroupGetName(i) == 'Source (Parent)':
lPosConst.ReferenceAdd(i, t.null[j])
elif lPosConst.ReferenceGroupGetName(i) == 'Constrained object (Child)':
lPosConst.ReferenceAdd(i, t.selected_obj[j])
# snap/activate constraint
lPosConst.Snap()
# store ref to constraint objects
t.constraint.append(lPosConst)
###################################################################################
# Circle Mode
#
# if mode selected move spline points around into circle
###################################################################################
if t.circle_button.State:
###################################################################################
# turn on path constraint and set yaw offset to angle between world X axis (1,0,0) and Mover Y axis direction
###################################################################################
for path_constraint in t.pathConstraint:
path_constraint.PropertyList.Find("Follow Path").Data = True
# calc angle
world_x_axis_in_mover_space = FBVector4d()
FBVectorMatrixMult(world_x_axis_in_mover_space, invMoverMx,
FBVector4d(mover_start_position[0], mover_start_position[1],
mover_start_position[2], 0.0) + FBVector4d(100.0, 0.0, 0.0, 0.0))
dot = world_x_axis_in_mover_space.DotProduct(FBVector4d(0.0, 1.0, 0.0, 0.0))
# catch for zero angle (1.0) since it causes math.acos to error
# requires dot rounded since very tiny floats were also slipping through comparison check
# but still causing math.acos to bomb out
dot = clean_cos(dot)
angle_between_x_axes = math.acos(dot) * 180.0 / math.pi
if world_x_axis_in_mover_space[0] >= 0.0:
path_constraint.PropertyList.Find("Yaw").Data = -angle_between_x_axes
else:
path_constraint.PropertyList.Find("Yaw").Data = angle_between_x_axes
worldCoords = FBVector4d()
objectPositionInMoverSpace = FBVector4d()
ModelMx = FBMatrix()
TransformedModelMx = FBMatrix()
# unit to metre conversion in MB
scale = 100.0
################################################################################################
# cache user direction choice for circle - (note: flip value)
################################################################################################
if t.clockwise_button.State == 1:
direction = 1
else:
direction = -1
for j in range(0, t.numOfObjects):
################################################################################################
# calcluate radius
# either direct from UI if radius mode is selected, or calculated from the angular velocity
################################################################################################
if t.radius_mode_button.State == 1:
radius = t.radius.Value
elif t.auto_AV_mode_button.State == 1:
average_velocity_ms = (path_length[j] / scale) / (frame_range / 30.0)
print "average_velocity_ms is " + str(average_velocity_ms)
# calculate the desired angular velocity of from overall average speed
currentDropDownSelection = t.dropDownList.ItemIndex
calculated_angular_velocity = calcAV(average_velocity_ms, currentDropDownSelection)
print "calculated angular velocity is " + str(calculated_angular_velocity)
radius = average_velocity_ms / calculated_angular_velocity
selectedMininumRadius = float(t.minRadius[currentDropDownSelection])
if t.large_turn_button.State == 1:
# clamp value of radius if it's too tight
if radius < (selectedMininumRadius * 2):
radius = (selectedMininumRadius * 2)
else:
if radius < selectedMininumRadius:
radius = selectedMininumRadius
print "calculated radius is " + str(radius)
else:
average_velocity_ms = (path_length[j] / scale) / (frame_range / 30.0)
print "average_velocity_ms is " + str(average_velocity_ms)
radius = average_velocity_ms / t.radius.Value
print "calculated radius is " + str(radius)
prescaled_radius = radius
# centre point is the circle origin with respect to the mover ( of radius)
FBVectorMatrixMult(worldCoords, moverWorldMx, FBVector4d(radius * direction, 0.0, 0.0, 0.0))
centrePoint = FBVector3d(worldCoords[0], worldCoords[1], worldCoords[2])
print "########################################"
print "OBJECT >> " + t.selected_obj_name[j]
print "########################################"
# make sure we have at least five points...
while (t.path[j].PathKeyGetCount() < 5):
t.path[j].PathKeyEndAdd(FBVector4d())
# remove any extraneous points over 5...
while (t.path[j].PathKeyGetCount() > 5):
t.path[j].PathKeyRemove(t.path[j].PathKeyGetCount() - 1)
# create four point circle points and edit tangents
circle_height = t.path[j].PathKeyGet(0)[1]
# convert selected object to Mover coord space
FBVectorMatrixMult(objectPositionInMoverSpace, invMoverMx,
FBVector4d(path_start_position[j][0], path_start_position[j][1],
path_start_position[j][2], 0.0))
# copy to a FBVector3d type for ease of use
objectOffsetFromMover = FBVector3d(objectPositionInMoverSpace[0], objectPositionInMoverSpace[1],
objectPositionInMoverSpace[2])
radius = (FBVector3d(path_start_position[j][0], 0.0, path_start_position[j][2]) - FBVector3d(
centrePoint[0], 0.0, centrePoint[2])).Length() / scale
# magic number/constant below is (4/3)*tan(math.pi/8) based on four control points
# see http://stackoverflow.com/questions/1734745/how-to-create-circle-with-b%C3%A9zier-curves
tangent_length = 0.552284749831 * radius
############################################################################################
# calculate circle angle offset
############################################################################################
v2 = path_start_position[j] - centrePoint
v2[1] = 0.0
v1 = mover_start_position - centrePoint
v1[1] = 0.0
v1.Normalize()
v2.Normalize()
dot = v1.DotProduct(v2)
# catch for zero angle (1.0) since it causes math.acos to error
# requires dot rounded since very tiny floats were also slipping through comparison check
# but still causing math.acos to bomb out
if (round(dot, 4) == 1.0):
circleAngleOffset = 0.0
else:
circleAngleOffset = math.acos(dot)
# if object position is in front or behind mover then flip angle depending on circle direction
if (objectOffsetFromMover[1] > 0.0 and direction == 1) or (
objectOffsetFromMover[1] < 0.0 and direction == -1):
circleAngleOffset *= -1
############################################################################################
# create circle with all points rotated by circleAngleOffset
############################################################################################
###################################
# Circle Point 0
###################################
circlePoint = FBVector3d(0.0, 0.0, 0.0)
rotatedCirclePoint = RotateVectorRadians(circlePoint, circleAngleOffset)
# add any offset between object and mover
rotatedCirclePoint += objectOffsetFromMover
# convert to WS & set
FBVectorMatrixMult(worldCoords, moverWorldMx,
FBVector4d(rotatedCirclePoint[0], rotatedCirclePoint[1], rotatedCirclePoint[2],
1.0))
# cache circle point position for tangent use
transformedCirclePoint = FBVector4d(worldCoords[0], worldCoords[1], worldCoords[2], 0.0)
t.path[j].PathKeySet(0, transformedCirclePoint)
# rotate tangent
tangent = FBVector3d(0.0, tangent_length, 0.0)
rotatedTangent = RotateVectorRadians(tangent, circleAngleOffset)
# convert to WS
FBVectorMatrixMult(worldCoords, moverWorldMx,
FBVector4d(rotatedTangent[0], rotatedTangent[1], rotatedTangent[2], 0.0))
# create relative vector from mover to tangent end, and add to circle point
worldCoords = FBVector4d((worldCoords[0] - mover_start_position[0]) + transformedCirclePoint[0],
(worldCoords[1] - mover_start_position[1]) + transformedCirclePoint[1],
(worldCoords[2] - mover_start_position[2]) + transformedCirclePoint[2],
0.0)
# have to set both tangent sides on the first point for some strange reason only known to MB.....
t.path[j].PathKeySetLeftTangent(0, FBVector4d(worldCoords[0], worldCoords[1], worldCoords[2], 0.0),
True)
t.path[j].PathKeySetRightTangent(0, FBVector4d(worldCoords[0], worldCoords[1], worldCoords[2], 0.0),
True)
###################################
# Circle Point 1
###################################
circlePoint = FBVector3d(direction * radius, radius, 0.0)
rotatedCirclePoint = RotateVectorRadians(circlePoint, circleAngleOffset)
# add any offset between object and mover
rotatedCirclePoint += objectOffsetFromMover
# convert to WS & set
FBVectorMatrixMult(worldCoords, moverWorldMx,
FBVector4d(rotatedCirclePoint[0], rotatedCirclePoint[1], rotatedCirclePoint[2],
0.0))
# cache circle point position for tangent use
transformedCirclePoint = FBVector4d(worldCoords[0], worldCoords[1], worldCoords[2], 0.0)
t.path[j].PathKeySet(1, transformedCirclePoint)
# rotate tangent
tangent = FBVector3d(-direction * tangent_length, 0.0, 0.0)
rotatedTangent = RotateVectorRadians(tangent, circleAngleOffset)
# convert to WS
FBVectorMatrixMult(worldCoords, moverWorldMx,
FBVector4d(rotatedTangent[0], rotatedTangent[1], rotatedTangent[2], 0.0))
# create relative vector from mover to tangent end, and add to circle point
worldCoords = FBVector4d((worldCoords[0] - mover_start_position[0]) + transformedCirclePoint[0],
(worldCoords[1] - mover_start_position[1]) + transformedCirclePoint[1],
(worldCoords[2] - mover_start_position[2]) + transformedCirclePoint[2],
0.0)
t.path[j].PathKeySetLeftTangent(1, FBVector4d(worldCoords[0], worldCoords[1], worldCoords[2], 0.0),
True)
###################################
# Circle Point 2
###################################
circlePoint = FBVector3d(direction * radius * 2.0, 0.0, 0.0)
rotatedCirclePoint = RotateVectorRadians(circlePoint, circleAngleOffset)
# add any offset between object and mover
rotatedCirclePoint += objectOffsetFromMover
# convert to WS & set
FBVectorMatrixMult(worldCoords, moverWorldMx,
FBVector4d(rotatedCirclePoint[0], rotatedCirclePoint[1], rotatedCirclePoint[2],
0.0))
# cache circle point position for tangent use
transformedCirclePoint = FBVector4d(worldCoords[0], worldCoords[1], worldCoords[2], 0.0)
t.path[j].PathKeySet(2, transformedCirclePoint)
# rotate tangent
tangent = FBVector3d(0.0, tangent_length, 0.0)
rotatedTangent = RotateVectorRadians(tangent, circleAngleOffset)
# convert to WS
FBVectorMatrixMult(worldCoords, moverWorldMx,
FBVector4d(rotatedTangent[0], rotatedTangent[1], rotatedTangent[2], 0.0))
# create relative vector from mover to tangent end, and add to circle point
worldCoords = FBVector4d((worldCoords[0] - mover_start_position[0]) + transformedCirclePoint[0],
(worldCoords[1] - mover_start_position[1]) + transformedCirclePoint[1],
(worldCoords[2] - mover_start_position[2]) + transformedCirclePoint[2],
0.0)
t.path[j].PathKeySetLeftTangent(2, FBVector4d(worldCoords[0], worldCoords[1], worldCoords[2], 0.0),
True)
###################################
# Circle Point 3
###################################
circlePoint = FBVector3d(direction * radius, -radius, 0.0)
rotatedCirclePoint = RotateVectorRadians(circlePoint, circleAngleOffset)
# add any offset between object and mover
rotatedCirclePoint += objectOffsetFromMover
# convert to WS & set
FBVectorMatrixMult(worldCoords, moverWorldMx,
FBVector4d(rotatedCirclePoint[0], rotatedCirclePoint[1], rotatedCirclePoint[2],
0.0))
# cache circle point position for tangent use
transformedCirclePoint = FBVector4d(worldCoords[0], worldCoords[1], worldCoords[2], 0.0)
t.path[j].PathKeySet(3, worldCoords)
# rotate tangent
tangent = FBVector3d(direction * tangent_length, 0.0, 0.0)
rotatedTangent = RotateVectorRadians(tangent, circleAngleOffset)
# convert to WS
FBVectorMatrixMult(worldCoords, moverWorldMx,
FBVector4d(rotatedTangent[0], rotatedTangent[1], rotatedTangent[2], 0.0))
# create relative vector from mover to tangent end, and add to circle point
worldCoords = FBVector4d((worldCoords[0] - mover_start_position[0]) + transformedCirclePoint[0],
(worldCoords[1] - mover_start_position[1]) + transformedCirclePoint[1],
(worldCoords[2] - mover_start_position[2]) + transformedCirclePoint[2],
0.0)
t.path[j].PathKeySetLeftTangent(3, FBVector4d(worldCoords[0], worldCoords[1], worldCoords[2], 0.0),
True)
###################################
# Circle Point 4
###################################
circlePoint = FBVector3d(0.0, 0.0, 0.0)
rotatedCirclePoint = RotateVectorRadians(circlePoint, circleAngleOffset)
# add any offset between object and mover
rotatedCirclePoint += objectOffsetFromMover
# convert to WS & set
FBVectorMatrixMult(worldCoords, moverWorldMx,
FBVector4d(rotatedCirclePoint[0], rotatedCirclePoint[1], rotatedCirclePoint[2],
0.0))
# cache circle point position for tangent use
transformedCirclePoint = FBVector4d(worldCoords[0], worldCoords[1], worldCoords[2], 0.0)
t.path[j].PathKeySet(4, worldCoords)
# rotate tangent
tangent = FBVector3d(0.0, -tangent_length, 0.0)
rotatedTangent = RotateVectorRadians(tangent, circleAngleOffset)
# convert to WS
FBVectorMatrixMult(worldCoords, moverWorldMx,
FBVector4d(rotatedTangent[0], rotatedTangent[1], rotatedTangent[2], 0.0))
# create relative vector from mover to tangent end, and add to circle point
worldCoords = FBVector4d((worldCoords[0] - mover_start_position[0]) + transformedCirclePoint[0],
(worldCoords[1] - mover_start_position[1]) + transformedCirclePoint[1],
(worldCoords[2] - mover_start_position[2]) + transformedCirclePoint[2],
0.0)
t.path[j].PathKeySetLeftTangent(4, FBVector4d(worldCoords[0], worldCoords[1], worldCoords[2], 0.0),
True)
###############################
# alter curve pivot to sit at centre and move null to beginning
###############################
pivot = t.path[j].PropertyList.Find('Scaling Pivot')
if pivot:
pivot.Data = FBVector3d(centrePoint[0], path_start_position[j][1], centrePoint[2])
pivot = t.path[j].PropertyList.Find('Rotation Pivot')
if pivot:
pivot.Data = FBVector3d(centrePoint[0], path_start_position[j][1], centrePoint[2])
# move null to beginning of circle
t.null[j].SetVector(FBVector3d(path_start_position[j][0], circle_height, path_start_position[j][2]),
FBModelTransformationType.kModelTranslation, True)
###############################
# alter path warp to match object %
###############################
warpProperty = t.pathConstraint[j].PropertyList.Find("Warp")
warpAn = warpProperty.GetAnimationNode()
warpFc = warpAn.FCurve
keys = warpProperty.GetAnimationNode().FCurve.Keys
for key in keys:
key.Value = (key.Value / 100.0) * (
(path_length[j] / (2.0 * math.pi * prescaled_radius * scale)) * 100.0)
# handle circle wrap
if (key.Value > 100.0):
key.Value -= 100.0 * int(key.Value / 100.0)
print "Original path length was ~ " + str(path_length[j]) + ", circle circumference is " + str(
2.0 * math.pi * radius * scale)
print "Warp value has been scaled proportionally by ~" + str(
(path_length[j] / (2.0 * math.pi * radius * scale)) * 100.0) + " % "
###################################################################################
# Zonal Start Mode
#
# if mode selected rotate spline points around at angle but maintain start pose
###################################################################################
if t.zonal_start_button.State:
print "Zonal Start Mode!"
# note. Reverse the angle to match convention
rotationAngleAV3 = FBVector3d(0.0, -t.angle_a.Value, 0.0)
for i in range(0, t.numOfObjects):
# grab starting position pre rotation
startKeyPositionV4 = t.path[i].PathKeyGet(0)
# rotate splines
t.path[i].Rotation = FBVector3d(t.path[i].Rotation[0] + rotationAngleAV3[0],
t.path[i].Rotation[1] + rotationAngleAV3[1],
t.path[i].Rotation[2] + rotationAngleAV3[2])
# have to force a refresh then get key position again. Note, PathKeyGet( 0 ) does not work after rotation, even with a scene refresh. MB bug. Total_GlobalPathEvaluate does work...
FBSystem().Scene.Evaluate()
rotatedKeyPositionV4 = t.path[i].Total_GlobalPathEvaluate(0.0)
# calc difference in new position and use this to set translation offset
offsetV4 = rotatedKeyPositionV4 - startKeyPositionV4
# set offsets so pose at start is the same
yaw_prop = t.pathConstraint[i].PropertyList.Find("Yaw")
if yaw_prop:
yaw_prop.SetAnimated(True)
existing_data = yaw_prop.Data
# set key on first frame
yaw_prop.GetAnimationNode().FCurve.KeyAdd(FBTime(0, 0, 0, t.take_start_frame),
existing_data - rotationAngleAV3[1])
# set key on last frame
yaw_prop.GetAnimationNode().FCurve.KeyAdd(FBTime(0, 0, 0, t.take_end_frame), existing_data)
FlattenKeys(yaw_prop.GetAnimationNode().FCurve)
translation_prop = t.pathConstraint[i].PropertyList.Find("Translation Offset")
if translation_prop:
translation_prop.SetAnimated(True)
existing_data = translation_prop.Data
# set key on first frame
translation_prop.GetAnimationNode().Nodes[0].FCurve.KeyAdd(FBTime(0, 0, 0, t.take_start_frame),existing_data[0] - offsetV4[0])
translation_prop.GetAnimationNode().Nodes[1].FCurve.KeyAdd(FBTime(0, 0, 0, t.take_start_frame), existing_data[1] - offsetV4[1])
translation_prop.GetAnimationNode().Nodes[2].FCurve.KeyAdd(FBTime(0, 0, 0, t.take_start_frame), existing_data[2] - offsetV4[2])
# set key on last frame
translation_prop.GetAnimationNode().Nodes[0].FCurve.KeyAdd(FBTime(0, 0, 0, t.take_end_frame),existing_data[0])
translation_prop.GetAnimationNode().Nodes[1].FCurve.KeyAdd(FBTime(0, 0, 0, t.take_end_frame),existing_data[1])
translation_prop.GetAnimationNode().Nodes[2].FCurve.KeyAdd(FBTime(0, 0, 0, t.take_end_frame), existing_data[2])
for node in translation_prop.GetAnimationNode().Nodes:
FlattenKeys(node.FCurve)
###################################################################################
# Enable Zonal Helper UI
###################################################################################
t.zonalKeyHelper.Enabled = True
t.zonalKeyHelper.ReadOnly = False
###################################################################################
# Zonal Stop Mode
#
# if mode selected rotate spline points around at angle but maintain start pose
###################################################################################
if t.zonal_stop_button.State:
print "Zonal Stop Mode!"
# note. Reverse the angle to match convention
rotationAngleAV3 = FBVector3d(0.0, -t.angle_a.Value, 0.0)
# create a new matrix with the rotation angle
rotationAngleMx = FBMatrix()
FBTRSToMatrix(rotationAngleMx, FBVector4d(), rotationAngleAV3, FBSVector())
for i in range(0, t.numOfObjects):
# grab starting position pre rotation of last point
endKeyPositionV4 = t.path[i].PathKeyGet(t.path[i].PathKeyGetCount() - 1)
# create vector as offset from mover
offsetObjectV3 = FBVector3d(endKeyPositionV4[0], endKeyPositionV4[1],
endKeyPositionV4[2]) - mover_end_position
rotatedOffsetObjectV4 = FBVector4d()
# multiply offsetObjectV3 by rotationAngleMx to find new transformed position
FBVectorMatrixMult(rotatedOffsetObjectV4, rotationAngleMx,
FBVector4d(offsetObjectV3[0], offsetObjectV3[1], offsetObjectV3[2], 1.0))
# move back to mover
rotatedObjectV3 = mover_end_position + FBVector3d(rotatedOffsetObjectV4[0],
rotatedOffsetObjectV4[1],
rotatedOffsetObjectV4[2])
# work out difference between prerotate and rotated
translationOffsetV3 = rotatedObjectV3 - FBVector3d(endKeyPositionV4[0], endKeyPositionV4[1],
endKeyPositionV4[2])
# set offsets so pose at end is rotated
yaw_prop = t.pathConstraint[i].PropertyList.Find("Yaw")
if yaw_prop:
yaw_prop.SetAnimated(True)
existing_data = yaw_prop.Data
# set key on first frame
yaw_prop.GetAnimationNode().FCurve.KeyAdd(FBTime(0, 0, 0, t.take_start_frame), existing_data)
# set key on last frame
yaw_prop.GetAnimationNode().FCurve.KeyAdd(FBTime(0, 0, 0, t.take_end_frame),
existing_data + rotationAngleAV3[1])
FlattenKeys(yaw_prop.GetAnimationNode().FCurve)
translation_prop = t.pathConstraint[i].PropertyList.Find("Translation Offset")
if translation_prop:
translation_prop.SetAnimated(True)
existing_data = translation_prop.Data
# set key on first frame
translation_prop.GetAnimationNode().Nodes[0].FCurve.KeyAdd(FBTime(0, 0, 0, t.take_start_frame),
existing_data[0])
translation_prop.GetAnimationNode().Nodes[1].FCurve.KeyAdd(FBTime(0, 0, 0, t.take_start_frame),
existing_data[1])
translation_prop.GetAnimationNode().Nodes[2].FCurve.KeyAdd(FBTime(0, 0, 0, t.take_start_frame),
existing_data[2])
# set key on last frame
translation_prop.GetAnimationNode().Nodes[0].FCurve.KeyAdd(FBTime(0, 0, 0, t.take_end_frame),
existing_data[0] +
translationOffsetV3[0])
translation_prop.GetAnimationNode().Nodes[1].FCurve.KeyAdd(FBTime(0, 0, 0, t.take_end_frame),
existing_data[1] +
translationOffsetV3[1])
translation_prop.GetAnimationNode().Nodes[2].FCurve.KeyAdd(FBTime(0, 0, 0, t.take_end_frame),
existing_data[2] +
translationOffsetV3[2])
for node in translation_prop.GetAnimationNode().Nodes:
FlattenKeys(node.FCurve)
###################################################################################
# Enable Zonal Helper UI
###################################################################################
t.zonalKeyHelper.Enabled = True
t.zonalKeyHelper.ReadOnly = False
###################################################################################
# Zonal Advanced Mode
#
# if mode selected allows user to set both an offset to the moving direction and end heading
# mainly for creating strafing style assets
###################################################################################
if t.zonal_advanced_button.State:
FBSystem().Scene.Evaluate()
print "Zonal Advanced Mode!"
# note. Reverse the angle to match convention
rotationAngleAV3 = FBVector3d(0.0, -t.angle_a.Value, 0.0)
for i in range(0, t.numOfObjects):
# grab starting position pre rotation
startKeyPositionV4 = t.path[i].PathKeyGet(0)
# rotate splines
t.path[i].Rotation = FBVector3d(t.path[i].Rotation[0] + rotationAngleAV3[0],
t.path[i].Rotation[1] + rotationAngleAV3[1],
t.path[i].Rotation[2] + rotationAngleAV3[2])
# have to force a refresh then get key position again. Note, PathKeyGet( 0 ) does not work after rotation, even with a scene refresh. MB bug. Total_GlobalPathEvaluate does work...
FBSystem().Scene.Evaluate()
rotatedKeyPositionV4 = t.path[i].Total_GlobalPathEvaluate(0.0)
# calc difference in new position and use this to set translation offset
offsetV4 = rotatedKeyPositionV4 - startKeyPositionV4
# set offsets so pose at start is the same
yaw_prop = t.pathConstraint[i].PropertyList.Find("Yaw")
if yaw_prop:
yaw_prop.SetAnimated(True)
existing_data = yaw_prop.Data
# set key on first frame
yaw_prop.GetAnimationNode().FCurve.KeyAdd(FBTime(0, 0, 0, t.take_start_frame),
existing_data - rotationAngleAV3[1])
# set key on last frame
yaw_prop.GetAnimationNode().FCurve.KeyAdd(FBTime(0, 0, 0, t.take_end_frame), existing_data)
FlattenKeys(yaw_prop.GetAnimationNode().FCurve)
translation_prop = t.pathConstraint[i].PropertyList.Find("Translation Offset")
if translation_prop:
translation_prop.SetAnimated(True)
existing_data = translation_prop.Data
# set key on first frame
translation_prop.GetAnimationNode().Nodes[0].FCurve.KeyAdd(FBTime(0, 0, 0, t.take_start_frame),
existing_data[0] - offsetV4[0])
translation_prop.GetAnimationNode().Nodes[1].FCurve.KeyAdd(FBTime(0, 0, 0, t.take_start_frame),
existing_data[1] - offsetV4[1])
translation_prop.GetAnimationNode().Nodes[2].FCurve.KeyAdd(FBTime(0, 0, 0, t.take_start_frame),
existing_data[2] - offsetV4[2])
# set key on last frame
translation_prop.GetAnimationNode().Nodes[0].FCurve.KeyAdd(FBTime(0, 0, 0, t.take_end_frame),
existing_data[0])
translation_prop.GetAnimationNode().Nodes[1].FCurve.KeyAdd(FBTime(0, 0, 0, t.take_end_frame),
existing_data[1])
translation_prop.GetAnimationNode().Nodes[2].FCurve.KeyAdd(FBTime(0, 0, 0, t.take_end_frame),
existing_data[2])
for node in translation_prop.GetAnimationNode().Nodes:
FlattenKeys(node.FCurve)
####################################################################################
# incorporate second offset
####################################################################################
# go to end frame and eval
FBPlayerControl().Goto(FBTime(0, 0, 0, t.take_end_frame))
FBSystem().Scene.Evaluate()
# create matrix around mover end position
rotationAngleBV3 = FBVector3d(0.0, -t.angle_b.Value, 0.0)
straferotationAngleAV3 = -rotationAngleAV3 + rotationAngleBV3
pre_strafe_mover_end_pos = FBVector3d()
t.moverObject.GetVector(pre_strafe_mover_end_pos, FBModelTransformationType.kModelTranslation, True)
rotationAngleMx = FBMatrix()
FBTRSToMatrix(rotationAngleMx, FBVector4d(pre_strafe_mover_end_pos[0], pre_strafe_mover_end_pos[1],
pre_strafe_mover_end_pos[2], 0.0), straferotationAngleAV3,
FBSVector())
# go through each object and transform current ws position by rotationAngleMx
# this should give us the position of object as if it had not been rotated by the spline
for i in range(0, t.numOfObjects):
current_ws_obj_pos = FBVector3d()
t.selected_obj[i].GetVector(current_ws_obj_pos, FBModelTransformationType.kModelTranslation, True)
transformed_ws_obj_pos = FBVector4d()
FBVectorMatrixMult(transformed_ws_obj_pos, rotationAngleMx,
FBVector4d(current_ws_obj_pos[0] - pre_strafe_mover_end_pos[0],
current_ws_obj_pos[1] - pre_strafe_mover_end_pos[1],
current_ws_obj_pos[2] - pre_strafe_mover_end_pos[2], 0.0))
final_offset_ws_pos = transformed_ws_obj_pos - FBVector4d(current_ws_obj_pos[0],
current_ws_obj_pos[1],
current_ws_obj_pos[2], 0.0)
# finally set prop values
yaw_prop = t.pathConstraint[i].PropertyList.Find("Yaw")
if yaw_prop:
existing_data = yaw_prop.Data
# update key on last frame to be same as first
yaw_prop.GetAnimationNode().FCurve.Keys[-1].Value = yaw_prop.GetAnimationNode().FCurve.Keys[
0].Value - t.angle_b.Value
translation_prop = t.pathConstraint[i].PropertyList.Find("Translation Offset")
if translation_prop:
existing_data = translation_prop.Data
# update keys on last frame
translation_prop.GetAnimationNode().Nodes[0].FCurve.Keys[-1].Value = final_offset_ws_pos[0]
translation_prop.GetAnimationNode().Nodes[1].FCurve.Keys[-1].Value = final_offset_ws_pos[1]
translation_prop.GetAnimationNode().Nodes[2].FCurve.Keys[-1].Value = final_offset_ws_pos[2]
###################################################################################
# Enable Zonal Helper UI
###################################################################################
t.zonalKeyHelper.Enabled = True
t.zonalKeyHelper.ReadOnly = False
###################################################################################
# update UI
###################################################################################
# turn expressions back on
# ToggleDevices()
t.delete_button.Enabled = True
# prevent user from altering curve steps
t.slider.Enabled = False
t.status.Enabled = False
# prevent user from altering Mode
t.circle_button.Enabled = False
t.spline_button.Enabled = False
t.zonal_start_button.Enabled = False
t.zonal_stop_button.Enabled = False
if t.numOfObjects == 1:
t.pin_button.Caption = "Plot MotionWarp from '" + t.selected_obj_name[0] + "'"
else:
t.pin_button.Caption = "Plot MotionWarp from " + str(t.numOfObjects) + " objects"
###################################################################################
# restore user timeslider
###################################################################################
FBPlayerControl().Goto(FBTime(0, 0, 0, t.current_frame))
t.pinned = True
else:
########################################
# Apply Motionwarp!
########################################
# if user has selected character mode then simply plot current character
if t.plot_mode_dropdown.Items[t.plot_mode_dropdown.ItemIndex] == "Plot Character":
current_character = FBApplication().CurrentCharacter
plotToSkeleton( current_character )
# else plot each individual selected node
else:
clearSelection()
for j in range(0, t.numOfObjects):
# plot selected object
t.selected_obj[j].Selected = True
FBSystem().CurrentTake.PlotTakeOnSelected(plotOptions())
# eval scene following plot
FBSystem().Scene.Evaluate()
# if we were in a zonal mode store the settings to custom properties
if t.zonal_start_button.State or t.zonal_stop_button.State or t.zonal_advanced_button.State:
storeZonalValues()
if t.zonal_start_button.State or t.zonal_stop_button.State or t.zonal_advanced_button.State:
if hasattr(t, 'zonal'):
closeZonalHelperWindow()
# and we're done...
cleanupAndReset()
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 RotateVectorRadians(vector, radians):
ca = math.cos(radians)
sa = math.sin(radians)
return FBVector3d(ca * vector[0] - sa * vector[1], sa * vector[0] + ca * vector[1], vector[2])
####################################################################
# UI definition
####################################################################
def PopulateTool(t):
# get selected object
models = FBModelList()
FBGetSelectedModels(models)
t.selected_obj = []
t.selected_obj_name = []
parseMotionWarpXML(t)
if len(models) == 0:
FBMessageBox("Message", "Nothing selected", "OK", None, None)
elif t.XMLRead == False:
print str(t.XMLRead)
FBMessageBox("Message", ("Could not find: " + t.motionWarpPath), "OK", None, None)
else:
# set up arrays
t.null = []
t.midNull = []
t.pathNull = []
t.path = []
t.pathConstraint = []
t.midNullConstraint = []
t.constraint = []
ui_x_offset = 5
ui_y_offset = 5
ui_x_width = 240
ui_button_height = 30
ui_button_width = 40
ui_column_a = 20
ui_column_b = 110
ui_column_c = 100
for obj in models:
t.selected_obj.append(obj)
t.selected_obj_name.append(obj.Name)
t.numOfObjects = len(models)
# Pin button
x = FBAddRegionParam(ui_x_offset, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("go_button_region", "go_button_region", x, y, w, h)
t.pin_button = FBButton()
t.SetControl("go_button_region", t.pin_button)
t.pin_button.Visible = True
t.pin_button.ReadOnly = False
t.pin_button.Enabled = True
t.pin_button.Hint = ""
if t.numOfObjects == 1:
t.pin_button.Caption = "Apply MotionWarp to '" + t.selected_obj_name[0] + "'"
else:
t.pin_button.Caption = "Apply MotionWarp to " + str(t.numOfObjects) + " objects"
t.pin_button.State = 0
t.pin_button.Style = FBButtonStyle.kFBPushButton
t.pin_button.Justify = FBTextJustify.kFBTextJustifyCenter
t.pin_button.Look = FBButtonLook.kFBLookNormal
t.pin_button.OnClick.Add(goButtonCallBack)
# set pin state
t.pinned = False
# Delete button
ui_y_offset += 35
x = FBAddRegionParam(ui_x_offset, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("delete_button_region", "delete_button_region", x, y, w, h)
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 = False
t.delete_button.Hint = ""
if t.numOfObjects == 1:
t.delete_button.Caption = "Delete MotionWarp from '" + t.selected_obj_name[0] + "'"
else:
t.delete_button.Caption = "Delete MotionWarp from " + str(t.numOfObjects) + " objects"
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(deleteButtonCallBack)
##########################################################################################
# Mode Border and Controls
##########################################################################################
ui_y_offset += 40
x = FBAddRegionParam(ui_x_offset, FBAttachType.kFBAttachNone, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(100, FBAttachType.kFBAttachNone, "")
t.AddRegion("mode_border", "Mode", x, y, w, h)
t.SetBorder("mode_border", FBBorderStyle.kFBEmbossBorder, True, True, 2, 0, 90.0, 0)
ui_y_offset += 5
# Buttons
x = FBAddRegionParam(ui_column_a, FBAttachType.kFBAttachTop, "circle_button")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(90, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("circle_button", "circle_button", x, y, w, h)
t.circle_button = FBButton()
t.SetControl("circle_button", t.circle_button)
t.circle_button.Visible = True
t.circle_button.ReadOnly = False
t.circle_button.Enabled = True
t.circle_button.Hint = ""
t.circle_button.Caption = "Turn Circle"
t.circle_button.State = 1
t.circle_button.Style = FBButtonStyle.kFBRadioButton
t.circle_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.circle_button.Look = FBButtonLook.kFBLookNormal
t.circle_button.OnClick.Add(modeButtonsCallback)
x = FBAddRegionParam(ui_column_b, FBAttachType.kFBAttachTop, "spline_button")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(90, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("spline_button", "spline_button", x, y, w, h)
t.spline_button = FBButton()
t.SetControl("spline_button", t.spline_button)
t.spline_button.Visible = True
t.spline_button.ReadOnly = False
t.spline_button.Enabled = True
t.spline_button.Hint = ""
t.spline_button.Caption = "Spline"
t.spline_button.State = 0
t.spline_button.Style = FBButtonStyle.kFBRadioButton
t.spline_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.spline_button.Look = FBButtonLook.kFBLookNormal
t.spline_button.OnClick.Add(modeButtonsCallback)
ui_y_offset += 30
x = FBAddRegionParam(ui_column_a, FBAttachType.kFBAttachTop, "zonal_start")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(90, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("zonal_start", "zonal_start", x, y, w, h)
t.zonal_start_button = FBButton()
t.SetControl("zonal_start", t.zonal_start_button)
t.zonal_start_button.Visible = True
t.zonal_start_button.ReadOnly = False
t.zonal_start_button.Enabled = True
t.zonal_start_button.Hint = ""
t.zonal_start_button.Caption = "Zonal Start"
t.zonal_start_button.State = 0
t.zonal_start_button.Style = FBButtonStyle.kFBRadioButton
t.zonal_start_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.zonal_start_button.Look = FBButtonLook.kFBLookNormal
t.zonal_start_button.OnClick.Add(modeButtonsCallback)
x = FBAddRegionParam(ui_column_b, FBAttachType.kFBAttachTop, "zonal_stop")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width / 2 + 10, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("zonal_stop", "zonal_stop", x, y, w, h)
t.zonal_stop_button = FBButton()
t.SetControl("zonal_stop", t.zonal_stop_button)
t.zonal_stop_button.Visible = True
t.zonal_stop_button.ReadOnly = False
t.zonal_stop_button.Enabled = True
t.zonal_stop_button.Hint = ""
t.zonal_stop_button.Caption = "Zonal Stop / Idle Turn"
t.zonal_stop_button.State = 0
t.zonal_stop_button.Style = FBButtonStyle.kFBRadioButton
t.zonal_stop_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.zonal_stop_button.Look = FBButtonLook.kFBLookNormal
t.zonal_stop_button.OnClick.Add(modeButtonsCallback)
t.mode_radio_buttons = FBButtonGroup()
t.mode_radio_buttons.Add(t.circle_button)
t.mode_radio_buttons.Add(t.spline_button)
t.mode_radio_buttons.Add(t.zonal_start_button)
t.mode_radio_buttons.Add(t.zonal_stop_button)
ui_y_offset += 30
x = FBAddRegionParam(ui_column_a, FBAttachType.kFBAttachTop, "zonal_advanced")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width / 2 + 10, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("zonal_advanced", "zonal_advanced", x, y, w, h)
t.zonal_advanced_button = FBButton()
t.SetControl("zonal_advanced", t.zonal_advanced_button)
t.zonal_advanced_button.Visible = True
t.zonal_advanced_button.ReadOnly = False
t.zonal_advanced_button.Enabled = True
t.zonal_advanced_button.Hint = "Allows user to set both Moving Direction and Heading Direction offset."
t.zonal_advanced_button.Caption = "Zonal Advanced"
t.zonal_advanced_button.State = 0
t.zonal_advanced_button.Style = FBButtonStyle.kFBRadioButton
t.zonal_advanced_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.zonal_advanced_button.Look = FBButtonLook.kFBLookNormal
t.zonal_advanced_button.OnClick.Add(modeButtonsCallback)
t.mode_radio_buttons = FBButtonGroup()
t.mode_radio_buttons.Add(t.circle_button)
t.mode_radio_buttons.Add(t.spline_button)
t.mode_radio_buttons.Add(t.zonal_start_button)
t.mode_radio_buttons.Add(t.zonal_stop_button)
t.mode_radio_buttons.Add(t.zonal_advanced_button)
##########################################################################################
# Circle Options Border
##########################################################################################
ui_y_offset += 50
x = FBAddRegionParam(ui_x_offset, FBAttachType.kFBAttachNone, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(170, FBAttachType.kFBAttachNone, "")
t.AddRegion("circle_border", "Circle Radius & Direction", x, y, w, h)
t.SetBorder("circle_border", FBBorderStyle.kFBEmbossBorder, True, True, 2, 0, 90.0, 0)
##########################################################################################
# Circle Options
##########################################################################################
ui_y_offset += 10
# MODE
x = FBAddRegionParam(ui_column_a, FBAttachType.kFBAttachTop, "radius_mode_button")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(90, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("radius_mode_button", "radius_mode_button", x, y, w, h)
t.radius_mode_button = FBButton()
t.SetControl("radius_mode_button", t.radius_mode_button)
t.radius_mode_button.Visible = True
t.radius_mode_button.ReadOnly = False
t.radius_mode_button.Enabled = True
t.radius_mode_button.Hint = "User defines radius of circle in Metres."
t.radius_mode_button.Caption = "Radius"
t.radius_mode_button.State = 1
t.radius_mode_button.Style = FBButtonStyle.kFBRadioButton
t.radius_mode_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.radius_mode_button.Look = FBButtonLook.kFBLookNormal
t.radius_mode_button.OnClick.Add(radiusModeButtonsCallback)
x = FBAddRegionParam(85, FBAttachType.kFBAttachTop, "manual_AV_mode_button")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(80, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("manual_AV_mode_button", "manual_AV_mode_button", x, y, w, h)
t.manual_AV_mode_button = FBButton()
t.SetControl("manual_AV_mode_button", t.manual_AV_mode_button)
t.manual_AV_mode_button.Visible = True
t.manual_AV_mode_button.ReadOnly = False
t.manual_AV_mode_button.Enabled = True
t.manual_AV_mode_button.Hint = "Radius of turn its automatically generated based on average velocity to create a wide turning circle."
t.manual_AV_mode_button.Caption = "Manual A.V."
t.manual_AV_mode_button.State = 0
t.manual_AV_mode_button.Style = FBButtonStyle.kFBRadioButton
t.manual_AV_mode_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.manual_AV_mode_button.Look = FBButtonLook.kFBLookNormal
t.manual_AV_mode_button.OnClick.Add(radiusModeButtonsCallback)
x = FBAddRegionParam(170, FBAttachType.kFBAttachTop, "auto_AV_mode_button")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(70, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("auto_AV_mode_button", "auto_AV_mode_button", x, y, w, h)
t.auto_AV_mode_button = FBButton()
t.SetControl("auto_AV_mode_button", t.auto_AV_mode_button)
t.auto_AV_mode_button.Visible = True
t.auto_AV_mode_button.ReadOnly = False
t.auto_AV_mode_button.Enabled = True
t.auto_AV_mode_button.Hint = "Radius of turn its automatically generated based on average velocity to create a tight turning circle."
t.auto_AV_mode_button.Caption = "Auto A.V."
t.auto_AV_mode_button.State = 0
t.auto_AV_mode_button.Style = FBButtonStyle.kFBRadioButton
t.auto_AV_mode_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.auto_AV_mode_button.Look = FBButtonLook.kFBLookNormal
t.auto_AV_mode_button.OnClick.Add(radiusModeButtonsCallback)
t.circle_direction_radio_buttons = FBButtonGroup()
t.circle_direction_radio_buttons.Add(t.manual_AV_mode_button)
t.circle_direction_radio_buttons.Add(t.auto_AV_mode_button)
t.circle_direction_radio_buttons.Add(t.radius_mode_button)
ui_y_offset += 35
x = FBAddRegionParam(ui_x_offset + 5, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width - 10, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(20, FBAttachType.kFBAttachNone, "")
t.AddRegion("radius_edit", "radius_edit", x, y, w, h)
t.radius = FBEditNumber()
t.SetControl("radius_edit", t.radius)
# t.radius.Justify = FBTextJustify.kFBTextJustifyLeft
t.radius.Visible = True
t.radius.ReadOnly = False
t.radius.Enabled = True
t.radius.Value = 1.0
t.radius.Hint = "Radius of circle in Metres"
t.radius.Min = 0.0
ui_y_offset += 30
# Drop Down
x = FBAddRegionParam(ui_x_offset + 5, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width - 10, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(25, FBAttachType.kFBAttachNone, "")
t.AddRegion("dropdown", "dropdown", x, y, w, h)
t.dropDownList = FBList()
t.SetControl("dropdown", t.dropDownList)
setupTurnParameterList(t)
t.dropDownList.Enabled = False
t.dropDownList.ReadOnly = True
ui_y_offset += 30
# Buttons
x = FBAddRegionParam(ui_column_a, FBAttachType.kFBAttachTop, "small_turn_button")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(90, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("small_turn_button", "small_turn_button", x, y, w, h)
t.small_turn_button = FBButton()
t.SetControl("small_turn_button", t.small_turn_button)
t.small_turn_button.Visible = True
t.small_turn_button.ReadOnly = False
t.small_turn_button.Enabled = False
t.small_turn_button.Hint = "Create a turn normally used for L2 and R2"
t.small_turn_button.Caption = "Small Turn"
t.small_turn_button.State = 1
t.small_turn_button.Style = FBButtonStyle.kFBRadioButton
t.small_turn_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.small_turn_button.Look = FBButtonLook.kFBLookNormal
x = FBAddRegionParam(ui_column_b, FBAttachType.kFBAttachTop, "large_turn_button")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(90, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("large_turn_button", "large_turn_button", x, y, w, h)
t.large_turn_button = FBButton()
t.SetControl("large_turn_button", t.large_turn_button)
t.large_turn_button.Visible = True
t.large_turn_button.ReadOnly = False
t.large_turn_button.Enabled = False
t.large_turn_button.Hint = "Create a turn normally used for L1 and R1"
t.large_turn_button.Caption = "Large Turn"
t.large_turn_button.State = 0
t.large_turn_button.Style = FBButtonStyle.kFBRadioButton
t.large_turn_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.large_turn_button.Look = FBButtonLook.kFBLookNormal
t.turn_radius = FBButtonGroup()
t.turn_radius.Add(t.small_turn_button)
t.turn_radius.Add(t.large_turn_button)
ui_y_offset += 30
# Buttons
x = FBAddRegionParam(ui_column_a, FBAttachType.kFBAttachTop, "clockwise_button")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(90, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("clockwise_button", "clockwise_button", x, y, w, h)
t.clockwise_button = FBButton()
t.SetControl("clockwise_button", t.clockwise_button)
t.clockwise_button.Visible = True
t.clockwise_button.ReadOnly = False
t.clockwise_button.Enabled = True
t.clockwise_button.Hint = ""
t.clockwise_button.Caption = "Clock"
t.clockwise_button.State = 1
t.clockwise_button.Style = FBButtonStyle.kFBRadioButton
t.clockwise_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.clockwise_button.Look = FBButtonLook.kFBLookNormal
x = FBAddRegionParam(ui_column_b, FBAttachType.kFBAttachTop, "counterclockwise_button")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(90, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("counterclockwise_button", "counterclockwise_button", x, y, w, h)
t.counter_button = FBButton()
t.SetControl("counterclockwise_button", t.counter_button)
t.counter_button.Visible = True
t.counter_button.ReadOnly = False
t.counter_button.Enabled = True
t.counter_button.Hint = ""
t.counter_button.Caption = "Counter"
t.counter_button.State = 0
t.counter_button.Style = FBButtonStyle.kFBRadioButton
t.counter_button.Justify = FBTextJustify.kFBTextJustifyLeft
t.counter_button.Look = FBButtonLook.kFBLookNormal
t.circle_direction_radio_buttons = FBButtonGroup()
t.circle_direction_radio_buttons.Add(t.clockwise_button)
t.circle_direction_radio_buttons.Add(t.counter_button)
##########################################################################################
# Spline Points Border
##########################################################################################
ui_y_offset += 50
x = FBAddRegionParam(ui_x_offset, FBAttachType.kFBAttachNone, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(60, FBAttachType.kFBAttachNone, "")
t.AddRegion("spline_border", "Spline Points", x, y, w, h)
t.SetBorder("spline_border", FBBorderStyle.kFBEmbossBorder, True, True, 2, 0, 90.0, 0)
##########################################################################################
# Spline Points Options
##########################################################################################
ui_y_offset += 15
x = FBAddRegionParam(ui_x_offset + 5, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width - 10, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(20, FBAttachType.kFBAttachNone, "")
t.AddRegion("slider", "slider", x, y, w, h)
t.slider = FBSlider()
t.slider.Value = 0.0
t.slider.ReadOnly = True
t.slider.Enabled = False
t.slider.Orientation = FBOrientation.kFBHorizontal
t.slider.OnTransaction.Add(sliderUpdated)
t.SetControl("slider", t.slider)
# Curve Points Label
ui_y_offset += 25
x = FBAddRegionParam(ui_x_offset + 5, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width - 10, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(20, FBAttachType.kFBAttachNone, "")
t.AddRegion("status_region", "status_region", x, y, w, h)
t.status = FBLabel()
t.SetControl("status_region", t.status)
t.status.Justify = FBTextJustify.kFBTextJustifyCenter
t.status.Visible = True
t.status.ReadOnly = False
t.status.Enabled = False
t.status.Caption = "2"
##########################################################################################
# Zonal Angle Border
##########################################################################################
ui_y_offset += 35
x = FBAddRegionParam(ui_x_offset, FBAttachType.kFBAttachNone, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(100, FBAttachType.kFBAttachNone, "")
t.AddRegion("zonal_angle_border", "Zonal Angle Offset", x, y, w, h)
t.SetBorder("zonal_angle_border", FBBorderStyle.kFBEmbossBorder, True, True, 2, 0, 90.0, 0)
ui_y_offset += 15
x = FBAddRegionParam(ui_x_offset + 5, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width - 10, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(20, FBAttachType.kFBAttachNone, "")
t.AddRegion("angle_a_edit", "angle_a_edit", x, y, w, h)
t.angle_a = FBEditNumber()
t.SetControl("angle_a_edit", t.angle_a)
# t.angle_a.Justify = FBTextJustify.kFBTextJustifyLeft
t.angle_a.Visible = True
t.angle_a.Hint = "Angle to offset is relative to Mover orientation for start and stop."
t.angle_a.ReadOnly = True
t.angle_a.Enabled = False
t.angle_a.Value = 0.0
t.angle_a.Min = -180.0
t.angle_a.Max = 180.0
ui_y_offset += 25
x = FBAddRegionParam(ui_x_offset + 5, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width - 10, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(20, FBAttachType.kFBAttachNone, "")
t.AddRegion("angle_b_edit", "angle_b_edit", x, y, w, h)
t.angle_b = FBEditNumber()
t.SetControl("angle_b_edit", t.angle_b)
# t.angle_b.Justify = FBTextJustify.kFBTextJustifyLeft
t.angle_b.Visible = True
t.angle_b.Hint = "Secondary Angle for Advanced mode only."
t.angle_b.ReadOnly = True
t.angle_b.Enabled = False
t.angle_b.Value = 0.0
t.angle_b.Min = -180.0
t.angle_b.Max = 180.0
ui_y_offset += 30
##########################################################################################
# Zonal Key Helper
##########################################################################################
x = FBAddRegionParam(ui_x_offset + 5, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width - 10, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(20, FBAttachType.kFBAttachNone, "")
t.AddRegion("zonal_key_helper", "zonal_key_helper", x, y, w, h)
t.zonalKeyHelper = FBButton()
t.SetControl("zonal_key_helper", t.zonalKeyHelper)
t.zonalKeyHelper.Visible = True
t.zonalKeyHelper.ReadOnly = False
t.zonalKeyHelper.Enabled = False
t.zonalKeyHelper.Hint = "Will launch a seperate window to aid with key placement."
t.zonalKeyHelper.Caption = "Zonal Key Helper"
t.zonalKeyHelper.Style = FBButtonStyle.kFBPushButton
t.zonalKeyHelper.Justify = FBTextJustify.kFBTextJustifyCenter
t.zonalKeyHelper.Look = FBButtonLook.kFBLookNormal
t.zonalKeyHelper.OnClick.Add(zonalKeyHelperCallBack)
##########################################################################################
# Advanced Settings/Plot Mode
##########################################################################################
ui_y_offset += 45
x = FBAddRegionParam(ui_x_offset, FBAttachType.kFBAttachNone, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(70, FBAttachType.kFBAttachNone, "")
t.AddRegion("advanced_settings_border", "Advanced Settings", x, y, w, h)
t.SetBorder("advanced_settings_border", FBBorderStyle.kFBEmbossBorder, True, True, 2, 0, 90.0, 0)
ui_y_offset += 10
# Drop Down
x = FBAddRegionParam(ui_x_offset + 5, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width - 10, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(25, FBAttachType.kFBAttachNone, "")
t.AddRegion("advanced_settings_dropdown", "advanced_settings_dropdown", x, y, w, h)
t.advanced_settings_dropdown = FBList()
t.SetControl("advanced_settings_dropdown", t.advanced_settings_dropdown)
setupAdvancedSettingsList(t)
t.advanced_settings_dropdown.Enabled = False
t.advanced_settings_dropdown.ReadOnly = True
ui_y_offset += 30
# Drop Down
x = FBAddRegionParam(ui_x_offset + 5, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width - 10, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(25, FBAttachType.kFBAttachNone, "")
t.AddRegion("plot_mode_dropdown", "plot_mode_dropdown", x, y, w, h)
t.plot_mode_dropdown = FBList()
t.plot_mode_dropdown.Hint = "Defines how results are plotted down. \n\n Plot Character means it will use the current character as defined in the Character Controls window and plot from rig down to skeleton.\n\n Plot Selected Nodes will treat each selected object seperately and plot each node. This is necessary when runnning on non-character entities."
t.SetControl("plot_mode_dropdown", t.plot_mode_dropdown)
setupPlotModeList(t)
##########################################################################################
# Calculate Tool Window Size and Draw
##########################################################################################
t.StartSizeX = 267
t.StartSizeY = ui_y_offset + 70
ShowTool(t)
####################################################################
# Zonal Methods
####################################################################
def PhaseToKeyFrame(phase):
frame = t.take_start_frame + ((t.take_end_frame - t.take_start_frame) * phase)
return frame
def KeyFrameToPhase(keyframe):
phase = float(keyframe - t.take_start_frame) / float(t.take_end_frame - t.take_start_frame)
return phase
####################################################################
# Zonal UI callbacks
####################################################################
def ScaleFCurveTime(pFCurve, pTimePivot, pScaleValue, offset):
lPivotDouble = pTimePivot.GetSecondDouble()
lTime = FBTime(0)
for lKey in pFCurve.Keys:
lTime.SetSecondDouble(lPivotDouble + (lKey.Time.GetSecondDouble() - lPivotDouble) * pScaleValue)
lTime += FBTime(0, 0, 0, int(offset))
lKey.Time = lTime
def Scale(pAnimationNode, pTimePivot, pScaleValue, offset):
if len(pAnimationNode.Nodes) == 0:
ScaleFCurveTime(pAnimationNode.FCurve, pTimePivot, pScaleValue, offset)
else:
for lNode in pAnimationNode.Nodes:
Scale(lNode, pTimePivot, pScaleValue, offset)
def zonalSliderUpdated(control, event=''):
properties = ['Yaw', 'Translation Offset/X', 'Translation Offset/Y', 'Translation Offset/Z']
# if start slider, make sure end slider isn't any lower in value
if control.StartSlider:
if t.zonal.startSlider[control.Id].Value >= t.zonal.endSlider[control.Id].Value:
t.zonal.startSlider[control.Id].Value = t.zonal.endSlider[control.Id].Value - KeyFrameToPhase(
t.take_start_frame + 1)
# if end slider, make sure start slider isn't any higher in value
else:
if t.zonal.endSlider[control.Id].Value <= t.zonal.startSlider[control.Id].Value:
t.zonal.endSlider[control.Id].Value = t.zonal.startSlider[control.Id].Value + KeyFrameToPhase(
t.take_start_frame + 1)
# calculate new times for yaw and translation offset based on slider positions
new_start_frame = int(PhaseToKeyFrame(t.zonal.startSlider[control.Id].Value))
new_end_frame = int(PhaseToKeyFrame(t.zonal.endSlider[control.Id].Value))
old_start_frame = int(t.zonal.startSlider[control.Id].range_min)
old_end_frame = int(t.zonal.endSlider[control.Id].range_max)
diff_start_frame = int(new_start_frame - old_start_frame)
# make sure we're not setting invalid times by making end frame always more than start
if new_end_frame <= new_start_frame:
new_end_frame += 1
# new desired slider range
desired_range = new_end_frame - new_start_frame
# existing range
existing_range = old_end_frame - old_start_frame
# new scale ratio
scale_ratio = float(desired_range) / existing_range
# scale all keys in fcurve for each property on constraint
for property in properties:
animation_node = FindPropertyAnimationNode(property, t.pathConstraint[control.Id])
Scale(animation_node, FBTime(0, 0, 0, old_start_frame), scale_ratio, diff_start_frame)
'''
DEBUG
for key in animation_node.FCurve.Keys:
print "key.LeftTangentWeight is " + str(key.LeftTangentWeight)
print "key.RightTangentWeight is " + str(key.RightTangentWeight)
print "key.Interpolation is " + str(key.Interpolation)
print "key.LeftDerivative is " + str(key.LeftDerivative)
print "key.RightDerivative is " + str(key.RightDerivative)
print "key.TangentConstantMode is " + str(key.TangentConstantMode)
print "key.TangentMode is " + str(key.TangentMode)
'''
# update edit boxes
t.zonal.startEdit[control.Id].Value = new_start_frame
t.zonal.endEdit[control.Id].Value = new_end_frame
t.zonal.endSlider[control.Id].range_max = new_end_frame
t.zonal.startSlider[control.Id].range_min = new_start_frame
def zonalEditUpdated(control, event=''):
if control.StartEdit:
if t.zonal.startEdit[control.Id].Value >= t.zonal.endEdit[control.Id].Value:
t.zonal.startEdit[control.Id].Value = t.zonal.endEdit[control.Id].Value - 1
t.zonal.startSlider[control.Id].Value = KeyFrameToPhase(control.Value)
zonalSliderUpdated(t.zonal.startSlider[control.Id])
else:
if t.zonal.endEdit[control.Id].Value <= t.zonal.startEdit[control.Id].Value:
t.zonal.endEdit[control.Id].Value = t.zonal.startEdit[control.Id].Value + 1
t.zonal.endSlider[control.Id].Value = KeyFrameToPhase(control.Value)
zonalSliderUpdated(t.zonal.endSlider[control.Id])
def zonalEditButtonClicked(control, event):
current_keyframe = FBSystem().LocalTime.GetFrame()
if control.StartEditButton:
t.zonal.startSlider[control.Id].Value = KeyFrameToPhase(current_keyframe)
# force slider callback
zonalSliderUpdated(t.zonal.startSlider[control.Id])
t.zonal.startEdit[control.Id].Value = current_keyframe
else:
t.zonal.endSlider[control.Id].Value = KeyFrameToPhase(current_keyframe)
# force slider callback
zonalSliderUpdated(t.zonal.endSlider[control.Id])
t.zonal.endEdit[control.Id].Value = current_keyframe
def fcurveButtonClicked(control, event):
# select pathconstraint
clearSelection()
t.pathConstraint[control.Id].Selected = True
# add constraint offset animation nodes
yaw_prop = t.pathConstraint[control.Id].PropertyList.Find("Yaw")
if yaw_prop:
# select custom property
yaw_prop.SetFocus(True)
translation_prop = t.pathConstraint[control.Id].PropertyList.Find("Translation Offset")
if translation_prop:
# select custom property
translation_prop.SetFocus(True)
# close zonal key helper window ( to avoid sync issues )
if t.zonal_start_button.State or t.zonal_stop_button.State:
if hasattr(t, 'zonal'):
closeZonalHelperWindow()
ShowToolByName("FCurve")
def zonalRestoreButtonClicked(control, event):
restoreZonalValues()
# update UI
for i in range(len(t.zonal.startSlider)):
new_start_frame = t.zonal.startSlider[i].range_min
new_end_frame = t.zonal.endSlider[i].range_max
new_start_phase = KeyFrameToPhase(new_start_frame)
new_end_phase = KeyFrameToPhase(new_end_frame)
t.zonal.startEdit[i].Value = new_start_frame
t.zonal.endEdit[i].Value = new_end_frame
t.zonal.startSlider[i].Value = new_start_phase
t.zonal.endSlider[i].Value = new_end_phase
####################################################################
# Zonal UI definition
####################################################################
def PopulateZonalUI(zonal):
t.zonal.startSlider = []
t.zonal.startEdit = []
t.zonal.startEditButton = []
t.zonal.endSlider = []
t.zonal.endEdit = []
t.zonal.endEditButton = []
t.zonal.fcurveButton = []
ui_x_offset = 10
ui_y_offset = 10
slider_height = 15
slider_width = 275
phase_box_width = 30
border_offset = 0
key_button_width = 15
fcurve_button_width = 25
ui_x_width = slider_width + phase_box_width + key_button_width + 8
ui_y_height = 40
object_counter = 0
for object in t.selected_obj_name:
start_frame = t.take_start_frame
end_frame = t.take_end_frame
# fetch any exisiting values in case window has been in previous use
# use yaw property as start/end guide though we could use any other properties
yaw_prop = t.pathConstraint[object_counter].PropertyList.Find("Yaw")
if yaw_prop:
start_frame = yaw_prop.GetAnimationNode().FCurve.Keys[0].Time.GetFrame()
end_frame = yaw_prop.GetAnimationNode().FCurve.Keys[-1].Time.GetFrame()
##########################################################################################
# Border
##########################################################################################
object_counter_str = str(object_counter)
x = FBAddRegionParam(ui_x_offset, FBAttachType.kFBAttachNone, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(slider_height * 3 + 10, FBAttachType.kFBAttachNone, "")
t.zonal.AddRegion("object_border" + object_counter_str, object, x, y, w, h)
t.zonal.SetBorder("object_border" + object_counter_str, FBBorderStyle.kFBEmbossBorder, True, True, 2, 0, 90.0,
0)
border_offset = ui_y_offset
##########################################################################################
# Start Slider
##########################################################################################
# add slider for start phase
ui_y_offset += slider_height
x = FBAddRegionParam(ui_x_offset + 5, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(slider_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(slider_height, FBAttachType.kFBAttachNone, "")
t.zonal.AddRegion("start_slider" + object_counter_str, "start_slider" + object_counter_str, x, y, w, h)
t.zonal.startSlider.append(FBSlider())
# add id to slider
t.zonal.startSlider[object_counter].Id = object_counter
t.zonal.startSlider[object_counter].StartSlider = True
t.zonal.startSlider[object_counter].Value = KeyFrameToPhase(start_frame)
t.zonal.startSlider[object_counter].range_min = start_frame
t.zonal.startSlider[object_counter].ReadOnly = False
t.zonal.startSlider[object_counter].Enabled = True
t.zonal.startSlider[object_counter].Orientation = FBOrientation.kFBHorizontal
t.zonal.startSlider[object_counter].OnTransaction.Add(zonalSliderUpdated)
t.zonal.SetControl("start_slider" + object_counter_str, t.zonal.startSlider[object_counter])
##########################################################################################
# Start Edit
##########################################################################################
# add edit box
x = FBAddRegionParam(slider_width + 10, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(phase_box_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(slider_height, FBAttachType.kFBAttachNone, "")
t.zonal.AddRegion("start_edit" + object_counter_str, "start_edit" + object_counter_str, x, y, w, h)
t.zonal.startEdit.append(FBEditNumber())
t.zonal.startEdit[object_counter].Id = object_counter
t.zonal.startEdit[object_counter].StartEdit = True
t.zonal.startEdit[object_counter].Visible = True
t.zonal.startEdit[object_counter].ReadOnly = False
t.zonal.startEdit[object_counter].Enabled = True
t.zonal.startEdit[object_counter].Precision = 0
t.zonal.startEdit[object_counter].Min = t.take_start_frame
t.zonal.startEdit[object_counter].Max = t.take_end_frame
t.zonal.startEdit[object_counter].Value = start_frame
t.zonal.SetControl("start_edit" + object_counter_str, t.zonal.startEdit[object_counter])
t.zonal.startEdit[object_counter].OnChange.Add(zonalEditUpdated)
##########################################################################################
# Start Edit Button
##########################################################################################
# add edit box
x = FBAddRegionParam(slider_width + 12 + phase_box_width, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(key_button_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(slider_height, FBAttachType.kFBAttachNone, "")
t.zonal.AddRegion("start_button" + object_counter_str, "start_button" + object_counter_str, x, y, w, h)
t.zonal.startEditButton.append(FBButton())
t.zonal.startEditButton[object_counter].Id = object_counter
t.zonal.startEditButton[object_counter].StartEditButton = True
t.zonal.startEditButton[object_counter].Visible = True
t.zonal.startEditButton[object_counter].ReadOnly = False
t.zonal.startEditButton[object_counter].Enabled = True
t.zonal.startEditButton[object_counter].Caption = '<'
t.zonal.startEditButton[object_counter].Hint = 'Set keyframe value to be the same as timeslider.'
t.zonal.SetControl("start_button" + object_counter_str, t.zonal.startEditButton[object_counter])
t.zonal.startEditButton[object_counter].OnClick.Add(zonalEditButtonClicked)
##########################################################################################
# End Slider
##########################################################################################
# add slider for end phase
ui_y_offset += slider_height
x = FBAddRegionParam(ui_x_offset + 5, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(slider_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(slider_height, FBAttachType.kFBAttachNone, "")
t.zonal.AddRegion("end_slider" + object_counter_str, "end_slider" + object_counter_str, x, y, w, h)
t.zonal.endSlider.append(FBSlider())
t.zonal.endSlider[object_counter].Id = object_counter
t.zonal.endSlider[object_counter].StartSlider = False
t.zonal.endSlider[object_counter].Value = KeyFrameToPhase(end_frame)
t.zonal.endSlider[object_counter].range_max = end_frame
t.zonal.endSlider[object_counter].ReadOnly = False
t.zonal.endSlider[object_counter].Enabled = True
t.zonal.endSlider[object_counter].Orientation = FBOrientation.kFBHorizontal
t.zonal.endSlider[object_counter].OnTransaction.Add(zonalSliderUpdated)
t.zonal.SetControl("end_slider" + object_counter_str, t.zonal.endSlider[object_counter])
##########################################################################################
# End Edit
##########################################################################################
# add edit box
x = FBAddRegionParam(slider_width + 10, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(phase_box_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(slider_height, FBAttachType.kFBAttachNone, "")
t.zonal.AddRegion("end_edit" + object_counter_str, "end_edit" + object_counter_str, x, y, w, h)
t.zonal.endEdit.append(FBEditNumber())
t.zonal.endEdit[object_counter].Id = object_counter
t.zonal.endEdit[object_counter].StartEdit = False
t.zonal.endEdit[object_counter].Visible = True
t.zonal.endEdit[object_counter].ReadOnly = False
t.zonal.endEdit[object_counter].Enabled = True
t.zonal.endEdit[object_counter].Value = end_frame
t.zonal.endEdit[object_counter].Precision = 0
t.zonal.endEdit[object_counter].Min = t.take_start_frame
t.zonal.endEdit[object_counter].Max = t.take_end_frame
t.zonal.endEdit[object_counter].Value = PhaseToKeyFrame(t.zonal.endSlider[object_counter].Value)
t.zonal.SetControl("end_edit" + object_counter_str, t.zonal.endEdit[object_counter])
t.zonal.endEdit[object_counter].OnChange.Add(zonalEditUpdated)
##########################################################################################
# End Edit Button
##########################################################################################
# add edit box
x = FBAddRegionParam(slider_width + 12 + phase_box_width, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(key_button_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(slider_height, FBAttachType.kFBAttachNone, "")
t.zonal.AddRegion("end_button" + object_counter_str, "end_button" + object_counter_str, x, y, w, h)
t.zonal.endEditButton.append(FBButton())
t.zonal.endEditButton[object_counter].Id = object_counter
t.zonal.endEditButton[object_counter].StartEditButton = False
t.zonal.endEditButton[object_counter].Visible = True
t.zonal.endEditButton[object_counter].ReadOnly = False
t.zonal.endEditButton[object_counter].Enabled = True
t.zonal.endEditButton[object_counter].Caption = '<'
t.zonal.endEditButton[object_counter].Hint = 'Set keyframe value to be the same as timeslider.'
t.zonal.SetControl("end_button" + object_counter_str, t.zonal.endEditButton[object_counter])
t.zonal.endEditButton[object_counter].OnClick.Add(zonalEditButtonClicked)
##########################################################################################
# Fcurve Button
##########################################################################################
# add edit box
x = FBAddRegionParam(slider_width + 12 + phase_box_width + 28, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(border_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(fcurve_button_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(50, FBAttachType.kFBAttachNone, "")
t.zonal.AddRegion("fcurve_button" + object_counter_str, "fcurve_button" + object_counter_str, x, y, w, h)
t.zonal.fcurveButton.append(FBButton())
t.zonal.fcurveButton[object_counter].Id = object_counter
t.zonal.fcurveButton[object_counter].Visible = True
t.zonal.fcurveButton[object_counter].ReadOnly = False
t.zonal.fcurveButton[object_counter].Enabled = True
t.zonal.fcurveButton[object_counter].Caption = '~'
t.zonal.fcurveButton[
object_counter].Hint = 'Open curve editor window for finer control with relevant properties.'
t.zonal.SetControl("fcurve_button" + object_counter_str, t.zonal.fcurveButton[object_counter])
t.zonal.fcurveButton[object_counter].OnClick.Add(fcurveButtonClicked)
##########################################################################################
# Next object in UI loop
##########################################################################################
ui_y_offset += slider_height * 2 + 10
object_counter += 1
##########################################################################################
# Restore Button
##########################################################################################
ui_y_offset -= 5
x = FBAddRegionParam(ui_x_offset, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(slider_height + 5, FBAttachType.kFBAttachNone, "")
t.zonal.AddRegion("restore_button", "restore_button", x, y, w, h)
t.zonal.restoreButton = FBButton()
t.zonal.SetControl("restore_button", t.zonal.restoreButton)
t.zonal.restoreButton.Visible = True
save_file_exists = DoesSaveFileExist()
if save_file_exists:
t.zonal.restoreButton.ReadOnly = False
t.zonal.restoreButton.Enabled = True
t.zonal.restoreButton.Caption = 'Restore previous helper settings'
else:
t.zonal.restoreButton.ReadOnly = False
t.zonal.restoreButton.Enabled = False
t.zonal.restoreButton.Caption = 'Previous helper settings file not found.'
t.zonal.restoreButton.Hint = 'Min/Max keytimes will be restored from previous tool use. Previous settings are saved in ' + tempfile.gettempdir() + '\\motionwarp_save_file.txt'
t.zonal.restoreButton.Style = FBButtonStyle.kFBPushButton
t.zonal.restoreButton.Look = FBButtonLook.kFBLookNormal
t.zonal.restoreButton.OnClick.Add(zonalRestoreButtonClicked)
##########################################################################################
# Calculate Tool Window Size and Draw
##########################################################################################
t.zonal.StartSizeX = ui_x_width + ui_x_offset + fcurve_button_width + 28
t.zonal.StartSizeY = ui_y_offset + 60
ShowTool(zonal)
####################################################################
# Main
####################################################################
def CreateTool():
global t
###################################################################################
# v1.66 - zonal helper keys now default to clamp tangent keys
# v1.67 - mover splines are blue to differentiate them from non-mover objects which are red
###################################################################################
version = 1.67
t = FBCreateUniqueTool("MotionWarp v" + str(version))
PopulateTool(t)
CreateTool()
####################################################################
# Switch to next take at start frame
####################################################################
from pyfbsdk import *
#get current take and increment
num_of_takes = len(FBSystem().Scene.Takes)
for i in range( num_of_takes ):
# go to take
if FBSystem().CurrentTake.Name == FBSystem().Scene.Takes[i].Name:
#increment take if you can
if ( i < ( num_of_takes-1 )):
FBSystem().CurrentTake = FBSystem().Scene.Takes[i + 1]
break
# set time to start
start_frame = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
FBPlayerControl().Goto(FBTime(0, 0, 0, start_frame))
FBSystem().Scene.Evaluate()PNG
from pyfbsdk import *
import subprocess
path, file = os.path.split( FBApplication().FBXFileName )
subprocess.Popen( "explorer " + path )
PNG
####################################################################
# Prints out a relation constraint as text to be scripted
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
import tempfile
class RelationBoxType():
Operator = 1
Receiver = 2
Sender = 3
class RelationBoxOperatorGroup():
Boolean = 'Boolean'
Converters = 'Converters'
Number = 'Number'
Other = 'Other'
Rotation = 'Rotation'
Shapes = 'Shapes'
Sources = 'Sources'
System = 'System'
Time = 'Time'
Vector = 'Vector'
class RelationBoxOperators():
Boolean = {'AND', 'Flip Flop', 'Memory (B1 when REC)', 'Memory (last trigger)', 'NAND', 'NOR', 'NOT', 'OR', 'XNOR', 'XOR' }
Converters = {'Deg To Rad', 'HSB to RGB', 'Number To RGBA', 'Number to Vector', 'Number to Vector2', 'Rad To Deg', 'RGB To HSB', 'RGB To RGBA', 'RGBA To Number', 'RGBA To RGB', 'Seconds to Time', 'Time to seconds', 'Time to Timecode', 'Timecode to Time', 'Vector to Number', 'Vector2 to Number'}
Number = {'Absolute (|a|)', 'Add (a + b)', 'arccos(a)', 'arcsin(a)', 'arctan(a)', 'arctan2(b/a)', 'Cosine cos(a)', 'Damp', 'Damp (Clock based)', 'Distance Numbers', 'Divide (a/b)', 'exp(a)', 'Exponent (a^b)', 'IF Cond Then A Else B', 'Integer', 'Invert (1/a)', 'Is Between A and B', 'Is Different (a != b)', 'Is Greater (a > b)', 'Is Greater or Equal (a >= b)', 'Is Identical (a == b)', 'Is Less (a < b)', 'Is Less or Equal(a <= b)', 'ln(a)', 'log(a)', 'Max Pass-thru', 'Memory (a when REC)', 'Min Pass-thru', 'Modulo mod(a,b)', 'Multiply (a x b)', 'Precision Numbers', 'Pull Number', 'Scale And Offset (Number)', 'Sine sin(a)', 'sqrt(a)', 'Subtract (a - b)', 'Sum 10 numbers', 'Tangeant tan(a)', 'Triggered Delay (Number)', 'Triggered Delay with Memory(Number)'}
Other = {'Bezier Curve', 'Damping (3D)', 'Damping (3D)(Clock based)', 'FCurve Number (%)', 'FCurve Number (Time)', 'Real Time Filter', 'Triggered Plus Minus Counter', 'Triggered Random'}
Rotation = {'Add (R1 + R2)', 'Angle Difference (Points)', 'Angle Difference (Rotations)', 'Angular Accleration', 'Angular Speed', 'Damp(Rotation)', 'Global To Local', 'Interpolate', 'Local To Global', 'Rotation Scaling', 'Sensor Rotation Helper', 'Subtract (R1 - R2)', 'Three-Point Constraint'}
Shapes = {'Select exclusive', 'Select exclusive 24', 'Shape calibration'}
Sources = {'Counter with Play Pause', 'Counter with Start Stop', 'Half Circle Ramp', 'Isoceles Triangle Ramp', 'Pulse', 'Ramp', 'Random', 'Right Triangle Ramp', 'Sine Ramp', 'Square Ramp'}
System = {'Current Time', 'Local Time', 'Play Mode', 'Reference Time', 'System Time', 'Transport Control' }
Time = {'IF Cond Then T1 Else T2', 'Is Different (T1 != T2)', 'Is Greater (T1 > T2)', 'Is Greater or Equal(T1 >= T2)', 'Is Identical (T1 == T2)', 'Is Less (T1 < T2)', 'Is Less or Equal(T1 <= T2)'}
Vector = {'Acceleration', 'Add (V1 + V2)', 'Angle', 'Center Of Mass', 'Damp Position', 'Derive', 'Determinent', 'Displacement', 'Distance', 'Dot Product (V1.V2)', 'Gravity', 'IF Cond Then A Else B', 'Is Different (V1 != V2)', 'Is Identical (V1 == V2)', 'Length', 'Memory (V1 when REC)', 'Middle Point', 'Normalize', 'Orbit Attraction', 'Precision Vectors', 'Pull Vector', 'Scale (a x V)', 'Scale And Offset (Vector)', 'Scale Damping', 'Speed', 'Subtract (V1 - V2)', 'Sum 10 vectors', 'Triggered Delay (Vector)', 'Triggered Delay with Memory(Vector)', 'Vector Product(V1 x V2)'}
def FindAnimationNode( pParent, pName ):
lResult = None
for lNode in pParent.Nodes:
if lNode.Name == pName:
lResult = lNode
break
return lResult
def PrintConstraint( lCon ):
print "*************************************************"
print "***These are the %d boxes in the %s Constraint***" % (len(lCon.Boxes), lCon.Name)
print "*************************************************"
for lBox in lCon.Boxes:
lOut = 0
lIn = 0
lAnimationNodesOUT = lBox.AnimationNodeOutGet().Nodes
for lAnimationNode in lAnimationNodesOUT:
for i in range(lAnimationNode.GetDstCount()):
if lAnimationNode.GetDst(0) != None:
#Workaround for why it's printing in nodes that aren't connected
if not lAnimationNode.GetDst(i).GetOwner().Name.startswith("Relation"):
lOut = 1
#IN Animation Nodes
lAnimationNodesIN = lBox.AnimationNodeInGet().Nodes
for lAnimationNode in lAnimationNodesIN:
for i in range(lAnimationNode.GetSrcCount()):
if lAnimationNode.GetSrc(0) != None:
lIn = 1
if lOut == 0 and lIn == 1:
print "%s is a Receiver Box" % lBox.Name
elif lOut == 1 and lIn == 0:
print "%s is a Sender Box" % lBox.Name
else:
print "%s is a Function (operator) Box" % lBox.Name
print
print "**********************************************************************"
print "***These are the connections between the boxes in the %s Constraint***" % lCon.Name
print "**********************************************************************"
for lBox in lCon.Boxes:
#TMP
if lBox.Name == 'Add (a + b)':
'''
print "-------%s Box connected Animation Nodes-------" % lBox.Name
#OUT Animation Nodes
#looks like we have an issue with Out Animation Nodes, I think it prints in nodes too :(
lAnimationNodesOUT = lBox.AnimationNodeOutGet().Nodes
for lAnimationNode in lAnimationNodesOUT:
for i in range(lAnimationNode.GetDstCount()):
if lAnimationNode.GetDst(0) != None:
#Workaround for why it's printing in nodes that aren't connected
if not lAnimationNode.GetDst(i).GetOwner().Name.startswith("Relation"):
print "OUT: %s (%s) > %s (%s) " % (lBox.Name, lAnimationNode.UserName, lAnimationNode.GetDst(i).GetOwner().Name, lAnimationNode.GetDst(i).UserName)
'''
#IN Animation Nodes
lAnimationNodesIN = lBox.AnimationNodeInGet().Nodes
for i in range( len( lAnimationNodesIN ) ):
try:
# get plug info if exists
data = lAnimationNodesIN[i].ReadData()
print "data is " + str( data )
except:
print "error: Can't read data from " + str( lAnimationNodesIN[i].UserName )
'''
try:
# get plug info if exists
owner_of_plug = lAnimationNodesIN[i].GetSrc(i).GetOwner()
#print "owner is " + str( owner_of_plug )
#print "inplug exists > " + str( lAnimationNode.GetSrc(i).UserName )
except IndexError:
print "inplug " + str( lAnimationNodesIN[i].UserName ) + " doesn't exist but value is " + str( lAnimationNodesIN[i].ReadData() )
print "box is " + str( lBox.Name )
'''
'''
for lAnimationNode in lAnimationNodesIN:
# first print connected Src Nodes
for i in range(lAnimationNode.GetSrcCount()):
# print "i is " + str(i)
if lAnimationNode.GetSrc(i) != None:
print "IN: %s (%s) > %s (%s) " % (lBox.Name, lAnimationNode.UserName, lAnimationNode.GetSrc(0).GetOwner().Name, lAnimationNode.GetSrc(0).UserName)
# finally print unconnected Src Node Values
#print " len( lAnimationNodesIN )" + str( len( lAnimationNodesIN ) )
for i in range( len( lAnimationNodesIN ) ):
try:
# get plug info if exists
inPlug = lAnimationNodesIN[i].GetSrc(i)
print "inplug exists > " + str( lAnimationNode.GetSrc(i).UserName )
except IndexError:
print "inplug doesn't exist but value is " + str( lAnimationNodesIN[i].ReadData() )
print lAnimationNodesIN[i].UserName
try:
# get plug info if exists
inPlug = lAnimationNodesIN[i].GetSrc(i)
except IndexError:
# check for set value
print lAnimationNodesIN[i].GetOwner()
for prop in lAnimationNodesIN[i].PropertyList:
print "prop is " + str( prop.Name )
value = FindAnimationNode( lAnimationNodesIN[i], lAnimationNodesIN[i].UserName )
print "value is " + str(value)
'''
print
def isAnimNodeTRSType( animationNode ):
if ( animationNode.UserName == 'Rotation' or animationNode.UserName == 'Lcl Rotation' or animationNode.UserName == 'Translation'
or animationNode.UserName == 'Lcl Translation'
or animationNode.UserName == 'Scaling'
or animationNode.UserName == 'Lcl Scaling'):
return True
else:
return False
def GetRelationType( box, constraint ):
relationType = None
lOut = 0
lIn = 0
lAnimationNodesOUT = box.AnimationNodeOutGet().Nodes
model = None
for lAnimationNode in lAnimationNodesOUT:
for i in range(lAnimationNode.GetDstCount()):
if lAnimationNode.GetDst(0) != None:
# ignore bogus/empty connections to the solver
if not lAnimationNode.GetDst(i).GetOwner().Name == constraint.Name:
lOut = 1
# if a model type, then save model reference
if type( lAnimationNode.GetOwner() ).__name__ == 'FBModelPlaceHolder':
box.ModelObject = lAnimationNode.GetOwner().Model
box.GlobalTransforms = lAnimationNode.GetOwner().UseGlobalTransforms
break
#IN Animation Nodes
lAnimationNodesIN = box.AnimationNodeInGet().Nodes
for lAnimationNode in lAnimationNodesIN:
for i in range(lAnimationNode.GetSrcCount()):
if lAnimationNode.GetSrc(0) != None:
# has this got T/R/S connections and its already been flagged as destination?
# then ignore
if not ( lOut == 1 and isAnimNodeTRSType( lAnimationNode ) ):
lIn = 1
# if a model type, then save model reference
if type( lAnimationNode.GetOwner() ).__name__ == 'FBModelPlaceHolder':
box.ModelObject = lAnimationNode.GetOwner().Model
box.GlobalTransforms = lAnimationNode.GetOwner().UseGlobalTransforms
break
if lOut == 0 and lIn == 1:
box.BoxType = RelationBoxType.Receiver
return box.BoxType
elif lOut == 1 and lIn == 0:
box.BoxType = RelationBoxType.Sender
return box.BoxType
else:
box.BoxType = RelationBoxType.Operator
return box.BoxType
def GetBoxNameStripped( box ):
return box.Name.rstrip('1234567890 ')
def GetOperatorGroup( box ):
# remove any numbers and whitespace due to user duplication
box_stripped_name = GetBoxNameStripped( box )
# find
box_operator_group = None
if box_stripped_name in RelationBoxOperators.Boolean:
box_operator_group = RelationBoxOperatorGroup.Boolean
elif box_stripped_name in RelationBoxOperators.Converters:
box_operator_group = RelationBoxOperatorGroup.Converters
elif box_stripped_name in RelationBoxOperators.Number:
box_operator_group = RelationBoxOperatorGroup.Number
elif box_stripped_name in RelationBoxOperators.Other:
box_operator_group = RelationBoxOperatorGroup.Other
elif box_stripped_name in RelationBoxOperators.Rotation:
box_operator_group = RelationBoxOperatorGroup.Rotation
elif box_stripped_name in RelationBoxOperators.Shapes:
box_operator_group = RelationBoxOperatorGroup.Shapes
elif box_stripped_name in RelationBoxOperators.Sources:
box_operator_group = RelationBoxOperatorGroup.Sources
elif box_stripped_name in RelationBoxOperators.System:
box_operator_group = RelationBoxOperatorGroup.System
elif box_stripped_name in RelationBoxOperators.Time:
box_operator_group = RelationBoxOperatorGroup.Time
elif box_stripped_name in RelationBoxOperators.Vector:
box_operator_group = RelationBoxOperatorGroup.Vector
if not box_operator_group:
print "error: Operator type NOT found! for " + box_stripped_name
return box_operator_group
def CreateRelationConstraint():
lMgr = FBConstraintManager()
# get index to parent/child constraint
lIndex = None
for i in range(0, lMgr.TypeGetCount()):
if lMgr.TypeGetName(i) == 'Relation':
lIndex = i
break
# create constraint
relationConstraint = lMgr.TypeCreateConstraint(lIndex)
relationConstraint.Name = 'RigFacingSolver'
return relationConstraint
def GetCharacterObjectFromBoxName( name ):
input_name = name
split_name = input_name.rsplit('_', 1 )
object = FBFindModelByLabelName(split_name[0] + ':' + split_name[1])
if object == None:
print "error in GetCharacterObjectFromBox: cannot find object " + str (split_name[0] + ':' + split_name[1])
else:
return object
def GetBoxIndexInConstraint( box, constraint ):
for i in range( len( constraint.Boxes )):
if box == constraint.Boxes[i]:
return i
print "error in GetBoxIndexInConstraint: match not found"
def ConnectPlugs( old_box, source_index, source_constraint, dest_constraint, output ):
lAnimationNodesOut = old_box.AnimationNodeOutGet().Nodes
lAnimationNodesIn = old_box.AnimationNodeInGet().Nodes
for i in range ( len( lAnimationNodesOut ) ):
for j in range( lAnimationNodesOut[i].GetDstCount() ):
if lAnimationNodesOut[i].GetDst(j) != None and lAnimationNodesOut[i].GetDst(j).GetOwner().Name != source_constraint.Name:
'''
print "source_index is " + str( source_index )
print "Num of destination nodes is " + str(lAnimationNodesOut[i].GetDstCount())
print "Source Object is " + str( lAnimationNodesOut[i].GetOwner().Name )
print "Source Plug is " + str( lAnimationNodesOut[i].UserName )
print "Destination Object is " + str(lAnimationNodesOut[i].GetDst(j).GetOwner().Name )
print "Destination Plug is " + str(lAnimationNodesOut[i].GetDst(j).UserName )
'''
dest_index = GetBoxIndexInConstraint( lAnimationNodesOut[i].GetDst(j).GetOwner(), source_constraint )
new_box_OUT_anim_node = FindAnimationNode( dest_constraint.Boxes[ source_index ].AnimationNodeOutGet(), lAnimationNodesOut[i].UserName )
new_box_IN_anim_node = FindAnimationNode( dest_constraint.Boxes[ dest_index ].AnimationNodeInGet(), lAnimationNodesOut[i].GetDst(j).UserName )
if new_box_OUT_anim_node and new_box_IN_anim_node:
FBConnect( new_box_OUT_anim_node, new_box_IN_anim_node )
else:
print "error in ConnectDestinationPlugs(OUT): Can't find nodes"
# >>>>>>>>>>>>> output
output += "new_box_OUT_anim_node = FindAnimationNode( new_constraint.Boxes[ " + str( source_index ) + " ].AnimationNodeOutGet(), '" + str( lAnimationNodesOut[i].UserName) + "' )"
output += "\n"
output += "new_box_IN_anim_node = FindAnimationNode( new_constraint.Boxes[ " + str( dest_index ) + " ].AnimationNodeInGet(), '" + str( lAnimationNodesOut[i].GetDst(j).UserName ) + "' )"
output += "\n"
output += "FBConnect( new_box_OUT_anim_node, new_box_IN_anim_node )"
output += "\n"
output += "\n"
for i in range ( len( lAnimationNodesIn ) ):
for j in range( lAnimationNodesIn[i].GetSrcCount() ):
if lAnimationNodesIn[i].GetSrc(j) != None and lAnimationNodesIn[i].GetSrc(j).GetOwner().Name != source_constraint.Name:
'''
print "source_index is " + str( source_index )
print "Num of Source nodes is " + str(lAnimationNodesIn[i].GetSrcCount())
print "Destination Object is " + str( lAnimationNodesIn[i].GetOwner().Name )
print "Destination Plug is " + str( lAnimationNodesIn[i].UserName )
print "Source Object is " + str(lAnimationNodesIn[i].GetSrc(j).GetOwner().Name )
print "Source Plug is " + str(lAnimationNodesIn[i].GetSrc(j).UserName )
'''
dest_index = GetBoxIndexInConstraint( lAnimationNodesIn[i].GetSrc(j).GetOwner(), source_constraint )
new_box_IN_anim_node = FindAnimationNode( dest_constraint.Boxes[ source_index ].AnimationNodeInGet(), lAnimationNodesIn[i].UserName )
new_box_OUT_anim_node = FindAnimationNode( dest_constraint.Boxes[ dest_index ].AnimationNodeOutGet(), lAnimationNodesIn[i].GetSrc(j).UserName )
if new_box_OUT_anim_node and new_box_IN_anim_node:
FBConnect( new_box_OUT_anim_node, new_box_IN_anim_node )
else:
print "error in ConnectDestinationPlugs (IN): Can't find nodes"
# >>>>>>>>>>>>> output
output += "new_box_IN_anim_node = FindAnimationNode( dest_constraint.Boxes[ " + str( source_index ) + " ].AnimationNodeInGet(), '" + str( lAnimationNodesIn[i].UserName) + "' )"
output += "\n"
output += "new_box_OUT_anim_node = FindAnimationNode( dest_constraint.Boxes[ " + str( dest_index) + " ].AnimationNodeOutGet(), '" + str( lAnimationNodesIn[i].GetSrc(j).UserName ) + "' )"
output += "\n"
output += "FBConnect( new_box_OUT_anim_node, new_box_IN_anim_node )"
output += "\n"
output += "\n"
return output
def SetValues( old_box, source_index, source_constraint, dest_constraint, output ):
lAnimationNodesIN = old_box.AnimationNodeInGet().Nodes
for i in range( len( lAnimationNodesIN ) ):
try:
inPlug = lAnimationNodesIN[i].GetSrc(i)
# get plug info if exists
except:
data = lAnimationNodesIN[i].ReadData()
########################################################################
# Set Value ( only on non Models for now )
########################################################################
if type( lAnimationNodesIN[i].GetOwner() ).__name__ != 'FBModelPlaceHolder':
dest_animation_node = FindAnimationNode( dest_constraint.Boxes[ source_index ].AnimationNodeInGet(), lAnimationNodesIN[i].UserName )
if dest_animation_node:
dest_animation_node.WriteData( data )
output += "dest_animation_node = FindAnimationNode( dest_constraint.Boxes[ " + str( source_index ) + " ].AnimationNodeInGet(), '" + str( lAnimationNodesIN[i].UserName ) + "' )"
output += "\n"
output += "dest_animation_node.WriteData( " + str( data ) + " )"
output += "\n"
return output
def CopyFCurves( old_box, source_index, source_constraint, dest_constraint, output ):
# only copy fcurves for constraint boxes - not animated models
if type( old_box ).__name__ != 'FBModelPlaceHolder':
lAnimationNodesOUT = old_box.AnimationNodeOutGet().Nodes
for i in range( len( lAnimationNodesOUT ) ):
try:
fcurve = lAnimationNodesOUT[i].FCurve
# copy fcurve if exists
dest_animation_node = FindAnimationNode( dest_constraint.Boxes[ source_index ].AnimationNodeOutGet(), lAnimationNodesOUT[i].UserName )
if dest_animation_node:
dest_animation_node.FCurve.KeyReplaceBy( fcurve )
output += "dest_animation_node = FindAnimationNode( dest_constraint.Boxes[ " + str( source_index ) + " ].AnimationNodeOutGet(), '" + str( lAnimationNodesOUT[i].UserName ) + "' )"
output += "\n"
for key in dest_animation_node.FCurve.Keys:
output += "dest_animation_node.FCurve.KeyAdd( " + str( key.Time) + ", " + str( key.Value ) + ", " + str( key.Interpolation ) + ", " + str( key.TangentMode ) + " )"
output += "\n"
except:
pass
return output
def PrintOutToTextFile( output ):
####################################################################
# Open text file with final result
####################################################################
output_file_path = tempfile.gettempdir() + '\\mj_OutputRelationConstraint_output.txt'
with open( output_file_path , 'w') as f:
f.write( output )
os.startfile( output_file_path )
def OutputRelationConstraint():
constraints = FBSystem().Scene.Constraints
character = FBApplication().CurrentCharacter
selected_constraint = None
box_relation_type = []
for constraint in constraints:
if constraint.Selected:
if type(constraint).__name__ == 'FBConstraintRelation':
selected_constraint = constraint
break
if selected_constraint:
new_constraint = CreateRelationConstraint()
#PrintConstraint( selected_constraint )
# output string to write python commands to
output = ''
##################################################################################
# Create Boxes
##################################################################################
for box in selected_constraint.Boxes:
# get receiver, sender or operator type
box_relation_type.append( GetRelationType( box, selected_constraint ) )
box_position = selected_constraint.GetBoxPosition( box )
# >>>>>>>>>>>>> output
output += "\n"
output += "#######################################################"
output += "\n"
output += "# Adding Box > " + str( box.Name )
output += "\n"
output += "#######################################################"
output += "\n"
output += "\n"
if box_relation_type[-1] == RelationBoxType.Operator:
# get operator group and operator ( assumes name is unmodified from creation )
box_operator_group = GetOperatorGroup( box )
box_operator_name = GetBoxNameStripped( box )
new_box = new_constraint.CreateFunctionBox( box_operator_group, box_operator_name )
# >>>>>>>>>>>>> output
output += "new_box = new_constraint.CreateFunctionBox( '" + str( box_operator_group ) + "', '" + str( box_operator_name ) + "' )"
output += "\n"
# set position
new_constraint.SetBoxPosition( new_box, box_position[1], box_position[2] )
# >>>>>>>>>>>>> output
output += "new_constraint.SetBoxPosition( new_box, " + str( box_position[1]) + ", " + str( box_position[2]) + " )"
output += "\n"
if box_relation_type[-1] == RelationBoxType.Receiver:
new_box = new_constraint.ConstrainObject( box.ModelObject )
# >>>>>>>>>>>>> output
output += "new_box = new_constraint.ConstrainObject( < insert pointer to object" + str( box.ModelObject.Name ) + " > )"
output += "\n"
new_box.UseGlobalTransforms = box.GlobalTransforms
# >>>>>>>>>>>>> output
output += "new_box.UseGlobalTransforms = " + str( box.GlobalTransforms )
output += "\n"
# set position
new_constraint.SetBoxPosition( new_box, box_position[1], box_position[2] )
# >>>>>>>>>>>>> output
output += "new_constraint.SetBoxPosition( new_box , " + str( box_position[1]) + ", " + str( box_position[2]) + " )"
output += "\n"
if box_relation_type[-1] == RelationBoxType.Sender:
new_box = new_constraint.SetAsSource( box.ModelObject )
# >>>>>>>>>>>>> output
output += "new_box = new_constraint.SetAsSource( < insert pointer to object" + str( box.ModelObject.Name) + " > )"
output += "\n"
new_box.UseGlobalTransforms = box.GlobalTransforms
# >>>>>>>>>>>>> output
output += "new_box.UseGlobalTransforms = " + str( box.GlobalTransforms )
output += "\n"
# set position
new_constraint.SetBoxPosition( new_box, box_position[1], box_position[2] )
# >>>>>>>>>>>>> output
output += "new_constraint.SetBoxPosition( new_box , " + str( box_position[1]) + ", " + str( box_position[2]) + " )"
output += "\n"
##################################################################################
# Create Connections
##################################################################################
# >>>>>>>>>>>>> output
output += "\n"
output += "#######################################################"
output += "\n"
output += "# Creating Connections"
output += "\n"
output += "#######################################################"
output += "\n"
output += "\n"
for i in range( len(selected_constraint.Boxes) ):
output = ConnectPlugs( selected_constraint.Boxes[i], i, selected_constraint, new_constraint, output )
##################################################################################
# Create Fixed Input Values/FCurves
##################################################################################
# >>>>>>>>>>>>> output
output += "\n"
output += "#######################################################"
output += "\n"
output += "# Create Fixed Input Values/FCurves"
output += "\n"
output += "#######################################################"
output += "\n"
output += "\n"
for i in range( len(selected_constraint.Boxes) ):
output = SetValues( selected_constraint.Boxes[i], i, selected_constraint, new_constraint, output )
output = CopyFCurves( selected_constraint.Boxes[i], i, selected_constraint, new_constraint, output )
##################################################################################
# Output text file
##################################################################################
PrintOutToTextFile( output )
else:
FBMessageBox( "Message", "Please select a single relation constraint to output.", "OK", None, None )
OutputRelationConstraint()####################################################################
# Allows user to paste a pose on character extensions
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
# Global UI components
#take control ui comps
take_radio_group = FBButtonGroup()
take_yes_button = FBButton()
take_no_button = FBButton()
take_radio_group.Add(take_yes_button)
take_radio_group.Add(take_no_button)
status = FBLabel()
button = []
selected_character = ""
UI_char_extension_objs = []
char_extension_objs = []
char_rollbone_objs = []
char_3lateral_objs = []
def clearSelection():
''' Clear selection function '''
# Get selected models
modelList = FBModelList ()
FBGetSelectedModels (modelList, None, True)
# Deselect models
for model in modelList:
model.Selected = False
def ClearAnim( pNode ):
# The FCurve property will not be null on a terminal node.
# i.e. the 'Lcl Translation' node will not have any animation on it
# directly... only the sub-nodes 'X', 'Y' or 'Z' may have animation.
if pNode.FCurve:
# Ah! there is a FCurve! Let's remove all the keys.
pNode.FCurve.EditClear()
else:
# Then we are dealing with a parent node. Let's look at it
# children nodes.
for lNode in pNode.Nodes:
# Recursively call ourselves to deal with sub-nodes.
ClearAnim( lNode )
# Cleanup
del( lNode )
def getAllSceneCharacterExtensions():
exts = FBSystem().Scene.CharacterExtensions
for e in exts:
components = e.Components
for c in components:
existing = False
for ext in char_extension_objs:
if c.Name == ext.Name:
existing = True
if not existing:
char_extension_objs.append( c )
def getSpecificCharacterExtension( obj ):
global selected_character
# get namespace of selected character
namespace = ( selected_character ).split(":")[0]
if namespace != "":
namespace += ":"
exts = FBSystem().Scene.CharacterExtensions
for e in exts:
components = e.Components
for c in components:
#print "combined namespace and obj.Name is " + namespace + obj.Name
#print "c.LongName is " + c.LongName
if namespace + obj.Name == c.LongName:
#print "found match! with component " + c.LongName
return c
def getUniqueCharacterExtensions():
exts = FBSystem().Scene.CharacterExtensions
for e in exts:
components = e.Components
for c in components:
existing = False
for ext in UI_char_extension_objs:
if c.Name == ext.Name:
existing = True
if not existing:
UI_char_extension_objs.append( c )
def getCharacters():
return FBSystem().Scene.Characters
def setupPropertyList(tool):
tool.list.Items.removeAll()
tool.prop_list = []
character_list = getCharacters()
if len(character_list):
for char in character_list:
tool.list.Items.append(char.LongName)
else:
tool.list.Items.append('No characters found!')
selected_character = character_list[0]
####################################################################
# UI CallBacks
####################################################################
def ListCallback(control, event):
global selected_character
selected_character = control.Items[control.ItemIndex]
def OnDragAndDropCallback(control, event):
if event.State == FBDragAndDropState.kFBDragAndDropDrag:
event.Accept()
if event.State == FBDragAndDropState.kFBDragAndDropDrop:
for e in event.Components:
print type(e)
# only allow poses to be dropped
if type(e) is pyfbsdk.FBPose or type(e) is pyfbsdk.FBCharacterPose:
event.Accept()
control.Items.removeAll()
control.Items.append(e.Name)
t.pasteButton.Enabled = True
def pasteButtonCallBack(control, event):
system = FBSystem()
currentTake = system.CurrentTake
#############################################################
# get char reference
#############################################################
chars = system.Scene.Characters
characterIndex = 0
for char in chars:
if char.LongName == t.list.Items[t.list.ItemIndex]:
break
else:
characterIndex += 1
selectedCharacter = chars[ characterIndex ]
#############################################################
# get pose reference
#############################################################
poses = FBSystem().Scene.CharacterPoses
characterPoseIndex = 0
for p in poses:
if p.Name == t.container.Items[0]:
break
else:
characterPoseIndex += 1
targetPose = poses[ characterPoseIndex ]
poseOptions = FBCharacterPoseOptions()
poseOptions.mCharacterPoseKeyingMode = FBCharacterPoseKeyingMode.kFBCharacterPoseKeyingModeFullBody
player = FBPlayerControl()
#############################################################
# set key controls
# first store current setting
#############################################################
currentKeyMode = selectedCharacter.KeyingMode
selectedCharacter.KeyingMode = FBCharacterKeyingMode.kFBCharacterKeyingSelection
#######################################################################
# ALL TAKES
#######################################################################
if take_yes_button.State == 1:
for take in FBSystem().Scene.Takes:
system.CurrentTake = take
FBSystem().Scene.Evaluate()
index = 0
#deselect all
clearSelection()
# paste pose (Fullbody)
targetPose.PastePose( selectedCharacter, poseOptions )
FBSystem().Scene.Evaluate()
for obj in char_extension_objs:
if ( button[index].State == True ):
obj.Selected = True
FBSystem().Scene.Evaluate()
index += 1
# key
player.Key()
FBSystem().Scene.Evaluate()
# restore take
system.CurrentTake = currentTake
#######################################################################
# SINGLE TAKE
#######################################################################
else:
print "Pasting just this take"
index = 0
#deselect all
clearSelection()
# paste pose (Fullbody)
targetPose.PastePose( selectedCharacter, poseOptions )
FBSystem().Scene.Evaluate()
for obj in char_extension_objs:
if ( button[index].State == True ):
obj.Selected = True
index += 1
# key
player.Key()
# restore key controls
selectedCharacter.KeyingMode = currentKeyMode
print "Selected extensions pasted!"
status.Caption = "Extensions keyed with pose!"
FBSystem().Scene.Evaluate()
####################################################################
# UI
####################################################################
def PopulateTool(t):
# ui variables for easier modification
ui_border_x = 10
ui_border_y = 10
ui_border_width = 140
ui_border_height = 100
ui_column_a = 20
ui_column_b = 60
ui_column_c = 100
ui_row_offset = 10
ui_button_width = 120
ui_button_height = 15
#Mover Selection----------------------------------------------
#Drop Down
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(25,FBAttachType.kFBAttachNone,"")
t.AddRegion("dropdown","dropdown", x, y, w, h)
t.list = FBList()
t.SetControl("dropdown", t.list)
setupPropertyList(t)
#Extensions--------------------------------------------------
#get all scene character extension objects
getAllSceneCharacterExtensions()
ui_row_offset += 40
#Border
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam( ( 20 * len(char_extension_objs) ) + 15,FBAttachType.kFBAttachNone,"")
t.AddRegion("trans_border","Character Extensions", x, y, w, h)
t.SetBorder("trans_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_row_offset += 10
#Buttons
# create a button for each extension obj
for i in range( 0, len(char_extension_objs) ):
region = "extButton" + str(i)
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop, region )
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_height,FBAttachType.kFBAttachNone,"")
t.AddRegion(region,region, x, y, w, h)
button.append( FBButton() )
t.SetControl(region, button[i] )
button[i].Visible = True
button[i].ReadOnly = False
button[i].Enabled = True
button[i].Hint = ""
button[i].Caption = char_extension_objs[i].Name
# set certain options as off for ease of use
if ( "mover" in char_extension_objs[i].Name ) or \
( "PH_R_Hand" in char_extension_objs[i].Name ) or \
( "PH_L_Hand" in char_extension_objs[i].Name ):
button[i].State = 0
else:
button[i].State = 1
button[i].Style = FBButtonStyle.kFBCheckbox
button[i].Justify = FBTextJustify.kFBTextJustifyLeft
button[i].Look = FBButtonLook.kFBLookNormal
ui_row_offset += 20
#Takes--------------------------------------------------
#clear all takes?
ui_row_offset += 20
#Border
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam( 60 ,FBAttachType.kFBAttachNone,"")
t.AddRegion("takes","Paste On All Takes?", x, y, w, h)
t.SetBorder("takes",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_row_offset += 10
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"take_yes_button")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(120,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("take_yes_button","take_yes_button", x, y, w, h)
t.SetControl("take_yes_button", take_yes_button )
take_yes_button.Visible = True
take_yes_button.ReadOnly = False
take_yes_button.Enabled = True
take_yes_button.Hint = ""
take_yes_button.Caption = "Yes"
take_yes_button.State = 1
take_yes_button.Style = FBButtonStyle.kFBRadioButton
take_yes_button.Justify = FBTextJustify.kFBTextJustifyLeft
take_yes_button.Look = FBButtonLook.kFBLookNormal
ui_row_offset += 20
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"take_no_button")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(120,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("take_no_button","take_no_button", x, y, w, h)
t.SetControl("take_no_button", take_no_button )
take_no_button.Visible = True
take_no_button.ReadOnly = False
take_no_button.Enabled = True
take_no_button.Hint = ""
take_no_button.Caption = "No"
take_no_button.State = 0
take_no_button.Style = FBButtonStyle.kFBRadioButton
take_no_button.Justify = FBTextJustify.kFBTextJustifyLeft
take_no_button.Look = FBButtonLook.kFBLookNormal
#Pose Container--------------------------------------------------
ui_row_offset = ui_row_offset + 40
t.container = FBVisualContainer()
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"container_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(30,FBAttachType.kFBAttachNone,"")
t.AddRegion("container_region","container_region", x, y, w, h)
t.SetControl("container_region", t.container)
t.container.Items.append("Drag Pose Here")
t.container.ItemHeight = 30
t.container.ItemWidth = ui_border_width - 2
t.container.OnDragAndDrop.Add(OnDragAndDropCallback)
#Paste Button--------------------------------------------------
ui_row_offset = ui_row_offset + 40
t.pasteButton = FBButton()
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"paste_button_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(30,FBAttachType.kFBAttachNone,"")
t.AddRegion("paste_button_region","paste_button_region", x, y, w, h)
t.SetControl("paste_button_region", t.pasteButton)
t.pasteButton.Visible = True
t.pasteButton.ReadOnly = False
t.pasteButton.Enabled = False
t.pasteButton.Hint = ""
t.pasteButton.Caption = "Paste Pose on Selected"
t.pasteButton.State = 0
t.pasteButton.Style = FBButtonStyle.kFBPushButton
t.pasteButton.Justify = FBTextJustify.kFBTextJustifyCenter
t.pasteButton.Look = FBButtonLook.kFBLookNormal
t.pasteButton.OnClick.Add(pasteButtonCallBack)
#Status --------------------------------------------------
ui_row_offset = ui_row_offset + 35
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"status_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(30,FBAttachType.kFBAttachNone,"")
t.AddRegion("status_region","status_region", x, y, w, h)
t.SetControl("status_region", status)
status.Visible = True
status.ReadOnly = False
status.Enabled = True
status.Caption = ">"
# set tool ui size
t.StartSizeX = 175
t.StartSizeY = ui_row_offset + 60
####################################################################
# Main
####################################################################
def CreateTool():
print "DEBUG"
global t
t = FBCreateUniqueTool("Paste Pose On Extensions")
PopulateTool(t)
ShowTool(t)
CreateTool()
PNG
from pyfbsdk import *
from pyfbsdk_additions import *
def clearSelection():
''' Clear selection function '''
# Get selected models
modelList = FBModelList ()
FBGetSelectedModels (modelList, None, True)
# Deselect models
for model in modelList:
model.Selected = False
####################################################################
# UI callbacks
####################################################################
def goButtonCallBack(control, event):
if t.pinned == False:
# get time span
current_start = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
current_end = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()
t.null = []
# lists for storing object pos and rotations
trans_array = []
rot_array = []
########################################
# Pin object
########################################
for i in range( 0, t.numOfObjects ):
# create null
t.null.append( FBModelNull('constraint_null_' + t.selected_obj_name[i]) )
t.null[i].Parent = FBModelNull('constraint_null_Parent')
#----------------------------------------------------------------------------------
# loop for every frame - get pos/rot of selected object
#----------------------------------------------------------------------------------
for frame in range(current_start, current_end + 1):
# update slider
FBPlayerControl().Goto(FBTime(0,0,0,frame))
FBSystem().Scene.Evaluate()
# get selected translation and rotation for object
obj_trans = FBVector3d()
obj_rot = FBVector3d()
for i in range( 0, t.numOfObjects ):
t.selected_obj[i].GetVector (obj_trans, FBModelTransformationType.kModelTranslation, True)
t.selected_obj[i].GetVector (obj_rot, FBModelTransformationType.kModelRotation, True)
FBSystem().Scene.Evaluate()
# store translation/rotation
trans_array.append(obj_trans)
rot_array.append(obj_rot)
# only select nulls
clearSelection()
for i in range( 0, t.numOfObjects ):
t.null[i].Selected = True
#----------------------------------------------------------------------------------
# loop for every frame - set pos/rot on null
#----------------------------------------------------------------------------------
count = 0
for frame in range(current_start, current_end + 1):
# update slider
FBPlayerControl().Goto(FBTime(0,0,0,frame))
FBSystem().Scene.Evaluate()
for i in range( 0, t.numOfObjects ):
# if we're on the first frame set up the parent of the null to sit in the starting position
# this parent won't be keyed.
if count == 0:
t.null[i].Parent.SetVector(trans_array[ i + count * t.numOfObjects ],FBModelTransformationType.kModelTranslation, True)
t.null[i].Parent.SetVector(rot_array[i + count * t.numOfObjects], FBModelTransformationType.kModelRotation, True)
FBSystem().Scene.Evaluate()
# set selected translation and rotation for object
t.null[i].SetVector (trans_array[i + count * t.numOfObjects], FBModelTransformationType.kModelTranslation, True)
t.null[i].SetVector (rot_array[i + count * t.numOfObjects], FBModelTransformationType.kModelRotation, True)
FBSystem().Scene.Evaluate()
# key null
FBPlayerControl().Key()
FBSystem().Scene.Evaluate()
count += 1
#----------------------------------------------------------------------------------
# create constraints
#----------------------------------------------------------------------------------
# constrain selected object to null
lMgr = FBConstraintManager()
# get index to parent/child constraint
lIndex = None
t.constraint = []
for i in range(0, lMgr.TypeGetCount()):
if lMgr.TypeGetName(i) == 'Parent/Child':
lIndex = i
break
for j in range( 0, t.numOfObjects ):
# create constraint
lPosConst = lMgr.TypeCreateConstraint(lIndex)
# add ref objects
for i in range(0, lPosConst.ReferenceGroupGetCount()):
if lPosConst.ReferenceGroupGetName(i) == 'Source (Parent)':
lPosConst.ReferenceAdd(i, t.null[j])
elif lPosConst.ReferenceGroupGetName(i) == 'Constrained object (Child)':
lPosConst.ReferenceAdd(i, t.selected_obj[j])
# snap/activate constraint
lPosConst.Snap()
# store ref to constraint objects
t.constraint.append( lPosConst )
# update UI
if t.numOfObjects == 1:
t.pin_button.Caption = "Plot & Unpin '" + t.selected_obj_name[0] + "'"
else:
t.pin_button.Caption = "Plot & Unpin " + str(t.numOfObjects) + " objects"
t.pinned = True
else:
########################################
# UnPin object
########################################
# plot selected object
clearSelection()
for i in range( 0, t.numOfObjects ):
t.selected_obj[i].Selected = True
FBSystem().CurrentTake.PlotTakeOnSelected( plotOptions() )
FBSystem().Scene.Evaluate()
# delete constraint
for i in range( 0, t.numOfObjects ):
t.constraint[i].FBDelete()
# delete Parent Null
t.null[ i ].Parent.FBDelete()
# delete null
t.null[i].FBDelete()
print 'contraint(s) deleted'
# update UI
if t.numOfObjects == 1:
t.pin_button.Caption = "Plot & Pin '" + t.selected_obj_name[0] + "'"
else:
t.pin_button.Caption = "Plot & Pin " + str(t.numOfObjects) + " objects"
t.pinned = False
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
####################################################################
# UI definition
####################################################################
def PopulateTool(t):
t.selected_obj = []
t.selected_obj_name = []
# get selected object
models = FBModelList()
FBGetSelectedModels( models )
if len(models) == 0:
FBMessageBox( "Message", "Nothing selected", "OK", None, None )
else:
for obj in models:
t.selected_obj.append( obj )
t.selected_obj_name.append( obj.Name )
t.numOfObjects = len( models )
#Pin button
x = FBAddRegionParam(5,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(5,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(240,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(30,FBAttachType.kFBAttachNone,"")
t.AddRegion("go_button_region","go_button_region", x, y, w, h)
t.pin_button = FBButton()
t.SetControl("go_button_region", t.pin_button)
t.pin_button.Visible = True
t.pin_button.ReadOnly = False
t.pin_button.Enabled = True
t.pin_button.Hint = ""
if t.numOfObjects == 1:
t.pin_button.Caption = "Plot & Pin '" + t.selected_obj_name[0] + "'"
else:
t.pin_button.Caption = "Plot & Pin " + str(t.numOfObjects) + " objects"
t.pin_button.State = 0
t.pin_button.Style = FBButtonStyle.kFBPushButton
t.pin_button.Justify = FBTextJustify.kFBTextJustifyCenter
t.pin_button.Look = FBButtonLook.kFBLookNormal
t.pin_button.OnClick.Add(goButtonCallBack)
# set pin state
t.pinned = False
ShowTool(t)
####################################################################
# Main
####################################################################
def CreateTool():
global t
t = FBCreateUniqueTool("Pin Selected")
t.StartSizeX = 265
t.StartSizeY = 75
PopulateTool(t)
CreateTool()
PNG
####################################################################
# Plot from a selection of Takes
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
import RS.Globals
# Global UI components
MAX_LIST_BOX_ENTRIES = 40
####################################################################
# UI CallBacks
####################################################################
def AllTakesCallback(control, event):
for item in range( len(t.list.Items) ):
t.list.Selected( item, True )
def NoTakesCallback(control, event):
for item in range( len(t.list.Items) ):
t.list.Selected( item, False )
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 PlotButtonCallBack(control, event):
if t.skeletonModeButton.State:
print "Plotting Selected Takes to Skeleton"
else:
print "Plotting Selected Takes to Rig"
character_list = []
if t.currentCharacterButton.State == True:
character_list.append( FBApplication().CurrentCharacter )
else:
for char in RS.Globals.Characters:
character_list.append( char )
for character in character_list:
# only plot on selected takes
for item in range( len(t.list.Items) ):
if( t.list.IsSelected( item ) ):
# go to take
FBSystem().CurrentTake = FBSystem().Scene.Takes[ item ]
# plot to skeleton
if t.skeletonModeButton.State:
# make sure rig is active
character.Active = True
# plot
character.PlotAnimation( FBCharacterPlotWhere.kFBCharacterPlotOnSkeleton, plotOptions() )
# plot to rig
else:
# if rig is active already then do a plot to skeleton first
if character.Active == True:
# plot to skeleton first
character.PlotAnimation( FBCharacterPlotWhere.kFBCharacterPlotOnSkeleton, plotOptions() )
# make sure rig is deactivated
character.Active = False
# plot
character.PlotAnimation( FBCharacterPlotWhere.kFBCharacterPlotOnControlRig, plotOptions() )
print "Plotting Complete"
####################################################################
# UI
####################################################################
def PopulateTool(t):
# ui variables for easier modification
ui_border_x = 10
ui_border_y = 10
ui_border_width = 250
ui_border_height = 40
ui_column_a = 20
ui_column_b = ui_border_width / 2
ui_row_offset = 10
ui_button_width = 40
########################################################################
# All Takes Button
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width / 6 ,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("all_takes_button","all_takes_button", x, y, w, h)
t.alltakesbutton = FBButton()
t.alltakesbutton.Caption = "All"
t.SetControl("all_takes_button", t.alltakesbutton)
#callback
t.alltakesbutton.OnClick.Add( AllTakesCallback )
########################################################################
# No Takes Button
x = FBAddRegionParam(ui_border_width + 10 - ui_border_width / 4 ,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width / 4 ,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("no_takes_button","no_takes_button", x, y, w, h)
t.nonetakesbutton = FBButton()
t.nonetakesbutton.Caption = "None"
t.SetControl("no_takes_button", t.nonetakesbutton)
#callback
t.nonetakesbutton.OnClick.Add( NoTakesCallback )
########################################################################
ui_row_offset += 25
#Take List
t.list = FBList()
t.list.Style = FBListStyle.kFBVerticalList
t.list.MultiSelect = True
t.list.ExtendedSelect = True
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
# get take names and calculate size required for UI list at same time
for iTake in FBSystem().Scene.Takes:
t.list.Items.append(iTake.Name)
# select UI if user had take selected
if ( iTake.Selected == True ):
t.list.Selected( len( t.list.Items) - 1, True )
#limit UI size
if( len(t.list.Items) < MAX_LIST_BOX_ENTRIES ):
ui_row_offset += 15
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
t.AddRegion("takes","takes", x, y, w, h)
t.SetControl("takes", t.list)
ui_row_offset = ui_row_offset + 10
########################################################################
ui_row_offset += 40
t.modeRadios = FBButtonGroup()
t.skeletonModeButton = FBButton()
t.rigModeButton = FBButton()
t.modeRadios.Add( t.skeletonModeButton )
t.modeRadios.Add( t.rigModeButton )
#Border
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_border_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("mode_border","Plot Mode", x, y, w, h)
t.SetBorder("mode_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_row_offset += 10
#Buttons
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"skeleton_mode_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width / 2,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_border_height / 2,FBAttachType.kFBAttachNone,"")
t.AddRegion("skeleton_mode_region","skeleton_mode_region", x, y, w, h)
t.SetControl("skeleton_mode_region", t.skeletonModeButton)
t.skeletonModeButton.Visible = True
t.skeletonModeButton.ReadOnly = False
t.skeletonModeButton.Enabled = True
t.skeletonModeButton.Hint = ""
t.skeletonModeButton.Caption = "To Skeleton"
t.skeletonModeButton.State = 1
t.skeletonModeButton.Style = FBButtonStyle.kFBRadioButton
t.skeletonModeButton.Justify = FBTextJustify.kFBTextJustifyLeft
t.skeletonModeButton.Look = FBButtonLook.kFBLookNormal
x = FBAddRegionParam(ui_column_b,FBAttachType.kFBAttachTop,"rig_mode_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width / 2,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_border_height / 2,FBAttachType.kFBAttachNone,"")
t.AddRegion("rig_mode_region","rig_mode_region", x, y, w, h)
t.SetControl("rig_mode_region", t.rigModeButton )
t.rigModeButton.Visible = True
t.rigModeButton.ReadOnly = False
t.rigModeButton.Enabled = True
t.rigModeButton.Hint = ""
t.rigModeButton.Caption = "To Rig"
t.rigModeButton.State = 0
t.rigModeButton.Style = FBButtonStyle.kFBRadioButton
t.rigModeButton.Justify = FBTextJustify.kFBTextJustifyLeft
t.rigModeButton.Look = FBButtonLook.kFBLookNormal
########################################################################
# Current Character or All?
########################################################################
ui_row_offset += 45
t.modeRadios = FBButtonGroup()
t.currentCharacterButton = FBButton()
t.allCharacterButton = FBButton()
t.modeRadios.Add( t.currentCharacterButton )
t.modeRadios.Add( t.allCharacterButton )
#Border
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_border_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("character_mode_border","Character?", x, y, w, h)
t.SetBorder("character_mode_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_row_offset += 10
#Buttons
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"current_mode_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width / 2,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_border_height / 2,FBAttachType.kFBAttachNone,"")
t.AddRegion("current_mode_region","current_mode_region", x, y, w, h)
t.SetControl("current_mode_region", t.currentCharacterButton)
t.currentCharacterButton.Visible = True
t.currentCharacterButton.ReadOnly = False
t.currentCharacterButton.Enabled = True
t.currentCharacterButton.Hint = ""
t.currentCharacterButton.Caption = "Current"
t.currentCharacterButton.State = 1
t.currentCharacterButton.Style = FBButtonStyle.kFBRadioButton
t.currentCharacterButton.Justify = FBTextJustify.kFBTextJustifyLeft
t.currentCharacterButton.Look = FBButtonLook.kFBLookNormal
x = FBAddRegionParam(ui_column_b,FBAttachType.kFBAttachTop,"all_mode_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width / 2,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_border_height / 2,FBAttachType.kFBAttachNone,"")
t.AddRegion("all_mode_region","all_mode_region", x, y, w, h)
t.SetControl("all_mode_region", t.allCharacterButton )
t.allCharacterButton.Visible = True
t.allCharacterButton.ReadOnly = False
t.allCharacterButton.Enabled = True
t.allCharacterButton.Hint = ""
t.allCharacterButton.Caption = "All"
t.allCharacterButton.State = 0
t.allCharacterButton.Style = FBButtonStyle.kFBRadioButton
t.allCharacterButton.Justify = FBTextJustify.kFBTextJustifyLeft
t.allCharacterButton.Look = FBButtonLook.kFBLookNormal
########################################################################
#Plot Button
ui_row_offset += 40
x = FBAddRegionParam(ui_border_x ,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(30,FBAttachType.kFBAttachNone,"")
t.AddRegion("plot_button","plot_button", x, y, w, h)
t.plotButton = FBButton()
t.plotButton.Caption = "Plot Selected Takes"
t.SetControl("plot_button", t.plotButton)
#callback
t.plotButton.OnClick.Add( PlotButtonCallBack )
########################################################################
# draw tool
ui_row_offset += 70
# set tool ui size
t.StartSizeX = ui_border_width + 35
t.StartSizeY = ui_row_offset
####################################################################
# Main
####################################################################
def CreateTool():
global t
t = FBCreateUniqueTool("Plot Selected Takes")
PopulateTool(t)
ShowTool(t)
CreateTool()
PNG
####################################################################
# Quickly Mirror Selected Character and Takes
####################################################################
from pyfbsdk import *
import RS.Globals
from RS.Utils import Scene
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 getCharacterNodeList( character ):
characterNodeList = []
hips = character.GetModel( FBBodyNodeId.kFBHipsNodeId )
dummy = Scene.GetParent( hips )
Scene.GetChildren( dummy, characterNodeList, "", True )
return characterNodeList
def getCharacterNodeFromList( characterNodeList, node_name ):
for node in characterNodeList:
if node.Name == node_name:
return node
def mirrorCurrentCharacter():
# get current character
current_character = FBApplication().CurrentCharacter
# make sure rig is off
current_character.Active = False
# turn on mirror mode
current_character.MirrorMode = True
# plot to rig
plotToRig( current_character )
# turn off mirror mode
current_character.MirrorMode = False
# get mover node
characterNodeList = getCharacterNodeList( current_character )
mover = getCharacterNodeFromList( characterNodeList, 'mover' )
oh_facing = getCharacterNodeFromList( characterNodeList, 'OH_FacingDirection' )
oh_fixup = getCharacterNodeFromList( characterNodeList, 'OH_UpperFixupDirection' )
########################################################################################
# mirror mover key values
########################################################################################
if mover:
# flip Y translation axis key values
for key in mover.Translation.GetAnimationNode().Nodes[1].FCurve.Keys:
key.Value *= -1.0
# flip Z rotation axis key values and add 180'
for key in mover.Rotation.GetAnimationNode().Nodes[2].FCurve.Keys:
key.Value *= -1.0
key.Value += 180.0
########################################################################################
# mirror oh_facing key values
########################################################################################
if oh_facing:
# flip Z rotation axis key values
for key in oh_facing.Rotation.GetAnimationNode().Nodes[2].FCurve.Keys:
key.Value *= -1.0
########################################################################################
# mirror oh_facing key values
########################################################################################
if oh_fixup:
# flip Z rotation axis key values
for key in oh_fixup.Rotation.GetAnimationNode().Nodes[2].FCurve.Keys:
key.Value *= -1.0
# plot back to skeleton
plotToSkeleton( current_character )
########################################################################################
# flip mover around so animation is facing the same way as it started
########################################################################################
if mover:
FBSystem().Scene.Evaluate()
mover.Selected = True
keyControl = FBKeyControl()
current_start = FBSystem().CurrentTake.LocalTimeSpan.GetStart()
current_end = FBSystem().CurrentTake.LocalTimeSpan.GetStop()
range = FBTimeSpan( current_start, current_end )
current_mover_rotation = FBVector3d()
current_mover_translation = FBVector3d()
mover.GetVector( current_mover_translation, FBModelTransformationType.kModelTranslation, True )
mover.GetVector( current_mover_rotation, FBModelTransformationType.kModelRotation, True )
keyControl.MoveKeys( range, mover, current_mover_translation, FBVector3d(current_mover_rotation[0], current_mover_rotation[1] - 180.0, current_mover_rotation[2])
, FBVector3d(100.0, 100.0, 100.0), current_start )
mover.Selected = False
def quickMirror():
number_of_selected_takes = getNumberOfSelectedTakes()
if number_of_selected_takes == 0:
mirrorCurrentCharacter()
else:
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 ]
mirrorCurrentCharacter()
print "Mirroring Complete"
####################################################################
# Main
####################################################################
quickMirror()PNG
####################################################################
# Quickly Plot either down to skeleton or vice versa depending on current state
####################################################################
from pyfbsdk import *
import RS.Globals
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:
plotToSkeleton( current_character )
else:
plotToRig( current_character )
# ToggleDevices()
print "Plotting Complete"
####################################################################
# Main
####################################################################
QuickPlot()PNG
####################################################################
# Captures the current take soft range to a tmp clipboard.
# Allows user to set another takes soft range to match this.
# Useful for reviewing mocap.
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
####################################################################
# UI callbacks
####################################################################
def sliderUpdated(control, event):
current_start = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
current_end = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()
current_frame = FBSystem().LocalTime.GetFrame()
total_frame_count = current_end - current_start
# set zoom bars to be 10% (of total frames) either side of the current time
new_zoom_start = current_frame - (control.Value * control.Value * total_frame_count)
new_zoom_stop = current_frame + (control.Value * control.Value * total_frame_count)
# set values
FBPlayerControl().ZoomWindowStart = (FBTime(0,0,0,int(new_zoom_start)))
FBPlayerControl().ZoomWindowStop = (FBTime(0,0,0,int(new_zoom_stop)))
####################################################################
# UI definition
####################################################################
def pasteButtonCallBack(control, event):
FBPlayerControl().ZoomWindowStart = (FBTime(0, 0, 0, int(t.zoom_start)))
FBPlayerControl().ZoomWindowStop = (FBTime(0, 0, 0, int(t.zoom_end)))
def copyButtonCallBack(control, event):
t.zoom_start = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
t.zoom_end = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()
# update paste button UI
t.paste_button.Caption = "Set Zoom Range to [ " + str(t.zoom_start) + ":" + str(t.zoom_end) + " ]"
def PopulateTool(t):
# ui modifiers for easier element positioning
ui_tool_width = 275
ui_gap = 5
ui_copy_button_width = 25
ui_copy_button_height = 25
ui_paste_button_width = ui_tool_width - ui_copy_button_width - ui_gap*6
ui_paste_button_height = 25
ui_offset_width = 5
ui_offset_height = 0
# ----------------------------------------------------------------------------
# Reset Button
# ----------------------------------------------------------------------------
ui_offset_height += ui_gap
x = FBAddRegionParam( ui_offset_width, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam( ui_offset_height, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam( ui_copy_button_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam( ui_copy_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("copy_button_region", "copy_button_region", x, y, w, h)
t.copy_button = FBButton()
t.SetControl("copy_button_region", t.copy_button)
t.copy_button.Visible = True
t.copy_button.ReadOnly = False
t.copy_button.Enabled = True
t.copy_button.Hint = "Copy the zoom range from the current take."
t.copy_button.Caption = ">"
t.copy_button.State = 0
t.copy_button.Style = FBButtonStyle.kFBPushButton
t.copy_button.Justify = FBTextJustify.kFBTextJustifyCenter
t.copy_button.Look = FBButtonLook.kFBLookNormal
t.copy_button.OnClick.Add(copyButtonCallBack)
# ----------------------------------------------------------------------------
# Paste Range Button
# ----------------------------------------------------------------------------
# set zoom extents on tool start
t.zoom_start = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
t.zoom_end = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()
ui_offset_width += ui_copy_button_width + ui_gap
x = FBAddRegionParam(ui_offset_width, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_offset_height, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_paste_button_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_paste_button_height, FBAttachType.kFBAttachNone, "")
t.AddRegion("paste_button_region", "paste_button_region", x, y, w, h)
t.paste_button = FBButton()
t.SetControl("paste_button_region", t.paste_button)
t.paste_button.Visible = True
t.paste_button.ReadOnly = False
t.paste_button.Enabled = True
t.paste_button.Hint = "Sets zoom time range to previous captured range. \nTo update range to current take extents press > button."
t.paste_button.Caption = "Set Zoom Range to [ " + str(t.zoom_start) + ":"+ str(t.zoom_end) + " ]"
t.paste_button.State = 0
t.paste_button.Style = FBButtonStyle.kFBPushButton
t.paste_button.Justify = FBTextJustify.kFBTextJustifyCenter
t.paste_button.Look = FBButtonLook.kFBLookNormal
t.paste_button.OnClick.Add(pasteButtonCallBack)
# ----------------------------------------------------------------------------
# Draw Tool
# ----------------------------------------------------------------------------
ui_offset_height += 70
t.StartSizeX = ui_tool_width
t.StartSizeY = ui_offset_height
ShowTool(t)
####################################################################
# Main
####################################################################
def CreateTool():
global t
t = FBCreateUniqueTool("Range Clipboard")
PopulateTool(t)
CreateTool()
PNG
####################################################################
# Records from a selected object controlled by Physics
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
class RecordPhysics():
def __init__(self):
self.lSystem = FBSystem()
self.lScene = self.lSystem.Scene
self.lSysOnUIIdle = self.lSystem.OnUIIdle
self.lSysPlayer = FBPlayerControl()
self.recording_state = False
self.callback_added = False
self.selected_model_pos = [ ]
self.selected_model_rot = [ ]
self.captured_frame_number = [ ]
self.record_button = FBButton()
# get selected object
self.selected_models = FBModelList()
FBGetSelectedModels(self.selected_models)
if len(self.selected_models) == 0:
FBMessageBox("Message", "Nothing selected", "OK", None, None)
else:
self.selected_model = self.selected_models[ 0 ]
# clear selection to allow physics to work!
self.clearSelection()
def populateLayout(self, tool):
"""
UI definition
"""
ui_x_offset = 5
ui_y_offset = 5
ui_x_width = 250
ui_button_height = 30
x = FBAddRegionParam(ui_x_offset, FBAttachType.kFBAttachTop, "")
y = FBAddRegionParam(ui_y_offset, FBAttachType.kFBAttachNone, "")
w = FBAddRegionParam(ui_x_width, FBAttachType.kFBAttachNone, "")
h = FBAddRegionParam(ui_button_height, FBAttachType.kFBAttachNone, "")
tool.AddRegion("record_button_region", "record_button_region", x, y, w, h)
tool.SetControl("record_button_region", self.record_button)
self.record_button.Visible = True
self.record_button.ReadOnly = False
self.record_button.Enabled = True
self.record_button.Hint = "Record"
self.record_button.Caption = "Record Current Take"
self.record_button.OnClick.Add(self.recordButtonCallBack)
def clearSelection(self):
"""
Clear selection function
"""
# Get selected models
model_list = FBModelList()
FBGetSelectedModels(model_list, None, True)
# Deselect models
for model in model_list:
model.Selected = False
def recordButtonCallBack(self, control, event):
if self.callback_added == False:
self.callback_added = True
self.record_button.Caption = "Recording"
# create new take
current_take_name = self.lSystem.CurrentTake.Name
self.lSystem.CurrentTake.CopyTake('recorded_' + current_take_name)
# go to new take
self.lSystem.CurrentTake = self.lSystem.Scene.Takes[ -1 ]
# set playback control at start
self.lSysPlayer.GotoStart()
# start playback
self.lSysPlayer.Play()
self.lSystem.Scene.Evaluate()
print "Capturing animation of " + self.selected_model.Name + "."
# add UI callback
self.lSysOnUIIdle.Add( self.playbackCallback )
def playbackCallback(self, control, event):
if self.lSysPlayer.IsPlaying:
self.recording_state = True
current_frame = self.lSystem.LocalTime.GetFrame()
frame_index = current_frame - self.lSystem.CurrentTake.LocalTimeSpan.GetStart().GetFrame()
# only capture pos/rot if it hasn't already this frame
if len(self.selected_model_pos) < frame_index + 1:
# store frame we are capturing on since we need to handle skipped frames
self.captured_frame_number.append(frame_index)
# print "capturing position, frame index is " + str(frame_index) + " len of arrays is " + str(len(self.selected_model_pos))
obj_trans = FBVector3d()
obj_rot = FBVector3d()
self.selected_model.GetVector(obj_trans, FBModelTransformationType.kModelTranslation, True)
self.selected_model.GetVector(obj_rot, FBModelTransformationType.kModelRotation, True)
self.selected_model_pos.append(obj_trans)
self.selected_model_rot.append(obj_rot)
###################################################################################
# end frame reached, stop recording paste results
###################################################################################
if not self.lSysPlayer.IsPlaying and self.recording_state == True:
#if current_frame >= self.lSystem.CurrentTake.LocalTimeSpan.GetStop().GetFrame():
self.lSysPlayer.Stop()
# go to new take
self.lSystem.CurrentTake = self.lSystem.Scene.Takes[ -1 ]
# create null
self.null = FBModelNull('recording_of_' + self.selected_model.Name)
self.null.Selected = True
frame_index = 0
for frame in range(0, len(self.captured_frame_number)):
self.lSysPlayer.Goto(FBTime(0, 0, 0, self.captured_frame_number[ frame ]))
self.lSystem.Scene.Evaluate()
self.null.SetVector(self.selected_model_pos[ frame_index ], FBModelTransformationType.kModelTranslation, True)
self.null.SetVector(self.selected_model_rot[ frame_index ], FBModelTransformationType.kModelRotation, True)
self.lSystem.Scene.Evaluate()
self.lSysPlayer.Key()
frame_index += 1
print "Completed capture."
# remove callback
self.lSystem.OnUIIdle.Remove( self.playbackCallback )
def createTool():
"""
Record physics on selected object
"""
t = FBCreateUniqueTool("Record Physics")
t.StartSizeX = 275
t.StartSizeY = 80
rpt = RecordPhysics()
rpt.populateLayout(t)
ShowTool(t)
createTool()
PNG
####################################################################
# Allows user to paste a pose on character extensions
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
# Global UI components
MAX_LIST_BOX_ENTRIES = 40
def GetTakeNames():
pass
####################################################################
# UI CallBacks
####################################################################
def AllTakesCallback(control, event):
for item in range( len(t.list.Items) ):
t.list.Selected( item, True )
def NoTakesCallback(control, event):
for item in range( len(t.list.Items) ):
t.list.Selected( item, False )
def RenameCallback(control, event):
# capture current user selection
selection_list = []
print "Renaming Takes"
for item in range( len(t.list.Items) ):
#only apply to selected takes
if( t.list.IsSelected( item ) ):
# cache user selection
selection_list.append( True )
#replace string operation first...
new_name = FBSystem().Scene.Takes[ item ].Name.replace( t.findEdit.Text, t.replaceEdit.Text)
#... then add any prefix or suffix
new_name = t.prefix.Text + new_name + t.suffix.Text
#capitalise string if wanted
if( t.capitaliseButton.State == True ):
new_name = new_name.upper()
#remove any spaces in string if wanted
if( t.whiteSpaceButton.State == True ):
new_name = new_name.replace(" ", "")
# rename take!
FBSystem().Scene.Takes[ item ].Name = new_name
else:
# cache user selection
selection_list.append( False )
# update UI to match new names
t.list.Items.removeAll()
for iTake in FBSystem().Scene.Takes:
t.list.Items.append(iTake.Name)
# restore user selection
for index in range( len(t.list.Items) ):
t.list.Selected( index, selection_list[ index ] )
####################################################################
# UI
####################################################################
def PopulateTool(t):
# ui variables for easier modification
ui_border_x = 10
ui_border_y = 10
ui_border_width = 215
ui_border_height = 100
ui_row_offset = 10
########################################################################
# All Takes Button
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width / 6 ,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("all_takes_button","all_takes_button", x, y, w, h)
t.alltakesbutton = FBButton()
t.alltakesbutton.Caption = "All"
t.SetControl("all_takes_button", t.alltakesbutton)
#callback
t.alltakesbutton.OnClick.Add( AllTakesCallback )
########################################################################
# No Takes Button
x = FBAddRegionParam(ui_border_width + 10 - ui_border_width / 4 ,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width / 4 ,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("no_takes_button","no_takes_button", x, y, w, h)
t.nonetakesbutton = FBButton()
t.nonetakesbutton.Caption = "None"
t.SetControl("no_takes_button", t.nonetakesbutton)
#callback
t.nonetakesbutton.OnClick.Add( NoTakesCallback )
########################################################################
ui_row_offset += 25
#Take List
t.list = FBList()
t.list.Style = FBListStyle.kFBVerticalList
t.list.MultiSelect = True
t.list.ExtendedSelect = True
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
# get take names and calculate size required for UI list at same time
for iTake in FBSystem().Scene.Takes:
t.list.Items.append(iTake.Name)
# select UI if user had take selected
if ( iTake.Selected == True ):
t.list.Selected( len( t.list.Items) - 1, True )
#limit UI size
if( len(t.list.Items) < MAX_LIST_BOX_ENTRIES ):
ui_row_offset += 15
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
t.AddRegion("takes","takes", x, y, w, h)
t.SetControl("takes", t.list)
########################################################################
#Border
ui_row_offset += 40
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_border_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("border_a","", x, y, w, h)
t.SetBorder("border_a",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
########################################################################
#Prefix Label
x = FBAddRegionParam(ui_border_x + 5,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width - 10,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("prefix_region","prefix_region", x, y, w, h)
t.prefixLabel = FBLabel()
t.SetControl("prefix_region", t.prefixLabel)
t.prefixLabel.Justify = FBTextJustify.kFBTextJustifyLeft
t.prefixLabel.Visible = True
t.prefixLabel.ReadOnly = False
t.prefixLabel.Enabled = True
t.prefixLabel.Caption = "Prefix"
#Prefix Edit
ui_row_offset += 20
x = FBAddRegionParam(ui_border_x + 5,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width - 10,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("prefix_edit","prefix_edit", x, y, w, h)
t.prefix = FBEdit()
t.SetControl("prefix_edit", t.prefix)
########################################################################
#Suffix Label
ui_row_offset += 25
x = FBAddRegionParam(ui_border_x + 5,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width - 10,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("suffix_region","suffix_region", x, y, w, h)
t.suffixLabel = FBLabel()
t.SetControl("suffix_region", t.suffixLabel)
t.suffixLabel.Justify = FBTextJustify.kFBTextJustifyLeft
t.suffixLabel.Visible = True
t.suffixLabel.ReadOnly = False
t.suffixLabel.Enabled = True
t.suffixLabel.Caption = "Suffix"
#Suffix Edit
ui_row_offset += 20
x = FBAddRegionParam(ui_border_x + 5,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width - 10,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("suffix_edit","suffix_edit", x, y, w, h)
t.suffix = FBEdit()
t.SetControl("suffix_edit", t.suffix)
########################################################################
#Border
ui_row_offset += 40
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_border_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("border_b","", x, y, w, h)
t.SetBorder("border_b",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
########################################################################
#Find Label
x = FBAddRegionParam(ui_border_x + 5,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width - 10,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("find_region","find_region", x, y, w, h)
t.findLabel = FBLabel()
t.SetControl("find_region", t.findLabel)
t.findLabel.Justify = FBTextJustify.kFBTextJustifyLeft
t.findLabel.Visible = True
t.findLabel.ReadOnly = False
t.findLabel.Enabled = True
t.findLabel.Caption = "Find"
#Find Edit
ui_row_offset += 20
x = FBAddRegionParam(ui_border_x + 5,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width - 10,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("find_edit","find_edit", x, y, w, h)
t.findEdit = FBEdit()
t.SetControl("find_edit", t.findEdit)
########################################################################
#Replace Label
ui_row_offset += 25
x = FBAddRegionParam(ui_border_x + 5,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width - 10,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("replace_label","replace_label", x, y, w, h)
t.replaceLabel = FBLabel()
t.SetControl("replace_label", t.replaceLabel)
t.replaceLabel.Justify = FBTextJustify.kFBTextJustifyLeft
t.replaceLabel.Visible = True
t.replaceLabel.ReadOnly = False
t.replaceLabel.Enabled = True
t.replaceLabel.Caption = "Replace"
#Replace Edit
ui_row_offset += 20
x = FBAddRegionParam(ui_border_x + 5,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width - 10,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("replace_edit","replace_edit", x, y, w, h)
t.replaceEdit = FBEdit()
t.SetControl("replace_edit", t.replaceEdit)
########################################################################
# Capitalise?
ui_row_offset += 45
x = FBAddRegionParam(ui_border_x ,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("capitalise","capitalise", x, y, w, h)
t.capitaliseButton = FBButton()
t.SetControl("capitalise", t.capitaliseButton)
t.capitaliseButton.Visible = True
t.capitaliseButton.ReadOnly = False
t.capitaliseButton.Enabled = True
t.capitaliseButton.Hint = "capitalise selected take names"
t.capitaliseButton.Caption = "Capitalise names?"
t.capitaliseButton.State = 1
t.capitaliseButton.Style = FBButtonStyle.kFBCheckbox
t.capitaliseButton.Justify = FBTextJustify.kFBTextJustifyLeft
t.capitaliseButton.Look = FBButtonLook.kFBLookNormal
########################################################################
# Remove White Space?
ui_row_offset += 25
x = FBAddRegionParam(ui_border_x ,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("whiteSpace","whiteSpace", x, y, w, h)
t.whiteSpaceButton = FBButton()
t.SetControl("whiteSpace", t.whiteSpaceButton)
t.whiteSpaceButton.Visible = True
t.whiteSpaceButton.ReadOnly = False
t.whiteSpaceButton.Enabled = True
t.whiteSpaceButton.Hint = "Delete any spaces contained within take names"
t.whiteSpaceButton.Caption = "Remove white space?"
t.whiteSpaceButton.State = 1
t.whiteSpaceButton.Style = FBButtonStyle.kFBCheckbox
t.whiteSpaceButton.Justify = FBTextJustify.kFBTextJustifyLeft
t.whiteSpaceButton.Look = FBButtonLook.kFBLookNormal
########################################################################
#Rename Button
ui_row_offset += 30
x = FBAddRegionParam(ui_border_x ,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(30,FBAttachType.kFBAttachNone,"")
t.AddRegion("rename_button","rename_button", x, y, w, h)
t.renameButton = FBButton()
t.renameButton.Caption = "Rename Selected"
t.SetControl("rename_button", t.renameButton)
#callback
t.renameButton.OnClick.Add( RenameCallback )
########################################################################
# draw tool
ui_row_offset += 70
# set tool ui size
t.StartSizeX = 250
t.StartSizeY = ui_row_offset + 10
####################################################################
# Main
####################################################################
def CreateTool():
global t
t = FBCreateUniqueTool("Rename Takes")
PopulateTool(t)
ShowTool(t)
CreateTool()
PNG
####################################################################
# Allows user to lock selected horse's saddle
####################################################################
from pyfbsdk import *
SKEL_SADDLE = None
SKEL_RearSeat = None
# Get Skel_Seat
obj_list = FBComponentList()
FBFindObjectsByName('SKEL_SADDLE', obj_list , False, False)
if len(obj_list) > 0:
SKEL_SADDLE = obj_list[0]
obj_list = FBComponentList()
FBFindObjectsByName('SKEL_RearSeat', obj_list , False, False)
if len(obj_list) > 0:
SKEL_RearSeat = obj_list[0]
if SKEL_SADDLE != None and SKEL_RearSeat != None:
# Lock SKEL_SADDLE
SKEL_SADDLE.PropertyList.Find("Enable Translation DOF").Data = True
SKEL_SADDLE.PropertyList.Find("TranslationMinX").Data = True
SKEL_SADDLE.PropertyList.Find("TranslationMinY").Data = True
SKEL_SADDLE.PropertyList.Find("TranslationMinZ").Data = True
SKEL_SADDLE.PropertyList.Find("TranslationMaxX").Data = True
SKEL_SADDLE.PropertyList.Find("TranslationMaxY").Data = True
SKEL_SADDLE.PropertyList.Find("TranslationMaxZ").Data = True
SKEL_SADDLE.PropertyList.Find("TranslationMin").Data = FBVector3d(0.11934,-0.12884,0.00000)
SKEL_SADDLE.PropertyList.Find("TranslationMax").Data = FBVector3d(0.11934,-0.12884,0.00000)
# Lock SKEL_RearSeat
SKEL_RearSeat.PropertyList.Find("Enable Translation DOF").Data = True
SKEL_RearSeat.PropertyList.Find("TranslationMinX").Data = True
SKEL_RearSeat.PropertyList.Find("TranslationMinY").Data = True
SKEL_RearSeat.PropertyList.Find("TranslationMinZ").Data = True
SKEL_RearSeat.PropertyList.Find("TranslationMaxX").Data = True
SKEL_RearSeat.PropertyList.Find("TranslationMaxY").Data = True
SKEL_RearSeat.PropertyList.Find("TranslationMaxZ").Data = True
SKEL_RearSeat.PropertyList.Find("TranslationMin").Data = FBVector3d(-0.18352,-0.14310,0.00000)
SKEL_RearSeat.PropertyList.Find("TranslationMax").Data = FBVector3d(-0.18352,-0.14310,0.00000)
else:
print "SKEL_SADDLE or SKEL_RearSeat dofs not found in scene!"PNG
from pyfbsdk import *
SEARCH_STRING = 'mover'
#get current character
character = FBApplication().CurrentCharacter
if character is not None:
obj_to_select = FBFindModelByLabelName(character.OwnerNamespace.Name + ':' + SEARCH_STRING)
if obj_to_select is not None:
obj_to_select.Selected = True
else:
print SEARCH_STRING + ' Not Found!'PNG
from pyfbsdk import *
SEARCH_STRING = 'PH_R_Hand'
#get current character
character = FBApplication().CurrentCharacter
if character is not None:
obj_to_select = FBFindModelByLabelName(character.OwnerNamespace.Name + ':' + SEARCH_STRING)
if obj_to_select is not None:
obj_to_select.Selected = True
else:
print SEARCH_STRING + ' Not Found!'PNG
from pyfbsdk import *
from pyfbsdk_additions import *
from RS.Utils.ContextManagers import SceneExpressionsDisabled
def clamp(n, minn, maxn):
return max(min(maxn, n), minn)
####################################################################
# UI callbacks
####################################################################
def enableAngleButtonCallback(control, event):
if t.enableAngleButton.State:
t.absAngle.Enabled = True
else:
t.absAngle.Enabled = False
return
def enableAutoButtonCallback(control, event):
if t.enableAutoButton.State:
t.minHeight.Enabled = False
t.maxHeight.Enabled = False
else:
t.minHeight.Enabled = True
t.maxHeight.Enabled = True
return
def findAnimationNode( pName, pNode ):
lResult = None
lName = pName.split( '/' )
for lNode in pNode.Nodes:
if lNode.Name == lName[0]:
if len( lName ) > 1:
lResult = findAnimationNode( pName.replace( '%s/' % lName[0], '' ), lNode )
else:
lResult = lNode
return lResult
def resetButtonCallBack(control, event):
# Disable all expressions for the duration of this event
with SceneExpressionsDisabled():
# get selection
models = FBModelList()
FBGetSelectedModels( models )
num_of_models = len( models )
if num_of_models == 0:
FBMessageBox( "Message", "Nothing selected", "OK", None, None )
else:
print "Resetting IK"
for model in models:
ik_property = model.PropertyList.Find('IK Reach Translation')
if ik_property:
animNode = ik_property.GetAnimationNode()
if animNode:
animNode.FCurve.EditClear()
ik_property.Data = 100.0
ik_property.SetAnimated( False )
ik_property = model.PropertyList.Find('IK Reach Rotation')
if ik_property:
animNode = ik_property.GetAnimationNode()
if animNode:
animNode.FCurve.EditClear()
ik_property.Data = 100.0
ik_property.SetAnimated( False )
ik_property = model.PropertyList.Find('IK Pull')
if ik_property:
animNode = ik_property.GetAnimationNode()
if animNode:
animNode.FCurve.EditClear()
ik_property.Data = 0.0
ik_property.SetAnimated( False )
ik_property = model.PropertyList.Find('IK Pull Hips')
if ik_property:
animNode = ik_property.GetAnimationNode()
if animNode:
animNode.FCurve.EditClear()
ik_property.Data = 0.0
ik_property.SetAnimated( False )
def applyButtonCallBack(control, event):
# Disable all expressions for the duration of this event
with SceneExpressionsDisabled():
# get selection
models = FBModelList()
FBGetSelectedModels( models )
model_height = []
model_rotation_z = []
model_translation = FBVector3d()
num_of_models = len(models)
if num_of_models == 0:
FBMessageBox( "Message", "Nothing selected", "OK", None, None )
else:
# get time span
current_start = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
current_end = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()
lowest_height = []
highest_height = []
# initialise heights
for model in models:
lowest_height.append( 1000 )
highest_height.append( -1000 )
for frame in range(current_start, current_end + 1):
# update slider
FBPlayerControl().Goto(FBTime(0,0,0,frame))
model_count = 0
# get height in WS of each object
for model in models:
FBSystem().Scene.Evaluate()
# get ws position
model.GetVector( model_translation, FBModelTransformationType.kModelTranslation, True)
#model.GetVector( model_rotation, FBModelTransformationType.kModelRotation, False )
if model_translation[1] < lowest_height[model_count]:
lowest_height[model_count] = model_translation[1]
if model_translation[1] > highest_height[model_count]:
highest_height[model_count] = model_translation[1]
rotationNode = findAnimationNode( 'Lcl Rotation/Z', model.AnimationNode )
model_rotation = rotationNode.FCurve.Evaluate( FBTime(0,0,0,frame) )
# store height (Y axis)
model_height.append( model_translation[1] )
# store angle (z axis)
model_rotation_z.append( model_rotation )
model_count += 1
key_count = 0
for frame in range(current_start, current_end + 1):
model_count = 0
# print percentage of zero height for each object
for model in models:
if t.enableAutoButton.State:
max_height = highest_height[ model_count ]
min_height = lowest_height[ model_count ]
else:
max_height = t.maxHeight.Value
min_height = t.minHeight.Value
# simply clamp values outside ranges since we want to deal with IK weights between 0, 100 only
clamped_model_height = clamp( model_height[ key_count * num_of_models + model_count ], min_height, max_height )
height_weight_percent = ( ( clamped_model_height - min_height ) / ( max_height - min_height ) ) * 100.0
# finally we need to flip the percentage (since max means zero weight and vice versa)
height_weight_percent = 100 - height_weight_percent
# set appropriate IK weight for selected transforms
# first see if attribute exists (valid IK effector)
if t.transButton.State:
ik_property = model.PropertyList.Find('IK Reach Translation')
if ik_property:
ik_property.SetAnimated(True)
ik_property.GetAnimationNode().FCurve.KeyAdd( FBTime(0,0,0,frame), height_weight_percent )
# if we're at the end frame and we want to filter curves
if frame == current_end and t.enableSmoothFilterButton.State:
lFilter = FBFilterManager().CreateFilter( 'Smooth' )
if lFilter:
lFilter.Apply( ik_property.GetAnimationNode(), True )
if t.rotButton.State:
ik_property = model.PropertyList.Find('IK Reach Rotation')
if ik_property:
ik_property.SetAnimated(True)
if t.enableAngleButton.State == 1:
# calculate abs angle and obtain rotation weighting
abs_angle = abs( model_rotation_z[ key_count * num_of_models + model_count ] )
clamped_abs_angle = clamp( abs_angle, 0.0, t.absAngle.Value )
angle_weight_percent = ( clamped_abs_angle / t.absAngle.Value ) * 100.0
# we need to flip the percentage (since max means zero weight and vice versa)
angle_weight_percent = 100 - angle_weight_percent
multiplied_height_and_angle_percent = ( angle_weight_percent * height_weight_percent ) / 100.0
ik_property.GetAnimationNode().FCurve.KeyAdd( FBTime(0,0,0,frame), multiplied_height_and_angle_percent )
else:
ik_property.GetAnimationNode().FCurve.KeyAdd( FBTime(0,0,0,frame), height_weight_percent )
# if we're at the end frame and we want to filter curves
if frame == current_end and t.enableSmoothFilterButton.State:
lFilter = FBFilterManager().CreateFilter( 'Smooth' )
if lFilter:
lFilter.Apply( ik_property.GetAnimationNode(), True )
model_count += 1
key_count += 1
####################################################################
# UI definition
####################################################################
def PopulateTool(t):
# UI constants
ui_x_offset = 10
ui_y_offset = 5
ui_x_width = 240
ui_button_height = 30
ui_button_width = 40
ui_column_a = 20
ui_column_b = 100
ui_column_c = 100
##########################################################################################
# Reset IK Button
#########################################################################################
x = FBAddRegionParam(ui_x_offset,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 20,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(25,FBAttachType.kFBAttachNone,"")
t.AddRegion("reset_button","reset_button", x, y, w, h)
t.resetButton = FBButton()
t.SetControl("reset_button", t.resetButton )
t.resetButton.Visible = True
t.resetButton.ReadOnly = False
t.resetButton.Enabled = True
t.resetButton.Hint = "Deletes any IK T/R animation on selected IK pivots, and resets them to 100%"
t.resetButton.Caption = "Reset Selected IK"
t.resetButton.State = 0
t.resetButton.Style = FBButtonStyle.kFBPushButton
t.resetButton.Justify = FBTextJustify.kFBTextJustifyCenter
t.resetButton.Look = FBButtonLook.kFBLookNormal
t.resetButton.OnClick.Add( resetButtonCallBack )
ui_y_offset += 30
##########################################################################################
# Min Height for IK effectors
##########################################################################################
ui_y_offset += 10
x = FBAddRegionParam(ui_x_offset,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 20,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_height + 10,FBAttachType.kFBAttachNone,"")
t.AddRegion("min_height_border","Height which IK weight is 100% (cms)", x, y, w, h)
t.SetBorder("min_height_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_y_offset += 10
x = FBAddRegionParam(ui_x_offset + 10,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 40,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("min_height_edit","min_height_edit", x, y, w, h)
t.minHeight = FBEditNumber()
t.SetControl("min_height_edit", t.minHeight)
t.minHeight.Visible = True
t.minHeight.ReadOnly = False
t.minHeight.Enabled = False
t.minHeight.Value = 10.0
ui_y_offset += ui_button_height + 10
##########################################################################################
# Max Height for IK effectors
##########################################################################################
ui_y_offset += 10
x = FBAddRegionParam(ui_x_offset,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 20,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_height + 10,FBAttachType.kFBAttachNone,"")
t.AddRegion("max_height_border","Height which IK weight is 0% (cms)", x, y, w, h)
t.SetBorder("max_height_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_y_offset += 10
x = FBAddRegionParam(ui_x_offset + 10,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 40,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("max_height_edit","max_height_edit", x, y, w, h)
t.maxHeight = FBEditNumber()
t.SetControl("max_height_edit", t.maxHeight)
t.maxHeight.Visible = True
t.maxHeight.ReadOnly = False
t.maxHeight.Enabled = False
t.maxHeight.Value = 60.0
##########################################################################################
# Use Auto Extents instead
##########################################################################################
ui_y_offset += ui_button_height + 10
x = FBAddRegionParam(ui_x_offset + 10,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 40,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("enable_auto","enable_auto", x, y, w, h)
t.enableAutoButton = FBButton()
t.SetControl("enable_auto", t.enableAutoButton)
t.enableAutoButton.Visible = True
t.enableAutoButton.ReadOnly = False
t.enableAutoButton.Enabled = True
t.enableAutoButton.Caption = "Auto Extents"
t.enableAutoButton.State = 1
t.enableAutoButton.Style = FBButtonStyle.kFBCheckbox
t.enableAutoButton.Justify = FBTextJustify.kFBTextJustifyLeft
t.enableAutoButton.Look = FBButtonLook.kFBLookNormal
t.enableAutoButton.OnClick.Add( enableAutoButtonCallback )
##########################################################################################
# Min Angle for IK effectors
##########################################################################################
ui_y_offset += ui_button_height + 5
x = FBAddRegionParam(ui_x_offset,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 20,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_height + 40,FBAttachType.kFBAttachNone,"")
t.AddRegion("abs_angle_border","Absolute Angle which IK weight is 0% (Z Axis)", x, y, w, h)
t.SetBorder("abs_angle_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
# enable button
ui_y_offset += 15
x = FBAddRegionParam(ui_x_offset + 10,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 40,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("enable_angle","enable_angle", x, y, w, h)
t.enableAngleButton = FBButton()
t.SetControl("enable_angle", t.enableAngleButton)
t.enableAngleButton.Visible = True
t.enableAngleButton.ReadOnly = False
t.enableAngleButton.Enabled = True
t.enableAngleButton.Caption = "Enable?"
t.enableAngleButton.State = 0
t.enableAngleButton.Style = FBButtonStyle.kFBCheckbox
t.enableAngleButton.Justify = FBTextJustify.kFBTextJustifyLeft
t.enableAngleButton.Look = FBButtonLook.kFBLookNormal
t.enableAngleButton.OnClick.Add( enableAngleButtonCallback )
# edit box
ui_y_offset += 25
x = FBAddRegionParam(ui_x_offset + 10,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 40,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("abs_angle_edit","abs_angle_edit", x, y, w, h)
t.absAngle = FBEditNumber()
t.SetControl("abs_angle_edit", t.absAngle)
t.absAngle.Visible = True
t.absAngle.ReadOnly = False
t.absAngle.Enabled = False
t.absAngle.Value = 30.0
ui_y_offset += ui_button_height + 10
##########################################################################################
# IK effectors to modify
##########################################################################################
ui_y_offset += 10
# border
x = FBAddRegionParam(ui_x_offset,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 20,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_height * 2 + 10,FBAttachType.kFBAttachNone,"")
t.AddRegion("IK_Effectors_border","IK transforms to modify", x, y, w, h)
t.SetBorder("IK_Effectors_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_y_offset += 15
# translation button
x = FBAddRegionParam(ui_x_offset + 10,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 40,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("trans_button","trans_button", x, y, w, h)
t.transButton = FBButton()
t.SetControl("trans_button", t.transButton)
t.transButton.Visible = True
t.transButton.ReadOnly = False
t.transButton.Enabled = True
t.transButton.Hint = "Modify weight of Translation on IK effector?"
t.transButton.Caption = "IK Blend T"
t.transButton.State = 1
t.transButton.Style = FBButtonStyle.kFBCheckbox
t.transButton.Justify = FBTextJustify.kFBTextJustifyLeft
t.transButton.Look = FBButtonLook.kFBLookNormal
ui_y_offset += 25
# rotation button
x = FBAddRegionParam(ui_x_offset + 10,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 40,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("rot_button","rot_button", x, y, w, h)
t.rotButton = FBButton()
t.SetControl("rot_button", t.rotButton)
t.rotButton.Visible = True
t.rotButton.ReadOnly = False
t.rotButton.Enabled = True
t.rotButton.Hint = "Modify weight of Rotation on IK effector?"
t.rotButton.Caption = "IK Blend R"
t.rotButton.State = 1
t.rotButton.Style = FBButtonStyle.kFBCheckbox
t.rotButton.Justify = FBTextJustify.kFBTextJustifyLeft
t.rotButton.Look = FBButtonLook.kFBLookNormal
ui_y_offset += 40
##########################################################################################
# Use Smooth Filter?
##########################################################################################
x = FBAddRegionParam(ui_x_offset + 10,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 40,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"")
t.AddRegion("smooth_filter","smooth_filter", x, y, w, h)
t.enableSmoothFilterButton = FBButton()
t.SetControl("smooth_filter", t.enableSmoothFilterButton)
t.enableSmoothFilterButton.Visible = True
t.enableSmoothFilterButton.ReadOnly = False
t.enableSmoothFilterButton.Enabled = True
t.enableSmoothFilterButton.Caption = "Smooth Filter on Weight Curves?"
t.enableSmoothFilterButton.State = 1
t.enableSmoothFilterButton.Style = FBButtonStyle.kFBCheckbox
t.enableSmoothFilterButton.Justify = FBTextJustify.kFBTextJustifyLeft
t.enableSmoothFilterButton.Look = FBButtonLook.kFBLookNormal
##########################################################################################
# Apply Button
##########################################################################################
ui_y_offset += 30
x = FBAddRegionParam(ui_x_offset,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_y_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_x_width - 20,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(25,FBAttachType.kFBAttachNone,"")
t.AddRegion("apply_button","apply_button", x, y, w, h)
t.applyButton = FBButton()
t.SetControl("apply_button", t.applyButton )
t.applyButton.Visible = True
t.applyButton.ReadOnly = False
t.applyButton.Enabled = True
t.applyButton.Hint = ""
t.applyButton.Caption = "Apply"
t.applyButton.State = 0
t.applyButton.Style = FBButtonStyle.kFBPushButton
t.applyButton.Justify = FBTextJustify.kFBTextJustifyCenter
t.applyButton.Look = FBButtonLook.kFBLookNormal
t.applyButton.OnClick.Add( applyButtonCallBack )
ui_y_offset += ui_button_height + 30
##########################################################################################
# Calculate Tool Window Size and Draw
##########################################################################################
t.StartSizeX = ui_x_width + ui_x_offset * 2
t.StartSizeY = ui_y_offset + 10
ShowTool(t)
####################################################################
# Main
####################################################################
def CreateTool():
global t
t = FBCreateUniqueTool("SetIKRelativeToHeight 2014")
PopulateTool(t)
CreateTool()
PNG
####################################################################
# Changes the in and out interpolation of all story clips to smooth
####################################################################
from pyfbsdk import *
def getClipsInTrack(track,clips):
for clip in track.Clips:
clips.append(clip)
for subtrack in track.SubTracks:
getClipsInTrack(subtrack, clips)
return clips
def smoothAllCharacterTracks():
story = FBStory()
tracks = story.RootFolder.Tracks
clips = []
for track in tracks:
getClipsInTrack(track,clips)
for clip in clips:
# Set to smooth. Enum value is '2'.
prop = clip.PropertyList.Find("Fade In Interpolation")
if prop:
prop.Data = 2
prop = clip.PropertyList.Find("Fade Out Interpolation")
if prop:
prop.Data = 2
smoothAllCharacterTracks()
####################################################################
# Create Secondary Motion
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
import math
####################################################################
# Vector Ops - Replace?
####################################################################
def VectorAdd( a, b ):
c = FBVector3d()
c[0] = a[0] + b[0]
c[1] = a[1] + b[1]
c[2] = a[2] + b[2]
return c
def VectorSub( a, b ):
c = FBVector3d()
c[0] = a[0] - b[0]
c[1] = a[1] - b[1]
c[2] = a[2] - b[2]
return c
def VectorLength( a ):
return math.sqrt( a[0]*a[0] + a[1]*a[1] + a[2]*a[2] )
def VectorNorm( v ):
len = VectorLength( v )
if len > 0.0:
v[0] /= len
v[1] /= len
v[2] /= len
return v
def VectorMul(a, scale ):
c = FBVector3d()
c[0] = a[0] * scale
c[1] = a[1] * scale
c[2] = a[2] * scale
return c
def VectorDiv( a, scale ):
c = FBVector3d()
c[0] = a[0] / scale
c[1] = a[1] / scale
c[2] = a[2] / scale
return c
def VectorDot( a, b ):
return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]
####################################################################
def GetSelectedObject():
models = FBModelList()
FBGetSelectedModels(models)
if len(models) == 0:
return None
else:
return models[0]
def CalculateSpring( dt, inputPos, oldPos, linVel ):
mass = 1.0 # <-- replace with mass variable!
friction = 0.1 # <-- replace with friction variable!
stiffness = 0.1 # <-- replace with stiffness variable!
damping = 0.01 # <-- replace with damping variable!
lForce = FBVector3d()
resistance = FBVector3d()
# position & velocity
px1 = FBVector3d()
px2 = FBVector3d()
pv1 = FBVector3d()
pv2 = FBVector3d()
dx = FBVector3d()
dv = FBVector3d()
# vector length
m = 0.0
r = 0.0
value = 0.0
# position
px1 = inputPos
px2 = oldPos
dx = VectorSub(px1, px2)
# velocity
pv1 = VectorSub(inputPos, oldPos)
pv2 = linVel
dv = VectorSub(pv1, pv2)
# force
r = 0.0 # <-- replace with length variable!
m = VectorLength(dx)
if m == 0.0:
m = 0.0001
lForce = dx
lForce = VectorNorm(lForce)
value = (stiffness * (m - r) + damping * (VectorDot( dv, dx )/m) )
lForce = VectorMul(lForce, value)
lForce = VectorDiv(lForce, mass)
# add friction
resistance = VectorMul(linVel, -friction)
# add resistance to total forces
lForce = VectorAdd(lForce, resistance )
# update velocity
linVel = VectorAdd(linVel, lForce )
# update position based on new velocity
newPositions = VectorAdd( oldPos, linVel )
return newPositions, linVel
def Main():
# get selected object
obj = GetSelectedObject()
if obj is None:
FBMessageBox("Message", "Nothing selected", "OK", None, None)
else:
FBSystem().Scene.Evaluate()
# frame range
take_start_frame = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
take_end_frame = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()
# initialise
inputPositions = []
inputRotations = []
newPositions = []
newRotations = []
linVel = FBVector3d()
angVel = FBVector3d()
inputPos = FBVector3d()
inputRot = FBVector3d()
# init position
obj.GetVector( inputPos, FBModelTransformationType.kModelTranslation, True )
currentPos = inputPos
oldPos = currentPos
# init rotation
obj.GetVector(inputRot, FBModelTransformationType.kModelRotation, True)
currentRot = inputRot
oldRot = currentRot
dt = 1.0 / 30.0
####################################################################
# main loop through frames to calculate simulation
####################################################################
frame_count = 0
for frame in range(take_start_frame, take_end_frame + 1):
# update frame
FBPlayerControl().Goto(FBTime(0, 0, 0, frame))
FBSystem().Scene.Evaluate()
# get current transformation
obj.GetVector(inputPos, FBModelTransformationType.kModelTranslation, True)
obj.GetVector(inputRot, FBModelTransformationType.kModelRotation, True)
# apply Spring Forces
outPos, linVel = CalculateSpring( dt, inputPos, oldPos, linVel )
outRot, angVel = CalculateSpring( dt, inputRot, oldRot, angVel )
# Store pre/post simulation results
newPositions.append(FBVector3d(outPos[0],outPos[1],outPos[2]))
inputPositions.append(FBVector3d(inputPos[0],inputPos[1],inputPos[2]))
newRotations.append(FBVector3d(outRot[ 0 ], outRot[ 1 ], outRot[ 2 ]))
inputRotations.append(FBVector3d(inputRot[ 0 ], inputRot[ 1 ], inputRot[ 2 ]))
oldPos = currentPos
currentPos = newPositions[frame_count]
oldRot = currentRot
currentRot = newRotations[frame_count]
frame_count += 1
####################################################################
# apply results
####################################################################
# create layer for results
FBSystem().CurrentTake.CreateNewLayer()
# select new layer and rename
num_layers = FBSystem().CurrentTake.GetLayerCount()
new_layer = FBSystem().CurrentTake.GetLayer(num_layers - 1)
FBSystem().CurrentTake.SetCurrentLayer(num_layers - 1)
new_layer.SelectLayer(True, True)
new_layer.Name = "SpringLayer (" + str(obj.Name) + ")"
frame_count = 0
for frame in range(take_start_frame, take_end_frame + 1):
# apply position
obj.Translation.GetAnimationNode().Nodes[ 0 ].KeyAdd(FBTime(0, 0, 0, frame), newPositions[frame_count][ 0 ] - inputPositions[frame_count][0] )
obj.Translation.GetAnimationNode().Nodes[ 1 ].KeyAdd(FBTime(0, 0, 0, frame), newPositions[ frame_count ][ 1 ] - inputPositions[frame_count][1] )
obj.Translation.GetAnimationNode().Nodes[ 2 ].KeyAdd(FBTime(0, 0, 0, frame), newPositions[ frame_count ][ 2 ] - inputPositions[frame_count][2] )
# apply rotation
obj.Rotation.GetAnimationNode().Nodes[ 0 ].KeyAdd(FBTime(0, 0, 0, frame), newRotations[frame_count][ 0 ] - inputRotations[frame_count][0] )
obj.Rotation.GetAnimationNode().Nodes[ 1 ].KeyAdd(FBTime(0, 0, 0, frame), newRotations[ frame_count ][ 1 ] - inputRotations[frame_count][1] )
obj.Rotation.GetAnimationNode().Nodes[ 2 ].KeyAdd(FBTime(0, 0, 0, frame), newRotations[ frame_count ][ 2 ] - inputRotations[frame_count][2] )
frame_count += 1
Main()
PNG
####################################################################
# Toggles visibility of various OH dofs on character, and
# renders them as toon shader
####################################################################
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 createOrGetToonShader():
for shader in FBSystem().Scene.Shaders:
if 'FlatCartoonShader' in shader.Name or 'Edge Cartoon' in shader.Name:
return shader
# create a cartoon shader if there isn't one available to use
return FBShaderManager().CreateShader("FlatCartoonShader")
currentCharacter = FBApplication().CurrentCharacter
if not currentCharacter == None:
characterNodeList = getCharacterHeirarchyList(currentCharacter)
dofs = { 'mover':None, 'oh_independentmoverdirection':None, 'oh_upperfixupdirection':None, 'oh_torsodirection':None, 'oh_facingdirection':None, 'oh_moveroffset':None, 'ph_movergroundlocation':None, 'camerabasepivotoffset_controller':None }
for node in characterNodeList:
node_name = node.Name.lower()
if node_name in dofs:
dofs[node_name] = node
myToonShader = createOrGetToonShader()
if dofs['mover'] != None:
moverVisibility = dofs['mover'].Show
for dof in dofs:
if dofs[dof] != None:
myToonShader.ReplaceAll( dofs[dof] )
dofs[dof].ShadingMode = FBModelShadingMode.kFBModelShadingAll
dofs[dof].Show = not moverVisibilityPNG
####################################################################
# Update Mover Node
# Mike Jones - November 2009
#
# Will create UI and allow user to auto animate a character's mover node.
#
# Known limitations:
# Mover node has to be called player:mover
# Assumes user will want mover to default to (global) pos 0,100,0 rot -90,0,0
# Gets rotational info from player:SKEL_Pelvis not player:SKEL_Root - Needs to be tested with new skel!
#
#
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
from RS.Utils.ContextManagers import SceneExpressionsDisabled
from RS import Globals
# Global UI components
trans_x_button = FBButton()
trans_y_button = FBButton()
trans_z_button = FBButton()
trans_offset_button = FBButton()
rot_y_button = FBButton()
rot_offset_button = FBButton()
rot_gimble_button = FBButton()
frame_radios = FBButtonGroup()
frame_current_button = FBButton()
frame_all_button = FBButton()
frame_radios.Add(frame_current_button)
frame_radios.Add(frame_all_button)
take_radios = FBButtonGroup()
take_current_button = FBButton()
take_selected_button = FBButton()
take_all_button = FBButton()
take_radios.Add(take_current_button)
take_radios.Add(take_selected_button)
take_radios.Add(take_all_button)
go_button = FBButton()
def getMoverNodes():
# get list of all models called 'mover'
mover_list = FBComponentList()
FBFindObjectsByName('mover', mover_list , False, True)
FBFindObjectsByName('Mover', mover_list , False, True)
FBFindObjectsByName('MOVER', mover_list , False, True)
filtered_mover_list = []
chars = FBSystem().Scene.Characters
# go through each model called mover and find which ones actually belong to characters
# so we get rid of vehicles etc.
# put result in new filtered_mover_list
for object in mover_list:
for char in chars:
extensions = char.CharacterExtensions
for e in extensions:
components = e.Components
for c in components:
if c.LongName == object.LongName:
filtered_mover_list.append(object)
return filtered_mover_list
def setupPropertyList(tool):
tool.list.Items.removeAll()
tool.prop_list = []
mover_list = getMoverNodes()
if len(mover_list):
for mover in mover_list:
tool.list.Items.append(mover.LongName)
else:
tool.list.Items.append('No mover node found!')
def resetMoverNode(moverNode):
# current mover defaults (local coords)
vMoverDefaultT = FBVector3d(0.0, 0.0, 1.0)
vMoverDefaultR = FBVector3d(0.0, 0.0, 0.0)
# set pos/rot
moverNode.SetVector (vMoverDefaultR, FBModelTransformationType.kModelRotation, False)
moverNode.SetVector (vMoverDefaultT, FBModelTransformationType.kModelTranslation, False)
FBSystem().Scene.Evaluate()
return
def rotButtonCallback(control, event):
if rot_y_button.State:
rot_offset_button.Enabled = True
rot_gimble_button.Enabled = True
else:
rot_offset_button.Enabled = False
rot_gimble_button.Enabled = False
return
def transButtonCallback(control, event):
if trans_x_button.State or trans_y_button.State or trans_z_button.State:
trans_offset_button.Enabled = True
else:
trans_offset_button.Enabled = False
return
####################################################################
# Go Button CallBack
####################################################################
def goButtonCallBack(control, event):
with SceneExpressionsDisabled():
# get bones
chosenMover = t.list.Items[t.list.ItemIndex]
mMover = FBFindModelByLabelName(chosenMover)
# need to replace the mover with bone
mRoot = FBFindModelByLabelName( ( chosenMover.rsplit(':', 1 ) )[0] + ":SKEL_ROOT" )
mPelvis = FBFindModelByLabelName( ( chosenMover.rsplit(':', 1 ) )[0] + ":SKEL_Pelvis" )
# error check models
if not (mRoot or mPelvis or mMover):
print "Error! Cannot find part of heirarchy!"
return
# --------------------------------------------------------
# create take list depending on Takes radio buttons
# --------------------------------------------------------
take_list = []
if take_all_button.State:
take_list = FBSystem().Scene.Takes
user_response = FBMessageBox( "Warning", "Are you sure you want to update all takes?", "Yes", "No" )
if user_response == 2:
return
elif take_selected_button.State:
user_response = FBMessageBox( "Warning", "Do you have all of your Takes selected?\n\nIf not, Hit 'No', select your takes and then try again.", "Yes", "No" )
if user_response == 2:
return
for take in Globals.Takes:
if take.Selected == True:
take_list.append(take)
if len(take_list) == 0:
FBMessageBox( "Warning", "There are no Takes selected.\n\nPlease select required takes and try again.", "Ok")
else:
take_list.append(FBSystem().CurrentTake)
# --------------------------------------------------------
# main loop for every take
# --------------------------------------------------------
for take in take_list:
FBSystem().CurrentTake = take
# make sure keys are set on the base layer
FBSystem().CurrentTake.SetCurrentLayer(0)
# --------------------------------------------------------
# get scene info - time/takes etc.
# --------------------------------------------------------
current_start = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
current_end = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()
current_frame = FBSystem().LocalTime.GetFrame()
current_take = FBSystem().CurrentTake
# --------------------------------------------------------
# switch to first frame of animation,
# and reset mover position/rotation to creation defaults(keep offset),
# or align to root(no offset),
# before applying constraints
# --------------------------------------------------------
FBPlayerControl().Goto(FBTime(0,0,0,current_start))
resetMoverNode(mMover)
if not trans_offset_button.State:
# get root position
root_trans = FBVector3d()
mRoot.GetVector (root_trans, FBModelTransformationType.kModelTranslation, True)
# set mover to match root pos
mMover.SetVector (root_trans, FBModelTransformationType.kModelTranslation, True)
if not rot_offset_button.State:
pelvis_rot = FBVector3d()
mPelvis.GetVector (pelvis_rot, FBModelTransformationType.kModelRotation, False)
# set mover to match root pos
mMover.SetVector (pelvis_rot, FBModelTransformationType.kModelRotation, False)
FBSystem().Scene.Evaluate()
# --------------------------------------------------------
# create position constraint between SKEL_Root/mover
# --------------------------------------------------------
if trans_x_button.State or trans_y_button.State or trans_z_button.State:
lMgr = FBConstraintManager()
# get index to parent/child constraint
lIndex = None
for i in range(0, lMgr.TypeGetCount()):
if lMgr.TypeGetName(i) == 'Position':
lIndex = i
break
# create constraint
lPosConst = lMgr.TypeCreateConstraint(lIndex)
#FBSystem().Scene.Constraints.append(lPosConst)
# add ref objects
for i in range(0, lPosConst.ReferenceGroupGetCount()):
if lPosConst.ReferenceGroupGetName(i) == 'Source':
lPosConst.ReferenceAdd(i, mRoot)
elif lPosConst.ReferenceGroupGetName(i) == 'Constrained Object':
lPosConst.ReferenceAdd(i, mMover)
# snap/activate constraint
lPosConst.Snap()
# --------------------------------------------------------
# create rotation constraint between SKEL_Pelvis/mover
# --------------------------------------------------------
if rot_y_button.State:
lMgr = FBConstraintManager()
# get index to parent/child constraint
lIndex = None
for i in range(0, lMgr.TypeGetCount()):
if lMgr.TypeGetName(i) == 'Rotation':
lIndex = i
break
# create constraint
lRotConst = lMgr.TypeCreateConstraint(lIndex)
#FBSystem().Scene.Constraints.append(lRotConst)
# add ref objects
for i in range(0, lRotConst.ReferenceGroupGetCount()):
if lRotConst.ReferenceGroupGetName(i) == 'Source':
lRotConst.ReferenceAdd(i, mPelvis)
elif lRotConst.ReferenceGroupGetName(i) == 'Constrained Object':
lRotConst.ReferenceAdd(i, mMover)
# snap/activate constraint
lRotConst.Snap()
# --------------------------------------------------------
# key constraints - current frame only
# --------------------------------------------------------
if frame_current_button.State == True:
# return player to original frame
FBPlayerControl().Goto(FBTime(0,0,0,current_frame))
# get mover translation and rotation
mover_trans = FBVector3d()
mover_rot = FBVector3d()
FBSystem().Scene.Evaluate()
mMover.GetVector (mover_trans, FBModelTransformationType.kModelTranslation, False)
mMover.GetVector (mover_rot, FBModelTransformationType.kModelRotation, False)
# key mover
if trans_x_button.State:
mMover.Translation.GetAnimationNode().Nodes[0].KeyAdd(mover_trans[0])
if trans_y_button.State:
mMover.Translation.GetAnimationNode().Nodes[1].KeyAdd(mover_trans[1])
if trans_z_button.State:
mMover.Translation.GetAnimationNode().Nodes[2].KeyAdd(mover_trans[2])
if rot_y_button.State:
mMover.Rotation.GetAnimationNode().Nodes[0].KeyAdd(0)
mMover.Rotation.GetAnimationNode().Nodes[1].KeyAdd(0)
mMover.Rotation.GetAnimationNode().Nodes[2].KeyAdd(mover_rot[2])
# reset mover before deleting constraints
resetMoverNode(mMover)
# delete constraints
if trans_x_button.State or trans_y_button.State or trans_z_button.State:
lPosConst.FBDelete()
if rot_y_button.State:
lRotConst.FBDelete()
# --------------------------------------------------------
# key constraints - all frames
# --------------------------------------------------------
else:
trans_array = []
rot_array = []
#----------------------------------------------------------------------------
# copy pos/rot values
for index in range(current_start,current_end+1):
# update time slider
FBPlayerControl().Goto(FBTime(0,0,0,index))
FBSystem().Scene.Evaluate()
# get mover translation and rotation
mover_trans = FBVector3d()
mover_rot = FBVector3d()
mMover.GetVector (mover_trans, FBModelTransformationType.kModelTranslation, False)
mMover.GetVector (mover_rot, FBModelTransformationType.kModelRotation, False)
trans_array.append(mover_trans)
rot_array.append(mover_rot)
#----------------------------------------------------------------------------
# reset mover before deleting constraints
resetMoverNode(mMover)
# delete constraints
if trans_x_button.State or trans_y_button.State or trans_z_button.State:
lPosConst.FBDelete()
if rot_y_button.State:
lRotConst.FBDelete()
#----------------------------------------------------------------------------
# set pos/rot values
count = 0
for index in range(current_start,current_end+1):
# key values on to mover
FBPlayerControl().Goto(FBTime(0,0,0,index))
FBSystem().Scene.Evaluate()
# key mover
if trans_x_button.State:
mMover.Translation.GetAnimationNode().Nodes[0].KeyAdd(trans_array[count][0])
if trans_y_button.State:
mMover.Translation.GetAnimationNode().Nodes[1].KeyAdd(trans_array[count][1])
if trans_z_button.State:
mMover.Translation.GetAnimationNode().Nodes[2].KeyAdd(trans_array[count][2])
if rot_y_button.State:
mMover.Rotation.GetAnimationNode().Nodes[0].KeyAdd(0)
mMover.Rotation.GetAnimationNode().Nodes[1].KeyAdd(0)
mMover.Rotation.GetAnimationNode().Nodes[2].KeyAdd(rot_array[count][2])
count = count + 1
# --------------------------------------------------------
# Gimble Killer filter rotation curve to avoid Euler problems
# --------------------------------------------------------
if rot_y_button.State and rot_gimble_button.State:
# get list of keys before filter(use rot z)
curr_key_times = []
keys = mMover.Rotation.GetAnimationNode().Nodes[2].FCurve.Keys
for key in keys:
curr_key_times.append(key.Time.Get())
#----------------------------------------------------------------
# apply gimble killer
lFilter = FBFilterManager().CreateFilter( 'Gimble Killer' )
if lFilter:
lFilter.Apply( mMover.Rotation.GetAnimationNode(), True )
del(lFilter)
#----------------------------------------------------------------
# get list of keys after filter(use rot z)
new_key_times = []
keys = mMover.Rotation.GetAnimationNode().Nodes[2].FCurve.Keys
for key in keys:
new_key_times.append(key.Time.Get())
#----------------------------------------------------------------
# go through before and after lists and remove new keys added by filter
i = 0
for loop in range(len(new_key_times)):
if new_key_times[i] != curr_key_times[i]:
# we have a mismatch - delete new keys
mMover.Rotation.GetAnimationNode().Nodes[0].FCurve.KeyRemove(i)
mMover.Rotation.GetAnimationNode().Nodes[1].FCurve.KeyRemove(i)
mMover.Rotation.GetAnimationNode().Nodes[2].FCurve.KeyRemove(i)
# remove from new list and don't iterate counter
del new_key_times[i]
else:
# fine, existing key from before filter - just iterate counter
i = i + 1
# --------------------------------------------------------
# leave user back at frame when script began and refresh
# need to go back a frame to force proper update - ???
# --------------------------------------------------------
FBPlayerControl().Goto(FBTime(0,0,0,current_frame-1))
FBSystem().Scene.Evaluate()
FBPlayerControl().Goto(FBTime(0,0,0,current_frame))
FBSystem().Scene.Evaluate()
####################################################################
# UI
####################################################################
def PopulateTool(t):
# ui variables for easier modification
ui_border_x = 10
ui_border_y = 10
ui_border_width = 140
ui_border_height = 100
ui_column_a = 20
ui_column_b = 60
ui_column_c = 100
ui_row_offset = 10
ui_button_width = 40
#Mover Selection----------------------------------------------
#Drop Down
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(25,FBAttachType.kFBAttachNone,"")
t.AddRegion("dropdown","dropdown", x, y, w, h)
t.list = FBList()
t.SetControl("dropdown", t.list)
setupPropertyList(t)
#Translation--------------------------------------------------
ui_row_offset += 40
#Border
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_border_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("trans_border","Translation", x, y, w, h)
t.SetBorder("trans_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_row_offset += 10
#Buttons
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"region1")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
t.AddRegion("region1","region1", x, y, w, h)
t.SetControl("region1", trans_x_button)
trans_x_button.Visible = True
trans_x_button.ReadOnly = False
trans_x_button.Enabled = True
trans_x_button.Hint = ""
trans_x_button.Caption = "X"
trans_x_button.State = 1
trans_x_button.Style = FBButtonStyle.kFBCheckbox
trans_x_button.Justify = FBTextJustify.kFBTextJustifyLeft
trans_x_button.Look = FBButtonLook.kFBLookNormal
trans_x_button.OnClick.Add(transButtonCallback)
x = FBAddRegionParam(ui_column_b,FBAttachType.kFBAttachNone,"region1")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
t.AddRegion("region2","region2", x, y, w, h)
t.SetControl("region2", trans_y_button)
trans_y_button.Visible = True
trans_y_button.ReadOnly = False
trans_y_button.Enabled = True
trans_y_button.Hint = ""
trans_y_button.Caption = "Y"
trans_y_button.State = 1
trans_y_button.Style = FBButtonStyle.kFBCheckbox
trans_y_button.Justify = FBTextJustify.kFBTextJustifyLeft
trans_y_button.Look = FBButtonLook.kFBLookNormal
trans_y_button.OnClick.Add(transButtonCallback)
x = FBAddRegionParam(ui_column_c,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
t.AddRegion("region3","region3", x, y, w, h)
t.SetControl("region3", trans_z_button)
trans_z_button.Visible = True
trans_z_button.ReadOnly = False
trans_z_button.Enabled = True
trans_z_button.Hint = ""
trans_z_button.Caption = "Up"
trans_z_button.State = 0
trans_z_button.Style = FBButtonStyle.kFBCheckbox
trans_z_button.Justify = FBTextJustify.kFBTextJustifyLeft
trans_z_button.Look = FBButtonLook.kFBLookNormal
trans_z_button.OnClick.Add(transButtonCallback)
ui_row_offset = ui_row_offset + 40
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(120,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
t.AddRegion("region4","region4", x, y, w, h)
t.SetControl("region4", trans_offset_button)
trans_offset_button.Visible = True
trans_offset_button.ReadOnly = False
trans_offset_button.Enabled = True
trans_offset_button.Hint = "Maintain initial offset on Mover?"
trans_offset_button.Caption = "Keep Offset?"
trans_offset_button.State = 0
trans_offset_button.Style = FBButtonStyle.kFBCheckbox
trans_offset_button.Justify = FBTextJustify.kFBTextJustifyLeft
trans_offset_button.Look = FBButtonLook.kFBLookNormal
#Rotation--------------------------------------------------
ui_row_offset = ui_row_offset + 60
#Border
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_border_height+30,FBAttachType.kFBAttachNone,"")
t.AddRegion("rot_border","Rotation", x, y, w, h)
t.SetBorder("rot_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_row_offset = ui_row_offset + 10
#Buttons
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"rot_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
t.AddRegion("rot_region","rot_region", x, y, w, h)
t.SetControl("rot_region", rot_y_button)
rot_y_button.Visible = True
rot_y_button.ReadOnly = False
rot_y_button.Enabled = True
rot_y_button.Hint = ""
rot_y_button.Caption = "Up"
rot_y_button.State = 0
rot_y_button.Style = FBButtonStyle.kFBCheckbox
rot_y_button.Justify = FBTextJustify.kFBTextJustifyLeft
rot_y_button.Look = FBButtonLook.kFBLookNormal
rot_y_button.OnClick.Add(rotButtonCallback)
ui_row_offset = ui_row_offset + 40
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"rot_offset_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(120,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
t.AddRegion("rot_offset_region","rot_offset_region", x, y, w, h)
t.SetControl("rot_offset_region", rot_offset_button)
rot_offset_button.Visible = True
rot_offset_button.ReadOnly = False
rot_offset_button.Enabled = False
rot_offset_button.Hint = "Maintain initial offset on Mover?"
rot_offset_button.Caption = "Keep Offset?"
rot_offset_button.State = 1
rot_offset_button.Style = FBButtonStyle.kFBCheckbox
rot_offset_button.Justify = FBTextJustify.kFBTextJustifyLeft
rot_offset_button.Look = FBButtonLook.kFBLookNormal
ui_row_offset = ui_row_offset + 40
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"rot_gimble_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(120,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
t.AddRegion("rot_gimble_region","rot_gimble_region", x, y, w, h)
t.SetControl("rot_gimble_region", rot_gimble_button)
rot_gimble_button.Visible = True
rot_gimble_button.ReadOnly = False
rot_gimble_button.Enabled = False
rot_gimble_button.Hint = "Apply Gimble Killer filter on rotation?"
rot_gimble_button.Caption = "Gimble Filter?"
rot_gimble_button.State = 1
rot_gimble_button.Style = FBButtonStyle.kFBCheckbox
rot_gimble_button.Justify = FBTextJustify.kFBTextJustifyLeft
rot_gimble_button.Look = FBButtonLook.kFBLookNormal
rot_gimble_button.OnClick.Add(rotButtonCallback)
#Frames--------------------------------------------------
ui_row_offset = ui_row_offset + 50
#Border
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_border_height,FBAttachType.kFBAttachNone,"")
t.AddRegion("frame_border","Frames", x, y, w, h)
t.SetBorder("frame_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_row_offset = ui_row_offset + 10
#Buttons
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"frame_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(120,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
t.AddRegion("frame_region","frame_region", x, y, w, h)
t.SetControl("frame_region", frame_current_button)
frame_current_button.Visible = True
frame_current_button.ReadOnly = False
frame_current_button.Enabled = True
frame_current_button.Hint = ""
frame_current_button.Caption = "Current"
frame_current_button.State = 1
frame_current_button.Style = FBButtonStyle.kFBRadioButton
frame_current_button.Justify = FBTextJustify.kFBTextJustifyLeft
frame_current_button.Look = FBButtonLook.kFBLookNormal
ui_row_offset = ui_row_offset + 30
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"frame_all_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(120,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
t.AddRegion("frame_all_region","frame_all_region", x, y, w, h)
t.SetControl("frame_all_region", frame_all_button)
frame_all_button.Visible = True
frame_all_button.ReadOnly = False
frame_all_button.Enabled = True
frame_all_button.Hint = ""
frame_all_button.Caption = "All"
frame_all_button.State = 0
frame_all_button.Style = FBButtonStyle.kFBRadioButton
frame_all_button.Justify = FBTextJustify.kFBTextJustifyLeft
frame_all_button.Look = FBButtonLook.kFBLookNormal
#Takes--------------------------------------------------
ui_row_offset = ui_row_offset + 70
#Border
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachNone,"")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_border_height+20,FBAttachType.kFBAttachNone,"")
t.AddRegion("take_border","Takes", x, y, w, h)
t.SetBorder("take_border",FBBorderStyle.kFBEmbossBorder,True,True,2,0,90.0,0)
ui_row_offset = ui_row_offset + 10
#Buttons
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"take_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(120,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
t.AddRegion("take_region","take_region", x, y, w, h)
t.SetControl("take_region", take_current_button)
take_current_button.Visible = True
take_current_button.ReadOnly = False
take_current_button.Enabled = True
take_current_button.Hint = ""
take_current_button.Caption = "Current"
take_current_button.State = 1
take_current_button.Style = FBButtonStyle.kFBRadioButton
take_current_button.Justify = FBTextJustify.kFBTextJustifyLeft
take_current_button.Look = FBButtonLook.kFBLookNormal
ui_row_offset = ui_row_offset + 30
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"take_selected_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(120,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
t.AddRegion("take_selected_region","take_selected_region", x, y, w, h)
t.SetControl("take_selected_region", take_selected_button)
take_selected_button.Visible = True
take_selected_button.ReadOnly = False
take_selected_button.Enabled = True
take_selected_button.Hint = ""
take_selected_button.Caption = "Selected"
take_selected_button.State = 0
take_selected_button.Style = FBButtonStyle.kFBRadioButton
take_selected_button.Justify = FBTextJustify.kFBTextJustifyLeft
take_selected_button.Look = FBButtonLook.kFBLookNormal
ui_row_offset = ui_row_offset + 30
x = FBAddRegionParam(ui_column_a,FBAttachType.kFBAttachTop,"take_all_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(120,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(ui_button_width,FBAttachType.kFBAttachNone,"")
t.AddRegion("take_all_region","take_all_region", x, y, w, h)
t.SetControl("take_all_region", take_all_button)
take_all_button.Visible = True
take_all_button.ReadOnly = False
take_all_button.Enabled = True
take_all_button.Hint = ""
take_all_button.Caption = "All"
take_all_button.State = 0
take_all_button.Style = FBButtonStyle.kFBRadioButton
take_all_button.Justify = FBTextJustify.kFBTextJustifyLeft
take_all_button.Look = FBButtonLook.kFBLookNormal
#Go Button--------------------------------------------------
ui_row_offset = ui_row_offset + 65
x = FBAddRegionParam(ui_border_x,FBAttachType.kFBAttachTop,"go_button_region")
y = FBAddRegionParam(ui_row_offset,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(ui_border_width,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(30,FBAttachType.kFBAttachNone,"")
t.AddRegion("go_button_region","go_button_region", x, y, w, h)
t.SetControl("go_button_region", go_button)
go_button.Visible = True
go_button.ReadOnly = False
go_button.Enabled = True
go_button.Hint = ""
go_button.Caption = "Go"
go_button.State = 0
go_button.Style = FBButtonStyle.kFBPushButton
go_button.Justify = FBTextJustify.kFBTextJustifyCenter
go_button.Look = FBButtonLook.kFBLookNormal
go_button.OnClick.Add(goButtonCallBack)
####################################################################
# Main
####################################################################
def CreateTool():
global t
t = FBCreateUniqueTool("Update Mover")
t.StartSizeX = 175
t.StartSizeY = 620
PopulateTool(t)
ShowTool(t)
CreateTool()PNG
####################################################################
# Frames the zoom bar around the current time
####################################################################
from pyfbsdk import *
from pyfbsdk_additions import *
####################################################################
# UI callbacks
####################################################################
def sliderUpdated(control, event):
current_start = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
current_end = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()
current_frame = FBSystem().LocalTime.GetFrame()
total_frame_count = current_end - current_start
# set zoom bars to be 10% (of total frames) either side of the current time
new_zoom_start = current_frame - (control.Value * control.Value * total_frame_count)
new_zoom_stop = current_frame + (control.Value * control.Value * total_frame_count)
# set values
FBPlayerControl().ZoomWindowStart = (FBTime(0,0,0,int(new_zoom_start)))
FBPlayerControl().ZoomWindowStop = (FBTime(0,0,0,int(new_zoom_stop)))
####################################################################
# UI definition
####################################################################
def PopulateTool(t):
#Slider
x = FBAddRegionParam(10,FBAttachType.kFBAttachTop,"")
y = FBAddRegionParam(10,FBAttachType.kFBAttachNone,"")
w = FBAddRegionParam(240,FBAttachType.kFBAttachNone,"")
h = FBAddRegionParam(15,FBAttachType.kFBAttachNone,"")
t.AddRegion("slider","slider", x, y, w, h)
t.slider = FBSlider()
t.slider.Value = 1.0
t.slider.Orientation = FBOrientation.kFBHorizontal
t.slider.OnTransaction.Add(sliderUpdated)
t.SetControl("slider", t.slider)
####################################################################
# Main
####################################################################
def CreateTool():
global t
t = FBCreateUniqueTool("Zoom Timebar")
t.StartSizeX = 275
t.StartSizeY = 70
PopulateTool(t)
ShowTool(t)
CreateTool()
<?xml version="1.0"?>
<data>
<type name="Human">
<multiplier>0.5453</multiplier>
<offset>2.2663</offset>
<minRadius>0.5</minRadius>
</type>
<!-- <type name="Animal - Medium">
<multiplier>0.3343</multiplier>
<offset>2.0042</offset>
<minRadius>0.5</minRadius>
</type> -->
</data>