Merge branch 'blender-v4.1-release'

This commit is contained in:
Bastien Montagne
2024-02-13 12:57:50 +01:00
7 changed files with 196 additions and 14 deletions

View File

@@ -12,6 +12,7 @@
#include <string>
#include "BLI_bitmap.h"
#include "BLI_vector.hh"
#include "DNA_anim_types.h"
#include "ED_transform.hh"
@@ -192,6 +193,8 @@ bool autokeyframe_property(bContext *C,
* expected to be the size of the property array.
* \param frame: is expected to be in the local time of the action, meaning it has to be NLA mapped
* already.
* \param keying_mask is expected to have the same size as `rna_path`. A false bit means that index
* will be skipped.
* \returns The number of keys inserted.
*/
int insert_key_action(Main *bmain,
@@ -202,7 +205,8 @@ int insert_key_action(Main *bmain,
float frame,
Span<float> values,
eInsertKeyFlags insert_key_flag,
eBezTriple_KeyframeType key_type);
eBezTriple_KeyframeType key_type,
const BLI_bitmap *keying_mask);
/**
* Insert keys to the ID of the given PointerRNA for the given RNA paths. Tries to create an
@@ -215,6 +219,7 @@ void insert_key_rna(PointerRNA *rna_pointer,
eInsertKeyFlags insert_key_flags,
eBezTriple_KeyframeType key_type,
Main *bmain,
ReportList *reports);
ReportList *reports,
const AnimationEvalContext &anim_eval_context);
} // namespace blender::animrig

View File

@@ -862,7 +862,8 @@ int insert_key_action(Main *bmain,
const float frame,
const Span<float> values,
eInsertKeyFlags insert_key_flag,
eBezTriple_KeyframeType key_type)
eBezTriple_KeyframeType key_type,
const BLI_bitmap *keying_mask)
{
BLI_assert(bmain != nullptr);
BLI_assert(action != nullptr);
@@ -879,6 +880,10 @@ int insert_key_action(Main *bmain,
int property_array_index = 0;
int inserted_keys = 0;
for (float value : values) {
if (!BLI_BITMAP_TEST_BOOL(keying_mask, property_array_index)) {
property_array_index++;
continue;
}
const bool inserted_key = insert_keyframe_fcurve_value(bmain,
nullptr,
ptr,
@@ -924,7 +929,8 @@ void insert_key_rna(PointerRNA *rna_pointer,
const eInsertKeyFlags insert_key_flags,
const eBezTriple_KeyframeType key_type,
Main *bmain,
ReportList *reports)
ReportList *reports,
const AnimationEvalContext &anim_eval_context)
{
ID *id = rna_pointer->owner_id;
bAction *action = id_action_ensure(bmain, id);
@@ -938,6 +944,15 @@ void insert_key_rna(PointerRNA *rna_pointer,
}
AnimData *adt = BKE_animdata_from_id(id);
/* Keyframing functions can deal with the nla_context being a nullptr. */
ListBase nla_cache = {nullptr, nullptr};
NlaKeyframingContext *nla_context = nullptr;
if (adt && adt->action == action) {
nla_context = BKE_animsys_get_nla_keyframing_context(
&nla_cache, rna_pointer, adt, &anim_eval_context);
}
const float nla_frame = BKE_nla_tweakedit_remap(adt, scene_frame, NLATIME_CONVERT_UNMAP);
const bool visual_keyframing = insert_key_flags & INSERTKEY_MATRIX;
@@ -960,6 +975,16 @@ void insert_key_rna(PointerRNA *rna_pointer,
prop);
Vector<float> rna_values = get_keyframe_values(&ptr, prop, visual_keyframing);
BLI_bitmap *successful_remaps = BLI_BITMAP_NEW(rna_values.size(), __func__);
BKE_animsys_nla_remap_keyframe_values(nla_context,
rna_pointer,
prop,
rna_values.as_mutable_span(),
-1,
&anim_eval_context,
nullptr,
successful_remaps);
insert_key_count += insert_key_action(bmain,
action,
rna_pointer,
@@ -968,7 +993,9 @@ void insert_key_rna(PointerRNA *rna_pointer,
nla_frame,
rna_values.as_span(),
insert_key_flags,
key_type);
key_type,
successful_remaps);
MEM_freeN(successful_remaps);
}
if (insert_key_count == 0) {

View File

@@ -160,7 +160,8 @@ void autokeyframe_object(bContext *C, Scene *scene, Object *ob, Span<std::string
flag,
eBezTriple_KeyframeType(scene->toolsettings->keyframe_type),
bmain,
reports);
reports,
anim_eval_context);
}
}
@@ -285,7 +286,8 @@ void autokeyframe_pose_channel(bContext *C,
flag,
eBezTriple_KeyframeType(scene->toolsettings->keyframe_type),
bmain,
reports);
reports,
anim_eval_context);
}
}

