[Bf-blender-cvs] [4f77297df8d] temp-angavrilov: Attribute Node: support accessing attributes of View Layer and Scene.

Alexander Gavrilov noreply at git.blender.org
Fri Sep 30 12:23:36 CEST 2022


Commit: 4f77297df8d2fb528463e53aa4897f36dfb8f0a7
Author: Alexander Gavrilov
Date:   Mon Sep 12 00:30:58 2022 +0300
Branches: temp-angavrilov
https://developer.blender.org/rB4f77297df8d2fb528463e53aa4897f36dfb8f0a7

Attribute Node: support accessing attributes of View Layer and Scene.

The attribute node already allows accessing attributes associated
with objects and meshes, which allows changing the behavior of the
same material between different objects or instances. The same idea
can be extended to an even more global level of layers and scenes.

Currently view layers provide an option to replace all materials
with a different one. However, since the same material will be applied
to all objects in the layer, varying the behavior between layers while
preserving distinct materials requires duplicating objects.

Providing access to properties of layers and scenes via the attribute
node enables making materials with built-in switches or settings that
can be controlled globally at the view layer level. This is probably
most useful for complex NPR shading and compositing. Like with objects,
the node can also access built-in scene properties, like render resolution
or FOV of the active camera. Lookup is also attempted in World, similar
to how the Object mode checks the Mesh datablock.

In Cycles this mode is implemented by replacing the attribute node with
the attribute value during sync, allowing constant folding to take the
values into account. This means however that materials that use this
feature have to be re-synced upon any changes to scene, world or camera.

The Eevee version uses a new uniform buffer containing a sorted array
mapping name hashes to values, with binary search lookup. The array
is limited to 512 entries, which is effectively limitless even
considering it is shared by all materials in the scene; it is also
just 16KB of memory so no point trying to optimize further.
The buffer has to be rebuilt when new attributes are detected in a
material, so the draw engine keeps a table of recently seen attribute
names to minimize the chance of extra rebuilds mid-draw.

Differential Revision: https://developer.blender.org/D15941

===================================================================

M	intern/cycles/blender/id_map.h
M	intern/cycles/blender/object.cpp
M	intern/cycles/blender/shader.cpp
M	intern/cycles/blender/sync.cpp
M	intern/cycles/blender/sync.h
M	intern/cycles/blender/util.h
M	source/blender/draw/CMakeLists.txt
M	source/blender/draw/engines/eevee_next/eevee_instance.cc
M	source/blender/draw/engines/eevee_next/eevee_instance.hh
M	source/blender/draw/engines/eevee_next/eevee_material.cc
M	source/blender/draw/engines/eevee_next/eevee_sync.cc
M	source/blender/draw/engines/eevee_next/eevee_sync.hh
M	source/blender/draw/engines/eevee_next/eevee_world.cc
M	source/blender/draw/intern/draw_defines.h
M	source/blender/draw/intern/draw_instance_data.c
M	source/blender/draw/intern/draw_manager.c
M	source/blender/draw/intern/draw_manager.cc
M	source/blender/draw/intern/draw_manager.h
M	source/blender/draw/intern/draw_manager.hh
M	source/blender/draw/intern/draw_manager_data.c
M	source/blender/draw/intern/draw_manager_exec.c
M	source/blender/draw/intern/draw_manager_shader.c
M	source/blender/draw/intern/draw_resource.cc
M	source/blender/draw/intern/draw_shader_shared.h
M	source/blender/draw/intern/shaders/draw_object_infos_info.hh
M	source/blender/gpu/GPU_material.h
M	source/blender/gpu/GPU_uniform_buffer.h
M	source/blender/gpu/intern/gpu_codegen.cc
M	source/blender/gpu/intern/gpu_material.c
M	source/blender/gpu/intern/gpu_node_graph.c
M	source/blender/gpu/intern/gpu_node_graph.h
M	source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl
M	source/blender/makesdna/DNA_node_types.h
M	source/blender/makesdna/DNA_scene_types.h
M	source/blender/makesrna/intern/rna_nodetree.c
M	source/blender/nodes/shader/nodes/node_shader_attribute.cc

===================================================================

diff --git a/intern/cycles/blender/id_map.h b/intern/cycles/blender/id_map.h
index e77d2f647bf..de55f92f17d 100644
--- a/intern/cycles/blender/id_map.h
+++ b/intern/cycles/blender/id_map.h
@@ -63,6 +63,11 @@ template<typename K, typename T> class id_map {
     b_recalc.insert(id_ptr);
   }
 
+  bool check_recalc(const BL::ID &id)
+  {
+    return id.ptr.data && b_recalc.find(id.ptr.data) != b_recalc.end();
+  }
+
   bool has_recalc()
   {
     return !(b_recalc.empty());
diff --git a/intern/cycles/blender/object.cpp b/intern/cycles/blender/object.cpp
index 109408c354d..456141baeca 100644
--- a/intern/cycles/blender/object.cpp
+++ b/intern/cycles/blender/object.cpp
@@ -94,6 +94,13 @@ bool BlenderSync::object_is_light(BL::Object &b_ob)
   return (b_ob_data && b_ob_data.is_a(&RNA_Light));
 }
 
