Cycles: improve Anisotropic BSDF node, changing the Roughness U/V inputs to
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Sun, 4 Nov 2012 22:31:32 +0000 (22:31 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Sun, 4 Nov 2012 22:31:32 +0000 (22:31 +0000)
Roughness, Anisotropy and Rotation. Also a fix for automatic tangents and
OSL attribute handling.

Meaning of new sockets explained in the documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Nodes/Shaders#Anisotropic

14 files changed:
intern/cycles/blender/blender_mesh.cpp
intern/cycles/kernel/kernel_object.h
intern/cycles/kernel/osl/osl_services.cpp
intern/cycles/kernel/shaders/node_geometry.osl
intern/cycles/kernel/shaders/node_ward_bsdf.osl
intern/cycles/kernel/svm/svm_closure.h
intern/cycles/kernel/svm/svm_geometry.h
intern/cycles/render/mesh.cpp
intern/cycles/render/nodes.cpp
intern/cycles/render/nodes.h
intern/cycles/util/util_attribute.cpp
intern/cycles/util/util_math.h
source/blender/gpu/shaders/gpu_shader_material.glsl
source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c

index b1b1a638219a5b52a3b1e0aad2c6b8ca348889bc..a0feec9020352373c2a6561ba941193f53fdda17 100644 (file)
@@ -141,7 +141,7 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer b_la
 
        /* create attribute */
        /* todo: create float4 attribute for sign */
-       Attribute *attr = mesh->attributes.add(ATTR_STD_TANGENT, ustring("Tangent"));
+       Attribute *attr = mesh->attributes.add(ATTR_STD_TANGENT, ustring("tangent"));
        float3 *tangent = attr->data_float3();
 
        for (int i = 0; i < nverts.size(); i++) {
index 2fa9443766ea6e8297129bde90e5eb3bf49aa3d1..112bfbb86b5ae27ebc59b3697413da1ee87e2565 100644 (file)
@@ -84,7 +84,8 @@ __device_inline Transform object_fetch_transform_motion_test(KernelGlobals *kg,
        }
        else {
                Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
-               *itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+               if(itfm)
+                       *itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
 
                return tfm;
        }
index ade085c795d61bffbe6ef42efd4ca41d04768437..ac26fc1c18d9e5e9ce2b9e89049edbdf015bf6ab 100644 (file)
@@ -393,25 +393,25 @@ static bool set_attribute_float3_3(float3 P[3], TypeDesc type, bool derivatives,
 static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd, const OSLGlobals::Attribute& attr,
                                const TypeDesc& type, bool derivatives, void *val)
 {
-       if (attr.type == TypeDesc::TypeFloat) {
-               float fval[3];
-               fval[0] = triangle_attribute_float(kg, sd, attr.elem, attr.offset,
-                                                  (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
-               set_attribute_float(fval, type, derivatives, val);
-               return true;
-       }
-       else if (attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
+       if (attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
                 attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor)
        {
-               /* todo: this won't work when float3 has w component */
                float3 fval[3];
                fval[0] = triangle_attribute_float3(kg, sd, attr.elem, attr.offset,
                                                    (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
                set_attribute_float3(fval, type, derivatives, val);
                return true;
        }
-       else
+       else if (attr.type == TypeDesc::TypeFloat) {
+               float fval[3];
+               fval[0] = triangle_attribute_float(kg, sd, attr.elem, attr.offset,
+                                                  (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
+               set_attribute_float(fval, type, derivatives, val);
+               return true;
+       }
+       else {
                return false;
+       }
 }
 
 static void get_object_attribute(const OSLGlobals::Attribute& attr, bool derivatives, void *val)
@@ -598,7 +598,7 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri
 
        if (it != attribute_map.end()) {
                const OSLGlobals::Attribute& attr = it->second;
-               
+
                if (attr.elem != ATTR_ELEMENT_VALUE) {
                        /* triangle and vertex attributes */
                        if (tri != ~0)
@@ -613,11 +613,11 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri
        else {
                /* not found in attribute, check standard object info */
                bool is_std_object_attribute = get_object_standard_attribute(kg, sd, name, type, derivatives, val);
+
                if (is_std_object_attribute)
                        return true;
-               else {
-                       return get_background_attribute(kg, sd, name, type, derivatives, val);
-               }
+
+               return get_background_attribute(kg, sd, name, type, derivatives, val);
        }
 
        return false;
index a3831cbec9c8ef34d2fbc2c45fd8a3d306097a88..953c5d1fa2b640c5030ef3c0b6e489c483d086d5 100644 (file)
@@ -32,7 +32,6 @@ shader node_geometry(
 {
        Position = P;
        Normal = NormalIn;
-       Tangent = normalize(dPdu);
        TrueNormal = Ng;
        Incoming = I;
        Parametric = point(u, v, 0.0);
@@ -46,5 +45,28 @@ shader node_geometry(
                Position += Dy(Position);
                Parametric += Dy(Parametric);
        }
+
+       /* first try to get tangent attribute */
+       vector T;
+
+       if (getattribute("geom:tangent", T)) {
+               /* ensure orthogonal and normalized (interpolation breaks it) */
+               T = transform("object", "world", T);
+               Tangent = cross(Normal, normalize(cross(T, Normal)));
+       }
+       else {
+               point generated;
+
+               /* try to create spherical tangent from generated coordinates */
+               if (getattribute("geom:generated", generated)) {
+                       T = vector(-(generated[1] - 0.5), (generated[0] - 0.5), 0.0);
+                       T = transform("object", "world", T);
+                       Tangent = cross(Normal, normalize(cross(T, Normal)));
+               }
+               else {
+                       /* otherwise use surface derivatives */
+                       Tangent = normalize(dPdu);
+               }
+       }
 }
 
index e204be123b82e4a0a5fd95e53e3589bb903e6be1..03a0477038e7d112b4b7ec85130e2c66a1b042a8 100644 (file)
 
 shader node_ward_bsdf(
        color Color = color(0.8, 0.8, 0.8),
-       float RoughnessU = 0.0,
-       float RoughnessV = 0.0,
+       float Roughness = 0.0,
+       float Anisotropy = 0.0,
+       float Rotation = 0.0,
        normal Normal = N,
+       normal Tangent = normalize(dPdu),
        output closure color BSDF = diffuse(Normal))
 {
-       BSDF = Color * ward(Normal, normalize(dPdu), RoughnessU, RoughnessV);
+       /* rotate tangent around normal */
+       vector T = Tangent;
+
+       if(Rotation != 0.0)
+               T = rotate(T, Rotation*2.0*M_PI, point(0.0, 0.0, 0.0), Normal);
+
+       /* compute roughness */
+       float RoughnessU, RoughnessV;
+       float aniso = clamp(Anisotropy, -0.99, 0.99);
+
+       if(aniso < 0.0) {
+               RoughnessU = Roughness*(1.0 + aniso);
+               RoughnessV = Roughness/(1.0 + aniso);
+       }
+       else {
+               RoughnessU = Roughness/(1.0 - aniso);
+               RoughnessV = Roughness*(1.0 - aniso);
+       }
+
+       BSDF = Color * ward(Normal, T, RoughnessU, RoughnessV);
 }
 
index b72fad26a1f7d3114a408b6f1c8d17d891a1d2de..11ce3b7c5d186b74fd769e91bef10c8b730666fe 100644 (file)
@@ -211,8 +211,24 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
                        sc->T = stack_load_float3(stack, data_node.z);
                        svm_node_closure_set_mix_weight(sc, mix_weight);
 
-                       sc->data0 = param1;
-                       sc->data1 = param2;
+                       /* rotate tangent */
+                       float rotation = stack_load_float(stack, data_node.w);
+
+                       if(rotation != 0.0f)
+                               sc->T = rotate_around_axis(sc->T, sc->N, rotation * 2.0f * M_PI_F);
+
+                       /* compute roughness */
+                       float roughness = param1;
+                       float anisotropy = clamp(param2, -0.99f, 0.99f);
+
+                       if(anisotropy < 0.0f) {
+                               sc->data0 = roughness*(1.0f + anisotropy);
+                               sc->data1 = roughness/(1.0f + anisotropy);
+                       }
+                       else {
+                               sc->data0 = roughness/(1.0f - anisotropy);
+                               sc->data1 = roughness*(1.0f - anisotropy);
+                       }
 
                        sd->flag |= bsdf_ward_setup(sc);
                        break;
index 501fed9500268a146de95f4bc4300dbbc03df3db..8e772f849c7662b7c4c5fee179b9400a1973f550 100644 (file)
@@ -20,22 +20,6 @@ CCL_NAMESPACE_BEGIN
 
 /* Geometry Node */
 
-__device_inline float3 svm_tangent_from_generated(float3 P)
-{
-       float length = len(P);
-
-       if(length == 0.0f)
-               return make_float3(0.0f, 0.0f, 0.0f);
-
-       float u = 0.0f;
-       if(!(P.x == 0.0f && P.y == 0.0f))
-               u = (1.0f - atan2f(P.x, P.y))/(2.0f*M_PI_F);
-       
-       float v = 1.0f - acosf(clamp(P.z/length, -1.0f, 1.0f))/M_PI_F;
-
-       return make_float3(u, v, 0.0f);
-}
-
 __device void svm_node_geometry(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset)
 {
        float3 data;
@@ -45,27 +29,30 @@ __device void svm_node_geometry(KernelGlobals *kg, ShaderData *sd, float *stack,
                case NODE_GEOM_N: data = sd->N; break;
 #ifdef __DPDU__
                case NODE_GEOM_T: {
-                       if(sd->object != ~0) {
-                               int attr_offset = find_attribute(kg, sd, ATTR_STD_TANGENT);
+                       /* first try to get tangent attribute */
+                       int attr_offset = (sd->object != ~0)? find_attribute(kg, sd, ATTR_STD_TANGENT): ATTR_STD_NOT_FOUND;
+
+                       if(attr_offset != ATTR_STD_NOT_FOUND) {
+                               /* ensure orthogonal and normalized (interpolation breaks it) */
+                               data = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, attr_offset, NULL, NULL);
+                               object_normal_transform(kg, sd, &data);
+                               data = cross(sd->N, normalize(cross(data, sd->N)));;
+                       }
+                       else {
+                               /* try to create spherical tangent from generated coordinates */
+                               int attr_offset = (sd->object != ~0)? find_attribute(kg, sd, ATTR_STD_GENERATED): ATTR_STD_NOT_FOUND;
 
                                if(attr_offset != ATTR_STD_NOT_FOUND) {
-                                       data = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, attr_offset, NULL, NULL);
+                                       data = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, attr_offset, NULL, NULL);
+                                       data = make_float3(-(data.y - 0.5), (data.x - 0.5), 0.0f);
                                        object_normal_transform(kg, sd, &data);
+                                       data = cross(sd->N, normalize(cross(data, sd->N)));;
                                }
                                else {
-                                       attr_offset = find_attribute(kg, sd, ATTR_STD_GENERATED);
-
-                                       if(attr_offset != ATTR_STD_NOT_FOUND) {
-                                               data = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, attr_offset, NULL, NULL);
-                                               svm_tangent_from_generated(data);
-                                               object_normal_transform(kg, sd, &data);
-                                       }
-                                       else
-                                               data = normalize(sd->dPdu);
+                                       /* otherwise use surface derivatives */
+                                       data = normalize(sd->dPdu);
                                }
                        }
-                       else
-                               data = normalize(sd->dPdu);
 
                        break;
                }
index 13c06a922cc13eeb9738d114e59df596960dfbc2..14f239926640d677f1a9f893a61c5939d3ce3318 100644 (file)
@@ -355,6 +355,9 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
 
                /* set object attributes */
                foreach(AttributeRequest& req, attributes.requests) {
+                       if(req.element == ATTR_ELEMENT_NONE)
+                               continue;
+
                        OSLGlobals::Attribute osl_attr;
 
                        osl_attr.elem = req.element;
index 42ab3fe17aa98c32b39bf000cc105b6e0d2fb983..d7bf71337f6f707aa4b06345a73cf55a94768576 100644 (file)
@@ -1214,7 +1214,7 @@ BsdfNode::BsdfNode()
        add_output("BSDF", SHADER_SOCKET_CLOSURE);
 }
 
-void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2)
+void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3)
 {
        ShaderInput *color_in = input("Color");
        ShaderInput *normal_in = input("Normal");
@@ -1231,6 +1231,14 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *
                compiler.stack_assign(param1);
        if(param2)
                compiler.stack_assign(param2);
+       if(param3)
+               compiler.stack_assign(param3);
+
+       if(normal_in->link)
+               compiler.stack_assign(normal_in);
+
+       if(tangent_in && tangent_in->link)
+               compiler.stack_assign(tangent_in);
 
        compiler.add_node(NODE_CLOSURE_BSDF,
                compiler.encode_uchar4(closure,
@@ -1240,14 +1248,9 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *
                __float_as_int((param1)? param1->value.x: 0.0f),
                __float_as_int((param2)? param2->value.x: 0.0f));
 
-       if(normal_in->link)
-               compiler.stack_assign(normal_in);
-
        if(tangent_in) {
-               if(tangent_in->link)
-                       compiler.stack_assign(tangent_in);
-
-               compiler.add_node(NODE_CLOSURE_BSDF, normal_in->stack_offset, tangent_in->stack_offset);
+               compiler.add_node(NODE_CLOSURE_BSDF, normal_in->stack_offset, tangent_in->stack_offset,
+                       (param3)? param3->stack_offset: SVM_STACK_INVALID);
        }
        else {
                compiler.add_node(NODE_CLOSURE_BSDF, normal_in->stack_offset);
@@ -1272,8 +1275,9 @@ WardBsdfNode::WardBsdfNode()
 
        add_input("Tangent", SHADER_SOCKET_VECTOR, ShaderInput::TANGENT);
 
-       add_input("Roughness U", SHADER_SOCKET_FLOAT, 0.2f);
-       add_input("Roughness V", SHADER_SOCKET_FLOAT, 0.2f);
+       add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f);
+       add_input("Anisotropy", SHADER_SOCKET_FLOAT, 0.5f);
+       add_input("Rotation", SHADER_SOCKET_FLOAT, 0.0f);
 }
 
 void WardBsdfNode::attributes(AttributeRequestSet *attributes)
@@ -1290,7 +1294,7 @@ void WardBsdfNode::attributes(AttributeRequestSet *attributes)
 
 void WardBsdfNode::compile(SVMCompiler& compiler)
 {
-       BsdfNode::compile(compiler, input("Roughness U"), input("Roughness V"));
+       BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
 }
 
 void WardBsdfNode::compile(OSLCompiler& compiler)
index 0508bf6b266651411341110c5359e09cd1b80dee..d90cae5f66861ae2dba709cff6cad845748d6942 100644 (file)
@@ -193,7 +193,7 @@ class BsdfNode : public ShaderNode {
 public:
        SHADER_NODE_CLASS(BsdfNode)
 
-       void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2);
+       void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3 = NULL);
 
        ClosureType closure;
 };
index 3a1c2b6f332355e6443eda6a628cc471f13a49f6..163a92902f3d555cd7945dfe1f48cf9d04293eb4 100644 (file)
@@ -30,6 +30,8 @@ const char *attribute_standard_name(AttributeStandard std)
                return "uv";
        else if(std == ATTR_STD_GENERATED)
                return "generated";
+       else if(std == ATTR_STD_TANGENT)
+               return "tangent";
        else if(std == ATTR_STD_POSITION_UNDEFORMED)
                return "undeformed";
        else if(std == ATTR_STD_POSITION_UNDISPLACED)
index 0b6f020ade5426b5b9518807e7b01e16504ce98f..70adee4385b0a347cb3bace04a89e4e95b263162 100644 (file)
@@ -1069,6 +1069,29 @@ __device_inline float3 safe_divide_color(float3 a, float3 b)
        return make_float3(x, y, z);
 }
 
+/* Rotation of point around axis and angle */
+
+__device_inline float3 rotate_around_axis(float3 p, float3 axis, float angle)
+{
+       float costheta = cosf(angle);
+       float sintheta = sinf(angle);
+       float3 r;
+
+       r.x = ((costheta + (1 - costheta) * axis.x * axis.x) * p.x) +
+               (((1 - costheta) * axis.x * axis.y - axis.z * sintheta) * p.y) +
+               (((1 - costheta) * axis.x * axis.z + axis.y * sintheta) * p.z);
+
+       r.y = (((1 - costheta) * axis.x * axis.y + axis.z * sintheta) * p.x) +
+               ((costheta + (1 - costheta) * axis.y * axis.y) * p.y) +
+               (((1 - costheta) * axis.y * axis.z - axis.x * sintheta) * p.z);
+
+       r.z = (((1 - costheta) * axis.x * axis.z - axis.y * sintheta) * p.x) +
+               (((1 - costheta) * axis.y * axis.z + axis.x * sintheta) * p.y) +
+               ((costheta + (1 - costheta) * axis.z * axis.z) * p.z);
+
+       return r;
+}
+
 CCL_NAMESPACE_END
 
 #endif /* __UTIL_MATH_H__ */
index 5713c5e88a256537799579c29208faaf33b2059d..b930058864c92bd2a4b77afc396af0aaf347bc79 100644 (file)
@@ -2013,7 +2013,7 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result)
        result = vec4(L*color.rgb, 1.0);
 }
 
-void node_bsdf_anisotropic(vec4 color, float roughnessU, float roughnessV, vec3 N, vec3 T, out vec4 result)
+void node_bsdf_anisotropic(vec4 color, float roughness, float anisotropy, float rotation, vec3 N, vec3 T, out vec4 result)
 {
        node_bsdf_diffuse(color, 0.0, N, result);
 }
index 7e023ff854773dde46d5a74695f10b7022aa912a..71780e9316ecfafe66226116f7419a6cd769bf5d 100644 (file)
@@ -31,8 +31,9 @@
 
 static bNodeSocketTemplate sh_node_bsdf_anisotropic_in[] = {
        {       SOCK_RGBA, 1, N_("Color"),                      0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
-       {       SOCK_FLOAT, 1, N_("Roughness U"),       0.2f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
-       {       SOCK_FLOAT, 1, N_("Roughness V"),       0.2f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+       {       SOCK_FLOAT, 1, N_("Roughness"),     0.2f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+       {       SOCK_FLOAT, 1, N_("Anisotropy"),        0.5f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f},
+       {       SOCK_FLOAT, 1, N_("Rotation"),          0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
        {       SOCK_VECTOR, 1, N_("Normal"),           0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
        {       SOCK_VECTOR, 1, N_("Tangent"),          0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
        {       -1, 0, ""       }