2025-12-01
This commit is contained in:
@@ -3,7 +3,7 @@ from . import anim_layers
|
||||
from . import subscriptions
|
||||
from mathutils import Vector, Quaternion
|
||||
import numpy as np
|
||||
#import time
|
||||
# import time
|
||||
|
||||
def frame_start_end(scene):
|
||||
if scene.use_preview_range:
|
||||
@@ -12,7 +12,7 @@ def frame_start_end(scene):
|
||||
else:
|
||||
frame_start = scene.frame_start
|
||||
frame_end = scene.frame_end
|
||||
return frame_start, frame_end
|
||||
return float(frame_start), float(frame_end)
|
||||
|
||||
def smart_start_end(smartkeys, frame_start, frame_end):
|
||||
'''add the first and last frame of the scene if necessery'''
|
||||
@@ -65,11 +65,11 @@ def smart_repeat(smartkeys, fcu, strip):
|
||||
#duplicate the keys on the cycle after
|
||||
keyframes_dup = []
|
||||
|
||||
|
||||
for i in range(1, int(strip.repeat)):
|
||||
for key in smartkeys[1:]:
|
||||
keydup = smartkey(key)
|
||||
keydup.frame += fcu_range*(i)
|
||||
keydup.frame += round(fcu_range*(i), 2)
|
||||
|
||||
#duplicate the tangents tuple values
|
||||
if hasattr(key, 'handle_left'):
|
||||
keydup.handle_left = Vector([key.handle_left[0] + fcu_range*(i+1), key.handle_left[1]])
|
||||
@@ -104,7 +104,6 @@ def smart_cycle(smartkeys, fcu, frame_start, frame_end):
|
||||
cycle_end_dup = int((mod.frame_end - fcu.range()[1])/fcu_range)+2
|
||||
|
||||
#copy the the right handle of the first keyframe to the last, and the left handle from the last keyframe to the first
|
||||
|
||||
smartkeys[-1].handle_right_type = smartkeys[0].handle_left_type
|
||||
smartkeys[0].handle_left_type = smartkeys[-1].handle_right_type
|
||||
# if smartkeys[-1].interpolation == 'BEZIER':
|
||||
@@ -113,13 +112,13 @@ def smart_cycle(smartkeys, fcu, frame_start, frame_end):
|
||||
# if smartkeys[0].interpolation == 'BEZIER':
|
||||
if hasattr(smartkeys[0], 'handle_left'):
|
||||
smartkeys[0].handle_left = [smartkeys[-1].handle_left[0] - fcu_range, smartkeys[0].handle_left[1]]
|
||||
|
||||
#duplicate the keys on the cycle after
|
||||
keyframes_dup = []
|
||||
for key in smartkeys[1:]:
|
||||
for i in range(cycle_end_dup):
|
||||
keydup = smartkey(key)
|
||||
keydup.frame += float(fcu_range*(i+1))
|
||||
keydup.frame += float(round(fcu_range, 2)*(i+1))
|
||||
|
||||
if hasattr(keydup, 'handle_left'):
|
||||
#duplicate the tangents tuple values
|
||||
keydup.handle_left = Vector([key.handle_left[0] + fcu_range*(i+1), key.handle_left[1]])
|
||||
@@ -127,8 +126,8 @@ def smart_cycle(smartkeys, fcu, frame_start, frame_end):
|
||||
#if it's the last keyframe then the right handle get the value from the first keyframes
|
||||
keydup.handle_right = Vector([key.handle_right[0] + fcu_range*(i+1), key.handle_right[1]])
|
||||
if keydup not in keyframes_dup:
|
||||
keydup.frame = round(keydup.frame, 2)
|
||||
keyframes_dup.append(keydup)
|
||||
|
||||
#if it's an iternal cycle then duplicate the keyframes before the cycle keyframes
|
||||
if not mod.cycles_before and mod.mode_before != 'None':
|
||||
cycle_start_dup = int((fcu.range()[0] - frame_start) /fcu_range)+2
|
||||
@@ -138,37 +137,52 @@ def smart_cycle(smartkeys, fcu, frame_start, frame_end):
|
||||
cycle_start_dup = mod.cycles_before
|
||||
if mod.use_restricted_range and mod.frame_start > (fcu.range()[0] + fcu_range * cycle_start_dup):
|
||||
cycle_start_dup = int((fcu.range()[0]-mod.frame_start)/fcu_range)+2
|
||||
|
||||
#duplicate the keys on the cycle before
|
||||
for key in smartkeys[:-1]:
|
||||
for i in range(cycle_start_dup):
|
||||
keydup = smartkey(key)
|
||||
keydup.frame -= float(fcu_range*(i+1))
|
||||
keydup.frame -= fcu_range*(i+1)
|
||||
if hasattr(keydup, 'handle_left'):
|
||||
#duplicate the tangents
|
||||
keydup.handle_left = [key.handle_left[0] - fcu_range*(i+1), key.handle_left[1]]
|
||||
if hasattr(keydup, 'handle_right'):
|
||||
keydup.handle_right = [key.handle_right[0] - fcu_range*(i+1), key.handle_right[1]]
|
||||
#if frame_end > key.frame > frame_start:
|
||||
|
||||
if keydup not in keyframes_dup:
|
||||
keydup.frame = round(keydup.frame, 2)
|
||||
keyframes_dup.append(keydup)
|
||||
#merge the keyframes from the cycle with the or iginal keyframes
|
||||
smartkeys.extend(keyframes_dup)
|
||||
smartkeys = list(set(smartkeys))
|
||||
smartkeys.sort()
|
||||
|
||||
|
||||
if mod.use_restricted_range:
|
||||
smartkeys = smart_start_end(smartkeys, mod.frame_start, mod.frame_end)
|
||||
smartkeys = smart_start_end(smartkeys, mod.frame_start+1, mod.frame_end-1)
|
||||
|
||||
return smartkeys
|
||||
|
||||
|
||||
def smart_bake(context):
|
||||
#record all the keyframes into smartkeys
|
||||
obj = context.object
|
||||
frame_start, frame_end = context.scene.als.bake_range
|
||||
fcu_smartkeys = {}
|
||||
anim_data = anim_layers.anim_data_type(obj)
|
||||
|
||||
# Initialize the progress bar
|
||||
wm = context.window_manager
|
||||
total_iterations = 0
|
||||
for track in anim_data.nla_tracks:
|
||||
if track.mute:
|
||||
continue
|
||||
if len(track.strips) != 1 or track.strips[0].action is None:
|
||||
continue
|
||||
fcurves = anim_layers.get_fcurves(obj, track.strips[0].action)
|
||||
total_iterations += len(fcurves)
|
||||
|
||||
wm.progress_begin(0, total_iterations)
|
||||
processed = 0
|
||||
|
||||
for layer, track in zip(obj.Anim_Layers, anim_data.nla_tracks):
|
||||
if track.mute:
|
||||
continue
|
||||
@@ -181,7 +195,8 @@ def smart_bake(context):
|
||||
for strip_fcu in strip.fcurves:
|
||||
strip_keyframes = [keyframe for keyframe in strip_fcu.keyframe_points if len(strip_fcu.keyframe_points) and not strip_fcu.mute]
|
||||
|
||||
for fcu in strip.action.fcurves:
|
||||
fcurves = anim_layers.get_fcurves(obj, strip.action)
|
||||
for fcu in fcurves:
|
||||
if not fcu.is_valid or fcu.mute or selected_bones_filter(obj, fcu.data_path):
|
||||
continue
|
||||
smartkeys = []
|
||||
@@ -192,9 +207,12 @@ def smart_bake(context):
|
||||
if strip.blend_type in {'COMBINE', 'REPLACE'}:
|
||||
keyframe.handle_left = Vector(key.handle_left)
|
||||
keyframe.handle_right = Vector(key.handle_right)
|
||||
|
||||
keyframe.handle_left[0] = strip_start * layer.speed + (keyframe.handle_left[0] - strip_start) * layer.speed + layer.offset
|
||||
keyframe.handle_right[0] = strip_start * layer.speed + (keyframe.handle_right[0] - strip_start) * layer.speed + layer.offset
|
||||
|
||||
#keyframe.frame += layer.offset
|
||||
keyframe.frame = strip_start * layer.speed + (keyframe.frame - strip_start) * layer.speed + layer.offset
|
||||
keyframe.frame = strip_start * layer.speed + (keyframe.frame - strip_start) * layer.speed + layer.offset# * layer.speed
|
||||
keyframe.frame = round(keyframe.frame, 2)
|
||||
if keyframe not in smartkeys:
|
||||
smartkeys.append(keyframe)
|
||||
|
||||
@@ -210,37 +228,44 @@ def smart_bake(context):
|
||||
smartkeys.sort()
|
||||
if len(fcu.modifiers) and obj.als.mergefcurves:
|
||||
smartkeys = smart_cycle(smartkeys, fcu, frame_start, frame_end)
|
||||
|
||||
|
||||
#apply strip action settings
|
||||
last_frame = (strip.frame_end - strip.frame_start) / strip.repeat + strip.frame_start
|
||||
if strip.use_reverse:
|
||||
for key in smartkeys:
|
||||
key.frame = last_frame - (key.frame - strip.frame_start)
|
||||
key.frame = last_frame - (key.frame - strip.frame_start)
|
||||
if strip.repeat > 1:
|
||||
smartkeys = smart_start_end(smartkeys, last_frame , last_frame+1) #strip.frame_start
|
||||
smartkeys = remove_outofrange_keys(smartkeys, strip.frame_start, last_frame+1) #+ layer.offset
|
||||
smartkeys = smart_repeat(smartkeys, fcu, strip)
|
||||
|
||||
if layer.frame_range:
|
||||
if layer.custom_frame_range:
|
||||
smartkeys = smart_start_end(smartkeys, strip.frame_start, strip.frame_end)
|
||||
smartkeys = remove_outofrange_keys(smartkeys, strip.frame_start, strip.frame_end)
|
||||
|
||||
#if the strip is cutting with a different strip, then add keyframes in the cut
|
||||
for layercut in obj.Anim_Layers:
|
||||
if layercut.mute or not layercut.frame_range or layercut == layer:
|
||||
if layercut.mute or not layercut.custom_frame_range or layercut == layer:
|
||||
continue
|
||||
if strip_start < layercut.frame_start < strip_end:
|
||||
smartkeys = smart_start_end(smartkeys, (layercut.frame_start-1), strip.frame_end-1)
|
||||
if strip_start < layercut.frame_end < strip_end:
|
||||
smartkeys = smart_start_end(smartkeys, (layercut.frame_end+1), strip.frame_end-1)
|
||||
|
||||
|
||||
#if the list of keyframes exists in a different track list then add them
|
||||
if (fcu.data_path, fcu.array_index) in fcu_smartkeys:
|
||||
smartkeys = list(set(fcu_smartkeys[(fcu.data_path, fcu.array_index)]+smartkeys))
|
||||
#Merge all duplicated keyframes
|
||||
smartkeys = list(set(smartkeys))
|
||||
|
||||
smartkeys.sort()
|
||||
|
||||
fcu_smartkeys.update({(fcu.data_path, fcu.array_index):smartkeys})
|
||||
|
||||
processed += 1
|
||||
wm.progress_update(processed)
|
||||
|
||||
wm.progress_end()
|
||||
|
||||
#add inbetweens
|
||||
for fcu, smartkeys in fcu_smartkeys.items():
|
||||
if not smartkeys:
|
||||
@@ -267,11 +292,13 @@ def add_inbetween(smartkeys):
|
||||
|
||||
key2 = smartkey()
|
||||
key2.frame = smartkeys[i].frame + (smartkeys[i+1].frame - smartkeys[i].frame)*2/3
|
||||
key1.frame = round(key1.frame, 2)
|
||||
key2.frame = round(key2.frame, 2)
|
||||
|
||||
key2.inbetween = True
|
||||
smartkeys.insert(i+1, key1)
|
||||
smartkeys.insert(i+2, key2)
|
||||
i += 3
|
||||
|
||||
return smartkeys
|
||||
|
||||
class smartkey:
|
||||
@@ -345,7 +372,8 @@ def mute_modifiers(obj, nla_tracks):
|
||||
for track in nla_tracks:
|
||||
if len(track.strips) != 1 or track.strips[0].action is None:
|
||||
continue
|
||||
for fcu in track.strips[0].action.fcurves:
|
||||
fcurves = anim_layers.get_fcurves(obj, track.strips[0].action)
|
||||
for fcu in fcurves:
|
||||
if selected_bones_filter(obj, fcu.data_path):
|
||||
continue
|
||||
if fcu.extrapolation == 'LINEAR':
|
||||
@@ -370,7 +398,8 @@ def unmute_modifiers(obj, nla_tracks, modifier_rec):
|
||||
for track in nla_tracks:
|
||||
if track.strips[0].action is None:
|
||||
continue
|
||||
for fcu in track.strips[0].action.fcurves:
|
||||
fcurves = anim_layers.get_fcurves(obj, track.strips[0].action)
|
||||
for fcu in fcurves:
|
||||
if not fcu.is_valid or selected_bones_filter(obj, fcu.data_path):
|
||||
continue
|
||||
if not len(fcu.modifiers):
|
||||
@@ -398,7 +427,7 @@ def select_keyframed_bones(self, context, obj):
|
||||
bpy.ops.object.posemode_toggle()
|
||||
bpy.ops.pose.select_all(action='DESELECT')
|
||||
for i in range(0, obj.als.layer_index+1):
|
||||
obj.als.layer_index = i
|
||||
obj.als['layer_index'] = i
|
||||
anim_layers.select_layer_bones(self, context)
|
||||
|
||||
def mute_constraints(obj):
|
||||
@@ -422,14 +451,15 @@ def smartbake_apply(obj, nla_tracks, fcu_keys, extrapolations):
|
||||
# return
|
||||
|
||||
# action_range = strip.frame_end - strip.frame_start
|
||||
for fcu in strip.action.fcurves:
|
||||
fcurves = anim_layers.get_fcurves(obj, strip.action)
|
||||
for fcu in fcurves:
|
||||
if not fcu.is_valid:
|
||||
continue
|
||||
if selected_bones_filter(obj, fcu.data_path):
|
||||
continue
|
||||
fcu_key = (fcu.data_path, fcu.array_index)
|
||||
if fcu_key not in fcu_keys.keys():
|
||||
strip.action.fcurves.remove(fcu)
|
||||
fcurves.remove(fcu)
|
||||
continue
|
||||
#get all the frames of the smart keys
|
||||
smartkeys = fcu_keys[fcu_key]
|
||||
@@ -453,34 +483,6 @@ def smartbake_apply(obj, nla_tracks, fcu_keys, extrapolations):
|
||||
fcu.keyframe_points[-1].co = (smart_key.frame, value)
|
||||
fcu.update()
|
||||
|
||||
#remove unnecessery keyframes
|
||||
# for i in range(int(strip.action.frame_range[0]),int(strip.action.frame_range[1]+1)):
|
||||
# if i in smart_frames:
|
||||
# #get the index of the smart key based on the smart frames + interpolations
|
||||
# smart_index = (smart_frames.index(i)+1)*3-3
|
||||
|
||||
# #if key was founded add the interpolation and handles
|
||||
# for key in fcu.keyframe_points:
|
||||
# if key.co[0] != i:
|
||||
# continue
|
||||
# key.co[1] = round(key.co[1], 4)
|
||||
# key.interpolation = smartkeys[smart_index].interpolation
|
||||
# # key.handle_left_type = smartkeys[smart_index].handle_left_type
|
||||
# # key.handle_right_type = smartkeys[smart_index].handle_right_type
|
||||
# key.handle_left_type = 'AUTO_CLAMPED' if smartkeys[smart_index].handle_left_type != 'VECTOR' else 'VECTOR'
|
||||
# key.handle_right_type = 'AUTO_CLAMPED' if smartkeys[smart_index].handle_right_type != 'VECTOR' else 'VECTOR'
|
||||
# break
|
||||
#delete the keys that are not in the list
|
||||
# else:
|
||||
# if fcu.data_path.split(".")[-1] in transform_types:
|
||||
# print('fcu.id_data', fcu.id_data, obj.animation_data.action)
|
||||
# fcu.keyframe_delete(fcu.data_path.split(".")[-1] ,index = fcu_key[1], frame = i)
|
||||
# else:
|
||||
# try:
|
||||
# fcu.keyframe_delete(fcu.data_path.split(".")[-1], frame = i)
|
||||
# except TypeError:
|
||||
# pass
|
||||
|
||||
i = 0
|
||||
while i < len(fcu.keyframe_points):
|
||||
key = fcu.keyframe_points[i]
|
||||
@@ -518,7 +520,7 @@ def armature_restore(obj, b_layers, layers_rec, constraint_rec):
|
||||
def attr_default(obj, fcu_key):
|
||||
'''Returns the default value or default array value in a list'''
|
||||
#check if the fcurve source belongs to a bone or obj
|
||||
if fcu_key[0][:10] == 'pose.bones':
|
||||
if fcu_key[0][:10] == 'pose.bones':
|
||||
transform = fcu_key[0].split('.')[-1]
|
||||
attr = fcu_key[0].split('"')[-2]
|
||||
bone = fcu_key[0].split('"')[1]
|
||||
@@ -557,7 +559,7 @@ def attr_default(obj, fcu_key):
|
||||
attr = fcu_key[0].split('"')[1]
|
||||
|
||||
if 'attr' not in locals():
|
||||
print(fcu_key[0], 'has no attributes returning 0')
|
||||
# print(fcu_key[0], 'has no attributes returning 0')
|
||||
return [0]
|
||||
|
||||
#since blender 3 access to custom property settings changed
|
||||
@@ -571,6 +573,7 @@ def attr_default(obj, fcu_key):
|
||||
return [0]
|
||||
|
||||
def selected_bones_filter(obj, fcu_data_path):
|
||||
'''using obj.als.onlyselected property for the bake'''
|
||||
if not obj.als.onlyselected:
|
||||
return False
|
||||
if obj.mode != 'POSE':
|
||||
@@ -597,7 +600,6 @@ def evaluate_combine(data_path, added_array, eval_array, array_default, influenc
|
||||
return eval_array
|
||||
|
||||
def frame_evaluation(frame, strip):
|
||||
|
||||
frame_eval = frame
|
||||
#change the frame if the strip is on hold
|
||||
if frame < strip.frame_start:
|
||||
@@ -620,6 +622,17 @@ def frame_evaluation(frame, strip):
|
||||
|
||||
return frame_eval
|
||||
|
||||
def clean_no_user_slots(action):
|
||||
'''Remove all the slots that are connected to the action and object but not part of the action slot'''
|
||||
if not hasattr(action, 'slots'):
|
||||
return
|
||||
for slot in action.slots:
|
||||
if slot is None:
|
||||
continue
|
||||
if len(slot.users()):
|
||||
continue
|
||||
|
||||
action.slots.remove(slot)
|
||||
|
||||
def AL_bake(frame_start, frame_end, nla_tracks, fcu_keys, additive, step, actioncopy, baked_layer = None):
|
||||
|
||||
@@ -627,19 +640,37 @@ def AL_bake(frame_start, frame_end, nla_tracks, fcu_keys, additive, step, action
|
||||
if obj is None:
|
||||
return
|
||||
anim_data = anim_layers.anim_data_type(obj)
|
||||
baked_action = anim_data.action
|
||||
if obj.als.operator == 'MERGE' and not additive and anim_data.action is not None: #and obj.als.onlyselected
|
||||
# baked_action = anim_data.action
|
||||
track = nla_tracks[obj.als.layer_index]
|
||||
baked_action = track.strips[0].action
|
||||
clean_no_user_slots(baked_action)
|
||||
#create the baked fcurve
|
||||
baked_channelbag = anim_layers.get_channelbag(obj, baked_action)
|
||||
baked_fcurves = baked_channelbag.fcurves
|
||||
|
||||
if obj.als.operator == 'MERGE':# and not additive: # and anim_data.action is not None: #and obj.als.onlyselected
|
||||
#overwrite action
|
||||
anim_data.use_tweak_mode = False
|
||||
|
||||
#create a duplicate of the action on the merged layer to have a clean action in order to not write over the calculation
|
||||
action_copy = bpy.data.actions[baked_action.name].copy()
|
||||
nla_tracks[obj.als.layer_index].strips[0].action = action_copy
|
||||
|
||||
baked_action.id_root = obj.als.data_type
|
||||
track.strips[0].action = action_copy
|
||||
|
||||
|
||||
if hasattr(baked_action, 'id_root'):
|
||||
baked_action.id_root = obj.als.data_type
|
||||
|
||||
blend_types = {'ADD' : '+', 'SUBTRACT' : '-', 'MULTIPLY' : '*'}
|
||||
fcu_paths = []
|
||||
|
||||
|
||||
# Initialize the progress bar
|
||||
wm = bpy.context.window_manager
|
||||
fcu_set = {fcu_key[0] for fcu_key in fcu_keys.keys()}
|
||||
total_iterations = len(fcu_set)
|
||||
wm.progress_begin(0, total_iterations) # (start, end range)
|
||||
processed = 0
|
||||
|
||||
for fcu_key in fcu_keys.keys():
|
||||
if fcu_key[0] in fcu_paths:
|
||||
continue
|
||||
@@ -674,18 +705,30 @@ def AL_bake(frame_start, frame_end, nla_tracks, fcu_keys, additive, step, action
|
||||
for track in nla_tracks:
|
||||
if track.mute:
|
||||
continue
|
||||
if not len(track.strips):
|
||||
continue
|
||||
if track.strips[0].action is None:
|
||||
continue
|
||||
# if track == baked_layer:
|
||||
# continue
|
||||
#finding the channel group of array
|
||||
fcu = track.strips[0].action.fcurves.find(fcu_key[0], index = i)
|
||||
channelbag = anim_layers.get_channelbag(obj, track.strips[0].action)
|
||||
if channelbag is None:
|
||||
continue
|
||||
|
||||
fcurves = channelbag.fcurves
|
||||
fcu = fcurves.find(fcu_key[0], index = i)
|
||||
# print(f'track {track.name} fcurves {len(fcurves)}')
|
||||
if fcu is None:
|
||||
# print('fcu is none', fcu_key[0], track.name)
|
||||
continue
|
||||
group = fcu.group if fcu.group is not None else None
|
||||
|
||||
if group is not None:
|
||||
if group.name in baked_action.groups:
|
||||
group = baked_action.groups[group.name]
|
||||
if group.name in baked_channelbag.groups:
|
||||
group = baked_channelbag.groups[group.name]
|
||||
else:
|
||||
group = baked_action.groups.new(group.name)
|
||||
group = baked_channelbag.groups.new(group.name)
|
||||
|
||||
#copy and append Modifiers into mod_list. Mute them if turned on
|
||||
if len(fcu.modifiers) and not obj.als.mergefcurves:
|
||||
@@ -697,20 +740,22 @@ def AL_bake(frame_start, frame_end, nla_tracks, fcu_keys, additive, step, action
|
||||
# modifier_rec.append(mod)
|
||||
mod.mute = True
|
||||
extrapolation = True if fcu.extrapolation == 'LINEAR' else False
|
||||
|
||||
#### Creating or overwritting (during merge) the new baked fcurves####
|
||||
|
||||
baked_fcu = ensure_fcurves_bversion(baked_fcurves, fcu_key[0], i)
|
||||
|
||||
#create the baked fcurve
|
||||
baked_fcu = baked_action.fcurves.find(fcu_key[0], index = i)
|
||||
if baked_fcu is not None:
|
||||
baked_action.fcurves.remove(baked_fcu)
|
||||
baked_fcu = baked_action.fcurves.new(fcu_key[0], index = i)
|
||||
baked_fcu.color_mode = 'AUTO_RGB'
|
||||
|
||||
if group is not None:
|
||||
if baked_fcu.group != group:
|
||||
baked_fcu.group = group
|
||||
|
||||
if extrapolation:
|
||||
baked_fcu.extrapolation = 'LINEAR'
|
||||
|
||||
baked_fcus.append(baked_fcu)
|
||||
|
||||
|
||||
#select smart bake frame range or every frame in the range
|
||||
if obj.als.smartbake:
|
||||
#merge all the smartframe arrays
|
||||
@@ -726,9 +771,15 @@ def AL_bake(frame_start, frame_end, nla_tracks, fcu_keys, additive, step, action
|
||||
|
||||
#ITERATE through all the layers to evaluate
|
||||
for track in nla_tracks:
|
||||
if not len(track.strips):
|
||||
continue
|
||||
|
||||
if track.mute or track == baked_layer or track.strips[0].action is None:
|
||||
continue
|
||||
strip = track.strips[0]
|
||||
fcurves = anim_layers.get_fcurves(obj, strip.action)
|
||||
if not len(fcurves):
|
||||
continue
|
||||
if (frame < strip.frame_start or frame > strip.frame_end) and strip.extrapolation == 'NOTHING':
|
||||
layers_count += 1
|
||||
continue
|
||||
@@ -750,11 +801,14 @@ def AL_bake(frame_start, frame_end, nla_tracks, fcu_keys, additive, step, action
|
||||
added_array = []
|
||||
missing = 0
|
||||
for i in range(array_length):
|
||||
fcu = strip.action.fcurves.find(fcu_key[0], index = i)
|
||||
|
||||
fcu = fcurves.find(fcu_key[0], index = i)
|
||||
#if the fcurve is not found then get the default value
|
||||
if fcu is None:
|
||||
missing += 1
|
||||
value = array_default[i] if blend_type in ('REPLACE', 'COMBINE') else 0
|
||||
#getting the previous value if the fcurve is missing instead of just default
|
||||
#the other option would be to use an array for the influence as well
|
||||
value = eval_array[i] if blend_type in ('REPLACE', 'COMBINE') else 0
|
||||
else:
|
||||
value = fcu.evaluate(frame_eval)
|
||||
added_array.append(value)
|
||||
@@ -773,7 +827,6 @@ def AL_bake(frame_start, frame_end, nla_tracks, fcu_keys, additive, step, action
|
||||
eval_array = evaluate_combine(fcu_key[0], added_array, eval_array, array_default, influence)
|
||||
else:
|
||||
eval_array = eval('eval_array' + blend_types[blend_type] +' added_array' + '*' + str(influence))
|
||||
#extrapolation = True if fcu.extrapolation == 'LINEAR' else False
|
||||
layers_count += 1
|
||||
|
||||
if not eval_array.size:
|
||||
@@ -792,18 +845,11 @@ def AL_bake(frame_start, frame_end, nla_tracks, fcu_keys, additive, step, action
|
||||
smartkey.value = eval_array[i]
|
||||
if smartkey.inbetween:
|
||||
continue
|
||||
|
||||
# if hasattr(smartkey, 'handle_left') and not additive:
|
||||
# if not smartkey.handle_left[1]:
|
||||
# smartkey.handle_left[1] = array_default[i]
|
||||
# if hasattr(smartkey, 'handle_right') and not additive:
|
||||
# if not smartkey.handle_right[1]:
|
||||
# smartkey.handle_right[1] = array_default[i]
|
||||
|
||||
baked_fcu.keyframe_points.add(1)
|
||||
keyframe = baked_fcu.keyframe_points[-1]
|
||||
keyframe.co = (frame, eval_array[i])
|
||||
|
||||
|
||||
for baked_fcu in baked_fcus:
|
||||
if not len(baked_fcu.keyframe_points):
|
||||
continue
|
||||
@@ -818,12 +864,32 @@ def AL_bake(frame_start, frame_end, nla_tracks, fcu_keys, additive, step, action
|
||||
#paste the modifiers to the new baked fcurve
|
||||
if i in mod_list and not len(baked_fcu.modifiers):
|
||||
anim_layers.paste_modifiers(baked_fcu, mod_list[i])
|
||||
|
||||
|
||||
processed += 1
|
||||
wm.progress_update(processed)
|
||||
wm.progress_end()
|
||||
|
||||
if not actioncopy and obj.als.operator == 'MERGE':
|
||||
bpy.data.actions.remove(action_copy)
|
||||
|
||||
return baked_action
|
||||
|
||||
def ensure_fcurves_bversion(fcurves, data_path, i):
|
||||
'''Either use ensure in Blender 5.0 and above or use find and new in older version'''
|
||||
|
||||
if hasattr(fcurves, 'ensure'):
|
||||
baked_fcu = fcurves.ensure(data_path, index = i)
|
||||
else:
|
||||
baked_fcu = fcurves.find(data_path, index = i)
|
||||
if baked_fcu is None:
|
||||
baked_fcu = fcurves.new(data_path, index = i)
|
||||
|
||||
|
||||
if len(baked_fcu.keyframe_points):
|
||||
baked_fcu.keyframe_points.clear()
|
||||
|
||||
return baked_fcu
|
||||
|
||||
def non_recalc_handle_type(baked_keys):
|
||||
|
||||
handles_type = bpy.context.scene.als.handles_type
|
||||
@@ -849,7 +915,9 @@ def add_interpolations(baked_fcu, smartkeys, layers_count = 0):
|
||||
P2index = 2
|
||||
if len(baked_keys) != len(keys):
|
||||
print('unequal length of keys ',baked_fcu.data_path, len(baked_keys), len(keys))
|
||||
print('set difference ', set([key.frame for key in keys]).difference(set([round(key.co[0], 2) for key in baked_keys])))
|
||||
print('keys ', [key.frame for key in keys])
|
||||
print('baked keys ', [round(key.co[0], 2) for key in baked_keys])
|
||||
print('set difference ', set([key.frame for key in keys]).difference(set([key.co[0] for key in baked_keys])))
|
||||
|
||||
baked_keys[0].handle_left_type = 'VECTOR'
|
||||
baked_keys[-1].handle_right_type = 'VECTOR'
|
||||
@@ -876,7 +944,6 @@ def add_interpolations(baked_fcu, smartkeys, layers_count = 0):
|
||||
skip = True
|
||||
|
||||
if not smartkeys[P1index].inbetween :
|
||||
# print(baked_fcu.data_path, baked_keys[i].co[0], 'not with inbetween', P1index, P2index, i)
|
||||
P1index += 1
|
||||
P2index += 1
|
||||
continue
|
||||
@@ -911,11 +978,10 @@ def add_interpolations(baked_fcu, smartkeys, layers_count = 0):
|
||||
#iterate through the inbetween smartkeys
|
||||
P1index += 3
|
||||
P2index += 3
|
||||
|
||||
# baked_fcu.update()
|
||||
|
||||
#add in-betweener
|
||||
|
||||
|
||||
def apply_handle_types(baked_keys, smartkeys, i):
|
||||
|
||||
handles_type = bpy.context.scene.als.handles_type
|
||||
@@ -933,35 +999,40 @@ def apply_handle_types(baked_keys, smartkeys, i):
|
||||
|
||||
def bake_range_type(self, context):
|
||||
if self.bake_range_type == 'SCENE':
|
||||
self.bake_range = frame_start_end(bpy.context.scene)
|
||||
frame_start, frame_end = frame_start_end(context.scene)
|
||||
self.bake_range = (int(frame_start), int(frame_end))
|
||||
|
||||
if self.bake_range_type == 'KEYFRAMES':
|
||||
obj = context.object
|
||||
anim_data = anim_layers.anim_data_type(obj)
|
||||
frame_end = []
|
||||
frame_start = []
|
||||
posebones = context.selected_pose_bones
|
||||
#if baking only selected bones then find the longest fcurves for the range
|
||||
if obj.als.onlyselected:
|
||||
posebones = context.selected_pose_bones
|
||||
if obj.als.onlyselected and posebones:
|
||||
bonespath = [bone.path_from_id() for bone in posebones]
|
||||
#get the frame range from
|
||||
if not bonespath:
|
||||
return
|
||||
for track in obj.animation_data.nla_tracks:
|
||||
if not len(track.strips):
|
||||
continue
|
||||
action = track.strips[0].action
|
||||
for fcu in action.fcurves:
|
||||
for track in anim_data.nla_tracks:
|
||||
if not len(track.strips):
|
||||
continue
|
||||
action = track.strips[0].action
|
||||
if obj.als.onlyselected and posebones:
|
||||
# Get fcurve range from the selected objects
|
||||
fcurves = anim_layers.get_fcurves(obj, action)
|
||||
for fcu in fcurves:
|
||||
#check if the fcurve is in the selected bones
|
||||
if any(path in fcu.data_path for path in bonespath):
|
||||
frame_start.append(fcu.range()[0])
|
||||
frame_end.append(fcu.range()[1])
|
||||
else:
|
||||
for track in obj.animation_data.nla_tracks:
|
||||
if not len(track.strips):
|
||||
continue
|
||||
else:
|
||||
# Get the action range
|
||||
action = track.strips[0].action
|
||||
frame_start.append(action.frame_range[0])
|
||||
frame_end.append(action.frame_range[1])
|
||||
|
||||
# Checking for the longest action in all the actions
|
||||
if frame_start:
|
||||
self.bake_range = (int(min(frame_start)), int(max(frame_end)))
|
||||
|
||||
@@ -1042,10 +1113,23 @@ class MergeAnimLayerDown(bpy.types.Operator):
|
||||
obj.als.smartbake = False
|
||||
|
||||
subscriptions.subscriptions_remove()
|
||||
#start = time.time()
|
||||
# start = time.time()
|
||||
#define the start and end frame of the bake, according to scene or preview length
|
||||
frame_start, frame_end = context.scene.als.bake_range
|
||||
|
||||
# Incase the strips are shorter then the keyframe range (because scene is shorter)
|
||||
# Then updating the strips length
|
||||
for layer, track in zip(obj.Anim_Layers, anim_data.nla_tracks):
|
||||
if layer.custom_frame_range:
|
||||
continue
|
||||
if len(track.strips) != 1:
|
||||
continue
|
||||
strip = track.strips[0]
|
||||
strip.frame_start =frame_start
|
||||
anim_layers.update_action_frame_range(frame_start, frame_end, layer, strip)
|
||||
strip.scale = layer.speed
|
||||
strip.frame_end = frame_end
|
||||
|
||||
obj.als.view_all_keyframes = False
|
||||
if context.scene.frame_current > frame_end:
|
||||
context.scene.frame_current = frame_end
|
||||
@@ -1054,8 +1138,9 @@ class MergeAnimLayerDown(bpy.types.Operator):
|
||||
blendings = [track.strips[0].blend_type for track in nla_tracks[layer_index:] if len(track.strips) == 1]
|
||||
|
||||
#define if the new baked layer is going to be additive or replace
|
||||
additive = False
|
||||
if obj.als.direction == 'UP' and 'REPLACE' not in blendings and obj.als.baketype == 'AL':
|
||||
additive = False
|
||||
|
||||
if obj.als.direction == 'UP' and 'REPLACE' not in blendings and obj.als.baketype == 'AL' and layer_index:
|
||||
if 'COMBINE' in blendings:
|
||||
blend = 'COMBINE'
|
||||
else:
|
||||
@@ -1063,15 +1148,19 @@ class MergeAnimLayerDown(bpy.types.Operator):
|
||||
additive = True
|
||||
else:
|
||||
blend = 'REPLACE'
|
||||
|
||||
|
||||
mute_rec = mute_unbaked_layers(layer_index, nla_tracks, additive)
|
||||
|
||||
fcu_keys = smart_bake(context)
|
||||
|
||||
|
||||
if obj.als.operator == 'MERGE':
|
||||
if obj.als.direction == 'DOWN':
|
||||
obj.als.layer_index = 0
|
||||
baked_layer = None
|
||||
action = anim_data.nla_tracks[obj.als.layer_index].strips[0].action
|
||||
strip = anim_data.nla_tracks[obj.als.layer_index].strips[0]
|
||||
action = strip.action
|
||||
if hasattr(strip, 'action_slot'):
|
||||
action_slot = strip.action_slot
|
||||
if action is not None: action_name = action.name
|
||||
|
||||
#if baking to a new layer then setup the new index and layer
|
||||
@@ -1109,7 +1198,8 @@ class MergeAnimLayerDown(bpy.types.Operator):
|
||||
for col in obj.data.collections:
|
||||
layers_rec.update({col : col.is_visible})
|
||||
col.is_visible = True
|
||||
|
||||
# Select the bones from all the layers
|
||||
self.shift = True
|
||||
select_keyframed_bones(self, context, obj)
|
||||
|
||||
constraint_rec = mute_constraints(obj)
|
||||
@@ -1123,7 +1213,7 @@ class MergeAnimLayerDown(bpy.types.Operator):
|
||||
if not obj.select_get():
|
||||
obj.select_set(True)
|
||||
bpy.ops.nla.bake(frame_start = frame_start, frame_end = frame_end, only_selected = True, visual_keying=True, clear_constraints=obj.als.clearconstraints, bake_types = bake_type, step = self.step)
|
||||
anim_data.action.fcurves.update()
|
||||
# anim_data.action.fcurves.update()
|
||||
strip = track.strips[0]
|
||||
old_action = strip.action
|
||||
|
||||
@@ -1133,7 +1223,6 @@ class MergeAnimLayerDown(bpy.types.Operator):
|
||||
track.strips.remove(strip)
|
||||
strip = track.strips.new(track.name, 0, action)
|
||||
anim_layers.tweak_mode_upper_stack(context, obj, anim_data, enter = False)
|
||||
#strip.action = anim_data.action
|
||||
|
||||
if obj.als.smartbake:
|
||||
smartbake_apply(obj, nla_tracks, fcu_keys, extrapolations)
|
||||
@@ -1141,35 +1230,39 @@ class MergeAnimLayerDown(bpy.types.Operator):
|
||||
armature_restore(obj, b_layers, layers_rec, constraint_rec)
|
||||
unmute_modifiers(obj, nla_tracks, modifier_rec)
|
||||
|
||||
anim_data.action = None
|
||||
# anim_data.action = None
|
||||
#bpy.data.actions.remove(old_action)
|
||||
if self.actioncopy:
|
||||
old_action.name = action_name + '_old'
|
||||
else:
|
||||
bpy.data.actions.remove(old_action)
|
||||
strip.action.name = action_name
|
||||
# strip.action.name = action_name
|
||||
if blendings.count('COMBINE') == len(blendings) and len(blendings) and obj.als.direction == 'UP':
|
||||
track.strips[0].blend_type = 'COMBINE'
|
||||
|
||||
|
||||
else: #use anim layers bake
|
||||
#print(frame_start, frame_end)
|
||||
action = AL_bake(frame_start, frame_end, nla_tracks, fcu_keys, additive, self.step, self.actioncopy, baked_layer)
|
||||
#action = AL_bake(self, frame_start, frame_end, nla_tracks, fcu_keys, additive, baked_layer)
|
||||
anim_layers.tweak_mode_upper_stack(context, obj, anim_data, enter = False)
|
||||
track.strips.remove(track.strips[0])
|
||||
strip = track.strips.new(track.name, 0, action)
|
||||
strip.blend_type = blend
|
||||
#track.strips[0].action = action
|
||||
|
||||
#removing layers after merge
|
||||
if obj.als.operator == 'MERGE':
|
||||
if hasattr(strip, 'action_slot'):
|
||||
if action_slot in strip.action.slots.values():
|
||||
strip.action_slot = action_slot
|
||||
else:
|
||||
# During NLA Bake slot doesn't exist need to find a new on
|
||||
strip.action_slot = anim_layers.get_obj_slot(obj, action)
|
||||
|
||||
#reset layer settings
|
||||
baked_layer = obj.Anim_Layers[obj.als.layer_index]
|
||||
baked_layer.repeat, baked_layer.speed, baked_layer.offset = 1, 1, 0
|
||||
strip.use_sync_length = False
|
||||
if baked_layer.frame_range:
|
||||
baked_layer.frame_range = False
|
||||
if baked_layer.custom_frame_range:
|
||||
baked_layer.custom_frame_range = False
|
||||
baked_layer.frame_start = frame_start
|
||||
baked_layer.frame_end = frame_end
|
||||
|
||||
@@ -1210,7 +1303,6 @@ class MergeAnimLayerDown(bpy.types.Operator):
|
||||
track.mute = True
|
||||
else:
|
||||
track.mute = False
|
||||
|
||||
action.use_fake_user = True
|
||||
anim_layers.register_layers(obj, nla_tracks)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user