Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/intern
diff options
context:
space:
mode:
authorAlexander Gavrilov <angavrilov@gmail.com>2022-09-12 00:30:58 +0300
committerAlexander Gavrilov <angavrilov@gmail.com>2022-10-08 16:43:18 +0300
commitf61ff22967c5f3be2d5f661ce2d455e3e9d39f0a (patch)
treecd604a87c4f9538dc2e0656b26eb1586ed497a5f /intern
parenta716e696584e90fc8ccb6b2af09fd15190af7f05 (diff)
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
Diffstat (limited to 'intern')
-rw-r--r--intern/cycles/blender/id_map.h32
-rw-r--r--intern/cycles/blender/object.cpp10
-rw-r--r--intern/cycles/blender/shader.cpp111
-rw-r--r--intern/cycles/blender/sync.cpp8
-rw-r--r--intern/cycles/blender/sync.h10
5 files changed, 164 insertions, 7 deletions
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_layer_attributes(shader, graph, b_depsgraph);
+
shader->set_graph(graph);
shader->tag_update(scene);
}
diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp
index 23bc92de022..a69a94614d3 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_camera(b_ob)) {
+ shader_map.set_recalc(b_ob);
+ }
}
/* Mesh */
else if (b_id.is_a(&RNA_Mesh)) {
@@ -218,6 +221,11 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d
if (world_map == b_world.ptr.data) {
world_recalc = true;
}
+ shader_map.set_recalc(b_world);
+ }
+ /* World */
+ else if (b_id.is_a(&RNA_Scene)) {
+ shader_map.set_recalc(b_id);
}
/* Volume */
else if (b_id.is_a(&RNA_Volume)) {
diff --git a/intern/cycles/blender/sync.h b/intern/cycles/blender/sync.h
index ae6c2420e55..fbb17bab0c8 100644
--- a/intern/cycles/blender/sync.h
+++ b/intern/cycles/blender/sync.h
@@ -120,6 +120,11 @@ class BlenderSync {
void sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all);
void sync_nodes(Shader *shader, BL::ShaderNodeTree &b_ntree);
+ bool scene_attr_needs_recalc(Shader *shader, BL::Depsgraph &b_depsgraph);
+ void resolve_view_layer_attributes(Shader *shader,
+ ShaderGraph *graph,
+ BL::Depsgraph &b_depsgraph);
+
/* Object */
Object *sync_object(BL::Depsgraph &b_depsgraph,
BL::ViewLayer &b_view_layer,
@@ -207,13 +212,16 @@ class BlenderSync {
bool object_is_geometry(BObjectInfo &b_ob_info);
bool object_can_have_geometry(BL::Object &b_ob);
bool object_is_light(BL::Object &b_ob);
+ bool object_is_camera(BL::Object &b_ob);
/* variables */
BL::RenderEngine b_engine;
BL::BlendData b_data;
BL::Scene b_scene;
- id_map<void *, Shader> shader_map;
+ enum ShaderFlags { SHADER_WITH_LAYER_ATTRS };
+
+ id_map<void *, Shader, ShaderFlags> shader_map;
id_map<ObjectKey, Object> object_map;
id_map<void *, Procedural> procedural_map;
id_map<GeometryKey, Geometry> geometry_map;