Page MenuHome

Cycles: Support for accessing custom mesh attributes.
ClosedPublic

Authored by Jacques Lucke (JacquesLucke) on Jan 26 2021, 2:33 PM.
Tags
None
Tokens
"Love" token, awarded by grzelins."Love" token, awarded by shader."Love" token, awarded by chironamo."Love" token, awarded by someuser."Love" token, awarded by Yuro."Love" token, awarded by rboxman."Love" token, awarded by brecht."Love" token, awarded by DimitriBastos."Love" token, awarded by wilBr."Love" token, awarded by kursadk."Love" token, awarded by Lumpengnom."Love" token, awarded by lone_noel."Love" token, awarded by Rusculleda.

Details

Summary

This makes custom mesh attributes available in Cycles. Typically, these attributes are generated by geometry nodes, but they can also be created with a Python script.

Possible todos:

  • Support subdivision. Still have to investigate what that actually means exactly and how to test it. Not sure if it is acceptible to merge this without support for it.
  • Investigate potential conflicts with sculpt vertex colors (which are a subset of custom attributes). Problem is I don't really know how to use sculpt vertex colors, also they are still an experimental feature, so maybe sculpt vertex colors should check how to interact with generic attributes instead of the other way around.
  • (can be improved later) Potentially use different types for integer and bool attributes, currently they just become floats in cycles. This wastes memory in some cases, but I'm not sure how Cycles handles other geometry types internally, or if everything should just be floats.

This script can be used for testing. It simply adds a new attribute that can then be accessed using the Attribute node in Cycles.

import bpy
import random

attribute_name = "a"

mesh = bpy.context.active_object.data
try:
    mesh.attributes.remove(mesh.attributes.get(attribute_name))
except:
    pass

attribute = mesh.attributes.new(attribute_name, "FLOAT_VECTOR", "POLYGON")

for value in attribute.data:
    value.vector = (random.random(), random.random(), random.random())

Diff Detail

Repository
rB Blender
Branch
cycles-attribute-rendering (branched from master)
Build Status
Buildable 12391
Build 12391: arc lint + arc unit

Event Timeline

Jacques Lucke (JacquesLucke) requested review of this revision.Jan 26 2021, 2:33 PM
Jacques Lucke (JacquesLucke) created this revision.

@Kévin Dietrich (kevindietrich) Sorry for summoning you again for a Cycles update issue. Maybe you know how to fix that correctly. I did notice that simply inserting rebuild = true; at the end of BlenderSync::sync_mesh does solve the issue, but that's obviously not the correct solution.

This is actually a bug in the device update where we do not properly detect if attributes were added or removed so the kernel's attribute map is not updated.

This patch should solve the issue, I would need to double check that all cases are properly handled:

diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp
index ce4ae6e4295..409c3de6d0e 100644
--- a/intern/cycles/render/attribute.cpp
+++ b/intern/cycles/render/attribute.cpp
@@ -440,6 +440,7 @@ Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement eleme
 
   Attribute new_attr(name, type, element, geometry, prim);
   attributes.emplace_back(std::move(new_attr));
+  modified = true;
   return &attributes.back();
 }
 
