diff options
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); +} |