Cycles: Support texture coordinate from another object
authorSergey Sharybin <sergey.vfx@gmail.com>
Wed, 21 Jan 2015 17:19:31 +0000 (22:19 +0500)
committerSergey Sharybin <sergey.vfx@gmail.com>
Tue, 27 Jan 2015 08:36:30 +0000 (13:36 +0500)
This is the same as blender internal's texture mapping from another object,
so this way it's possible to control texture space of one object by another.

Quite straightforward change apart from the workaround for the stupidness of
the dependency graph. Now shader has flag telling that it depends on object
transform. This is the simplest way to know which shaders needs to be tagged
for update when object changes. This might give some false-positive tags now
but reducing them should not be priority for Cycles and rather be a priority
to bring new dependency graph.

Also GLSL preview does not support using other object for mapping.

This is actually correct for BI shading as well and to be addressed as
a part of general GLSL viewport improvements since it's not really clear
how to support this in GLSL.

Reviewers: brecht, juicyfruit

Subscribers: eyecandy, venomgfx

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

14 files changed:
intern/cycles/blender/blender_shader.cpp
intern/cycles/blender/blender_sync.cpp
intern/cycles/kernel/shaders/node_texture_coordinate.osl
intern/cycles/kernel/svm/svm.h
intern/cycles/kernel/svm/svm_tex_coord.h
intern/cycles/render/graph.h
intern/cycles/render/nodes.cpp
intern/cycles/render/nodes.h
intern/cycles/render/osl.cpp
intern/cycles/render/shader.cpp
intern/cycles/render/shader.h
intern/cycles/render/svm.cpp
source/blender/editors/space_node/drawnode.c
source/blender/makesrna/intern/rna_nodetree.c

index 806eae72b23de8c53c9d8ee80552ea4302bf9110..baf79a78987a745cc7ba90adee22950741940418 100644 (file)
@@ -687,6 +687,10 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
                BL::ShaderNodeTexCoord b_tex_coord_node(b_node);
                TextureCoordinateNode *tex_coord = new TextureCoordinateNode();
                tex_coord->from_dupli = b_tex_coord_node.from_dupli();
+               if(b_tex_coord_node.object()) {
+                       tex_coord->use_transform = true;
+                       tex_coord->ob_tfm = get_transform(b_tex_coord_node.object().matrix_world());
+               }
                node = tex_coord;
        }
        else if (b_node.is_a(&RNA_ShaderNodeTexSky)) {
index 97ceae7237bbb3cc486ac93c8fdd42d0161d2155..79ee6d51196d0dd73855e2458da9f3b276933ad9 100644 (file)
@@ -70,10 +70,18 @@ bool BlenderSync::sync_recalc()
         * so we can do it later on if doing it immediate is not suitable */
 
        BL::BlendData::materials_iterator b_mat;
-
-       for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat)
-               if(b_mat->is_updated() || (b_mat->node_tree() && b_mat->node_tree().is_updated()))
+       bool has_updated_objects = b_data.objects.is_updated();
+       for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat) {
+               if(b_mat->is_updated() || (b_mat->node_tree() && b_mat->node_tree().is_updated())) {
                        shader_map.set_recalc(*b_mat);
+               }
+               else {
+                       Shader *shader = shader_map.find(*b_mat);
+                       if(has_updated_objects && shader != NULL && shader->has_object_dependency) {
+                               shader_map.set_recalc(*b_mat);
+                       }
+               }
+       }
 
        BL::BlendData::lamps_iterator b_lamp;
 
