[Bf-blender-cvs] [b364be84a02] temp-angavrilov-material-uniforms: Materials: add custom object properties as uniform attributes.

Alexander Gavrilov noreply at git.blender.org
Mon Oct 12 13:15:35 CEST 2020


Commit: b364be84a02d8a50175c31836783bc4e7791981d
Author: Alexander Gavrilov
Date:   Wed Aug 5 19:14:40 2020 +0300
Branches: temp-angavrilov-material-uniforms
https://developer.blender.org/rBb364be84a02d8a50175c31836783bc4e7791981d

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 Cycles design
seems to intend to treat all attributes equally, so the Blender
interface uses a name prefix that can't be entered with keyboard.

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	intern/cycles/kernel/geom/geom_attribute.h
M	intern/cycles/render/attribute.h
M	intern/cycles/render/geometry.cpp
M	intern/cycles/render/geometry.h
M	intern/cycles/render/object.cpp
M	intern/cycles/render/object.h
M	source/blender/editors/space_node/drawnode.c
M	source/blender/makesdna/DNA_node_types.h
M	source/blender/makesrna/intern/rna_nodetree.c

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

diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index 212b9cbe103..9931eeab17a 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -216,6 +216,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;
@@ -325,6 +329,130 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
   return object;
 }
 
+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;
+}
+
+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 03ed88ea9ec..65ac22268ca 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 62fd1ac2351..68f31542a7d 100644
--- a/intern/cycles/blender/blender_sync.h
+++ b/intern/cycles/blender/blender_sync.h
@@ -147,6 +147,8 @@ class BlenderSync {
                       BlenderObjectCulling &culling,
                       bool *use_portal);
 
+  bool sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object);
+
   /* Volume */
   void sync_volume(BL::Object &b_ob, Volume *volume, const vector<Shader *> &used_shaders);
 
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/intern/cycles/kernel/geom/geom_attribute.h b/intern/cycles/kernel/geom/geom_attribute.h
index e1b0e6fb81c..d90e092a7b9 100644
--- a/intern/cycles/kernel/geom/geom_attribute.h
+++ b/intern/cycles/kernel/geom/geom_attribute.h
@@ -66,9 +66,17 @@ ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals *kg,
 
   while (attr_map.x != id) {
     if (UNLIKELY(attr_map.x == ATTR_STD_NONE)) {
-      return attribute_not_found();
+      if (UNLIKELY(attr_map.y == 0)) {
+        return attribute_not_found();
+      }
+      else {
+        /* chain jump to a different part of the table */
+        attr_offset = attr_map.z;
+      }
+    }
+    else {
+      attr_offset += ATTR_PRIM_TYPES;
     }
-    attr_offset += ATTR_PRIM_TYPES;
     attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
   }
 
diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h
index 5871fa04a31..9990a1325a7 100644
--- a/intern/cycles/render/attribute.h
+++ b/intern/cycles/render/attribute.h
@@ -177,6 +177,7 @@ class AttributeSet {
   list<Attribute> attributes;
 
   AttributeSet(Geometry *geometry, AttributePrimitive prim);
+  AttributeSet(AttributeSet &&) = default;
   ~AttributeSet();
 
   Attribute *add(ustring name, TypeDesc type, AttributeElement element);
diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp
index 3614ffd5630..986c3c18108 100644
--- a/intern/cycles/render/geometry.cpp
+++ b/intern/cycles/render/geometry.cpp
@@ -116,6 +116,16 @@ bool Geometry::need_attribute(Scene * /*scene*/, u

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list