I'm implementing a Python script that sets a start frame for multiple selected objects. The objects each have their own NLA strips with their respective values. I've been trying to 'group' these animations together, and shift them according to a user input value. For example, if a user inputs the start frame as 200, the offsets start from that frame.

Making each of the NLA strips move by +value works for adding to the NLA strips seems to work well, but when the value is changed to something lower, it would keep adding to the start frame value. Also, if the value is adjusted slightly higher, like from frame 241 to 242, the strip jumps 242 frames.

I've tried using conditional statements/expressions to control the values, but on user update, the results tend to vary or cause the animations to start on the wrong frame.

A solution I think would be to have the strips revert to their original values before each update, but I don't know how to achieve such a function. The code below is what I have so far. I have a Blend example with 3 cubes attached below

import os
import re
import bpy
from bpy.props import *
import bpy.utils.previews
from bpy.types import WindowManager
from bpy.props import StringProperty, BoolProperty, IntProperty, CollectionProperty
from bpy.types import WindowManager
from bpy.props import (StringProperty,
                       PointerProperty,
                       )
from bpy.types import (Panel,
                       Operator,
                       AddonPreferences,
                       PropertyGroup,
                       )

# Panel
class PreviewsPanel(bpy.types.Panel):
    # Create a Panel in the Tool Shelf
    bl_category = "My Panel"
    bl_label = "My Panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'

    # Draw            
    def draw(self, context):
        layout = self.layout
        scn = context.scene
        layout.label("") 
        row = layout.row(align=False)
        box = layout.box()
        row = box.row()
        row.prop(context.window_manager, "slide_1_start",text = "Start")
        box = layout.box()
        row = box.row()        

def frame_slide(self, context):
    obj = bpy.context.selected_objects
    ob = bpy.context.object
    DEFAULT = 0
    STRINGVALUE = bpy.data.window_managers["WinMan"].slide_1_start
    START1 = 70

    for obj in bpy.context.selected_objects:
        obj.animation_data.nla_tracks[0].strips[0].frame_start += STRINGVALUE 
        obj.animation_data.nla_tracks[0].strips[0].frame_end += STRINGVALUE  
        obj.animation_data.nla_tracks[0].strips[0].frame_start += 0
        obj.animation_data.nla_tracks[0].strips[0].frame_end += 0
        obj.animation_data.nla_tracks[0].strips[0].scale = 1

    for obj in bpy.context.selected_objects:

        obj.animation_data.nla_tracks[0].strips[0].frame_start += 0
        obj.animation_data.nla_tracks[0].strips[0].frame_end += 0 
        obj.animation_data.nla_tracks[0].strips[0].scale = 1
        return None

#####################################################################

# Register
def register():
    bpy.types.WindowManager.slide_1_start = bpy.props.IntProperty(name="Slide_1_SF", update=frame_slide,min=1,options={'SKIP_SAVE'})
    bpy.utils.register_module(__name__)

# Unregister
def unregister():
    bpy.utils.unregister_module(__name__)
    bpy.utils.unregister_module(__name__)

if __name__ == '__main__':
    register()   

Blend file

So, I want to create a script so that the original NLA strip values will be stored. if a user sets the start frame to 24, the NLA strips shift by +24. If a user changes the start frame to 13, original NLA strips values are restored and then shifted +13.

An example of what I'm trying to achieve is basically similar to: if I have a scene of multiple objects (like dominoes or cubes), I want to set a start frame for the animation without altering their offsets from each other.

  • Is there a reason why you didn't put this in an bpy.types.Operator. Perhaps the solution is to have another value to store the previous setting slide_1_start_previous subtract those two from each other and use the difference for movement of the strips – J. Bakker Mar 7 at 7:30
  • It is quite hard to read your code as it has a lot of unneeded code. can you clean your code up a bit? – J. Bakker Mar 7 at 7:36
up vote 0 down vote accepted

I only added the relevant parts of the code. The solution is to keep an additional setting that remembers the previous setting slide_1_start_previous. We now can calculate the difference by subtracting both values. and shift the strip using this value.

def frame_slide(self, context):
    difference = self.slide_1_start - self.slide_1_start_previous

    for obj in bpy.context.selected_objects:
        strip = obj.animation_data.nla_tracks[0].strips[0]
        scale = strip.scale
        strip.frame_start += difference
        strip.frame_end += difference  
        strip.scale = scale

    self.slide_1_start_previous = self.slide_1_start
    return None

# Register
def register():
    bpy.types.WindowManager.slide_1_start = bpy.props.IntProperty(name="Slide_1_SF", update=frame_slide,min=1,options={'SKIP_SAVE'})
    bpy.types.WindowManager.slide_1_start_previous = bpy.props.IntProperty(default=1)

    bpy.utils.register_module(__name__)

As you didn't implement it as an operator it is hard to determine when you want to reset these values. I would suggest placing this in an operator.

  • Using the difference was actually a concept I'd already tested - it gives a few errors for some reason. When the value is adjusted with a slider, it works well. However, when the value is manually entered in the slider, it does not shift the NLA strips properly. – Dassie Mar 7 at 14:30

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.