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

Alexander Gavrilov noreply at git.blender.org
Fri Oct 7 12:15:00 CEST 2022


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

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	source/blender/blenkernel/BKE_duplilist.h
M	source/blender/blenkernel/intern/object_dupli.cc
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.cc
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..5fb17bb0d50 100644
--- a/intern/cycles/blender/id_map.h
+++ b/intern/cycles/blender/id_map.h
@@ -20,7 +20,7 @@ CCL_NAMESPACE_BEGIN
  * Utility class to map between Blender datablocks and Cycles data structures,
  * and keep track of recalc tags from the dependency graph. */
 
-template<typename K, typename T> class id_map {
+template<typename K, typename T, typename Flags = uint> class id_map {
  public:
   id_map(Scene *scene_) : scene(scene_)
   {
@@ -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());
@@ -154,6 +159,7 @@ template<typename K, typename T> class id_map {
       TMapPair &pair = *jt;
 
       if (do_delete && used_set.find(pair.second) == used_set.end()) {
+        flags.erase(pair.second);
         scene->delete_node(pair.second);
       }
       else {
@@ -171,9 +177,33 @@ template<typename K, typename T> class id_map {
     return b_map;
   }
 
+  bool test_flag(T *data, Flags val)
+  {
+    typename map<T *, uint>::iterator it = flags.find(data);
+    return it != flags.end() && (it->second & (1 << val)) != 0;
+  }
+
+  void set_flag(T *data, Flags val)
+  {
+    flags[data] |= (1 << val);
+  }
+
+  void clear_flag(T *data, Flags val)
+  {
+    typename map<T *, uint>::iterator it = flags.find(data);
+    if (it != flags.end()) {
+      it->second &= ~(1 << val);
+
+      if (it->second == 0) {
+        flags.erase(it);
+      }
+    }
+  }
+
  protected:
   map<K, T *> b_map;
   set<T *> used_set;
+  map<T *, uint> flags;
   set<void *> b_recalc;
   Scene *scene;
 };
diff --git a/intern/cycles/blender/object.cpp b/intern/cycles/blender/object.cpp
index 8a3c1136104..5af1e18a597 100644
--- a/intern/cycles/blender/object.cpp
+++ b/intern/cycles/blender/object.cpp
@@ -96,6 +96,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
@@ -400,7 +407,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..fd32e7ca1d7 100644
--- a/intern/cycles/blender/shader.cpp
+++ b/intern/cycles/blender/shader.cpp
@@ -22,6 +22,8 @@
 #include "util/string.h"
 #include "util/task.h"
 
+#include "BKE_duplilist.h"
+
 CCL_NAMESPACE_BEGIN
 
 typedef map<void *, ShaderInput *> PtrInputMap;
@@ -103,6 +105,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 +114,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 +135,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 +1430,89 @@ 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. */
+        BL::ViewLayer b_layer = b_depsgraph.view_layer_eval();
+        BL::Scene b_scene = b_depsgraph.scene_eval();
+        float4 value;
+
+        BKE_view_layer_find_rgba_attribute((::Scene *)b_scene.ptr.data,
+                                           (::ViewLayer *)b_layer.ptr.data,
+                                           real_name.c_str(),
+                                           &value.x);
+
+        /* 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) {
+    shader_map.set_flag(shader, SHADER_WITH_LAYER_ATTRS);
+  }
+  else {
+    shader_map.clear_flag(shader, SHADER_WITH_LAYER_ATTRS);
+  }
+}
+
+bool BlenderSync::scene_attr_needs_recalc(Shader *shader, BL::Depsgraph &b_depsgraph)
+{
+  if (shader && shader_map.test_flag(shader, SHADER_WITH_LAYER_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,7 +1531,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 +1553,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 +1611,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 +1713,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 +1781,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 +1803,8 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all)
         graph->connect(emission->output("Emission"), out->input("Surface"));
       }
 
+      resolve_view

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list