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

Alexander Gavrilov noreply at git.blender.org
Tue Sep 13 14:16:50 CEST 2022


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

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.

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	intern/cycles/scene/shader.cpp
M	intern/cycles/scene/shader.h
M	source/blender/draw/CMakeLists.txt
M	source/blender/draw/engines/eevee_next/eevee_material.cc
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/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..c030f51f287 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,8 +360,9 @@ 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)
+/* This function mirrors drw_uniform_property_lookup in draw_instance_data.cpp
+ * and ptr_property_lookup in draw_resource.cc */
+bool lookup_property(BL::Pointer b_id, const string &name, float4 *r_value)
 {
   PointerRNA ptr;
   PropertyRNA *prop;
@@ -451,7 +459,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..b66705a38ca 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,84 @@ static void add_nodes(Scene *scene,
             empty_proxy_map);
 }
 
+/* Look up and constant fold all references to View Layer attributes. */
+static bool resolve_view_layer_attributes(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;
+
+        if (!(lookup_property(b_depsgraph.view_layer_eval(), idprop_name, &value) ||
+              lookup_property(b_depsgraph.view_layer_eval(), real_name, &value) ||
+              lookup_property(b_depsgraph.scene_eval(), idprop_name, &value) ||
+              lookup_property(b_depsgraph.scene_eval(), 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);
+        }
+
+        attr_node->set_attribute(ustring(""));
+        updated = true;
+      }
+    }
+  }
+
+  return updated;
+}
+
+static bool scene_attr_needs_recalc(Shader *shader,
+                                    id_map<void *, Shader> &shader_map,
+                                    BL::Depsgraph &b_depsgraph)
+{
+  if (shader && shader->has_blender_scene_attrs) {
+    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,17 +1524,22 @@ 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, shader_map, b_depsgraph)) {
       ShaderGraph *graph = new ShaderGraph();
 
       shader->name = b_mat.name().c_str();
       shader->set_pass_id(b_mat.pass_index());
 
+      shader->has_blender_scene_attrs = false;
+
       /* create nodes */
       if (b_mat.use_nodes() && b_mat.node_tree()) {
         BL::ShaderNodeTree b_ntree(b_mat.node_tree());
 
         add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree);
+
+        shader->has_blender_scene_attrs = resolve_view_layer_attributes(graph, b_depsgraph);
       }
       else {
         DiffuseBsdfNode *diffuse = graph->create_node<DiffuseBsdfNode>();
@@ -1515,11 +1606,15 @@ 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, shader_map, b_depsgraph)) {
     ShaderGraph *graph = new ShaderGraph();
 
+    shader->has_blender_scene_attrs = false;
+
     /* create nodes */
     if (new_viewport_parameters.use_scene_world && b_world && b_world.use_nodes() &&
         b_world.node_tree()) {
@@ -1527,6 +1622,8 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
 
       add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree);
 
+      shader->has_blender_scene_attrs = resolve_view_layer_attributes(graph, b_depsgraph);
+
       /* volume */
       PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
       shader->set_heterogeneous_volume(!get_boolean(cworld, "homogeneous_volume"));
@@ -1681,9 +1778,12 @@ 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, shader_map, b_depsgraph)) {
       ShaderGraph *graph = new ShaderGraph();
 
+      shader->has_blender_scene_attrs = false;
+
       /* create nodes */
       if (b_light.use_nodes() && b_light.node_tree()) {
         shader->name = b_light.name().c_str();
@@ -1691,6 +1791,8 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all)
         BL::ShaderNodeTree b_ntree(b_light.node_tree());
 
         add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree);
+
+        shader->has_blender_scene_attrs = resolve_view_layer_attributes(graph, b_depsgraph);
       }
       else {
         EmissionNode *emission = graph->create_node<EmissionNode>();
diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp
index 6081c4626f0..4cded5f239b 100644
--- a/intern/cycles/blender/sync.cpp
+++ b/intern/cycles/blender/sync.cpp
@@ -206,6 +206,9 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d
           }
         }
       }
+      else if (object_is_

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list