Depsgraph: handle camera switching via markers in context drivers.
Blender allows animating the active camera selection (i.e. scene.camera) by binding cameras to markers in the timeline. The dependency graph was completely ignoring this by not building nodes for these cameras (it is possible to reference a camera not directly included in the scene), and not taking this into account in driver relations. This change ensures that all cameras are included in the dependency graph, and any drivers referencing scene.camera get dependencies on all cameras of the timeline, and also time itself to ensure switches are processed. Pull Request #110139
This commit is contained in:
parent
406f601c4b
commit
b248295530
|
@ -148,6 +148,27 @@ bool DepsgraphBuilder::check_pchan_has_bbone_segments(const Object *object, cons
|
||||||
return check_pchan_has_bbone_segments(object, pchan);
|
return check_pchan_has_bbone_segments(object, pchan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *DepsgraphBuilder::get_rna_path_relative_to_scene_camera(const Scene *scene,
|
||||||
|
const PointerRNA &target_prop,
|
||||||
|
const char *rna_path)
|
||||||
|
{
|
||||||
|
if (rna_path == nullptr || target_prop.data != scene || target_prop.type != &RNA_Scene ||
|
||||||
|
!BLI_str_startswith(rna_path, "camera"))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the part of the path relative to the camera. */
|
||||||
|
switch (rna_path[6]) {
|
||||||
|
case '.':
|
||||||
|
return rna_path + 7;
|
||||||
|
case '[':
|
||||||
|
return rna_path + 6;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
|
@ -13,6 +13,8 @@ struct ID;
|
||||||
struct Main;
|
struct Main;
|
||||||
struct ModifierData;
|
struct ModifierData;
|
||||||
struct Object;
|
struct Object;
|
||||||
|
struct PointerRNA;
|
||||||
|
struct Scene;
|
||||||
struct bPoseChannel;
|
struct bPoseChannel;
|
||||||
|
|
||||||
namespace blender::deg {
|
namespace blender::deg {
|
||||||
|
@ -33,6 +35,12 @@ class DepsgraphBuilder {
|
||||||
virtual bool check_pchan_has_bbone_segments(const Object *object, const bPoseChannel *pchan);
|
virtual bool check_pchan_has_bbone_segments(const Object *object, const bPoseChannel *pchan);
|
||||||
virtual bool check_pchan_has_bbone_segments(const Object *object, const char *bone_name);
|
virtual bool check_pchan_has_bbone_segments(const Object *object, const char *bone_name);
|
||||||
|
|
||||||
|
/** If `target_prop` + `rna_path` uses indirection via the `scene.camera` pointer, returns
|
||||||
|
* the substring of `rna_path` relative to the camera; otherwise returns nullptr. */
|
||||||
|
static const char *get_rna_path_relative_to_scene_camera(const Scene *scene,
|
||||||
|
const PointerRNA &target_prop,
|
||||||
|
const char *rna_path);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* NOTE: The builder does NOT take ownership over any of those resources. */
|
/* NOTE: The builder does NOT take ownership over any of those resources. */
|
||||||
DepsgraphBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache);
|
DepsgraphBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache);
|
||||||
|
|
|
@ -1300,11 +1300,34 @@ void DepsgraphNodeBuilder::build_driver_variables(ID *id, FCurve *fcurve)
|
||||||
|
|
||||||
build_id(target_id);
|
build_id(target_id);
|
||||||
build_driver_id_property(target_prop, dtar->rna_path);
|
build_driver_id_property(target_prop, dtar->rna_path);
|
||||||
|
|
||||||
|
/* For rna_path based variables: */
|
||||||
|
if ((dtar->flag & DTAR_FLAG_STRUCT_REF) == 0) {
|
||||||
|
/* Handle all other cameras used by the scene timeline if applicable. */
|
||||||
|
if (const char *camera_path = get_rna_path_relative_to_scene_camera(
|
||||||
|
scene_, target_prop, dtar->rna_path))
|
||||||
|
{
|
||||||
|
build_driver_scene_camera_variable(scene_, camera_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DRIVER_TARGETS_LOOPER_END;
|
DRIVER_TARGETS_LOOPER_END;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DepsgraphNodeBuilder::build_driver_scene_camera_variable(Scene *scene,
|
||||||
|
const char *camera_path)
|
||||||
|
{
|
||||||
|
/* This skips scene->camera, which was already handled by the caller. */
|
||||||
|
LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) {
|
||||||
|
if (!ELEM(marker->camera, nullptr, scene->camera)) {
|
||||||
|
PointerRNA camera_ptr;
|
||||||
|
RNA_id_pointer_create(&marker->camera->id, &camera_ptr);
|
||||||
|
build_driver_id_property(camera_ptr, camera_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DepsgraphNodeBuilder::build_driver_id_property(const PointerRNA &target_prop,
|
void DepsgraphNodeBuilder::build_driver_id_property(const PointerRNA &target_prop,
|
||||||
const char *rna_path_from_target_prop)
|
const char *rna_path_from_target_prop)
|
||||||
{
|
{
|
||||||
|
|
|
@ -164,6 +164,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
|
||||||
virtual void build_idproperties(IDProperty *id_property);
|
virtual void build_idproperties(IDProperty *id_property);
|
||||||
|
|
||||||
virtual void build_scene_render(Scene *scene, ViewLayer *view_layer);
|
virtual void build_scene_render(Scene *scene, ViewLayer *view_layer);
|
||||||
|
virtual void build_scene_camera(Scene *scene);
|
||||||
virtual void build_scene_parameters(Scene *scene);
|
virtual void build_scene_parameters(Scene *scene);
|
||||||
virtual void build_scene_compositor(Scene *scene);
|
virtual void build_scene_compositor(Scene *scene);
|
||||||
|
|
||||||
|
@ -223,6 +224,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
|
||||||
virtual void build_driver(ID *id, FCurve *fcurve, int driver_index);
|
virtual void build_driver(ID *id, FCurve *fcurve, int driver_index);
|
||||||
|
|
||||||
virtual void build_driver_variables(ID *id, FCurve *fcurve);
|
virtual void build_driver_variables(ID *id, FCurve *fcurve);
|
||||||
|
virtual void build_driver_scene_camera_variable(Scene *scene, const char *camera_path);
|
||||||
|
|
||||||
/* Build operations of a property value from which is read by a driver target.
|
/* Build operations of a property value from which is read by a driver target.
|
||||||
*
|
*
|
||||||
|
|
|
@ -31,8 +31,18 @@ void DepsgraphNodeBuilder::build_scene_render(Scene *scene, ViewLayer *view_laye
|
||||||
build_scene_sequencer(scene);
|
build_scene_sequencer(scene);
|
||||||
build_scene_speakers(scene, view_layer);
|
build_scene_speakers(scene, view_layer);
|
||||||
}
|
}
|
||||||
|
build_scene_camera(scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DepsgraphNodeBuilder::build_scene_camera(Scene *scene)
|
||||||
|
{
|
||||||
if (scene->camera != nullptr) {
|
if (scene->camera != nullptr) {
|
||||||
build_object(-1, scene->camera, DEG_ID_LINKED_DIRECTLY, true);
|
build_object(-1, scene->camera, DEG_ID_LINKED_INDIRECTLY, true);
|
||||||
|
}
|
||||||
|
LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) {
|
||||||
|
if (!ELEM(marker->camera, nullptr, scene->camera)) {
|
||||||
|
build_object(-1, marker->camera, DEG_ID_LINKED_INDIRECTLY, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,9 +114,7 @@ void DepsgraphNodeBuilder::build_view_layer(Scene *scene,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
build_layer_collections(&view_layer->layer_collections);
|
build_layer_collections(&view_layer->layer_collections);
|
||||||
if (scene->camera != nullptr) {
|
build_scene_camera(scene);
|
||||||
build_object(-1, scene->camera, DEG_ID_LINKED_INDIRECTLY, true);
|
|
||||||
}
|
|
||||||
/* Rigidbody. */
|
/* Rigidbody. */
|
||||||
if (scene->rigidbody_world != nullptr) {
|
if (scene->rigidbody_world != nullptr) {
|
||||||
build_rigidbody(scene);
|
build_rigidbody(scene);
|
||||||
|
|
|
@ -1930,14 +1930,81 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
|
||||||
add_relation(target_key, driver_key, "Target -> Driver");
|
add_relation(target_key, driver_key, "Target -> Driver");
|
||||||
}
|
}
|
||||||
else if (dtar->rna_path != nullptr && dtar->rna_path[0] != '\0') {
|
else if (dtar->rna_path != nullptr && dtar->rna_path[0] != '\0') {
|
||||||
RNAPathKey variable_exit_key(target_prop, dtar->rna_path, RNAPointerSource::EXIT);
|
build_driver_rna_path_variable(
|
||||||
|
driver_key, self_key, target_id, target_prop, dtar->rna_path);
|
||||||
|
|
||||||
|
/* Add relations to all other cameras used by the scene timeline if applicable. */
|
||||||
|
if (const char *camera_path = get_rna_path_relative_to_scene_camera(
|
||||||
|
scene_, target_prop, dtar->rna_path))
|
||||||
|
{
|
||||||
|
build_driver_scene_camera_variable(driver_key, self_key, scene_, camera_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The RNA getter for `object.data` can write to the mesh datablock due
|
||||||
|
* to the call to `BKE_mesh_wrapper_ensure_subdivision()`. This relation
|
||||||
|
* ensures it is safe to call when the driver is evaluated.
|
||||||
|
*
|
||||||
|
* For the sake of making the code more generic/defensive, the relation
|
||||||
|
* is added for any geometry type.
|
||||||
|
*
|
||||||
|
* See #96289 for more info. */
|
||||||
|
if (object != nullptr && OB_TYPE_IS_GEOMETRY(object->type)) {
|
||||||
|
StringRef rna_path(dtar->rna_path);
|
||||||
|
if (rna_path == "data" || rna_path.startswith("data.")) {
|
||||||
|
ComponentKey ob_key(target_id, NodeType::GEOMETRY);
|
||||||
|
add_relation(ob_key, driver_key, "ID -> Driver");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* If rna_path is nullptr, and DTAR_FLAG_STRUCT_REF isn't set, this
|
||||||
|
* is an incomplete target reference, so nothing to do here. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DRIVER_TARGETS_LOOPER_END;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DepsgraphRelationBuilder::build_driver_scene_camera_variable(const OperationKey &driver_key,
|
||||||
|
const RNAPathKey &self_key,
|
||||||
|
Scene *scene,
|
||||||
|
const char *rna_path)
|
||||||
|
{
|
||||||
|
/* First, add relations to all cameras used in the timeline,
|
||||||
|
* excluding scene->camera which was already handled by the caller. */
|
||||||
|
bool animated = false;
|
||||||
|
|
||||||
|
LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) {
|
||||||
|
if (!ELEM(marker->camera, nullptr, scene->camera)) {
|
||||||
|
PointerRNA camera_ptr;
|
||||||
|
RNA_id_pointer_create(&marker->camera->id, &camera_ptr);
|
||||||
|
build_driver_id_property(camera_ptr, rna_path);
|
||||||
|
build_driver_rna_path_variable(driver_key, self_key, &scene->id, camera_ptr, rna_path);
|
||||||
|
animated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If timeline indeed switches the camera, this variable also implicitly depends on time. */
|
||||||
|
if (animated) {
|
||||||
|
TimeSourceKey time_src_key;
|
||||||
|
add_relation(time_src_key, driver_key, "TimeSrc -> Driver Camera Ref");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DepsgraphRelationBuilder::build_driver_rna_path_variable(const OperationKey &driver_key,
|
||||||
|
const RNAPathKey &self_key,
|
||||||
|
ID *target_id,
|
||||||
|
const PointerRNA &target_prop,
|
||||||
|
const char *rna_path)
|
||||||
|
{
|
||||||
|
RNAPathKey variable_exit_key(target_prop, rna_path, RNAPointerSource::EXIT);
|
||||||
if (RNA_pointer_is_null(&variable_exit_key.ptr)) {
|
if (RNA_pointer_is_null(&variable_exit_key.ptr)) {
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
if (is_same_bone_dependency(variable_exit_key, self_key) ||
|
if (is_same_bone_dependency(variable_exit_key, self_key) ||
|
||||||
is_same_nodetree_node_dependency(variable_exit_key, self_key))
|
is_same_nodetree_node_dependency(variable_exit_key, self_key))
|
||||||
{
|
{
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
add_relation(variable_exit_key, driver_key, "RNA Target -> Driver");
|
add_relation(variable_exit_key, driver_key, "RNA Target -> Driver");
|
||||||
|
|
||||||
|
@ -1979,30 +2046,6 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
|
||||||
add_relation(target_id_key, driver_key, "Target ID -> Driver");
|
add_relation(target_id_key, driver_key, "Target ID -> Driver");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The RNA getter for `object.data` can write to the mesh datablock due
|
|
||||||
* to the call to `BKE_mesh_wrapper_ensure_subdivision()`. This relation
|
|
||||||
* ensures it is safe to call when the driver is evaluated.
|
|
||||||
*
|
|
||||||
* For the sake of making the code more generic/defensive, the relation
|
|
||||||
* is added for any geometry type.
|
|
||||||
*
|
|
||||||
* See #96289 for more info. */
|
|
||||||
if (object != nullptr && OB_TYPE_IS_GEOMETRY(object->type)) {
|
|
||||||
StringRef rna_path(dtar->rna_path);
|
|
||||||
if (rna_path == "data" || rna_path.startswith("data.")) {
|
|
||||||
ComponentKey ob_key(target_id, NodeType::GEOMETRY);
|
|
||||||
add_relation(ob_key, driver_key, "ID -> Driver");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* If rna_path is nullptr, and DTAR_FLAG_STRUCT_REF isn't set, this
|
|
||||||
* is an incomplete target reference, so nothing to do here. */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DRIVER_TARGETS_LOOPER_END;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DepsgraphRelationBuilder::build_driver_id_property(const PointerRNA &target_prop,
|
void DepsgraphRelationBuilder::build_driver_id_property(const PointerRNA &target_prop,
|
||||||
|
|
|
@ -177,6 +177,16 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
|
||||||
virtual void build_driver_data(ID *id, FCurve *fcurve);
|
virtual void build_driver_data(ID *id, FCurve *fcurve);
|
||||||
virtual void build_driver_variables(ID *id, FCurve *fcurve);
|
virtual void build_driver_variables(ID *id, FCurve *fcurve);
|
||||||
|
|
||||||
|
virtual void build_driver_scene_camera_variable(const OperationKey &driver_key,
|
||||||
|
const RNAPathKey &self_key,
|
||||||
|
Scene *scene,
|
||||||
|
const char *rna_path);
|
||||||
|
virtual void build_driver_rna_path_variable(const OperationKey &driver_key,
|
||||||
|
const RNAPathKey &self_key,
|
||||||
|
ID *target_id,
|
||||||
|
const PointerRNA &target_prop,
|
||||||
|
const char *rna_path);
|
||||||
|
|
||||||
/* Build operations of a property value from which is read by a driver target.
|
/* Build operations of a property value from which is read by a driver target.
|
||||||
*
|
*
|
||||||
* The driver target points to a data-block (or a sub-data-block like View Layer).
|
* The driver target points to a data-block (or a sub-data-block like View Layer).
|
||||||
|
|
Loading…
Reference in New Issue