在motionbuilder中使用Python脚本将动画时间码设置为零

Posted

技术标签:

【中文标题】在motionbuilder中使用Python脚本将动画时间码设置为零【英文标题】:Using Python Scripting to set animation timecode zero in motionbuilder 【发布时间】:2021-04-10 19:38:15 【问题描述】:

每个人。

我有一些动画文件的开始时间不为零。我正在尝试创建一个将动画时间码设置为零的脚本。例如,图片显示时间码不是从零开始的。非常感谢您的帮助。 enter image description here

【问题讨论】:

请提供更多细节,最好包括显示您尝试设置时间码的示例代码。 您是在尝试制作 MoBu 脚本还是 Maya 脚本?在 MoBu 中,您可以移动整个剪辑/所有关键帧以重新计时场景。我想不出改变实际时间码的简单方法 【参考方案1】:

我有点晚了,但这可能还是很有趣的分享!

您可以使用这样的 FBTimeSpan() 实例轻松设置当前镜头的时间跨度,方法是将开始和结束帧指定为 FBTime() 对象:

lStartFrame = 0
lEndFrame = 100
FBSystem().CurrentTake.LocalTimeSpan = FBTimeSpan(FBTime(0, 0, 0, lStartFrame, 0), FBTime(0, 0, 0, lEndFrame, 0))

但我猜您正在寻找一种方法来抵消您的动画并使其从 0 开始,不是吗?

这是我自己的库中的两个函数,使用故事模式在给定帧处偏移当前动画。第一个适用于场景的当前或所有角色(角色动画轨道)。第二个关于选定的组件(通用动画轨道)。对于每一个,您可以将它应该开始的帧作为参数传递,如果您想在最后构建新的时间跨度(用新的替换旧的第一帧/最后一帧)。

from pyfbsdk import *


def offset_character_animation_at_frame(frame = 0, all_chars = True, frame_anim=True):
    ''' Offset current/all(default) characters animation to a given frame, 0 by default '''

    # get list of current/all characters
    if all_chars:
        char_list = FBSystem().Scene.Characters
    else:
        char_list = [FBApplication().CurrentCharacter]

    # get initial timespan
    lStartFrame = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
    lEndFrame = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()

    # turn on Story mode
    FBStory().Mute = False

    # process character list
    for char in char_list:
        # set timespan
        FBSystem().CurrentTake.LocalTimeSpan = FBTimeSpan(FBTime(0, 0, 0, lStartFrame, 0), FBTime(0, 0, 0, lEndFrame, 0))
        # set current character
        FBApplication().CurrentCharacter = char
        # insert character animation track
        track = FBStoryTrack(FBStoryTrackType.kFBStoryTrackCharacter, FBStory().RootFolder)
        track.Name = '_charAnimTrack'.format(FBApplication().CurrentCharacter.Name)
        track.Details.append(FBApplication().CurrentCharacter)
        # insert take in story mode
        take = FBSystem().CurrentTake
        inserted_clip = track.CopyTakeIntoTrack(take.LocalTimeSpan, take)
        # move inserted clip to given frame
        inserted_clip.Start = FBTime(0,0,0,frame)
        # frame new timespan
        FBSystem().CurrentTake.LocalTimeSpan = FBTimeSpan(FBTime(0, 0, 0, inserted_clip.Start.GetFrame(), 0), FBTime(0, 0, 0, inserted_clip.Stop.GetFrame(), 0))
        # defining plot options and plot to current take
        PlotOptions = FBPlotOptions()
        PlotOptions.ConstantKeyReducerKeepOneKey = True
        PlotOptions.PlotAllTakes = False
        PlotOptions.PlotOnFrame = True
        PlotOptions.PlotPeriod = FBTime( 0, 0, 0, 1 )
        PlotOptions.PlotTranslationOnRootOnly = True
        PlotOptions.PreciseTimeDiscontinuities = True
        PlotOptions.RotationFilterToApply = FBRotationFilter.kFBRotationFilterGimbleKiller
        PlotOptions.UseConstantKeyReducer = True
        char.PlotAnimation(FBCharacterPlotWhere.kFBCharacterPlotOnSkeleton, PlotOptions)
        # empty Story mode
        for track in FBStory().RootFolder.Tracks:
            for clip in track.Clips:
                clip.FBDelete()
            track.FBDelete()

    # set back original timespan if specified
    if not frame_anim:
        FBSystem().CurrentTake.LocalTimeSpan = FBTimeSpan(FBTime(0, 0, 0, lStartFrame, 0), FBTime(0, 0, 0, lEndFrame, 0))

    # turn off Story mode
    FBStory().Mute = True