+bool BlenderSync::object_is_camera(BL::Object &b_ob)
+{
+  BL::ID b_ob_data = b_ob.data();
+
+  return (b_ob_data && b_ob_data.is_a(&RNA_Camera));
+}
+
 void BlenderSync::sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object)
 {
   /* Initialize motion blur for object, detecting if it's enabled and creating motion
@@ -353,45 +360,6 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
   return object;
 }
 
-/* This function mirrors drw_uniform_property_lookup in draw_instance_data.cpp */
-static bool lookup_property(BL::ID b_id, const string &name, float4 *r_value)
-{
-  PointerRNA ptr;
-  PropertyRNA *prop;
-
-  if (!RNA_path_resolve(&b_id.ptr, name.c_str(), &ptr, &prop)) {
-    return false;
-  }
-
-  if (prop == NULL) {
-    return false;
-  }
-
-  PropertyType type = RNA_property_type(prop);
-  int arraylen = RNA_property_array_length(&ptr, prop);
-
-  if (arraylen == 0) {
-    float value;
-
-    if (type == PROP_FLOAT)
-      value = RNA_property_float_get(&ptr, prop);
-    else if (type == PROP_INT)
-      value = static_cast<float>(RNA_property_int_get(&ptr, prop));
-    else
-      return false;
-
-    *r_value = make_float4(value, value, value, 1.0f);
-    return true;
-  }
-  else if (type == PROP_FLOAT && arraylen <= 4) {
-    *r_value = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
-    RNA_property_float_get_array(&ptr, prop, &r_value->x);
-    return true;
-  }
-
-  return false;
-}
-
 /* This function mirrors drw_uniform_attribute_lookup in draw_instance_data.cpp */
 static float4 lookup_instance_property(BL::DepsgraphObjectInstance &b_instance,
                                        const string &name,
@@ -451,7 +419,8 @@ bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance
     std::string real_name;
     BlenderAttributeType type = blender_attribute_name_split_type(name, &real_name);
 
-    if (type != BL::ShaderNodeAttribute::attribute_type_GEOMETRY) {
+    if (type == BL::ShaderNodeAttribute::attribute_type_OBJECT ||
+        type == BL::ShaderNodeAttribute::attribute_type_INSTANCER) {
       bool use_instancer = (type == BL::ShaderNodeAttribute::attribute_type_INSTANCER);
       float4 value = lookup_instance_property(b_instance, real_name, use_instancer);
 
diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp
index 9505f4ba58f..e1925cccd9a 100644
--- a/intern/cycles/blender/shader.cpp
+++ b/intern/cycles/blender/shader.cpp
@@ -103,6 +103,7 @@ static ImageAlphaType get_image_alpha_type(BL::Image &b_image)
 
 static const string_view object_attr_prefix("\x01object:");
 static const string_view instancer_attr_prefix("\x01instancer:");
+static const string_view view_layer_attr_prefix("\x01layer:");
 
 static ustring blender_attribute_name_add_type(const string &name, BlenderAttributeType type)
 {
@@ -111,6 +112,8 @@ static ustring blender_attribute_name_add_type(const string &name, BlenderAttrib
       return ustring::concat(object_attr_prefix, name);
     case BL::ShaderNodeAttribute::attribute_type_INSTANCER:
       return ustring::concat(instancer_attr_prefix, name);
+    case BL::ShaderNodeAttribute::attribute_type_VIEW_LAYER:
+      return ustring::concat(view_layer_attr_prefix, name);
     default:
       return ustring(name);
   }
@@ -130,6 +133,11 @@ BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_r
     return BL::ShaderNodeAttribute::attribute_type_INSTANCER;
   }
 
+  if (sname.substr(0, view_layer_attr_prefix.size()) == view_layer_attr_prefix) {
+    *r_real_name = sname.substr(view_layer_attr_prefix.size());
+    return BL::ShaderNodeAttribute::attribute_type_VIEW_LAYER;
+  }
+
   return BL::ShaderNodeAttribute::attribute_type_GEOMETRY;
 }
 
@@ -1420,6 +1428,96 @@ static void add_nodes(Scene *scene,
             empty_proxy_map);
 }
 
+/* Look up and constant fold all references to View Layer attributes. */
+void BlenderSync::resolve_view_layer_attributes(Shader *shader,
+                                                ShaderGraph *graph,
+                                                BL::Depsgraph &b_depsgraph)
+{
+  bool updated = false;
+
+  foreach (ShaderNode *node, graph->nodes) {
+    if (node->is_a(AttributeNode::node_type)) {
+      AttributeNode *attr_node = static_cast<AttributeNode *>(node);
+
+      std::string real_name;
+      BlenderAttributeType type = blender_attribute_name_split_type(attr_node->get_attribute(),
+                                                                    &real_name);
+
+      if (type == BL::ShaderNodeAttribute::attribute_type_VIEW_LAYER) {
+        /* Look up the value. */
+        string idprop_name = string_printf("[\"%s\"]", real_name.c_str());
+        float4 value;
+
+        /* This lookup order mirrors Eevee code in draw_instance_data.cpp and draw_resource.cc */
+        BL::ViewLayer b_layer = b_depsgraph.view_layer_eval();
+        BL::Scene b_scene = b_depsgraph.scene_eval();
+
+        if (!(lookup_property(b_layer, idprop_name, &value) ||
+              lookup_property(b_layer, real_name, &value) ||
+              lookup_property(b_scene, idprop_name, &value) ||
+              lookup_property(b_scene, real_name, &value) ||
+              lookup_property(b_scene.world(), idprop_name, &value) ||
+              lookup_property(b_scene.world(), real_name, &value))) {
+          value = zero_float4();
+        }
+
+        /* Replace all outgoing links, using appropriate output types. */
+        float val_avg = (value.x + value.y + value.z) / 3.0f;
+
+        foreach (ShaderOutput *output, node->outputs) {
+          float val_float;
+          float3 val_float3;
+
+          if (output->type() == SocketType::FLOAT) {
+            val_float = (output->name() == "Alpha") ? value.w : val_avg;
+            val_float3 = make_float3(val_float);
+          }
+          else {
+            val_float = val_avg;
+            val_float3 = float4_to_float3(value);
+          }
+
+          foreach (ShaderInput *sock, output->links) {
+            if (sock->type() == SocketType::FLOAT) {
+              sock->set(val_float);
+            }
+            else if (SocketType::is_float3(sock->type())) {
+              sock->set(val_float3);
+            }
+
+            sock->constant_folded_in = true;
+          }
+
+          graph->disconnect(output);
+        }
+
+        /* Clear the attribute name to avoid further attempts to look up. */
+        attr_node->set_attribute(ustring());
+        updated = true;
+      }
+    }
+  }
+
+  if (updated) {
+    shaders_with_layer_attrs.insert(shader);
+  }
+  else {
+    shaders_with_layer_attrs.erase(shader);
+  }
+}
+
+bool BlenderSync::scene_attr_needs_recalc(Shader *shader, BL::Depsgraph &b_depsgraph)
+{
+  if (shader && shaders_with_layer_attrs.find(shader) != shaders_with_layer_attrs.end()) {
+    BL::Scene scene = b_depsgraph.scene_eval();
+
+    return shader_map.check_recalc(scene) || shader_map.check_recalc(scene.world()) ||
+           shader_map.check_recalc(scene.camera());
+  }
+
+  return false;
+}
+
 /* Sync Materials */
 
 void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
@@ -1438,7 +1536,8 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
     Shader *shader;
 
     /* test if we need to sync */
-    if (shader_map.add_or_update(&shader, b_mat) || update_all) {
+    if (shader_map.add_or_update(&shader, b_mat) || update_all ||
+        scene_attr_needs_recalc(shader, b_depsgraph)) {
       ShaderGraph *graph = new ShaderGraph();
 
       shader->name = b_mat.name().c_str();
@@ -1459,6 +1558,8 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
         graph->connect(diffuse->output("BSDF"), out->input("Surface"));
       }
 
+      resolve_view_layer_attributes(shader, graph, b_depsgraph);
+
       /* settings */
       PointerRNA cmat = RNA_pointer_get(&b_mat.ptr, "cycles");
       shader->set_use_mis(get_boolean(cmat, "sample_as_light"));
@@ -1515,9 +1616,11 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
 
   BlenderViewportParameters new_viewport_parameters(b_v3d, use_developer_ui);
 
+  Shader *shader = scene->default_background;
+
   if (world_recalc || update_all || b_world.ptr.data != world_map ||
-      viewport_parameters.shader_modified(new_viewport_parameters)) {
-    Shader *shader = scene->default_background;
+      viewport_parameters.shader_modified(new_viewport_parameters) ||
+      scene_attr_needs_recalc(shader, b_depsgraph)) {
     ShaderGraph *graph = new ShaderGraph();
 
     /* create nodes */
@@ -1615,6 +1718,8 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
       background->set_visibility(visibility);
     }
 
+    resolve_view_layer_attributes(shader, graph, b_depsgraph);
+
     shader->set_graph(graph);
     shader->tag_update(scene);
   }
@@ -1681,7 +1786,8 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all)
     Shader *shader;
 
     /* test if we need to sync */
-    if (shader_map.add_or_update(&shader, b_light) || update_all) {
+    if (shader_map.add_or_update(&shader, b_light) || update_all ||
+        scene_attr_needs_recalc(shader, b_depsgraph)) {
       ShaderGraph *graph = new ShaderGraph();
 
       /* create nodes */
@@ -1702,6 +1808,8 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list