[Bf-blender-cvs] [6fdcca8de64] master: Materials: add custom object properties as uniform attributes.

Alexander Gavrilov noreply at git.blender.org
Tue Nov 3 14:37:29 CET 2020


Commit: 6fdcca8de64cd70f237640b67ce2d0068b918d05
Author: Alexander Gavrilov
Date:   Wed Aug 5 19:14:40 2020 +0300
Branches: master
https://developer.blender.org/rB6fdcca8de64cd70f237640b67ce2d0068b918d05

Materials: add custom object properties as uniform attributes.

This patch allows the user to type a property name into the
Attribute node, which will then output the value of the property
for each individual object, allowing to e.g. customize shaders
by object without duplicating the shader.

In order to make supporting this easier for Eevee, it is necessary
to explicitly choose whether the attribute is varying or uniform
via a dropdown option of the Attribute node. The dropdown also
allows choosing whether instancing should be taken into account.

The Cycles design treats all attributes as one common namespace,
so the Blender interface converts the enum to a name prefix that
can't be entered using keyboard.

In Eevee, the attributes are provided to the shader via a UBO indexed
with resource_id, similar to the existing Object Info data. Unlike it,
however, it is necessary to maintain a separate buffer for every
requested combination of attributes.

This is done using a hash table with the attribute set as the key,
as it is expected that technically different but similar materials
may use the same set of attributes. In addition, in order to minimize
wasted memory, a sparse UBO pool is implemented, so that chunks that
don't contain any data don't have to be allocated.

The back-end Cycles code is already refactored and committed by Brecht.

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

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

M	intern/cycles/blender/blender_object.cpp
M	intern/cycles/blender/blender_shader.cpp
M	intern/cycles/blender/blender_sync.h
M	intern/cycles/blender/blender_util.h
M	source/blender/blenlib/BLI_bitmap.h
M	source/blender/draw/DRW_engine.h
M	source/blender/draw/intern/draw_instance_data.c
M	source/blender/draw/intern/draw_instance_data.h
M	source/blender/draw/intern/draw_manager.c
M	source/blender/draw/intern/draw_manager.h
M	source/blender/draw/intern/draw_manager_data.c
M	source/blender/draw/intern/draw_manager_exec.c
M	source/blender/editors/space_node/drawnode.c
M	source/blender/gpu/GPU_material.h
M	source/blender/gpu/GPU_shader.h
M	source/blender/gpu/GPU_uniform_buffer.h
M	source/blender/gpu/GPU_viewport.h
M	source/blender/gpu/intern/gpu_codegen.c
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/intern/gpu_viewport.c
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.c

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

diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index d8c4ce9c5df..5e99759fdac 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -234,6 +234,10 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
 
   /* special case not tracked by object update flags */
 
+  if (sync_object_attributes(b_instance, object)) {
+    object_updated = true;
+  }
+
   /* holdout */
   if (use_holdout != object->use_holdout) {
     object->use_holdout = use_holdout;
@@ -343,6 +347,132 @@ 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;
+  }
+
+  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 = 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,
+                                       bool use_instancer)
+{
+  string idprop_name = string_printf("[\"%s\"]", name.c_str());
+  float4 value;
+
+  /* If requesting instance data, check the parent particle system and object. */
+  if (use_instancer && b_instance.is_instance()) {
+    BL::ParticleSystem b_psys = b_instance.particle_system();
+
+    if (b_psys) {
+      if (lookup_property(b_psys.settings(), idprop_name, &value) ||
+          lookup_property(b_psys.settings(), name, &value)) {
+        return value;
+      }
+    }
+    if (lookup_property(b_instance.parent(), idprop_name, &value) ||
+        lookup_property(b_instance.parent(), name, &value)) {
+      return value;
+    }
+  }
+
+  /* Check the object and mesh. */
+  BL::Object b_ob = b_instance.object();
+  BL::ID b_data = b_ob.data();
+
+  if (lookup_property(b_ob, idprop_name, &value) || lookup_property(b_ob, name, &value) ||
+      lookup_property(b_data, idprop_name, &value) || lookup_property(b_data, name, &value)) {
+    return value;
+  }
+
+  return make_float4(0.0f);
+}
+
+bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object)
+{
+  /* Find which attributes are needed. */
+  AttributeRequestSet requests = object->geometry->needed_attributes();
+
+  /* Delete attributes that became unnecessary. */
+  vector<ParamValue> &attributes = object->attributes;
+  bool changed = false;
+
+  for (int i = attributes.size() - 1; i >= 0; i--) {
+    if (!requests.find(attributes[i].name())) {
+      attributes.erase(attributes.begin() + i);
+      changed = true;
+    }
+  }
+
+  /* Update attribute values. */
+  foreach (AttributeRequest &req, requests.requests) {
+    ustring name = req.name;
+
+    std::string real_name;
+    BlenderAttributeType type = blender_attribute_name_split_type(name, &real_name);
+
+    if (type != BL::ShaderNodeAttribute::attribute_type_GEOMETRY) {
+      bool use_instancer = (type == BL::ShaderNodeAttribute::attribute_type_INSTANCER);
+      float4 value = lookup_instance_property(b_instance, real_name, use_instancer);
+
+      /* Try finding the existing attribute value. */
+      ParamValue *param = NULL;
+
+      for (size_t i = 0; i < attributes.size(); i++) {
+        if (attributes[i].name() == name) {
+          param = &attributes[i];
+          break;
+        }
+      }
+
+      /* Replace or add the value. */
+      ParamValue new_param(name, TypeDesc::TypeFloat4, 1, &value);
+      assert(new_param.datasize() == sizeof(value));
+
+      if (!param) {
+        changed = true;
+        attributes.push_back(new_param);
+      }
+      else if (memcmp(param->data(), &value, sizeof(value)) != 0) {
+        changed = true;
+        *param = new_param;
+      }
+    }
+  }
+
+  return changed;
+}
+
 /* Object Loop */
 
 void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index c171982b29d..0c1b240c593 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -97,6 +97,53 @@ static ImageAlphaType get_image_alpha_type(BL::Image &b_image)
   return (ImageAlphaType)validate_enum_value(value, IMAGE_ALPHA_NUM_TYPES, IMAGE_ALPHA_AUTO);
 }
 
