Cycles Hair: Two basic bair shaders added
authorStuart Broadfoot <gbroadfoot@hotmail.com>
Sun, 15 Sep 2013 23:58:00 +0000 (23:58 +0000)
committerStuart Broadfoot <gbroadfoot@hotmail.com>
Sun, 15 Sep 2013 23:58:00 +0000 (23:58 +0000)
A new hair bsdf node, with two closure options, is added. These closures allow the generation of the reflective and transmission components of hair. The node allows control of the highlight colour, roughness and angular shift.

Llimitations include:
-No glint or fresnel adjustments.
-The 'offset' is un-used when triangle primitives are used.

26 files changed:
intern/cycles/blender/blender_shader.cpp
intern/cycles/kernel/CMakeLists.txt
intern/cycles/kernel/closure/bsdf.h
intern/cycles/kernel/closure/bsdf_hair.h [new file with mode: 0644]
intern/cycles/kernel/kernel_shader.h
intern/cycles/kernel/kernel_types.h
intern/cycles/kernel/osl/osl_closures.cpp
intern/cycles/kernel/osl/osl_shader.cpp
intern/cycles/kernel/shaders/CMakeLists.txt
intern/cycles/kernel/shaders/node_hair_bsdf.osl [new file with mode: 0644]
intern/cycles/kernel/shaders/stdosl.h
intern/cycles/kernel/svm/svm_closure.h
intern/cycles/kernel/svm/svm_types.h
intern/cycles/render/nodes.cpp
intern/cycles/render/nodes.h
release/scripts/startup/nodeitems_builtins.py
source/blender/blenkernel/BKE_node.h
source/blender/blenkernel/intern/node.c
source/blender/editors/space_node/drawnode.c
source/blender/gpu/shaders/gpu_shader_material.glsl
source/blender/makesdna/DNA_node_types.h
source/blender/makesrna/intern/rna_nodetree.c
source/blender/nodes/CMakeLists.txt
source/blender/nodes/NOD_shader.h
source/blender/nodes/NOD_static_types.h
source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c [new file with mode: 0644]

index 5dfbd97366a794cb1f3cef6d95a7bb1cf9acb679..2007171642f0cffc5eda50b8c4606b9d83966553 100644 (file)
@@ -395,6 +395,19 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
                }
                node = toon;
        }
+       else if (b_node.is_a(&RNA_ShaderNodeBsdfHair)) {
+               BL::ShaderNodeBsdfHair b_hair_node(b_node);
+               HairBsdfNode *hair = new HairBsdfNode();
+               switch(b_hair_node.component()) {
+                       case BL::ShaderNodeBsdfHair::component_Reflection:
+                               hair->component = ustring("Reflection");
+                               break;
+                       case BL::ShaderNodeBsdfHair::component_Transmission:
+                               hair->component = ustring("Transmission");
+                               break;
+               }
+               node = hair;
+       }
        else if (b_node.is_a(&RNA_ShaderNodeBsdfTranslucent)) {
                node = new TranslucentBsdfNode();
        }
index 9db05693fc3525cce21ca27101304e11877de4dd..eaa4e304ebb99102baf1c9b69750e77473f2b9cc 100644 (file)
@@ -67,6 +67,7 @@ set(SRC_CLOSURE_HEADERS
        closure/bsdf_util.h
        closure/bsdf_ward.h
        closure/bsdf_westin.h
+       closure/bsdf_hair.h
        closure/bssrdf.h
        closure/emissive.h
        closure/volume.h
index d81bbebd5a8f34c0d64d42316e18f20246302173..86fea48760f98e5eaa52f4687457daa7b8a9a2ee 100644 (file)
@@ -28,6 +28,7 @@
 #endif
 #include "../closure/bsdf_westin.h"
 #include "../closure/bsdf_toon.h"
+#include "../closure/bsdf_hair.h"
 #ifdef __SUBSURFACE__
 #include "../closure/bssrdf.h"
 #endif
@@ -114,6 +115,14 @@ __device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const ShaderCl
                        label = bsdf_westin_sheen_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
                                eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
                        break;
+               case CLOSURE_BSDF_HAIR_REFLECTION_ID:
+                       label = bsdf_hair_reflection_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+                               eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
+                       break;
+               case CLOSURE_BSDF_HAIR_TRANSMISSION_ID:
+                       label = bsdf_hair_transmission_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+                               eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
+                       break;
 #endif
                default:
                        label = LABEL_NONE;
@@ -188,6 +197,12 @@ __device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const ShaderC
                        case CLOSURE_BSDF_WESTIN_SHEEN_ID:
                                eval = bsdf_westin_sheen_eval_reflect(sc, sd->I, omega_in, pdf);
                                break;
+                       case CLOSURE_BSDF_HAIR_REFLECTION_ID:
+                               eval = bsdf_hair_reflection_eval_reflect(sc, sd->I, omega_in, pdf);
+                               break;
+                       case CLOSURE_BSDF_HAIR_TRANSMISSION_ID:
+                               eval = bsdf_hair_transmission_eval_reflect(sc, sd->I, omega_in, pdf);
+                               break;
 #endif
                        default:
                                eval = make_float3(0.0f, 0.0f, 0.0f);
@@ -244,6 +259,12 @@ __device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const ShaderC
                        case CLOSURE_BSDF_WESTIN_SHEEN_ID:
                                eval = bsdf_westin_sheen_eval_transmit(sc, sd->I, omega_in, pdf);
                                break;
+                       case CLOSURE_BSDF_HAIR_REFLECTION_ID:
+                               eval = bsdf_hair_reflection_eval_transmit(sc, sd->I, omega_in, pdf);
+                               break;
+                       case CLOSURE_BSDF_HAIR_TRANSMISSION_ID:
+                               eval = bsdf_hair_transmission_eval_transmit(sc, sd->I, omega_in, pdf);
+                               break;
 #endif
                        default:
                                eval = make_float3(0.0f, 0.0f, 0.0f);
@@ -318,6 +339,10 @@ __device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness)
                case CLOSURE_BSDF_WESTIN_SHEEN_ID:
                        bsdf_westin_sheen_blur(sc, roughness);
                        break;