@@ -461,6 +462,7 @@ void AttributeSet::remove(ustring name)
 
     for (it = attributes.begin(); it != attributes.end(); it++) {
       if (&*it == attr) {
+        modified = true;
         attributes.erase(it);
         return;
       }
@@ -606,6 +608,7 @@ void AttributeSet::remove(AttributeStandard std)
 
     for (it = attributes.begin(); it != attributes.end(); it++) {
       if (&*it == attr) {
+        modified = true;
         attributes.erase(it);
         return;
       }
@@ -671,12 +674,14 @@ void AttributeSet::update(AttributeSet &&new_attributes)
   for (it = attributes.begin(); it != attributes.end();) {
     if (it->std != ATTR_STD_NONE) {
       if (new_attributes.find(it->std) == nullptr) {
+        modified = true;
         attributes.erase(it++);
         continue;
       }
     }
     else if (it->name != "") {
       if (new_attributes.find(it->name) == nullptr) {
+        modified = true;
         attributes.erase(it++);
         continue;
       }
@@ -691,6 +696,8 @@ void AttributeSet::clear_modified()
   foreach (Attribute &attr, attributes) {
     attr.modified = false;
   }
+
+  modified = false;
 }
 
 /* AttributeRequest */
diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h
index 26536d28373..15a5948a2cb 100644
--- a/intern/cycles/render/attribute.h
+++ b/intern/cycles/render/attribute.h
@@ -183,6 +183,7 @@ class AttributeSet {
   Geometry *geometry;
   AttributePrimitive prim;
   list<Attribute> attributes;
+	bool modified = true;
 
   AttributeSet(Geometry *geometry, AttributePrimitive prim);
   AttributeSet(AttributeSet &&) = default;
diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp
index 425117e986b..c857f342c9e 100644
--- a/intern/cycles/render/geometry.cpp
+++ b/intern/cycles/render/geometry.cpp
@@ -1458,6 +1458,18 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
   foreach (Geometry *geom, scene->geometry) {
     geom->has_volume = false;
 
+    if (geom->attributes.modified) {
+      device_update_flags |= ATTRS_NEED_REALLOC;
+    }
+
+    if (geom->is_mesh()) {
+      Mesh *mesh = static_cast<Mesh *>(geom);
+
+      if (mesh->subd_attributes.modified) {
+        device_update_flags |= ATTRS_NEED_REALLOC;
+      }
+    }
+
     foreach (Node *node, geom->get_used_shaders()) {
       Shader *shader = static_cast<Shader *>(node);
       if (shader->has_volume) {
Jacques Lucke (JacquesLucke) retitled this revision from Cycles: Support for accessing custom mesh attributes (WIP). to Cycles: Support for accessing custom mesh attributes..Feb 15 2021, 11:32 AM
Jacques Lucke (JacquesLucke) edited the summary of this revision. (Show Details)
Jacques Lucke (JacquesLucke) retitled this revision from Cycles: Support for accessing custom mesh attributes. to Cycles: Support for accessing custom mesh attributes (WIP)..Feb 15 2021, 12:02 PM
Jacques Lucke (JacquesLucke) edited the summary of this revision. (Show Details)

Potentially use different types for integer and bool attributes, currently they just become floats in cycles. This wastes memory in some cases, but I'm not sure how Cycles handles other geometry types internally, or if everything should just be floats.

Adding more attribute types is possible (within the limitations, if any, of the various devices/platforms that we want to support), especially if memory usage is an issue, but that would be a bigger change, and outside of the scope of this patch. I think overall Cycles would need a better, more generic, way of handling attributes during Scene updates before adding more types.

  • fix corner and polygon attributes
Jacques Lucke (JacquesLucke) retitled this revision from Cycles: Support for accessing custom mesh attributes (WIP). to Cycles: Support for accessing custom mesh attributes..EditedFeb 15 2021, 1:13 PM
Jacques Lucke (JacquesLucke) edited the summary of this revision. (Show Details)

Quick demos using a script and using geometry nodes:

I think using floats instead of integers is quite reasonable, since for shaders that they will be converted anyway as there are no integer sockets. For booleans memory could be saved, but it's not really an important optimization. I don't expect them to be super common, and when they are used they're likely not that big a contributor to mesh memory.

intern/cycles/render/attribute.cpp
443 ↗(On Diff #34003)

I guess this isn't quite enough because the geometry node will not be tagged as modified, so if the only thing that was changed in the scene is that an attribute was added to a geometry, we won't detect that anything has been modified in the scene.

However this is a pre-existing issue, and I'm working on changes that should solve this better (P1966), so I think this is fine for now.

This revision is now accepted and ready to land.Feb 17 2021, 3:26 AM

For subdivision I think the attributes would need to be subdivided by the subdivision surface modifier (it it's not done already, I don't remember seeing them handled there) as the Blender exporter always accesses a subdivided mesh. Ideally we should have T68891 and not worry about any subdivision modifier, which can stay a modelling feature (and similarly for the subdivision node in the geometry nodes). This is something that I started looking into.