index f8a6f787288193c472fbab91d3ba08efd4c4f8bb..9e2109fa082e64ea0c287bd72ac5a332280da62a 100644 (file)
@@ -21,7 +21,9 @@ shader node_texture_coordinate(
        int is_background = 0,
        int is_volume = 0,
        int from_dupli = 0,
+       int use_transform = 0,
        string bump_offset = "center",
+       matrix object_itfm = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
 
        output point Generated = point(0.0, 0.0, 0.0),
        output point UV = point(0.0, 0.0, 0.0),
@@ -60,7 +62,12 @@ shader node_texture_coordinate(
                        getattribute("geom:uv", UV);
                }
 
-               Object = transform("object", P);
+               if (use_transform) {
+                       Object = transform(object_itfm, P);
+               }
+               else {
+                       Object = transform("object", P);
+               }
                Camera = transform("camera", P);
                Window = transform("NDC", P);
                Normal = transform("world", "object", NormalIn);
index 3465a743c3f5128d9c650c951899cf632da9189a..f1dfeb45265fdcaa8a30fcbecb3ec22780f6c53c 100644 (file)
@@ -395,7 +395,7 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade
                                svm_node_min_max(kg, sd, stack, node.y, node.z, &offset);
                                break;
                        case NODE_TEX_COORD:
-                               svm_node_tex_coord(kg, sd, path_flag, stack, node.y, node.z);
+                               svm_node_tex_coord(kg, sd, path_flag, stack, node, &offset);
                                break;
 #ifdef __EXTRA_NODES__
                        case NODE_TEX_COORD_BUMP_DX:
index b69f0d1c1c838638068fefb288632d6413f871e1..dcaa488ed31aae7776224bd520f9fdb077c13cbd 100644 (file)
@@ -18,15 +18,33 @@ CCL_NAMESPACE_BEGIN
 
 /* Texture Coordinate Node */
 
-ccl_device void svm_node_tex_coord(KernelGlobals *kg, ShaderData *sd, int path_flag, float *stack, uint type, uint out_offset)
+ccl_device void svm_node_tex_coord(KernelGlobals *kg,
+                                   ShaderData *sd,
+                                   int path_flag,
+                                   float *stack,
+                                   uint4 node,
+                                   int *offset)
 {
        float3 data;
+       uint type = node.y;
+       uint out_offset = node.z;
 
        switch(type) {
                case NODE_TEXCO_OBJECT: {
                        data = sd->P;
-                       if(sd->object != OBJECT_NONE)
-                               object_inverse_position_transform(kg, sd, &data);
+                       if(node.w == 0) {
+                               if(sd->object != OBJECT_NONE) {
+                                       object_inverse_position_transform(kg, sd, &data);
+                               }
+                       }
+                       else {
+                               Transform tfm;
+                               tfm.x = read_node_float(kg, offset);
+                               tfm.y = read_node_float(kg, offset);
+                               tfm.z = read_node_float(kg, offset);
+                               tfm.w = read_node_float(kg, offset);
+                               data = transform_point(&tfm, data);
+                       }
                        break;
                }
                case NODE_TEXCO_NORMAL: {
index 6821d0121667e7c50d4c45602d56ff3174657936..b39b3dae324a6f030a5054361ca089daaf34c910 100644 (file)
@@ -196,6 +196,7 @@ public:
        virtual bool has_converter_blackbody() { return false; }
        virtual bool has_bssrdf_bump() { return false; }
        virtual bool has_spatial_varying() { return false; }
+       virtual bool has_object_dependency() { return false; }
 
        vector<ShaderInput*> inputs;
        vector<ShaderOutput*> outputs;
index ed0be4d7b418cfb5624e22728e296dc046bd2642..3448209f101e8b0d68f3c7405c488c870f020502 100644 (file)
@@ -2263,6 +2263,8 @@ TextureCoordinateNode::TextureCoordinateNode()
        add_output("Reflection", SHADER_SOCKET_NORMAL);
 
        from_dupli = false;
+       use_transform = false;
+       ob_tfm = transform_identity();
 }
 
 void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -2350,7 +2352,14 @@ void TextureCoordinateNode::compile(SVMCompiler& compiler)
        out = output("Object");
        if(!out->links.empty()) {
                compiler.stack_assign(out);
-               compiler.add_node(texco_node, NODE_TEXCO_OBJECT, out->stack_offset);
+               compiler.add_node(texco_node, NODE_TEXCO_OBJECT, out->stack_offset, use_transform);
+               if(use_transform) {
+                       Transform ob_itfm = transform_inverse(ob_tfm);
+                       compiler.add_node(ob_itfm.x);
+                       compiler.add_node(ob_itfm.y);
+                       compiler.add_node(ob_itfm.z);
+                       compiler.add_node(ob_itfm.w);
+               }
        }
 
        out = output("Camera");
@@ -2391,7 +2400,10 @@ void TextureCoordinateNode::compile(OSLCompiler& compiler)
                compiler.parameter("is_background", true);
        if(compiler.output_type() == SHADER_TYPE_VOLUME)
                compiler.parameter("is_volume", true);
-       
+       compiler.parameter("use_transform", use_transform);
+       Transform ob_itfm = transform_transpose(transform_inverse(ob_tfm));
+       compiler.parameter("object_itfm", ob_itfm);
+
        compiler.parameter("from_dupli", from_dupli);
 
        compiler.add(this, "node_texture_coordinate");
index 3140ec939bb549e2b36e90fcd4f8106ec36d4116..0ec0fce512fb6dcdc17b4c09da655dbe2c77387a 100644 (file)
@@ -357,8 +357,11 @@ public:
        SHADER_NODE_CLASS(TextureCoordinateNode)
        void attributes(Shader *shader, AttributeRequestSet *attributes);
        bool has_spatial_varying() { return true; }
-       
+       bool has_object_dependency() { return use_transform; }
+
        bool from_dupli;
+       bool use_transform;
+       Transform ob_tfm;
 };
 
 class UVMapNode : public ShaderNode {
index 7ddfdaf6cc2ddeb5477262aace65df3682ec128c..7b22d200a9e73be88170ee56ba33ff2771123e21 100644 (file)
@@ -567,6 +567,10 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
                if(node->has_spatial_varying())
                        current_shader->has_heterogeneous_volume = true;
        }
+
+       if(node->has_object_dependency()) {
+               current_shader->has_object_dependency = true;
+       }
 }
 
 void OSLCompiler::parameter(const char *name, float f)
@@ -808,6 +812,7 @@ void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
                shader->has_volume = false;
                shader->has_displacement = false;
                shader->has_heterogeneous_volume = false;
+               shader->has_object_dependency = false;
 
                /* generate surface shader */
                if(shader->used && graph && output->input("Surface")->link) {
index dbf5c5ed7ff6419ae1c544b44943659e5b6eb225..5899c562f728215d7ed27982f6cd68f9b1bd45f9 100644 (file)
@@ -151,6 +151,7 @@ Shader::Shader()
        has_displacement = false;
        has_bssrdf_bump = false;
        has_heterogeneous_volume = false;
+       has_object_dependency = false;
 
        used = false;
 
index 1d903ee3a1328f9b6a5026aff0b5e094b9ed64ad..1dee47c7731e4e36f9787c9f990d5f298776f54a 100644 (file)
@@ -106,6 +106,7 @@ public:
        bool has_converter_blackbody;
        bool has_bssrdf_bump;
        bool has_heterogeneous_volume;
+       bool has_object_dependency;
 
        /* requested mesh attributes */
        AttributeRequestSet attributes;
index 8216669a1ecdd76f9dde076e2b9eb26446d56f94..2e3abfcffb97389c33364033b2cd5e1db752f7a9 100644 (file)
@@ -393,6 +393,10 @@ void SVMCompiler::generate_node(ShaderNode *node, set<ShaderNode*>& done)
        /* detect if we have a blackbody converter, to prepare lookup table */
        if(node->has_converter_blackbody())
                current_shader->has_converter_blackbody = true;
+
+       if(node->has_object_dependency()) {
+               current_shader->has_object_dependency = true;
+       }
 }
 
 void SVMCompiler::generate_svm_nodes(const set<ShaderNode*>& nodes, set<ShaderNode*>& done)
@@ -713,6 +717,7 @@ void SVMCompiler::compile(Shader *shader, vector<int4>& global_svm_nodes, int in
        shader->has_volume = false;
        shader->has_displacement = false;
        shader->has_heterogeneous_volume = false;
+       shader->has_object_dependency = false;
 
        /* generate surface shader */
        compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
index 870b4637f4bad460da96af06f590b6b88531ceab..f1dfa4f1e8f6354059632347550c0b47d208759f 100644 (file)
@@ -861,6 +861,7 @@ static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C),
 
 static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
 {
+       uiItemR(layout, ptr, "object", 0, NULL, 0);
        uiItemR(layout, ptr, "from_dupli", 0, NULL, 0);
 }
 
index ed3896b050d6012558cd8dd91fc2ae22962d5961..413531798f2ea084e4d158d68edb582c27f62a5c 100644 (file)
@@ -3647,7 +3647,14 @@ static void def_sh_tex_wave(StructRNA *srna)
 static void def_sh_tex_coord(StructRNA *srna)
 {
        PropertyRNA *prop;
-       
+
+       prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+       RNA_def_property_pointer_sdna(prop, NULL, "id");
+       RNA_def_property_struct_type(prop, "Object");
+       RNA_def_property_flag(prop, PROP_EDITABLE);
+       RNA_def_property_ui_text(prop, "Object", "Use coordinates from this object (for object texture coordinates output, currently only for SVM shading)");
+       RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
        prop = RNA_def_property(srna, "from_dupli", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1);
        RNA_def_property_ui_text(prop, "From Dupli", "Use the parent of the dupli object if possible");