+               case CLOSURE_BSDF_HAIR_REFLECTION_ID:
+               case CLOSURE_BSDF_HAIR_TRANSMISSION_ID:
+                       bsdf_hair_reflection_blur(sc, roughness);
+                       break;
 #endif
                default:
                        break;
diff --git a/intern/cycles/kernel/closure/bsdf_hair.h b/intern/cycles/kernel/closure/bsdf_hair.h
new file mode 100644 (file)
index 0000000..5791598
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ *   contributors may be used to endorse or promote products derived from
+ *   this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BSDF_HAIR_H__
+#define __BSDF_HAIR_H__
+
+CCL_NAMESPACE_BEGIN
+
+
+__device void bsdf_hair_reflection_blur(ShaderClosure *sc, float roughness)
+{
+}
+
+__device void bsdf_hair_transmission_blur(ShaderClosure *sc, float roughness)
+{
+}
+
+__device int bsdf_hair_reflection_setup(ShaderClosure *sc)
+{
+       sc->type = CLOSURE_BSDF_HAIR_REFLECTION_ID;
+       sc->data0 = clamp(sc->data0, 0.001f,1.0f);
+       sc->data1 = clamp(sc->data1, 0.001f,1.0f);
+       return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY;
+}
+
+__device int bsdf_hair_transmission_setup(ShaderClosure *sc)
+{
+       sc->type = CLOSURE_BSDF_HAIR_TRANSMISSION_ID;
+       sc->data0 = clamp(sc->data0, 0.001f,1.0f);
+       sc->data1 = clamp(sc->data1, 0.001f,1.0f);
+       return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY;
+}
+
+__device float3 bsdf_hair_reflection_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
+{
+#ifdef __HAIR__
+       float offset = sc->offset;
+       float3 Tg = sc->T;
+#else
+       float offset = 0.0f;
+       float3 Tg = make_float3(1.0f,0.0f,0.0f);
+#endif
+       float roughness1 = sc->data0;
+       float roughness2 = sc->data1;
+
+       float Iz = dot(Tg, I);
+       float3 locy = normalize(I - Tg * Iz);
+       float3 locx = cross(locy, Tg);
+
+       float theta_r = M_PI_2_F - safe_acosf(Iz);
+
+       float omega_in_z = dot(Tg, omega_in);
+       float3 omega_in_y = normalize(omega_in - Tg * omega_in_z);
+
+       float theta_i = M_PI_2_F - safe_acosf(omega_in_z);
+       float cosphi_i = dot(omega_in_y, locy);
+
+       if(M_PI_2_F - fabsf(theta_i) < 0.001f || cosphi_i < 0.0f){
+               *pdf = 0.0f;
+               return make_float3(*pdf, *pdf, *pdf);
+       }
+
+       float phi_i = safe_acosf(cosphi_i) / roughness2;
+       phi_i = fabsf(phi_i) < M_PI_F ? phi_i : M_PI_F;
+       float costheta_i = cosf(theta_i);
+
+       float a_R = atan2f(((M_PI_2_F + theta_r) * 0.5f - offset) / roughness1, 1.0f);
+       float b_R = atan2f(((-M_PI_2_F + theta_r) * 0.5f - offset) / roughness1, 1.0f);
+
+       float theta_h = (theta_i + theta_r) * 0.5f;
+       float t = theta_h - offset;
+
+       float phi_pdf = cos(phi_i * 0.5f) * 0.25f / roughness2;
+       float theta_pdf = roughness1 / (2 * (t*t + roughness1*roughness1) * (a_R - b_R)* costheta_i);
+       *pdf = phi_pdf * theta_pdf;
+
+       return make_float3(*pdf, *pdf, *pdf);
+}
+
+__device float3 bsdf_hair_transmission_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
+{
+       return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+
+__device float3 bsdf_hair_reflection_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
+{
+       return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+__device float3 bsdf_hair_transmission_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
+{
+#ifdef __HAIR__
+       float offset = sc->offset;
+       float3 Tg = sc->T;
+#else
+       float offset = 0.0f;
+       float3 Tg = make_float3(1.0f,0.0f,0.0f);
+#endif
+       float roughness1 = sc->data0;
+       float roughness2 = sc->data1;
+       float Iz = dot(Tg, I);
+       float3 locy = normalize(I - Tg * Iz);
+       float3 locx = cross(locy, Tg);
+
+       float theta_r = M_PI_2_F - safe_acosf(Iz);
+
+       float omega_in_z = dot(Tg, omega_in);
+       float3 omega_in_y = normalize(omega_in - Tg * omega_in_z);
+
+       float theta_i = M_PI_2_F - safe_acosf(omega_in_z);
+       float phi_i = safe_acosf(dot(omega_in_y, locy));
+
+       if(M_PI_2_F - fabsf(theta_i) < 0.001f){
+               *pdf = 0.0f;
+               return make_float3(*pdf, *pdf, *pdf);
+       }
+
+       float costheta_i = cosf(theta_i);
+
+       float a_TT = atan2f(((M_PI_2_F + theta_r)/2 - offset) / roughness1, 1.0f);
+       float b_TT = atan2f(((-M_PI_2_F + theta_r)/2 - offset) / roughness1, 1.0f);
+       float c_TT = 2 * atan2f(M_PI_2_F / roughness2, 1.0f);
+
+       float theta_h = (theta_i + theta_r) / 2;
+       float t = theta_h - offset;
+       float phi = fabsf(phi_i);
+
+       float p = M_PI_F - phi;
+       float theta_pdf = roughness1 / (2 * (t*t + roughness1 * roughness1) * (a_TT - b_TT)*costheta_i);
+       float phi_pdf = roughness2 / (c_TT * (p * p + roughness2 * roughness2));
+
+       *pdf = phi_pdf * theta_pdf;
+       return make_float3(*pdf, *pdf, *pdf);
+}
+
+__device int bsdf_hair_reflection_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
+{
+#ifdef __HAIR__
+       float offset = sc->offset;
+       float3 Tg = sc->T;
+#else
+       float offset = 0.0f;
+       float3 Tg = make_float3(1.0f,0.0f,0.0f);
+#endif
+       float roughness1 = sc->data0;
+       float roughness2 = sc->data1;
+       float Iz = dot(Tg, I);
+       float3 locy = normalize(I - Tg * Iz);
+       float3 locx = cross(locy, Tg);
+       float theta_r = M_PI_2_F - safe_acosf(Iz);
+
+       float a_R = atan2f(((M_PI_2_F + theta_r) * 0.5f - offset) / roughness1, 1.0f);
+       float b_R = atan2f(((-M_PI_2_F + theta_r) * 0.5f - offset) / roughness1, 1.0f);
+
+       float t = roughness1 * tanf(randu * (a_R - b_R) + b_R);
+
+       float theta_h = t + offset;
+       float theta_i = 2 * theta_h - theta_r;
+       float costheta_i = cosf(theta_i);
+       float sintheta_i = sinf(theta_i);
+
+       float phi = 2 * safe_asinf(1 - 2 * randv) * roughness2;
+
+       float phi_pdf = cos(phi * 0.5f) * 0.25f / roughness2;
+
+       float theta_pdf = roughness1 / (2 * (t*t + roughness1*roughness1) * (a_R - b_R)*costheta_i);
+
+       *omega_in =(cosf(phi) * costheta_i) * locy -
+                          (sinf(phi) * costheta_i) * locx +
+                          (            sintheta_i) * Tg;
+
+       //differentials - TODO: find a better approximation for the reflective bounce
+#ifdef __RAY_DIFFERENTIALS__
+       *domega_in_dx = 2 * dot(locy, dIdx) * locy - dIdx;
+       *domega_in_dy = 2 * dot(locy, dIdy) * locy - dIdy;
+#endif
+
+       *pdf = fabsf(phi_pdf * theta_pdf);
+       if(M_PI_2_F - fabsf(theta_i) < 0.001f)
+               *pdf = 0.0f;
+
+       *eval = make_float3(*pdf, *pdf, *pdf);
+
+       if(dot(locy, *omega_in) < 0.0f) {
+               return LABEL_REFLECT|LABEL_TRANSMIT|LABEL_GLOSSY;
+       }
+       
+       return LABEL_REFLECT|LABEL_GLOSSY;
+}
+
+__device int bsdf_hair_transmission_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
+{
+#ifdef __HAIR__
+       float offset = sc->offset;
+       float3 Tg = sc->T;
+#else
+       float offset = 0.0f;
+       float3 Tg = make_float3(1.0f,0.0f,0.0f);
+#endif
+       float roughness1 = sc->data0;
+       float roughness2 = sc->data1;
+       float Iz = dot(Tg, I);
+       float3 locy = normalize(I - Tg * Iz);
+       float3 locx = cross(locy, Tg);
+       float theta_r = M_PI_2_F - safe_acosf(Iz);
+
+       float a_TT = atan2f(((M_PI_2_F + theta_r)/2 - offset) / roughness1, 1.0f);
+       float b_TT = atan2f(((-M_PI_2_F + theta_r)/2 - offset) / roughness1, 1.0f);
+       float c_TT = 2 * atan2f(M_PI_2_F / roughness2, 1.0f);
+
+       float t = roughness1 * tanf(randu * (a_TT - b_TT) + b_TT);
+
+       float theta_h = t + offset;
+       float theta_i = 2 * theta_h - theta_r;
+       float costheta_i = cosf(theta_i);
+       float sintheta_i = sinf(theta_i);
+
+       float p = roughness2 * tanf(c_TT * (randv - 0.5f));
+       float phi = p + M_PI_F;
+       float theta_pdf = roughness1 / (2 * (t*t + roughness1*roughness1) * (a_TT - b_TT) * costheta_i);
+       float phi_pdf = roughness2 / (c_TT * (p * p + roughness2 * roughness2));
+
+       *omega_in =(cosf(phi) * costheta_i) * locy -
+                          (sinf(phi) * costheta_i) * locx +
+                          (            sintheta_i) * Tg;
+
+       //differentials - TODO: find a better approximation for the transmission bounce
+#ifdef __RAY_DIFFERENTIALS__
+       *domega_in_dx = 2 * dot(locy, dIdx) * locy - dIdx;
+       *domega_in_dy = 2 * dot(locy, dIdy) * locy - dIdy;
+#endif
+
+       *pdf = fabsf(phi_pdf * theta_pdf);
+       if(M_PI_2_F - fabsf(theta_i) < 0.001f){
+               *pdf = 0.0f;
+       }
+
+       *eval = make_float3(*pdf, *pdf, *pdf);
+
+       if(dot(locy, *omega_in) < 0.0f)
+               return LABEL_TRANSMIT|LABEL_GLOSSY;
+       
+       return LABEL_GLOSSY;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __BSDF_HAIR_H__ */
+
index e8e9af64df607b84f8900e96b3e841114467e021..bcc4c42c9cc50b0d734e571fbc2894dfdfb2ae46 100644 (file)
@@ -272,7 +272,7 @@ void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
 #ifdef __INSTANCING__
        sd->object = object;
 #endif
-       /* currently no access to bvh prim index for strand sd->prim - this will cause errors with needs fixing*/
+       /* currently no access to bvh prim index for strand sd->prim*/
        sd->prim = prim;
 #ifdef __UV__
        sd->u = u;
index 98594df8b1085d69a82ffb7deff8e4f1554336c7..d039b708bd4f5ba4be9078267d4cd51a214b9dca 100644 (file)
@@ -462,10 +462,14 @@ typedef struct ShaderClosure {
        float data1;
 
        float3 N;
-#if defined(__ANISOTROPIC__) || defined(__SUBSURFACE__)
+#if defined(__ANISOTROPIC__) || defined(__SUBSURFACE__) || defined(__HAIR__)
        float3 T;
 #endif
 
+#ifdef __HAIR__
+       float offset;
+#endif
+
 #ifdef __OSL__
        void *prim;
 #endif
index 6a3f27fb7b1f42184c1c94ae24f0f6654f12cd47..221406a171623aacfdc1c065cb9469d3ea5a8ec6 100644 (file)
@@ -54,6 +54,7 @@
 #include "closure/bsdf_ward.h"
 #include "closure/bsdf_westin.h"
 #include "closure/bsdf_toon.h"
+#include "closure/bsdf_hair.h"
 
 CCL_NAMESPACE_BEGIN
 
@@ -142,6 +143,32 @@ BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmannRefraction, microfacet_beckmann_refra
        CLOSURE_FLOAT_PARAM(MicrofacetBeckmannRefractionClosure, sc.data1),
 BSDF_CLOSURE_CLASS_END(MicrofacetBeckmannRefraction, microfacet_beckmann_refraction)
 
+BSDF_CLOSURE_CLASS_BEGIN(HairReflection, hair_reflection, hair_reflection, LABEL_GLOSSY)
+       CLOSURE_FLOAT3_PARAM(HairReflectionClosure, sc.N),
+       CLOSURE_FLOAT_PARAM(HairReflectionClosure, sc.data0),
+       CLOSURE_FLOAT_PARAM(HairReflectionClosure, sc.data1),
+#ifdef __HAIR__
+       CLOSURE_FLOAT3_PARAM(HairReflectionClosure, sc.T),
+       CLOSURE_FLOAT_PARAM(HairReflectionClosure, sc.offset),
+#else
+       CLOSURE_FLOAT3_PARAM(HairReflectionClosure, sc.N),
+       CLOSURE_FLOAT_PARAM(HairReflectionClosure, sc.data1),
+#endif
+BSDF_CLOSURE_CLASS_END(HairReflection, hair_reflection)
+
+BSDF_CLOSURE_CLASS_BEGIN(HairTransmission, hair_transmission, hair_transmission, LABEL_GLOSSY)
+       CLOSURE_FLOAT3_PARAM(HairTransmissionClosure, sc.N),
+       CLOSURE_FLOAT_PARAM(HairTransmissionClosure, sc.data0),
+       CLOSURE_FLOAT_PARAM(HairTransmissionClosure, sc.data1),
+#ifdef __HAIR__
+       CLOSURE_FLOAT3_PARAM(HairReflectionClosure, sc.T),
+       CLOSURE_FLOAT_PARAM(HairReflectionClosure, sc.offset),
+#else
+       CLOSURE_FLOAT3_PARAM(HairReflectionClosure, sc.N),
+       CLOSURE_FLOAT_PARAM(HairReflectionClosure, sc.data1),
+#endif
+BSDF_CLOSURE_CLASS_END(HairTransmission, hair_transmission)
+
 /* Registration */
 
 static void generic_closure_setup(OSL::RendererServices *, int id, void *data)
@@ -225,6 +252,11 @@ void OSLShader::register_closures(OSLShadingSystem *ss_)
                closure_bssrdf_cubic_extended_params(), closure_bssrdf_cubic_prepare);
        register_closure(ss, "bssrdf_gaussian", id++,
                closure_bssrdf_gaussian_extended_params(), closure_bssrdf_gaussian_prepare);
+
+       register_closure(ss, "hair_reflection", id++,
+               bsdf_hair_reflection_params(), bsdf_hair_reflection_prepare);
+       register_closure(ss, "hair_transmission", id++,
+               bsdf_hair_transmission_params(), bsdf_hair_transmission_prepare);
 }
 
 CCL_NAMESPACE_END
index 9ff3797b50f491bbf8ce5f6190f22f0d73fc85d7..625ad263f7f8b7b880c7dea5adc2d9440cf50547 100644 (file)
@@ -180,6 +180,10 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
                                        sc.data1 = bsdf->sc.data1;
                                        sc.prim = bsdf->sc.prim;
 
+#ifdef __HAIR__
+                                       sc.offset = bsdf->sc.offset;
+#endif
+
                                        /* add */
                                        if(sc.sample_weight > 1e-5f && sd->num_closure < MAX_CLOSURE) {
                                                sd->closure[sd->num_closure++] = sc;
index 660cfbce528e28036c1b907e5dc8b50861094595..0f8542b0546facf9fad421af868979895417213f 100644 (file)
@@ -74,6 +74,7 @@ set(SRC_OSL
        node_blackbody.osl
        node_wave_texture.osl
        node_wireframe.osl
+       node_hair_bsdf.osl
 )
 
 set(SRC_OSL_HEADERS
diff --git a/intern/cycles/kernel/shaders/node_hair_bsdf.osl b/intern/cycles/kernel/shaders/node_hair_bsdf.osl
new file mode 100644 (file)
index 0000000..d1d7d0f
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_hair_bsdf(
+    color Color = 0.8,
+    string component = "Reflection",
+       float Offset = 0.0,
+       float RoughnessU = 0.1,
+       float RoughnessV = 1.0,
+       normal Normal = Ng,
+       output closure color BSDF = 0)
+{
+       float IsStrand;
+       float roughnessh = clamp(RoughnessU, 0.001,1.0);
+       float roughnessv = clamp(RoughnessV, 0.001,1.0);
+       getattribute("geom:is_curve", IsStrand);
+
+    if (!IsStrand) {
+               if (backfacing())
+               BSDF = transparent();
+       else {
+               if (component == "Reflection")
+                       BSDF = Color * hair_reflection(Normal, roughnessh, roughnessv, normalize(dPdv), 0.0);
+               else
+                       BSDF = Color * hair_transmission(Normal, roughnessh, roughnessv, normalize(dPdv), 0.0);
+               }
+       }
+    else {
+               if (backfacing())
+               BSDF = transparent();
+       else {
+               if (component == "Reflection")
+                       BSDF = Color * hair_reflection(Normal, roughnessh, roughnessv, dPdu, -Offset);
+               else
+                       BSDF = Color * hair_transmission(Normal, roughnessh, roughnessv, dPdu, -Offset);
+               }
+       }
+}
+
index 3ad2bbc058841c8ad9ec2ad8fdb313f443da5b00..424ca3359030403a120ad0acddf70acf7a13c51f 100644 (file)
@@ -468,6 +468,9 @@ closure color ambient_occlusion() BUILTIN;
 closure color bssrdf_cubic(normal N, vector radius, float texture_blur, float sharpness) BUILTIN;
 closure color bssrdf_gaussian(normal N, vector radius, float texture_blur) BUILTIN;
 
+closure color hair_reflection(normal N, float roughnessu, float roughnessv, vector T, float offset) BUILTIN;
+closure color hair_transmission(normal N, float roughnessu, float roughnessv, vector T, float offset) BUILTIN;
+
 // Backwards compatibility
 closure color bssrdf_cubic(normal N, vector radius) BUILTIN;
 closure color bssrdf_gaussian(normal N, vector radius) BUILTIN;
index 9a9aefa5b29fc04191abf76917541529c763a179..6d9c4e215e6f21b08e7a8084e39670e932486b62 100644 (file)
@@ -337,6 +337,46 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
                        }
                        break;
                }
+#ifdef __HAIR__
+               case CLOSURE_BSDF_HAIR_REFLECTION_ID:
+               case CLOSURE_BSDF_HAIR_TRANSMISSION_ID: {
+                       
+                       if(sd->flag & SD_BACKFACING && sd->segment != ~0) {
+                               ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
+                               if(sc) {
+                                       sc->weight = make_float3(1.0f,1.0f,1.0f);
+                                       sc->N = N;
+                                       sd->flag |= bsdf_transparent_setup(sc);
+                               }
+                       }
+                       else {
+                               ShaderClosure *sc = &sd->closure[sd->num_closure];
+                               sc = svm_node_closure_get_bsdf(sd, mix_weight);
+
+                               if(sc) {
+                                       sc->N = N;
+                                       sc->data0 = param1;
+                                       sc->data1 = param2;
+                                       sc->offset = -stack_load_float(stack, data_node.z);
+                                       if(sd->segment == ~0) {
+                                               sc->T = normalize(sd->dPdv);
+                                               sc->offset = 0.0f;
+                                       }
+                                       else
+                                               sc->T = sd->dPdu;
+                                       if(type == CLOSURE_BSDF_HAIR_REFLECTION_ID) {
+                                               sd->flag |= bsdf_hair_reflection_setup(sc);
+                                       }
+                                       else {
+                                               sd->flag |= bsdf_hair_transmission_setup(sc);
+                                       }
+                               }
+                       }
+
+                       break;
+               }
+#endif
+
 #ifdef __SUBSURFACE__
                case CLOSURE_BSSRDF_COMPATIBLE_ID:
                case CLOSURE_BSSRDF_CUBIC_ID:
index e2b299e661dc4f217d01be408cba18fdec2b04d9..50daf159f260411b6f215743bb27255d86ceaaae 100644 (file)
@@ -357,6 +357,8 @@ typedef enum ClosureType {
        CLOSURE_BSDF_WESTIN_BACKSCATTER_ID,
        CLOSURE_BSDF_PHONG_RAMP_ID,
        CLOSURE_BSDF_GLOSSY_TOON_ID,
+       CLOSURE_BSDF_HAIR_REFLECTION_ID,
+
        
        /* Transmission */
        CLOSURE_BSDF_TRANSMISSION_ID,
@@ -367,6 +369,8 @@ typedef enum ClosureType {
        CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID,
        CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID,
        CLOSURE_BSDF_SHARP_GLASS_ID,
+       CLOSURE_BSDF_HAIR_TRANSMISSION_ID,
+
        
        /* Special cases */
        CLOSURE_BSDF_BSSRDF_ID,
@@ -395,8 +399,8 @@ typedef enum ClosureType {
 /* watch this, being lazy with memory usage */
 #define CLOSURE_IS_BSDF(type) (type <= CLOSURE_BSDF_TRANSPARENT_ID)
 #define CLOSURE_IS_BSDF_DIFFUSE(type) (type >= CLOSURE_BSDF_DIFFUSE_ID && type <= CLOSURE_BSDF_DIFFUSE_TOON_ID)
-#define CLOSURE_IS_BSDF_GLOSSY(type) (type >= CLOSURE_BSDF_GLOSSY_ID && type <= CLOSURE_BSDF_GLOSSY_TOON_ID)
-#define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSMISSION_ID && type <= CLOSURE_BSDF_SHARP_GLASS_ID)
+#define CLOSURE_IS_BSDF_GLOSSY(type) (type >= CLOSURE_BSDF_GLOSSY_ID && type <= CLOSURE_BSDF_HAIR_REFLECTION_ID)
+#define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSMISSION_ID && type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID)
 #define CLOSURE_IS_BSDF_BSSRDF(type) (type == CLOSURE_BSDF_BSSRDF_ID)
 #define CLOSURE_IS_BSSRDF(type) (type >= CLOSURE_BSSRDF_COMPATIBLE_ID && type <= CLOSURE_BSSRDF_GAUSSIAN_ID)
 #define CLOSURE_IS_VOLUME(type) (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_ISOTROPIC_ID)
index 30f51728e1bc4097896eb387df3086733e09ef3c..70cb5613e61700c2611ab4f0a3ee46605b5fa478 100644 (file)
@@ -1950,6 +1950,46 @@ void IsotropicVolumeNode::compile(OSLCompiler& compiler)
        compiler.add(this, "node_isotropic_volume");
 }
 
+/* Hair BSDF Closure */
+
+static ShaderEnum hair_component_init()
+{
+       ShaderEnum enm;
+
+       enm.insert("Reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID);
+       enm.insert("Transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID);
+       
+
+       return enm;
+}
+
+ShaderEnum HairBsdfNode::component_enum = hair_component_init();
+
+HairBsdfNode::HairBsdfNode()
+{
+       component = ustring("Reflection");
+
+       add_input("Offset", SHADER_SOCKET_FLOAT);
+       add_input("RoughnessU", SHADER_SOCKET_FLOAT);
+       add_input("RoughnessV", SHADER_SOCKET_FLOAT);
+
+}
+
+void HairBsdfNode::compile(SVMCompiler& compiler)
+{
+       closure = (ClosureType)component_enum[component];
+
+       BsdfNode::compile(compiler, input("RoughnessU"), input("RoughnessV"), input("Offset"));
+}
+
+void HairBsdfNode::compile(OSLCompiler& compiler)
+{
+       compiler.parameter("component", component);
+
+       compiler.add(this, "node_hair_bsdf");
+
+}
+
 /* Geometry */
 
 GeometryNode::GeometryNode()
index 50338ddd5c03ed85358197217b05660d026f4f6a..d58c6633a41be89845771cd75a69f719aeab9012 100644 (file)
@@ -321,6 +321,15 @@ public:
        SHADER_NODE_CLASS(IsotropicVolumeNode)
 };
 
+class HairBsdfNode : public BsdfNode {
+public:
+       SHADER_NODE_CLASS(HairBsdfNode)
+
+       ustring component;
+       static ShaderEnum component_enum;
+
+};
+
 class GeometryNode : public ShaderNode {
 public:
        SHADER_NODE_CLASS(GeometryNode)
index 6a5dccaed884b8513744c0bc5c246f8639b61270..71ff547f6da576f6576cbbb6fbfe7e8b09ebadaf 100644 (file)
@@ -186,6 +186,7 @@ shader_node_categories = [
         NodeItem("ShaderNodeBsdfToon"),
         NodeItem("ShaderNodeSubsurfaceScattering"),
         NodeItem("ShaderNodeEmission"),
+        NodeItem("ShaderNodeBsdfHair"),
         NodeItem("ShaderNodeBackground"),
         NodeItem("ShaderNodeAmbientOcclusion"),
         NodeItem("ShaderNodeHoldout"),
index afa0deebf3f658550690b8b438511393e6e0beca..7f19a8670931762285b9cd714481a0b3c8b8bb52 100644 (file)
@@ -746,6 +746,7 @@ struct ShadeResult;
 #define SH_NODE_VECT_TRANSFORM                 182
 #define SH_NODE_SEPHSV                                 183
 #define SH_NODE_COMBHSV                                        184
+#define SH_NODE_BSDF_HAIR                              185
 
 /* custom defines options for Material node */
 #define SH_NODE_MAT_DIFF   1
index dc1eb1cc4f69b61f10227439b7d5531a5079d321..2305c0696af9599816286d9bb415b30d5a2fb07f 100644 (file)
@@ -3449,6 +3449,7 @@ static void registerShaderNodes(void)
        register_node_type_sh_bsdf_transparent();
        register_node_type_sh_bsdf_velvet();
        register_node_type_sh_bsdf_toon();
+       register_node_type_sh_bsdf_hair();
        register_node_type_sh_emission();
        register_node_type_sh_holdout();
        //register_node_type_sh_volume_transparent();
index 4e98c9fd8940c85e6e237d0662ee445d59f5a7b6..45428425138bbd8f487a557ada8720541616d630 100644 (file)
@@ -921,6 +921,11 @@ static void node_shader_buts_toon(uiLayout *layout, bContext *UNUSED(C), Pointer
        uiItemR(layout, ptr, "component", 0, "", ICON_NONE);
 }
 
+static void node_shader_buts_hair(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+       uiItemR(layout, ptr, "component", 0, "", ICON_NONE);
+}
+
 static void node_shader_buts_script(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
 {
        uiLayout *row;
@@ -1054,6 +1059,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
                case SH_NODE_BSDF_TOON:
                        ntype->uifunc = node_shader_buts_toon;
                        break;
+               case SH_NODE_BSDF_HAIR:
+                       ntype->uifunc = node_shader_buts_hair;
+                       break;
                case SH_NODE_SCRIPT:
                        ntype->uifunc = node_shader_buts_script;
                        ntype->uifuncbut = node_shader_buts_script_details;
index cd8c2db1821a74175b95988a366cc84af2e199a3..3204c1f280dd4634b95ca04d393cc69a2ea5e0bc 100644 (file)
@@ -2092,6 +2092,11 @@ void node_subsurface_scattering(vec4 color, float scale, vec3 radius, float shar
        node_bsdf_diffuse(color, 0.0, N, result);
 }
 
+void node_bsdf_hair(vec4 color, float roughnessu, float roughnessv,, out vec4 result)
+{
+       result = color;
+}
+
 /* emission */
 
 void node_emission(vec4 color, float strength, vec3 N, out vec4 result)
index e7eb670572aed14265220b27f8cde04b94267ba1..a82d1a71a1e8a37eb9e7a5bf411f83a31b1624c5 100644 (file)
@@ -894,6 +894,10 @@ typedef struct NodeShaderNormalMap {
 #define SHD_TOON_DIFFUSE       0
 #define SHD_TOON_GLOSSY                1
 
+/* hair components */
+#define SHD_HAIR_REFLECTION            0
+#define SHD_HAIR_TRANSMISSION          1
+
 /* blend texture */
 #define SHD_BLEND_LINEAR                       0
 #define SHD_BLEND_QUADRATIC                    1
index 9e4118e67b603f6ac4f62c35d397ead2fe0857ba..0e4f1f96733c4e52f6e42463ea458ec6bff263b8 100644 (file)
@@ -2885,6 +2885,12 @@ static EnumPropertyItem node_toon_items[] = {
        {0, NULL, 0, NULL, NULL}
 };
 
+static EnumPropertyItem node_hair_items[] = {
+       {SHD_HAIR_REFLECTION,     "Reflection",    0,   "Reflection", ""},
+       {SHD_HAIR_TRANSMISSION,   "Transmission",    0,  "Transmission", ""},
+       {0, NULL, 0, NULL, NULL}
+};
+
 static EnumPropertyItem node_script_mode_items[] = {
        {NODE_SCRIPT_INTERNAL, "INTERNAL", 0, "Internal", "Use internal text datablock"},
        {NODE_SCRIPT_EXTERNAL, "EXTERNAL", 0, "External", "Use external .osl or .oso file"},
@@ -3583,6 +3589,17 @@ static void def_sh_bump(StructRNA *srna)
        RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
 }
 
+static void def_hair(StructRNA *srna)
+{
+       PropertyRNA *prop;
+       
+       prop = RNA_def_property(srna, "component", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_sdna(prop, NULL, "custom1");
+       RNA_def_property_enum_items(prop, node_hair_items);
+       RNA_def_property_ui_text(prop, "Component", "");
+       RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
 static void def_sh_normal_map(StructRNA *srna)
 {
        static EnumPropertyItem prop_space_items[] = {
index 4ac75c15efe6c71e7b56c166c6c4541e8f301de3..61c8cb5655df026edaf57b76b8db020545724660 100644 (file)
@@ -164,6 +164,7 @@ set(SRC
        shader/nodes/node_shader_bsdf_translucent.c
        shader/nodes/node_shader_bsdf_transparent.c
        shader/nodes/node_shader_bsdf_velvet.c
+       shader/nodes/node_shader_bsdf_hair.c
        shader/nodes/node_shader_bump.c
        shader/nodes/node_shader_emission.c
        shader/nodes/node_shader_fresnel.c
index e5d20f7dc7359569b8e98e4e00742cff9bad9cec..853046a2a2318ccc3f8359d230f627c530582c63 100644 (file)
@@ -106,6 +106,7 @@ void register_node_type_sh_emission(void);
 void register_node_type_sh_holdout(void);
 void register_node_type_sh_volume_transparent(void);
 void register_node_type_sh_volume_isotropic(void);
+void register_node_type_sh_bsdf_hair(void);
 void register_node_type_sh_subsurface_scattering(void);
 void register_node_type_sh_mix_shader(void);
 void register_node_type_sh_add_shader(void);
index 7cf277a12bae205a61e4dce258da2225b18e5f6f..f90ee49fc14e875e2cc7e4eed53f7db78e50dca1 100644 (file)
@@ -86,6 +86,7 @@ DefNode( ShaderNode,     SH_NODE_BSDF_TRANSLUCENT,   0,                      "BS
 DefNode( ShaderNode,     SH_NODE_BSDF_TRANSPARENT,   0,                      "BSDF_TRANSPARENT",   BsdfTransparent,  "Transparent BSDF",  ""       )
 DefNode( ShaderNode,     SH_NODE_BSDF_VELVET,        0,                      "BSDF_VELVET",        BsdfVelvet,       "Velvet BSDF",       ""       )
 DefNode( ShaderNode,     SH_NODE_BSDF_TOON,          def_toon,               "BSDF_TOON",          BsdfToon,         "Toon BSDF",         ""       )
+DefNode( ShaderNode,     SH_NODE_BSDF_HAIR,          def_hair,               "BSDF_HAIR",          BsdfHair,         "Hair BSDF",         ""       )
 DefNode( ShaderNode,     SH_NODE_SUBSURFACE_SCATTERING, def_sh_subsurface,   "SUBSURFACE_SCATTERING",SubsurfaceScattering,"Subsurface Scattering","")
 DefNode( ShaderNode,     SH_NODE_VOLUME_TRANSPARENT, 0,                      "VOLUME_TRANSPARENT", VolumeTransparent,"Transparent Volume",""       )
 DefNode( ShaderNode,     SH_NODE_VOLUME_ISOTROPIC,   0,                      "VOLUME_ISOTROPIC",   VolumeIsotropic,  "Isotropic Volume",  ""       )
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c
new file mode 100644 (file)
index 0000000..23f0a0b
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../node_shader_util.h"
+
+/* **************** OUTPUT ******************** */
+
+static bNodeSocketTemplate sh_node_bsdf_hair_in[] = {
+       {       SOCK_RGBA,  1, N_("Color"),                     0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+       {       SOCK_FLOAT, 1, N_("Offset"),            0.0f, 0.0f, 0.0f, 0.0f, -M_PI_2, M_PI_2, PROP_ANGLE},
+       {       SOCK_FLOAT, 1, N_("RoughnessU"),        0.1f, 0.1f, 0.1f, 0.0f, 0.0f, 1.0f},
+       {       SOCK_FLOAT, 1, N_("RoughnessV"),        1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f},    {       -1, 0, ""       }
+};
+
+static bNodeSocketTemplate sh_node_bsdf_hair_out[] = {
+       {       SOCK_SHADER, 0, N_("BSDF")},
+       {       -1, 0, ""       }
+};
+
+static int node_shader_gpu_bsdf_hair(GPUMaterial *mat, bNode *UNUSED(node), GPUNodeStack *in, GPUNodeStack *out)
+{
+       if (!in[2].link)
+               in[2].link = GPU_builtin(GPU_VIEW_NORMAL);
+
+       return GPU_stack_link(mat, "node_bsdf_hair", in, out);
+}
+
+/* node type definition */
+void register_node_type_sh_bsdf_hair(void)
+{
+       static bNodeType ntype;
+
+       sh_node_type_base(&ntype, SH_NODE_BSDF_HAIR, "Hair BSDF", NODE_CLASS_SHADER, 0);
+       node_type_compatibility(&ntype, NODE_NEW_SHADING);
+       node_type_socket_templates(&ntype, sh_node_bsdf_hair_in, sh_node_bsdf_hair_out);
+       node_type_size(&ntype, 150, 60, 200);
+       node_type_init(&ntype, NULL);
+       node_type_storage(&ntype, "", NULL, NULL);
+
+       nodeRegisterType(&ntype);
+}