Cycles: option to make background visible through glass transparent.
[blender-staging.git] / intern / cycles / kernel / closure / bsdf.h
index 76b80ba9d86c1c5a70bbc235fe170b5833a28af2..6f0bdb3fa38214338c8d330b3dfed419bc26c379 100644 (file)
@@ -1,49 +1,72 @@
 /*
- * Copyright 2011, Blender Foundation.
+ * Copyright 2011-2013 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.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- * 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.
+ * http://www.apache.org/licenses/LICENSE-2.0
  *
- * 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.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
-#include "../closure/bsdf_ashikhmin_velvet.h"
-#include "../closure/bsdf_diffuse.h"
-#include "../closure/bsdf_oren_nayar.h"
-#include "../closure/bsdf_phong_ramp.h"
-#include "../closure/bsdf_diffuse_ramp.h"
-#include "../closure/bsdf_microfacet.h"
-#include "../closure/bsdf_reflection.h"
-#include "../closure/bsdf_refraction.h"
-#include "../closure/bsdf_transparent.h"
-#ifdef __ANISOTROPIC__
-#include "../closure/bsdf_ward.h"
+#include "kernel/closure/bsdf_ashikhmin_velvet.h"
+#include "kernel/closure/bsdf_diffuse.h"
+#include "kernel/closure/bsdf_oren_nayar.h"
+#include "kernel/closure/bsdf_phong_ramp.h"
+#include "kernel/closure/bsdf_diffuse_ramp.h"
+#include "kernel/closure/bsdf_microfacet.h"
+#include "kernel/closure/bsdf_microfacet_multi.h"
+#include "kernel/closure/bsdf_reflection.h"
+#include "kernel/closure/bsdf_refraction.h"
+#include "kernel/closure/bsdf_transparent.h"
+#include "kernel/closure/bsdf_ashikhmin_shirley.h"
+#include "kernel/closure/bsdf_toon.h"
+#include "kernel/closure/bsdf_hair.h"
+#include "kernel/closure/bsdf_principled_diffuse.h"
+#include "kernel/closure/bsdf_principled_sheen.h"
+#include "kernel/closure/bssrdf.h"
+#ifdef __VOLUME__
+#  include "kernel/closure/volume.h"
 #endif
-#include "../closure/bsdf_westin.h"
-#include "../closure/bssrdf.h"
 
 CCL_NAMESPACE_BEGIN
 
-__device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf)
+/* Returns the square of the roughness of the closure if it has roughness,
+ * 0 for singular closures and 1 otherwise. */
+ccl_device_inline float bsdf_get_roughness_squared(const ShaderClosure *sc)
 {
-       int label;
+       if(CLOSURE_IS_BSDF_SINGULAR(sc->type)) {
+               return 0.0f;
+       }
 
-#ifdef __OSL__
-       if(kg->osl && sc->prim)
-               return OSLShader::bsdf_sample(sd, sc, randu, randv, *eval, *omega_in, *domega_in, *pdf);
-#endif
+       if(CLOSURE_IS_BSDF_MICROFACET(sc->type)) {
+               MicrofacetBsdf *bsdf = (MicrofacetBsdf*) sc;
+               return bsdf->alpha_x*bsdf->alpha_y;
+       }
+
+       return 1.0f;
+}
+
+ccl_device_forceinline int bsdf_sample(KernelGlobals *kg,
+                                       ShaderData *sd,
+                                       const ShaderClosure *sc,
+                                       float randu,
+                                       float randv,
+                                       float3 *eval,
+                                       float3 *omega_in,
+                                       differential3 *domega_in,
+                                       float *pdf)
+{
+       int label;
 
        switch(sc->type) {
                case CLOSURE_BSDF_DIFFUSE_ID:
+               case CLOSURE_BSDF_BSSRDF_ID:
                        label = bsdf_diffuse_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;
@@ -52,14 +75,16 @@ __device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const ShaderCl
                        label = bsdf_oren_nayar_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_PHONG_RAMP_ID:
+#ifdef __OSL__
+               case CLOSURE_BSDF_PHONG_RAMP_ID:
                        label = bsdf_phong_ramp_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_DIFFUSE_RAMP_ID:
                        label = bsdf_diffuse_ramp_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;*/
+                       break;
+#endif
                case CLOSURE_BSDF_TRANSLUCENT_ID:
                        label = bsdf_translucent_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
                                eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
@@ -77,66 +102,122 @@ __device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const ShaderCl
                                eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
                        break;
                case CLOSURE_BSDF_MICROFACET_GGX_ID:
+               case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID:
+               case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID:
+               case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
+               case CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID:
                case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
-                       label = bsdf_microfacet_ggx_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+                       label = bsdf_microfacet_ggx_sample(kg, 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_MICROFACET_MULTI_GGX_ID:
+               case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID:
+                       label = bsdf_microfacet_multi_ggx_sample(kg, sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+                               eval, omega_in,  &domega_in->dx, &domega_in->dy, pdf, &sd->lcg_state);
+                       break;
+               case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
+               case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID:
+                       label = bsdf_microfacet_multi_ggx_glass_sample(kg, sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+                               eval, omega_in,  &domega_in->dx, &domega_in->dy, pdf, &sd->lcg_state);
+                       break;
                case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
+               case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
                case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
-                       label = bsdf_microfacet_beckmann_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+                       label = bsdf_microfacet_beckmann_sample(kg, sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
                                eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
                        break;
-#ifdef __ANISOTROPIC__
-               case CLOSURE_BSDF_WARD_ID:
-                       label = bsdf_ward_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+               case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
+               case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID:
+                       label = bsdf_ashikhmin_shirley_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
                case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID:
                        label = bsdf_ashikhmin_velvet_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_WESTIN_BACKSCATTER_ID:
-                       label = bsdf_westin_backscatter_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+               case CLOSURE_BSDF_DIFFUSE_TOON_ID:
+                       label = bsdf_diffuse_toon_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_GLOSSY_TOON_ID:
+                       label = bsdf_glossy_toon_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;
-               case CLOSURE_BSDF_WESTIN_SHEEN_ID:
-                       label = bsdf_westin_sheen_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+#ifdef __PRINCIPLED__
+               case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID:
+               case CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID:
+                       label = bsdf_principled_diffuse_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;*/
+                       break;
+               case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID:
+                       label = bsdf_principled_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;
+#endif  /* __PRINCIPLED__ */
+#endif
+#ifdef __VOLUME__
+               case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID:
+                       label = volume_henyey_greenstein_sample(sc, 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;
                        break;
        }
 
+       /* Test if BSDF sample should be treated as transparent for background. */
+       if(label & LABEL_TRANSMIT) {
+               float threshold_squared = kernel_data.background.transparent_roughness_squared_threshold;
+
+               if(threshold_squared >= 0.0f) {
+                       if(bsdf_get_roughness_squared(sc) <= threshold_squared) {
+                               label |= LABEL_TRANSMIT_TRANSPARENT;
+                       }
+               }
+       }
+
        return label;
 }
 
-__device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, float *pdf)
+#ifndef __KERNEL_CUDA__
+ccl_device
+#else
+ccl_device_forceinline
+#endif
+float3 bsdf_eval(KernelGlobals *kg,
+                 ShaderData *sd,
+                 const ShaderClosure *sc,
+                 const float3 omega_in,
+                 float *pdf)
 {
        float3 eval;
 
-#ifdef __OSL__
-       if(kg->osl && sc->prim)
-               return OSLShader::bsdf_eval(sd, sc, omega_in, *pdf);
-#endif
-
        if(dot(sd->Ng, omega_in) >= 0.0f) {
                switch(sc->type) {
                        case CLOSURE_BSDF_DIFFUSE_ID:
+                       case CLOSURE_BSDF_BSSRDF_ID:
                                eval = bsdf_diffuse_eval_reflect(sc, sd->I, omega_in, pdf);
                                break;
 #ifdef __SVM__
                        case CLOSURE_BSDF_OREN_NAYAR_ID:
                                eval = bsdf_oren_nayar_eval_reflect(sc, sd->I, omega_in, pdf);
                                break;
-                       /*case CLOSURE_BSDF_PHONG_RAMP_ID:
+#ifdef __OSL__
+                       case CLOSURE_BSDF_PHONG_RAMP_ID:
                                eval = bsdf_phong_ramp_eval_reflect(sc, sd->I, omega_in, pdf);
                                break;
                        case CLOSURE_BSDF_DIFFUSE_RAMP_ID:
                                eval = bsdf_diffuse_ramp_eval_reflect(sc, sd->I, omega_in, pdf);
-                               break;*/
+                               break;
+#endif
                        case CLOSURE_BSDF_TRANSLUCENT_ID:
                                eval = bsdf_translucent_eval_reflect(sc, sd->I, omega_in, pdf);
                                break;
@@ -150,27 +231,59 @@ __device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const ShaderC
                                eval = bsdf_transparent_eval_reflect(sc, sd->I, omega_in, pdf);
                                break;
                        case CLOSURE_BSDF_MICROFACET_GGX_ID:
+                       case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID:
+                       case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID:
+                       case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
+                       case CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID:
                        case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
                                eval = bsdf_microfacet_ggx_eval_reflect(sc, sd->I, omega_in, pdf);
                                break;
+                       case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
+                       case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID:
+                               eval = bsdf_microfacet_multi_ggx_eval_reflect(sc, sd->I, omega_in, pdf, &sd->lcg_state);
+                               break;
+                       case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
+                       case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID:
+                               eval = bsdf_microfacet_multi_ggx_glass_eval_reflect(sc, sd->I, omega_in, pdf, &sd->lcg_state);
+                               break;
                        case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
+                       case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
                        case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
                                eval = bsdf_microfacet_beckmann_eval_reflect(sc, sd->I, omega_in, pdf);
                                break;
-#ifdef __ANISOTROPIC__
-                       case CLOSURE_BSDF_WARD_ID:
-                               eval = bsdf_ward_eval_reflect(sc, sd->I, omega_in, pdf);
+                       case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
+                       case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID:
+                               eval = bsdf_ashikhmin_shirley_eval_reflect(sc, sd->I, omega_in, pdf);
                                break;
-#endif
                        case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID:
                                eval = bsdf_ashikhmin_velvet_eval_reflect(sc, sd->I, omega_in, pdf);
                                break;
-                       /*case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID:
-                               eval = bsdf_westin_backscatter_eval_reflect(sc, sd->I, omega_in, pdf);
+                       case CLOSURE_BSDF_DIFFUSE_TOON_ID:
+                               eval = bsdf_diffuse_toon_eval_reflect(sc, sd->I, omega_in, pdf);
+                               break;
+                       case CLOSURE_BSDF_GLOSSY_TOON_ID:
+                               eval = bsdf_glossy_toon_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;
+#ifdef __PRINCIPLED__
+                       case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID:
+                       case CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID:
+                               eval = bsdf_principled_diffuse_eval_reflect(sc, sd->I, omega_in, pdf);
+                               break;
+                       case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID:
+                               eval = bsdf_principled_sheen_eval_reflect(sc, sd->I, omega_in, pdf);
+                               break;
+#endif  /* __PRINCIPLED__ */
+#endif
+#ifdef __VOLUME__
+                       case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID:
+                               eval = volume_henyey_greenstein_eval_phase(sc, sd->I, omega_in, pdf);
                                break;
-                       case CLOSURE_BSDF_WESTIN_SHEEN_ID:
-                               eval = bsdf_westin_sheen_eval_reflect(sc, sd->I, omega_in, pdf);
-                               break;*/
 #endif
                        default:
                                eval = make_float3(0.0f, 0.0f, 0.0f);
@@ -180,6 +293,7 @@ __device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const ShaderC
        else {
                switch(sc->type) {
                        case CLOSURE_BSDF_DIFFUSE_ID:
+                       case CLOSURE_BSDF_BSSRDF_ID:
                                eval = bsdf_diffuse_eval_transmit(sc, sd->I, omega_in, pdf);
                                break;
 #ifdef __SVM__
@@ -199,27 +313,59 @@ __device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const ShaderC
                                eval = bsdf_transparent_eval_transmit(sc, sd->I, omega_in, pdf);
                                break;
                        case CLOSURE_BSDF_MICROFACET_GGX_ID:
+                       case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID:
+                       case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID:
+                       case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
+                       case CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID:
                        case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
                                eval = bsdf_microfacet_ggx_eval_transmit(sc, sd->I, omega_in, pdf);
                                break;
+                       case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
+                       case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID:
+                               eval = bsdf_microfacet_multi_ggx_eval_transmit(sc, sd->I, omega_in, pdf, &sd->lcg_state);
+                               break;
+                       case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
+                       case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID:
+                               eval = bsdf_microfacet_multi_ggx_glass_eval_transmit(sc, sd->I, omega_in, pdf, &sd->lcg_state);
+                               break;
                        case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
+                       case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
                        case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
                                eval = bsdf_microfacet_beckmann_eval_transmit(sc, sd->I, omega_in, pdf);
                                break;
-#ifdef __ANISOTROPIC__
-                       case CLOSURE_BSDF_WARD_ID:
-                               eval = bsdf_ward_eval_transmit(sc, sd->I, omega_in, pdf);
+                       case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
+                       case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID:
+                               eval = bsdf_ashikhmin_shirley_eval_transmit(sc, sd->I, omega_in, pdf);
                                break;
-#endif
                        case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID:
                                eval = bsdf_ashikhmin_velvet_eval_transmit(sc, sd->I, omega_in, pdf);
                                break;
-                       /*case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID:
-                               eval = bsdf_westin_backscatter_eval_transmit(sc, sd->I, omega_in, pdf);
+                       case CLOSURE_BSDF_DIFFUSE_TOON_ID:
+                               eval = bsdf_diffuse_toon_eval_transmit(sc, sd->I, omega_in, pdf);
+                               break;
+                       case CLOSURE_BSDF_GLOSSY_TOON_ID:
+                               eval = bsdf_glossy_toon_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;
+#ifdef __PRINCIPLED__
+                       case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID:
+                       case CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID:
+                               eval = bsdf_principled_diffuse_eval_transmit(sc, sd->I, omega_in, pdf);
+                               break;
+                       case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID:
+                               eval = bsdf_principled_sheen_eval_transmit(sc, sd->I, omega_in, pdf);
+                               break;
+#endif  /* __PRINCIPLED__ */
+#endif
+#ifdef __VOLUME__
+                       case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID:
+                               eval = volume_henyey_greenstein_eval_phase(sc, sd->I, omega_in, pdf);
                                break;
-                       case CLOSURE_BSDF_WESTIN_SHEEN_ID:
-                               eval = bsdf_westin_sheen_eval_transmit(sc, sd->I, omega_in, pdf);
-                               break;*/
 #endif
                        default:
                                eval = make_float3(0.0f, 0.0f, 0.0f);
@@ -230,67 +376,93 @@ __device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const ShaderC
        return eval;
 }
 
-__device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness)
+ccl_device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness)
 {
-#ifdef __OSL__
-       if(kg->osl && sc->prim) {
-               OSLShader::bsdf_blur(sc, roughness);
-               return;
-       }
-#endif
-
-       switch(sc->type) {
-               case CLOSURE_BSDF_DIFFUSE_ID:
-                       bsdf_diffuse_blur(sc, roughness);
-                       break;
+       /* ToDo: do we want to blur volume closures? */
 #ifdef __SVM__
-               case CLOSURE_BSDF_OREN_NAYAR_ID:
-                       bsdf_oren_nayar_blur(sc, roughness);
-                       break;
-               /*case CLOSURE_BSDF_PHONG_RAMP_ID:
-                       bsdf_phong_ramp_blur(sc, roughness);
-                       break;
-               case CLOSURE_BSDF_DIFFUSE_RAMP_ID:
-                       bsdf_diffuse_ramp_blur(sc, roughness);
-                       break;*/
-               case CLOSURE_BSDF_TRANSLUCENT_ID:
-                       bsdf_translucent_blur(sc, roughness);
-                       break;
-               case CLOSURE_BSDF_REFLECTION_ID:
-                       bsdf_reflection_blur(sc, roughness);
-                       break;
-               case CLOSURE_BSDF_REFRACTION_ID:
-                       bsdf_refraction_blur(sc, roughness);
-                       break;
-               case CLOSURE_BSDF_TRANSPARENT_ID:
-                       bsdf_transparent_blur(sc, roughness);
+       switch(sc->type) {
+               case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
+               case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID:
+               case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
+               case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID:
+                       bsdf_microfacet_multi_ggx_blur(sc, roughness);
                        break;
                case CLOSURE_BSDF_MICROFACET_GGX_ID:
+               case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID:
+               case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID:
+               case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
+               case CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID:
                case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
                        bsdf_microfacet_ggx_blur(sc, roughness);
                        break;
                case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
+               case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
                case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
                        bsdf_microfacet_beckmann_blur(sc, roughness);
                        break;
-#ifdef __ANISOTROPIC__
-               case CLOSURE_BSDF_WARD_ID:
-                       bsdf_ward_blur(sc, roughness);
+               case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
+               case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID:
+                       bsdf_ashikhmin_shirley_blur(sc, roughness);
+                       break;
+               default:
                        break;
+       }
 #endif
+}
+
+ccl_device bool bsdf_merge(ShaderClosure *a, ShaderClosure *b)
+{
+#ifdef __SVM__
+       switch(a->type) {
+               case CLOSURE_BSDF_TRANSPARENT_ID:
+                       return true;
+               case CLOSURE_BSDF_DIFFUSE_ID:
+               case CLOSURE_BSDF_BSSRDF_ID:
+               case CLOSURE_BSDF_TRANSLUCENT_ID:
+                       return bsdf_diffuse_merge(a, b);
+               case CLOSURE_BSDF_OREN_NAYAR_ID:
+                       return bsdf_oren_nayar_merge(a, b);
+               case CLOSURE_BSDF_REFLECTION_ID:
+               case CLOSURE_BSDF_REFRACTION_ID:
+               case CLOSURE_BSDF_MICROFACET_GGX_ID:
+               case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID:
+               case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID:
+               case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
+               case CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID:
+               case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
+               case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
+               case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID:
+               case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
+               case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID:
+               case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
+               case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
+               case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
+               case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
+               case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID:
+                       return bsdf_microfacet_merge(a, b);
                case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID:
-                       bsdf_ashikhmin_velvet_blur(sc, roughness);
-                       break;
-               /*case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID:
-                       bsdf_westin_backscatter_blur(sc, roughness);
-                       break;
-               case CLOSURE_BSDF_WESTIN_SHEEN_ID:
-                       bsdf_westin_sheen_blur(sc, roughness);
-                       break;*/
+                       return bsdf_ashikhmin_velvet_merge(a, b);
+               case CLOSURE_BSDF_DIFFUSE_TOON_ID:
+               case CLOSURE_BSDF_GLOSSY_TOON_ID:
+                       return bsdf_toon_merge(a, b);
+               case CLOSURE_BSDF_HAIR_REFLECTION_ID:
+               case CLOSURE_BSDF_HAIR_TRANSMISSION_ID:
+                       return bsdf_hair_merge(a, b);
+#ifdef __PRINCIPLED__
+               case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID:
+               case CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID:
+                       return bsdf_principled_diffuse_merge(a, b);
+#endif
+#ifdef __VOLUME__
+               case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID:
+                       return volume_henyey_greenstein_merge(a, b);
 #endif
                default:
-                       break;
+                       return false;
        }
+#else
+       return false;
+#endif
 }
 
 CCL_NAMESPACE_END