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
diff options
context:
space:
mode:
-rw-r--r--intern/cycles/blender/blender_shader.cpp13
-rw-r--r--intern/cycles/kernel/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/closure/bsdf.h25
-rw-r--r--intern/cycles/kernel/closure/bsdf_hair.h279
-rw-r--r--intern/cycles/kernel/kernel_shader.h2
-rw-r--r--intern/cycles/kernel/kernel_types.h6
-rw-r--r--intern/cycles/kernel/osl/osl_closures.cpp32
-rw-r--r--intern/cycles/kernel/osl/osl_shader.cpp4
-rw-r--r--intern/cycles/kernel/shaders/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/shaders/node_hair_bsdf.osl56
-rw-r--r--intern/cycles/kernel/shaders/stdosl.h3
-rw-r--r--intern/cycles/kernel/svm/svm_closure.h40
-rw-r--r--intern/cycles/kernel/svm/svm_types.h8
-rw-r--r--intern/cycles/render/nodes.cpp40
-rw-r--r--intern/cycles/render/nodes.h9
-rw-r--r--release/scripts/startup/nodeitems_builtins.py1
-rw-r--r--source/blender/blenkernel/BKE_node.h1
-rw-r--r--source/blender/blenkernel/intern/node.c1
-rw-r--r--source/blender/editors/space_node/drawnode.c8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl5
-rw-r--r--source/blender/makesdna/DNA_node_types.h4
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c17
-rw-r--r--source/blender/nodes/CMakeLists.txt1
-rw-r--r--source/blender/nodes/NOD_shader.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c65
26 files changed, 620 insertions, 4 deletions
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index 5dfbd97366a..2007171642f 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -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();
}
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 9db05693fc3..eaa4e304ebb 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -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
diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h
index d81bbebd5a8..86fea48760f 100644
--- a/intern/cycles/kernel/closure/bsdf.h
+++ b/intern/cycles/kernel/closure/bsdf.h
@@ -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
index 00000000000..5791598459c
--- /dev/null
+++ b/intern/cycles/kernel/closure/bsdf_hair.h
@@ -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__ */
+
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index e8e9af64df6..bcc4c42c9cc 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -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;
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 98594df8b10..d039b708bd4 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -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
diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp
index 6a3f27fb7b1..221406a1716 100644
--- a/intern/cycles/kernel/osl/osl_closures.cpp
+++ b/intern/cycles/kernel/osl/osl_closures.cpp
@@ -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
diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp
index 9ff3797b50f..625ad263f7f 100644
--- a/intern/cycles/kernel/osl/osl_shader.cpp
+++ b/intern/cycles/kernel/osl/osl_shader.cpp
@@ -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;
diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt
index 660cfbce528..0f8542b0546 100644
--- a/intern/cycles/kernel/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/shaders/CMakeLists.txt
@@ -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
index 00000000000..d1d7d0fb6a6
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_hair_bsdf.osl
@@ -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);
+ }
+ }
+}
+
diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h
index 3ad2bbc0588..424ca335903 100644
--- a/intern/cycles/kernel/shaders/stdosl.h
+++ b/intern/cycles/kernel/shaders/stdosl.h
@@ -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;
diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h
index 9a9aefa5b29..6d9c4e215e6 100644
--- a/intern/cycles/kernel/svm/svm_closure.h
+++ b/intern/cycles/kernel/svm/svm_closure.h
@@ -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:
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index e2b299e661d..50daf159f26 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -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)
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 30f51728e1b..70cb5613e61 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -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()
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 50338ddd5c0..d58c6633a41 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -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)
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 6a5dccaed88..71ff547f6da 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -186,6 +186,7 @@ shader_node_categories = [
NodeItem("ShaderNodeBsdfToon"),
NodeItem("ShaderNodeSubsurfaceScattering"),
NodeItem("ShaderNodeEmission"),
+ NodeItem("ShaderNodeBsdfHair"),
NodeItem("ShaderNodeBackground"),
NodeItem("ShaderNodeAmbientOcclusion"),
NodeItem("ShaderNodeHoldout"),
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index afa0deebf3f..7f19a867093 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -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
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index dc1eb1cc4f6..2305c0696af 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -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();
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 4e98c9fd894..45428425138 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -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;
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index cd8c2db1821..3204c1f280d 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -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)
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index e7eb670572a..a82d1a71a1e 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -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
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 9e4118e67b6..0e4f1f96733 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -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[] = {
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 4ac75c15efe..61c8cb5655d 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -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
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index e5d20f7dc73..853046a2a23 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -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);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 7cf277a12ba..f90ee49fc14 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -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
index 00000000000..23f0a0b128f
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c
@@ -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);
+}