+/* Attribute name translation utilities */
+
+/* Since Eevee needs to know whether the attribute is uniform or varying
+ * at the time it compiles the shader for the material, Blender had to
+ * introduce different namespaces (types) in its attribute node. However,
+ * Cycles already has object attributes that form a uniform namespace with
+ * the more common varying attributes. Without completely reworking the
+ * attribute handling in Cycles to introduce separate namespaces (this could
+ * be especially hard for OSL which directly uses the name string), the
+ * space identifier has to be added to the attribute name as a prefix.
+ *
+ * The prefixes include a control character to ensure the user specified
+ * name can't accidentally include a special prefix.
+ */
+
+static const string_view object_attr_prefix("\x01object:");
+static const string_view instancer_attr_prefix("\x01instancer:");
+
+static ustring blender_attribute_name_add_type(const string &name, BlenderAttributeType type)
+{
+  switch (type) {
+    case BL::ShaderNodeAttribute::attribute_type_OBJECT:
+      return ustring::concat(object_attr_prefix, name);
+    case BL::ShaderNodeAttribute::attribute_type_INSTANCER:
+      return ustring::concat(instancer_attr_prefix, name);
+    default:
+      return ustring(name);
+  }
+}
+
+BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_real_name)
+{
+  string_view sname(name);
+
+  if (sname.substr(0, object_attr_prefix.size()) == object_attr_prefix) {
+    *r_real_name = sname.substr(object_attr_prefix.size());
+    return BL::ShaderNodeAttribute::attribute_type_OBJECT;
+  }
+
+  if (sname.substr(0, instancer_attr_prefix.size()) == instancer_attr_prefix) {
+    *r_real_name = sname.substr(instancer_attr_prefix.size());
+    return BL::ShaderNodeAttribute::attribute_type_INSTANCER;
+  }
+
+  return BL::ShaderNodeAttribute::attribute_type_GEOMETRY;
+}
+
 /* Graph */
 
 static BL::NodeSocket get_node_output(BL::Node &b_node, const string &name)
@@ -369,7 +416,8 @@ static ShaderNode *add_node(Scene *scene,
   else if (b_node.is_a(&RNA_ShaderNodeAttribute)) {
     BL::ShaderNodeAttribute b_attr_node(b_node);
     AttributeNode *attr = graph->create_node<AttributeNode>();
-    attr->attribute = b_attr_node.attribute_name();
+    attr->attribute = blender_attribute_name_add_type(b_attr_node.attribute_name(),
+                                                      b_attr_node.attribute_type());
     node = attr;
   }
   else if (b_node.is_a(&RNA_ShaderNodeBackground)) {
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
index 360468da0ef..8ca021ff0d2 100644
--- a/intern/cycles/blender/blender_sync.h
+++ b/intern/cycles/blender/blender_sync.h
@@ -149,6 +149,8 @@ class BlenderSync {
                       bool *use_portal,
                       TaskPool *geom_task_pool);
 
+  bool sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object);
+
   /* Volume */
   void sync_volume(BL::Object &b_ob, Volume *volume);
 
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index 1ea34b41aa2..5185ebae789 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -40,6 +40,9 @@ float *BKE_image_get_float_pixels_for_frame(void *image, int frame, int tile);
 
 CCL_NAMESPACE_BEGIN
 
+typedef BL::ShaderNodeAttribute::attribute_type_enum BlenderAttributeType;
+BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_real_name);
+
 void python_thread_state_save(void **python_thread_state);
 void python_thread_state_restore(void **python_thread_state);
 
diff --git a/source/blender/blenlib/BLI_bitmap.h b/source/blender/blenlib/BLI_bitmap.h
index 960ce44c58c..c97be6eed3c 100644
--- a/source/blender/blenlib/BLI_bitmap.h
+++ b/source/blender/blenlib/BLI_bitmap.h
@@ -106,7 +106,7 @@ typedef unsigned int BLI_bitmap;
 #define BLI_BITMAP_RESIZE(_bitmap, _tot) \
   { \
     CHECK_TYPE(_bitmap, BLI_bitmap *); \
-    (_bitmap) = MEM_reallocN(_bitmap, BLI_BITMAP_SIZE(_tot)); \
+    (_bitmap) = MEM_recallocN(_bitmap, BLI_BITMAP_SIZE(_tot)); \
   } \
   (void)0
 
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index ca5c2c94b40..2d5b93f4272 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -36,6 +36,7 @@ struct ARegion;
 struct DRWInstanceDataList;
 struct Depsgraph;
 struct DrawEngineType;
+struct GHash;
 struct GPUMaterial;
 struct GPUOffScreen;
 struct GPUViewport;
@@ -140,6 +141,7 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph
 /* This is here because GPUViewport needs it */
 struct DRWInstanceDataList *DRW_instance_data_list_create(void);
 void DRW_instance_data_list_free(struct DRWInstanceDataList *idatalist);
+void DRW_uniform_attrs_pool_free(struct GHash *table);
 
 void DRW_render_context_enable(struct Render *render);
 void DRW_render_context_disable(struct Render *render);
diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_ins

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list