fix: Blender 5.0 Action.fcurves API change — safe LINEAR keyframe setting

Blender 5.0 renamed Action.fcurves. Now tries fcurves first, falls
back to channels, and wraps in try/except so the render proceeds
even if LINEAR interpolation can't be set.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-15 22:05:58 +01:00
parent c159bff2df
commit 3a815a85c5
+23 -13
View File
@@ -380,20 +380,30 @@ def _setup_cinematic_camera(parts, bbox_center, bsphere_radius, total_frames):
cam_obj.data.dof.keyframe_insert(data_path="aperture_fstop", frame=frame)
# Set all keyframes to LINEAR interpolation (no bezier smoothing)
if cam_obj.animation_data and cam_obj.animation_data.action:
for fcurve in cam_obj.animation_data.action.fcurves:
for kp in fcurve.keyframe_points:
kp.interpolation = 'LINEAR'
if cam_obj.data.animation_data and cam_obj.data.animation_data.action:
for fcurve in cam_obj.data.animation_data.action.fcurves:
for kp in fcurve.keyframe_points:
kp.interpolation = 'LINEAR'
if cam_obj.data.dof.animation_data and cam_obj.data.dof.animation_data.action:
for fcurve in cam_obj.data.dof.animation_data.action.fcurves:
for kp in fcurve.keyframe_points:
kp.interpolation = 'LINEAR'
def _set_linear(anim_data):
if not anim_data or not anim_data.action:
return
action = anim_data.action
# Blender 5.0+: action.fcurves may be action.channels or similar
curves = None
if hasattr(action, 'fcurves'):
curves = action.fcurves
elif hasattr(action, 'channels'):
curves = action.channels
if curves:
for fc in curves:
for kp in fc.keyframe_points:
kp.interpolation = 'LINEAR'
print(f"[cinematic_render] camera keyframed: {total_frames} frames across {len(SEGMENTS)} segments (LINEAR interpolation)", flush=True)
try:
_set_linear(cam_obj.animation_data)
_set_linear(cam_obj.data.animation_data)
if hasattr(cam_obj.data, 'dof') and cam_obj.data.dof:
_set_linear(getattr(cam_obj.data.dof, 'animation_data', None))
except Exception as e:
print(f"[cinematic_render] WARNING: could not set LINEAR interpolation: {e}", flush=True)
print(f"[cinematic_render] camera keyframed: {total_frames} frames across {len(SEGMENTS)} segments", flush=True)
return cam_obj