def offset_generic_animation_at_frame(frame = 0, frame_anim = True):
    ''' Offset selected components animation to a given frame, 0 by default '''

    # get selected components
    lModelList = FBModelList()
    FBGetSelectedModels(lModelList)
    if not lModelList:
        raise ValueError("Select at least one component")

    # get initial timespan
    lStartFrame = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame()
    lEndFrame = FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame()

    # turn on Story mode
    FBStory().Mute = False

    # set timespan        
    FBSystem().CurrentTake.LocalTimeSpan = FBTimeSpan(FBTime(0, 0, 0, lStartFrame, 0), FBTime(0, 0, 0, lEndFrame, 0))
    # insert generic animation track and add selected components to it
    track = FBStoryTrack(FBStoryTrackType.kFBStoryTrackAnimation, FBStory().RootFolder)
    track.Name = 'genericAnimTrack'
    for comp in lModelList:
        track.Details.append(comp)
    # insert take in story mode
    take = FBSystem().CurrentTake
    inserted_clip = track.CopyTakeIntoTrack(take.LocalTimeSpan, take)
    # move inserted clip to given frame
    inserted_clip.Start = FBTime(0,0,0,frame)
    # frame new timespan
    FBSystem().CurrentTake.LocalTimeSpan = FBTimeSpan(FBTime(0, 0, 0, inserted_clip.Start.GetFrame(), 0), FBTime(0, 0, 0, inserted_clip.Stop.GetFrame(), 0))
    # plot selected take
    lOptions = FBPlotOptions()   
    lOptions.ConstantKeyReducerKeepOneKey = False
    lOptions.PlotAllTakes = False
    lOptions.PlotOnFrame = True
    lOptions.PlotPeriod = FBTime( 0, 0, 0, 1 )
    lOptions.PlotTranslationOnRootOnly = False
    lOptions.PreciseTimeDiscontinuities = True
    lOptions.RotationFilterToApply = FBRotationFilter.kFBRotationFilterGimbleKiller
    lOptions.UseConstantKeyReducer = False
    FBSystem().CurrentTake.PlotTakeOnSelected(lOptions)

    # empty Story mode
    for track in FBStory().RootFolder.Tracks:
        for clip in track.Clips:
            clip.FBDelete()
        track.FBDelete()

    # set back original timespan if specified
    if not frame_anim:
        FBSystem().CurrentTake.LocalTimeSpan = FBTimeSpan(FBTime(0, 0, 0, lStartFrame, 0), FBTime(0, 0, 0, lEndFrame, 0))

    # turn off Story mode
    FBStory().Mute = True


# MAIN
offset_generic_animation_at_frame(frame = 0, frame_anim = False)
offset_character_animation_at_frame(frame = 0, all_chars = True, frame_anim=True)

【讨论】:

以上是关于在motionbuilder中使用Python脚本将动画时间码设置为零的主要内容,如果未能解决你的问题,请参考以下文章

motionbuilder 使用总结

motionbuilder 使用总结

将日志消息打印到 MotionBuilder

如何像在 MotionBuilder 中一样计算旋转

使用批处理将 bvh 文件转换为 fbx

motionbuilder2020安装白屏