View File

@@ -2071,8 +2071,15 @@ static bool lib_override_library_resync(Main *bmain,
ID *id_root_reference = id_root->override_library->reference;
ID *id;
BKE_view_layer_synced_ensure(scene, view_layer);
const Object *old_active_object = BKE_view_layer_active_object_get(view_layer);
const Object *old_active_object = nullptr;
if (view_layer) {
BKE_view_layer_synced_ensure(scene, view_layer);
old_active_object = BKE_view_layer_active_object_get(view_layer);
}
else {
BKE_scene_view_layers_synced_ensure(scene);
}
if (id_root_reference->tag & LIB_TAG_MISSING) {
BKE_reportf(reports != nullptr ? reports->reports : nullptr,

View File

@@ -442,9 +442,9 @@ uint64_t BKE_library_id_can_use_filter_id(const ID *owner_id, const bool include
/* Could be more specific, but simpler to just always say 'yes' here. */
return FILTER_ID_ALL;
case ID_ME:
return FILTER_ID_ME | FILTER_ID_MA | FILTER_ID_IM;
return FILTER_ID_ME | FILTER_ID_MA | FILTER_ID_IM | FILTER_ID_KE;
case ID_CU_LEGACY:
return FILTER_ID_OB | FILTER_ID_MA | FILTER_ID_VF;
return FILTER_ID_OB | FILTER_ID_MA | FILTER_ID_VF | FILTER_ID_KE;
case ID_MB:
return FILTER_ID_MA;
case ID_MA:
@@ -454,7 +454,7 @@ uint64_t BKE_library_id_can_use_filter_id(const ID *owner_id, const bool include
case ID_LT:
return 0;
case ID_LA:
return FILTER_ID_TE;
return FILTER_ID_TE | FILTER_ID_KE;
case ID_CA:
return FILTER_ID_OB | FILTER_ID_IM;
case ID_KE:

View File

@@ -345,6 +345,9 @@ static int insert_key(bContext *C, wmOperator *op)
const eInsertKeyFlags insert_key_flags = ANIM_get_keyframing_flags(scene);
const eBezTriple_KeyframeType key_type = eBezTriple_KeyframeType(
scene->toolsettings->keyframe_type);
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
depsgraph, BKE_scene_frame_get(scene));
LISTBASE_FOREACH (CollectionPointerLink *, collection_ptr_link, &selection) {
ID *selected_id = collection_ptr_link->ptr.owner_id;
@@ -355,8 +358,14 @@ static int insert_key(bContext *C, wmOperator *op)
PointerRNA id_ptr = collection_ptr_link->ptr;
Vector<std::string> rna_paths = construct_rna_paths(&collection_ptr_link->ptr);
animrig::insert_key_rna(
&id_ptr, rna_paths.as_span(), scene_frame, insert_key_flags, key_type, bmain, op->reports);
animrig::insert_key_rna(&id_ptr,
rna_paths.as_span(),
scene_frame,
insert_key_flags,
key_type,
bmain,
op->reports,
anim_eval_context);
}
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, nullptr);

View File

@@ -36,6 +36,19 @@ def _get_view3d_context():
return ctx
def _get_nla_context():
ctx = bpy.context.copy()
for area in bpy.context.window.screen.areas:
if area.type != 'NLA_EDITOR':
continue
ctx['area'] = area
ctx['space'] = area.spaces.active
break
return ctx
def _create_animation_object():
anim_object = bpy.data.objects.new("anim_object", None)
# Ensure that the rotation mode is correct so we can check against rotation_euler
@@ -487,6 +500,125 @@ class InsertNeededTest(AbstractKeyframingTest, unittest.TestCase):
self.assertEqual(expected_keys[fcurve.data_path][fcurve.array_index], len(fcurve.keyframe_points))
def _create_nla_anim_object():
"""
Creates an object with 3 NLA tracks each with a strip that has its own action.
The middle layer is additive.
Creates a key on frame 0 and frame 10 for each of them.
The values are:
top: 0, 0
add: 0, 1
base: 0, 1
"""
anim_object = bpy.data.objects.new("anim_object", None)
bpy.context.scene.collection.objects.link(anim_object)
bpy.context.view_layer.objects.active = anim_object
anim_object.select_set(True)
anim_object.animation_data_create()
track = anim_object.animation_data.nla_tracks.new()
track.name = "base"
action_base = bpy.data.actions.new(name="action_base")
fcu = action_base.fcurves.new(data_path="location", index=0)
fcu.keyframe_points.insert(0, value=0).interpolation = 'LINEAR'
fcu.keyframe_points.insert(10, value=1).interpolation = 'LINEAR'
track.strips.new("base_strip", 0, action_base)
track = anim_object.animation_data.nla_tracks.new()
track.name = "add"
action_add = bpy.data.actions.new(name="action_add")
fcu = action_add.fcurves.new(data_path="location", index=0)
fcu.keyframe_points.insert(0, value=0).interpolation = 'LINEAR'
fcu.keyframe_points.insert(10, value=1).interpolation = 'LINEAR'
strip = track.strips.new("add_strip", 0, action_add)
strip.blend_type = "ADD"
track = anim_object.animation_data.nla_tracks.new()
track.name = "top"
action_top = bpy.data.actions.new(name="action_top")
fcu = action_top.fcurves.new(data_path="location", index=0)
fcu.keyframe_points.insert(0, value=0).interpolation = 'LINEAR'
fcu.keyframe_points.insert(10, value=0).interpolation = 'LINEAR'
track.strips.new("top_strip", 0, action_top)
return anim_object
class NlaInsertTest(AbstractKeyframingTest, unittest.TestCase):
"""
Testing inserting keys into an NLA stack.
The system is expected to remap the inserted values based on the strips blend_type.
"""
def setUp(self):
super().setUp()
bpy.context.preferences.edit.key_insert_channels = {'LOCATION'}
# Change one area to the NLA so we can call operators in it.
# Assumes there is at least one editor in the blender default startup file that is not the 3D viewport.
for area in bpy.context.window.screen.areas:
if area.type == 'VIEW_3D':
continue
area.type = "NLA_EDITOR"
break
def test_insert_failure(self):
# If the topmost track is set to "REPLACE" the system will fail
# when trying to insert keys into a layer beneath.
nla_anim_object = _create_nla_anim_object()
tracks = nla_anim_object.animation_data.nla_tracks
with bpy.context.temp_override(**_get_nla_context()):
bpy.ops.nla.select_all(action="DESELECT")
tracks.active = tracks["base"]
tracks["base"].strips[0].select = True
bpy.ops.nla.tweakmode_enter(use_upper_stack_evaluation=True)
with bpy.context.temp_override(**_get_view3d_context()):
bpy.context.scene.frame_set(5)
bpy.ops.anim.keyframe_insert()
base_action = bpy.data.actions["action_base"]
# Location X should not have been able to insert a keyframe because the top strip is overriding the result completely,
# making it impossible to calculate which value should be inserted.
self.assertEqual(len(base_action.fcurves.find("location", index=0).keyframe_points), 2)
# Location Y and Z will go through since they have not been defined in the action of the top strip.
self.assertEqual(len(base_action.fcurves.find("location", index=1).keyframe_points), 1)
self.assertEqual(len(base_action.fcurves.find("location", index=2).keyframe_points), 1)
def test_insert_additive(self):
nla_anim_object = _create_nla_anim_object()
tracks = nla_anim_object.animation_data.nla_tracks
# This leaves the additive track as the topmost track with influence
tracks["top"].mute = True
with bpy.context.temp_override(**_get_nla_context()):
bpy.ops.nla.select_all(action="DESELECT")
tracks.active = tracks["base"]
tracks["base"].strips[0].select = True
bpy.ops.nla.tweakmode_enter(use_upper_stack_evaluation=True)
# Inserting over the existing keyframe.
bpy.context.scene.frame_set(10)
with bpy.context.temp_override(**_get_view3d_context()):
bpy.ops.anim.keyframe_insert()
base_action = bpy.data.actions["action_base"]
# This should have added keys to Y and Z but not X.
# X already had two keys from the file setup.
self.assertEqual(len(base_action.fcurves.find("location", index=0).keyframe_points), 2)
self.assertEqual(len(base_action.fcurves.find("location", index=1).keyframe_points), 1)
self.assertEqual(len(base_action.fcurves.find("location", index=2).keyframe_points), 1)
# The keyframe value should not be changed even though the position of the
# object is modified by the additive layer.
self.assertAlmostEqual(nla_anim_object.location.x, 2.0, 8)
fcurve_loc_x = base_action.fcurves.find("location", index=0)
self.assertAlmostEqual(fcurve_loc_x.keyframe_points[-1].co[1], 1.0, 8)
def main():
global args
import argparse