Fix collection visibility evaluation
authorDalai Felinto <dfelinto@gmail.com>
Mon, 15 Jan 2018 22:08:50 +0000 (20:08 -0200)
committerDalai Felinto <dfelinto@gmail.com>
Mon, 15 Jan 2018 22:19:12 +0000 (20:19 -0200)
Collection       A [disabled]
 -> Collection   B
   -> Collection C
     -> object

Object should be invisible, but it is not. Reported by Antonio Vazquez.

Bug introduced on: 1f5106de610b

source/blender/blenkernel/intern/layer.c
tests/python/view_layer/CMakeLists.txt
tests/python/view_layer/test_evaluation_visibility_j.py [new file with mode: 0644]

index 288dcb34439f7d1d29f55255a4773a7c4f6d889c..c63cefbcd8c3fb83ba74b2187ec02f47dc6d84eb 100644 (file)
@@ -2099,18 +2099,22 @@ static const char *collection_type_lookup[] =
     "Group Internal", /* COLLECTION_TYPE_GROUP_INTERNAL */
 };
 
+/**
+ * \note We can't use layer_collection->flag because of 3 level nesting (where parent is visible, but not grand-parent)
+ * So layer_collection->flag_evaluated is expected to be up to date with layer_collection->flag.
+ */
 static bool layer_collection_visible_get(const EvaluationContext *eval_ctx, LayerCollection *layer_collection)
 {
-       bool is_visible = (layer_collection->flag & COLLECTION_DISABLED) == 0;
+       if (layer_collection->flag_evaluated & COLLECTION_DISABLED) {
+               return false;
+       }
 
        if (eval_ctx->mode == DAG_EVAL_VIEWPORT) {
-               is_visible &= (layer_collection->flag & COLLECTION_VIEWPORT) != 0;
+               return (layer_collection->flag_evaluated & COLLECTION_VIEWPORT) != 0;
        }
        else {
-               is_visible &= (layer_collection->flag & COLLECTION_RENDER) != 0;
+               return (layer_collection->flag_evaluated & COLLECTION_RENDER) != 0;
        }
-
-       return is_visible;
 }
 
 void BKE_layer_eval_layer_collection(const EvaluationContext *eval_ctx,
@@ -2129,15 +2133,22 @@ void BKE_layer_eval_layer_collection(const EvaluationContext *eval_ctx,
 
        /* visibility */
        layer_collection->flag_evaluated = layer_collection->flag;
-       bool is_visible = layer_collection_visible_get(eval_ctx, layer_collection);
-       bool is_selectable = is_visible && ((layer_collection->flag & COLLECTION_SELECTABLE) != 0);
 
        if (parent_layer_collection != NULL) {
-               is_visible &= layer_collection_visible_get(eval_ctx, parent_layer_collection);
-               is_selectable &= (parent_layer_collection->flag_evaluated & COLLECTION_SELECTABLE) != 0;
-               layer_collection->flag_evaluated &= parent_layer_collection->flag_evaluated;
+               if (layer_collection_visible_get(eval_ctx, parent_layer_collection) == false) {
+                       layer_collection->flag_evaluated |= COLLECTION_DISABLED;
+               }
+
+               if ((parent_layer_collection->flag_evaluated & COLLECTION_DISABLED) ||
+                   (parent_layer_collection->flag_evaluated & COLLECTION_SELECTABLE) == 0)
+               {
+                       layer_collection->flag_evaluated &= ~COLLECTION_SELECTABLE;
+               }
        }
 
+       const bool is_visible = layer_collection_visible_get(eval_ctx, layer_collection);
+       const bool is_selectable = is_visible && ((layer_collection->flag_evaluated & COLLECTION_SELECTABLE) != 0);
+
        /* overrides */
        if (is_visible) {
                if (parent_layer_collection == NULL) {
index 3f7149a67ad12744437ad23f1064e90951d81765..69b024164874fdd8a830cb047b72592ba985fe38 100644 (file)
@@ -81,6 +81,7 @@ VIEW_LAYER_TEST(evaluation_visibility_f)
 VIEW_LAYER_TEST(evaluation_visibility_g)
 VIEW_LAYER_TEST(evaluation_visibility_h)
 VIEW_LAYER_TEST(evaluation_visibility_i)
+VIEW_LAYER_TEST(evaluation_visibility_j)
 VIEW_LAYER_TEST(evaluation_selectability_a)
 VIEW_LAYER_TEST(evaluation_selectability_b)
 VIEW_LAYER_TEST(evaluation_selectability_c)
diff --git a/tests/python/view_layer/test_evaluation_visibility_j.py b/tests/python/view_layer/test_evaluation_visibility_j.py
new file mode 100644 (file)
index 0000000..53810fe
--- /dev/null
@@ -0,0 +1,61 @@
+# ############################################################
+# Importing - Same For All Render Layer Tests
+# ############################################################
+
+import unittest
+import os
+import sys
+
+from view_layer_common import *
+
+
+# ############################################################
+# Testing
+# ############################################################
+
+class UnitTesting(ViewLayerTesting):
+    def test_visibility_nested(self):
+        """
+        See if the depsgraph evaluation is correct
+        """
+        import bpy
+
+        # delete all initial objects
+        while bpy.data.objects:
+            bpy.data.objects.remove(bpy.data.objects[0])
+
+        # delete all initial collections
+        scene = bpy.context.scene
+        master_collection = scene.master_collection
+        while master_collection.collections:
+            master_collection.collections.remove(master_collection.collections[0])
+
+        collection_parent = master_collection.collections.new('parent')
+        collection_nested = collection_parent.collections.new('child linked')
+        ob = bpy.data.objects.new('An Empty', None)
+        collection_nested.objects.link(ob)
+
+        layer_collection = bpy.context.view_layer.collections.link(master_collection)
+        self.assertTrue(layer_collection.enabled)
+
+        # Update depsgraph.
+        scene.update()
+
+        self.assertTrue(ob.visible_get())
+
+        layer_collection.enabled = False
+        self.assertFalse(layer_collection.enabled)
+
+        # Update depsgraph.
+        scene.update()
+
+        self.assertFalse(ob.visible_get())
+
+
+# ############################################################
+# Main - Same For All Render Layer Tests
+# ############################################################
+
+if __name__ == '__main__':
+    UnitTesting._extra_arguments = setup_extra_arguments(__file__)
+    unittest.main()