diff options
author | Sergey Sharybin <sergey@blender.org> | 2022-07-26 13:11:54 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey@blender.org> | 2022-07-27 11:19:42 +0300 |
commit | 4dd409a185e2211e541479d6a878b17d5c7e2bdf (patch) | |
tree | fdf84c5e29c1f79cc165b0faa9a199b258c0d0d3 /source | |
parent | d706d0460c5721e2b07f18ab6354754267628130 (diff) |
Fix T99976: Animated visibility not rendering properly in viewport
A mistake in the 0dcee6a3866 which made specific driven visibility
to work, but did not properly handle actual time-based visibility.
The basic idea of the change is to preserve recalculation flags of
nodes which were tagged for update but were not evaluated due to
visibility constraints. In the file from the report this makes it
so tagging which is done first time ID is in the dependency graph
are handled when the ID actually becomes visible. This is what
solved the root of the problem from the report: there was missing
geometry update since it was "swallowed" by the evaluation during
the object being invisible. In other configurations this change
allows to handle pending geometry updates due to animated modifiers
be handled when object becomes visible without time change.
This change also solves visibility issue of the synchronization
component which also started to be handled badly since the
previous fix attempt. Basically, the needed exception in its
visibility handling did not happen and a regular logic was used
for it.
Tested with files from the T99733, T99976, and from the Heist
project.
Differential Revision: https://developer.blender.org/D15544
Diffstat (limited to 'source')
6 files changed, 42 insertions, 33 deletions
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index 89e1f1add18..9b2ce2bb707 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -111,7 +111,8 @@ void evaluate_node(const DepsgraphEvalState *state, OperationNode *operation_nod * times. * This is a thread-safe modification as the node's flags are only read for a non-scheduled nodes * and this node has been scheduled. */ - operation_node->flag &= ~DEPSOP_FLAG_NEEDS_UPDATE; + operation_node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE | + DEPSOP_FLAG_USER_MODIFIED); } void deg_task_run_func(TaskPool *pool, void *taskdata) @@ -466,7 +467,7 @@ void deg_evaluate_on_refresh(Depsgraph *graph) deg_eval_stats_aggregate(graph); } - /* Clear any uncleared tags - just in case. */ + /* Clear any uncleared tags. */ deg_graph_clear_tags(graph); graph->is_evaluating = false; diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index de4e26aa4b5..1c313d42d8e 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -378,11 +378,6 @@ void deg_graph_flush_updates(Depsgraph *graph) void deg_graph_clear_tags(Depsgraph *graph) { - /* Go over all operation nodes, clearing tags. */ - for (OperationNode *node : graph->operations) { - node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE | - DEPSOP_FLAG_USER_MODIFIED); - } /* Clear any entry tags which haven't been flushed. */ graph->entry_tags.clear(); diff --git a/source/blender/depsgraph/intern/eval/deg_eval_visibility.cc b/source/blender/depsgraph/intern/eval/deg_eval_visibility.cc index 8bf26e45e2a..05f7631b0d4 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_visibility.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_visibility.cc @@ -57,6 +57,27 @@ void deg_graph_flush_visibility_flags(Depsgraph *graph) for (ComponentNode *comp_node : id_node->components.values()) { comp_node->possibly_affects_visible_id = id_node->is_visible_on_build; comp_node->affects_visible_id = id_node->is_visible_on_build && id_node->is_enabled_on_eval; + + /* Visibility component is always to be considered to have the same visibility as the + * `id_node->is_visible_on_build`. This is because the visibility is to be evaluated + * regardless of its current state as it might get changed due to animation. */ + if (comp_node->type == NodeType::VISIBILITY) { + comp_node->affects_visible_id = id_node->is_visible_on_build; + } + + /* Enforce "visibility" of the synchronization component. + * + * This component is never connected to other ID nodes, and hence can not be handled in the + * same way as other components needed for evaluation. It is only needed for proper + * evaluation of the ID node it belongs to. + * + * The design is such that the synchronization is supposed to happen whenever any part of the + * ID changed/evaluated. Here we mark the component as "visible" so that genetic recalc flag + * flushing and scheduling will handle the component in a generic manner. */ + if (comp_node->type == NodeType::SYNCHRONIZATION) { + comp_node->possibly_affects_visible_id = true; + comp_node->affects_visible_id = true; + } } } @@ -85,6 +106,13 @@ void deg_graph_flush_visibility_flags(Depsgraph *graph) if (rel->from->type == NodeType::OPERATION) { const OperationNode *op_to = reinterpret_cast<const OperationNode *>(rel->to); const ComponentNode *comp_to = op_to->owner; + + /* Ignore the synchronization target. + * It is always visible and should not affect on other components. */ + if (comp_to->type == NodeType::SYNCHRONIZATION) { + continue; + } + OperationNode *op_from = reinterpret_cast<OperationNode *>(rel->from); ComponentNode *comp_from = op_from->owner; diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc index 32942f45a4a..f2d82e80fa6 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.cc +++ b/source/blender/depsgraph/intern/node/deg_node_component.cc @@ -218,10 +218,9 @@ void ComponentNode::clear_operations() void ComponentNode::tag_update(Depsgraph *graph, eUpdateSource source) { - OperationNode *entry_op = get_entry_operation(); - if (entry_op != nullptr && entry_op->flag & DEPSOP_FLAG_NEEDS_UPDATE) { - return; - } + /* Note that the node might already be tagged for an update due invisible state of the node + * during previous dependency evaluation. Here the node gets re-tagged, so we need to give + * the evaluated clues that evaluation needs to happen again. */ for (OperationNode *op_node : operations) { op_node->tag_update(graph, source); } diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h index a616dfdfe4c..f7f38b88854 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.h +++ b/source/blender/depsgraph/intern/node/deg_node_component.h @@ -201,6 +201,7 @@ DEG_COMPONENT_NODE_DECLARE_GENERIC(ShadingParameters); DEG_COMPONENT_NODE_DECLARE_GENERIC(Transform); DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(ObjectFromLayer); DEG_COMPONENT_NODE_DECLARE_GENERIC(Dupli); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Synchronization); DEG_COMPONENT_NODE_DECLARE_GENERIC(Audio); DEG_COMPONENT_NODE_DECLARE_GENERIC(Armature); DEG_COMPONENT_NODE_DECLARE_GENERIC(GenericDatablock); @@ -208,25 +209,6 @@ DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(Visibility); DEG_COMPONENT_NODE_DECLARE_GENERIC(Simulation); DEG_COMPONENT_NODE_DECLARE_GENERIC(NTreeOutput); -/* Synchronization Component. */ -struct SynchronizationComponentNode : public ComponentNode { - SynchronizationComponentNode() - { - /* Enforce "visibility" of the synchronization component. - * - * This component is never connected to other ID nodes, and hence can not be handled in the - * same way as other components needed for evaluation. It is only needed for proper - * evaluation of the ID node it belongs to. - * - * The design is such that the synchronization is supposed to happen whenever any part of the - * ID changed/evaluated. Here we mark the component as "visible" so that genetic recalc flag - * flushing and scheduling will handle the component in a generic manner. */ - affects_visible_id = true; - } - - DEG_COMPONENT_NODE_DECLARE; -}; - /* Bone Component */ struct BoneComponentNode : public ComponentNode { /** Initialize 'bone component' node - from pointer data given. */ diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc index 3029379d141..de4bc0668cf 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.cc +++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc @@ -218,9 +218,13 @@ string OperationNode::full_identifier() const void OperationNode::tag_update(Depsgraph *graph, eUpdateSource source) { - if ((flag & DEPSOP_FLAG_NEEDS_UPDATE) == 0) { - graph->add_entry_tag(this); - } + /* Ensure that there is an entry tag for this update. + * + * Note that the node might already be tagged for an update due invisible state of the node + * during previous dependency evaluation. Here the node gets re-tagged, so we need to give + * the evaluated clues that evaluation needs to happen again. */ + graph->add_entry_tag(this); + /* Tag for update, but also note that this was the source of an update. */ flag |= (DEPSOP_FLAG_NEEDS_UPDATE | DEPSOP_FLAG_DIRECTLY_MODIFIED); switch (source) { |