diff options
Diffstat (limited to 'intern/cycles/kernel/closure')
23 files changed, 4482 insertions, 3760 deletions
diff --git a/intern/cycles/kernel/closure/alloc.h b/intern/cycles/kernel/closure/alloc.h index acccba9ecec..341d1e16eb1 100644 --- a/intern/cycles/kernel/closure/alloc.h +++ b/intern/cycles/kernel/closure/alloc.h @@ -18,69 +18,72 @@ CCL_NAMESPACE_BEGIN ccl_device ShaderClosure *closure_alloc(ShaderData *sd, int size, ClosureType type, float3 weight) { - kernel_assert(size <= sizeof(ShaderClosure)); + kernel_assert(size <= sizeof(ShaderClosure)); - if(sd->num_closure_left == 0) - return NULL; + if (sd->num_closure_left == 0) + return NULL; - ShaderClosure *sc = &sd->closure[sd->num_closure]; + ShaderClosure *sc = &sd->closure[sd->num_closure]; - sc->type = type; - sc->weight = weight; + sc->type = type; + sc->weight = weight; - sd->num_closure++; - sd->num_closure_left--; + sd->num_closure++; + sd->num_closure_left--; - return sc; + return sc; } ccl_device ccl_addr_space void *closure_alloc_extra(ShaderData *sd, int size) { - /* Allocate extra space for closure that need more parameters. We allocate - * in chunks of sizeof(ShaderClosure) starting from the end of the closure - * array. - * - * This lets us keep the same fast array iteration over closures, as we - * found linked list iteration and iteration with skipping to be slower. */ - int num_extra = ((size + sizeof(ShaderClosure) - 1) / sizeof(ShaderClosure)); - - if(num_extra > sd->num_closure_left) { - /* Remove previous closure if it was allocated. */ - sd->num_closure--; - sd->num_closure_left++; - return NULL; - } - - sd->num_closure_left -= num_extra; - return (ccl_addr_space void*)(sd->closure + sd->num_closure + sd->num_closure_left); + /* Allocate extra space for closure that need more parameters. We allocate + * in chunks of sizeof(ShaderClosure) starting from the end of the closure + * array. + * + * This lets us keep the same fast array iteration over closures, as we + * found linked list iteration and iteration with skipping to be slower. */ + int num_extra = ((size + sizeof(ShaderClosure) - 1) / sizeof(ShaderClosure)); + + if (num_extra > sd->num_closure_left) { + /* Remove previous closure if it was allocated. */ + sd->num_closure--; + sd->num_closure_left++; + return NULL; + } + + sd->num_closure_left -= num_extra; + return (ccl_addr_space void *)(sd->closure + sd->num_closure + sd->num_closure_left); } ccl_device_inline ShaderClosure *bsdf_alloc(ShaderData *sd, int size, float3 weight) { - ShaderClosure *sc = closure_alloc(sd, size, CLOSURE_NONE_ID, weight); + ShaderClosure *sc = closure_alloc(sd, size, CLOSURE_NONE_ID, weight); - if(sc == NULL) - return NULL; + if (sc == NULL) + return NULL; - float sample_weight = fabsf(average(weight)); - sc->sample_weight = sample_weight; - return (sample_weight >= CLOSURE_WEIGHT_CUTOFF) ? sc : NULL; + float sample_weight = fabsf(average(weight)); + sc->sample_weight = sample_weight; + return (sample_weight >= CLOSURE_WEIGHT_CUTOFF) ? sc : NULL; } #ifdef __OSL__ -ccl_device_inline ShaderClosure *bsdf_alloc_osl(ShaderData *sd, int size, float3 weight, void *data) +ccl_device_inline ShaderClosure *bsdf_alloc_osl(ShaderData *sd, + int size, + float3 weight, + void *data) { - ShaderClosure *sc = closure_alloc(sd, size, CLOSURE_NONE_ID, weight); + ShaderClosure *sc = closure_alloc(sd, size, CLOSURE_NONE_ID, weight); - if(!sc) - return NULL; + if (!sc) + return NULL; - memcpy((void *)sc, data, size); + memcpy((void *)sc, data, size); - float sample_weight = fabsf(average(weight)); - sc->weight = weight; - sc->sample_weight = sample_weight; - return (sample_weight >= CLOSURE_WEIGHT_CUTOFF) ? sc : NULL; + float sample_weight = fabsf(average(weight)); + sc->weight = weight; + sc->sample_weight = sample_weight; + return (sample_weight >= CLOSURE_WEIGHT_CUTOFF) ? sc : NULL; } #endif diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h index 3a9629ea9d7..5e26f90a878 100644 --- a/intern/cycles/kernel/closure/bsdf.h +++ b/intern/cycles/kernel/closure/bsdf.h @@ -39,38 +39,38 @@ CCL_NAMESPACE_BEGIN * 0 for singular closures and 1 otherwise. */ ccl_device_inline float bsdf_get_specular_roughness_squared(const ShaderClosure *sc) { - if(CLOSURE_IS_BSDF_SINGULAR(sc->type)) { - return 0.0f; - } + if (CLOSURE_IS_BSDF_SINGULAR(sc->type)) { + return 0.0f; + } - if(CLOSURE_IS_BSDF_MICROFACET(sc->type)) { - MicrofacetBsdf *bsdf = (MicrofacetBsdf*)sc; - return bsdf->alpha_x*bsdf->alpha_y; - } + if (CLOSURE_IS_BSDF_MICROFACET(sc->type)) { + MicrofacetBsdf *bsdf = (MicrofacetBsdf *)sc; + return bsdf->alpha_x * bsdf->alpha_y; + } - return 1.0f; + return 1.0f; } ccl_device_inline float bsdf_get_roughness_squared(const ShaderClosure *sc) { - /* This version includes diffuse, mainly for baking Principled BSDF - * where specular and metallic zero otherwise does not bake the - * specified roughness parameter. */ - if(sc->type == CLOSURE_BSDF_OREN_NAYAR_ID) { - OrenNayarBsdf *bsdf = (OrenNayarBsdf*)sc; - return sqr(sqr(bsdf->roughness)); - } + /* This version includes diffuse, mainly for baking Principled BSDF + * where specular and metallic zero otherwise does not bake the + * specified roughness parameter. */ + if (sc->type == CLOSURE_BSDF_OREN_NAYAR_ID) { + OrenNayarBsdf *bsdf = (OrenNayarBsdf *)sc; + return sqr(sqr(bsdf->roughness)); + } - if(sc->type == CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID) { - PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf*)sc; - return sqr(sqr(bsdf->roughness)); - } + if (sc->type == CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID) { + PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf *)sc; + return sqr(sqr(bsdf->roughness)); + } - if(CLOSURE_IS_BSDF_DIFFUSE(sc->type)) { - return 0.0f; - } + if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) { + return 0.0f; + } - return bsdf_get_specular_roughness_squared(sc); + return bsdf_get_specular_roughness_squared(sc); } ccl_device_inline int bsdf_sample(KernelGlobals *kg, @@ -83,133 +83,349 @@ ccl_device_inline int bsdf_sample(KernelGlobals *kg, differential3 *domega_in, float *pdf) { - int label; + 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; + 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; #ifdef __SVM__ - case CLOSURE_BSDF_OREN_NAYAR_ID: - 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; -#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; -#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); - break; - case CLOSURE_BSDF_REFLECTION_ID: - label = bsdf_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_REFRACTION_ID: - label = bsdf_refraction_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_TRANSPARENT_ID: - label = bsdf_transparent_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_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(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(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_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; - 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_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_HAIR_PRINCIPLED_ID: - label = bsdf_principled_hair_sample(kg, sc, sd, randu, randv, - eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); - break; -#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; - 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__ */ + case CLOSURE_BSDF_OREN_NAYAR_ID: + 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; +# 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; +# 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); + break; + case CLOSURE_BSDF_REFLECTION_ID: + label = bsdf_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_REFRACTION_ID: + label = bsdf_refraction_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_TRANSPARENT_ID: + label = bsdf_transparent_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_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(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(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_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; + 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_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_HAIR_PRINCIPLED_ID: + label = bsdf_principled_hair_sample( + kg, sc, sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; +# 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; + 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; + 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; - } + 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; + /* 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_specular_roughness_squared(sc) <= threshold_squared) { - label |= LABEL_TRANSMIT_TRANSPARENT; - } - } - } + if (threshold_squared >= 0.0f) { + if (bsdf_get_specular_roughness_squared(sc) <= threshold_squared) { + label |= LABEL_TRANSMIT_TRANSPARENT; + } + } + } - return label; + return label; } #ifndef __KERNEL_CUDA__ @@ -217,285 +433,288 @@ ccl_device #else ccl_device_inline #endif -float3 bsdf_eval(KernelGlobals *kg, - ShaderData *sd, - const ShaderClosure *sc, - const float3 omega_in, - float *pdf) + float3 + bsdf_eval(KernelGlobals *kg, + ShaderData *sd, + const ShaderClosure *sc, + const float3 omega_in, + float *pdf) { - float3 eval; + float3 eval; - 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; + 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; -#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; -#endif - case CLOSURE_BSDF_TRANSLUCENT_ID: - eval = bsdf_translucent_eval_reflect(sc, sd->I, omega_in, pdf); - break; - case CLOSURE_BSDF_REFLECTION_ID: - eval = bsdf_reflection_eval_reflect(sc, sd->I, omega_in, pdf); - break; - case CLOSURE_BSDF_REFRACTION_ID: - eval = bsdf_refraction_eval_reflect(sc, sd->I, omega_in, pdf); - break; - case CLOSURE_BSDF_TRANSPARENT_ID: - 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; - 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; - case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: - eval = bsdf_ashikhmin_velvet_eval_reflect(sc, sd->I, omega_in, pdf); - break; - 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_PRINCIPLED_ID: - eval = bsdf_principled_hair_eval(kg, sd, sc, 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__ */ + case CLOSURE_BSDF_OREN_NAYAR_ID: + eval = bsdf_oren_nayar_eval_reflect(sc, sd->I, omega_in, pdf); + break; +# 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; +# endif + case CLOSURE_BSDF_TRANSLUCENT_ID: + eval = bsdf_translucent_eval_reflect(sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_REFLECTION_ID: + eval = bsdf_reflection_eval_reflect(sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_REFRACTION_ID: + eval = bsdf_refraction_eval_reflect(sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_TRANSPARENT_ID: + 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; + 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; + case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: + eval = bsdf_ashikhmin_velvet_eval_reflect(sc, sd->I, omega_in, pdf); + break; + 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_PRINCIPLED_ID: + eval = bsdf_principled_hair_eval(kg, sd, sc, 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_VOLUME_HENYEY_GREENSTEIN_ID: + eval = volume_henyey_greenstein_eval_phase(sc, sd->I, omega_in, pdf); + break; #endif - default: - eval = make_float3(0.0f, 0.0f, 0.0f); - break; - } - } - 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; + default: + eval = make_float3(0.0f, 0.0f, 0.0f); + break; + } + } + 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__ - case CLOSURE_BSDF_OREN_NAYAR_ID: - eval = bsdf_oren_nayar_eval_transmit(sc, sd->I, omega_in, pdf); - break; - case CLOSURE_BSDF_TRANSLUCENT_ID: - eval = bsdf_translucent_eval_transmit(sc, sd->I, omega_in, pdf); - break; - case CLOSURE_BSDF_REFLECTION_ID: - eval = bsdf_reflection_eval_transmit(sc, sd->I, omega_in, pdf); - break; - case CLOSURE_BSDF_REFRACTION_ID: - eval = bsdf_refraction_eval_transmit(sc, sd->I, omega_in, pdf); - break; - case CLOSURE_BSDF_TRANSPARENT_ID: - 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; - 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; - case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: - eval = bsdf_ashikhmin_velvet_eval_transmit(sc, sd->I, omega_in, pdf); - break; - 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_PRINCIPLED_ID: - eval = bsdf_principled_hair_eval(kg, sd, sc, 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__ */ + case CLOSURE_BSDF_OREN_NAYAR_ID: + eval = bsdf_oren_nayar_eval_transmit(sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_TRANSLUCENT_ID: + eval = bsdf_translucent_eval_transmit(sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_REFLECTION_ID: + eval = bsdf_reflection_eval_transmit(sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_REFRACTION_ID: + eval = bsdf_refraction_eval_transmit(sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_TRANSPARENT_ID: + 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; + 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; + case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: + eval = bsdf_ashikhmin_velvet_eval_transmit(sc, sd->I, omega_in, pdf); + break; + 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_PRINCIPLED_ID: + eval = bsdf_principled_hair_eval(kg, sd, sc, 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_VOLUME_HENYEY_GREENSTEIN_ID: + eval = volume_henyey_greenstein_eval_phase(sc, sd->I, omega_in, pdf); + break; #endif - default: - eval = make_float3(0.0f, 0.0f, 0.0f); - break; - } - } + default: + eval = make_float3(0.0f, 0.0f, 0.0f); + break; + } + } - return eval; + return eval; } ccl_device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness) { - /* ToDo: do we want to blur volume closures? */ + /* ToDo: do we want to blur volume closures? */ #ifdef __SVM__ - 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; - case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: - case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID: - bsdf_ashikhmin_shirley_blur(sc, roughness); - break; - case CLOSURE_BSDF_HAIR_PRINCIPLED_ID: - bsdf_principled_hair_blur(sc, roughness); - break; - default: - break; - } + 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; + case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: + case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID: + bsdf_ashikhmin_shirley_blur(sc, roughness); + break; + case CLOSURE_BSDF_HAIR_PRINCIPLED_ID: + bsdf_principled_hair_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: - 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: - return false; - } + 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: + 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: + return false; + } #else - return false; + return false; #endif } diff --git a/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h b/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h index 4e7425bd800..b3b1c37748d 100644 --- a/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h +++ b/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h @@ -33,203 +33,226 @@ CCL_NAMESPACE_BEGIN ccl_device int bsdf_ashikhmin_shirley_setup(MicrofacetBsdf *bsdf) { - bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); - bsdf->alpha_y = bsdf->alpha_x; + bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); + bsdf->alpha_y = bsdf->alpha_x; - bsdf->type = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL; + bsdf->type = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID; + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device int bsdf_ashikhmin_shirley_aniso_setup(MicrofacetBsdf *bsdf) { - bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); - bsdf->alpha_y = clamp(bsdf->alpha_y, 1e-4f, 1.0f); + bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); + bsdf->alpha_y = clamp(bsdf->alpha_y, 1e-4f, 1.0f); - bsdf->type = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL; + bsdf->type = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID; + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device void bsdf_ashikhmin_shirley_blur(ShaderClosure *sc, float roughness) { - MicrofacetBsdf *bsdf = (MicrofacetBsdf*)sc; + MicrofacetBsdf *bsdf = (MicrofacetBsdf *)sc; - bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x); - bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); + bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x); + bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); } ccl_device_inline float bsdf_ashikhmin_shirley_roughness_to_exponent(float roughness) { - return 2.0f / (roughness*roughness) - 2.0f; + return 2.0f / (roughness * roughness) - 2.0f; } -ccl_device_forceinline float3 bsdf_ashikhmin_shirley_eval_reflect( - const ShaderClosure *sc, - const float3 I, - const float3 omega_in, - float *pdf) +ccl_device_forceinline float3 bsdf_ashikhmin_shirley_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; - float3 N = bsdf->N; - - float NdotI = dot(N, I); /* in Cycles/OSL convention I is omega_out */ - float NdotO = dot(N, omega_in); /* and consequently we use for O omaga_in ;) */ - - float out = 0.0f; - - if(fmaxf(bsdf->alpha_x, bsdf->alpha_y) <= 1e-4f) - return make_float3(0.0f, 0.0f, 0.0f); - - if(NdotI > 0.0f && NdotO > 0.0f) { - NdotI = fmaxf(NdotI, 1e-6f); - NdotO = fmaxf(NdotO, 1e-6f); - float3 H = normalize(omega_in + I); - float HdotI = fmaxf(fabsf(dot(H, I)), 1e-6f); - float HdotN = fmaxf(dot(H, N), 1e-6f); - - float pump = 1.0f / fmaxf(1e-6f, (HdotI*fmaxf(NdotO, NdotI))); /* pump from original paper (first derivative disc., but cancels the HdotI in the pdf nicely) */ - /*float pump = 1.0f / fmaxf(1e-4f, ((NdotO + NdotI) * (NdotO*NdotI))); */ /* pump from d-brdf paper */ - - float n_x = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_x); - float n_y = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_y); - - if(n_x == n_y) { - /* isotropic */ - float e = n_x; - float lobe = powf(HdotN, e); - float norm = (n_x + 1.0f) / (8.0f * M_PI_F); - - out = NdotO * norm * lobe * pump; - *pdf = norm * lobe / HdotI; /* this is p_h / 4(H.I) (conversion from 'wh measure' to 'wi measure', eq. 8 in paper) */ - } - else { - /* anisotropic */ - float3 X, Y; - make_orthonormals_tangent(N, bsdf->T, &X, &Y); - - float HdotX = dot(H, X); - float HdotY = dot(H, Y); - float lobe; - if(HdotN < 1.0f) { - float e = (n_x * HdotX*HdotX + n_y * HdotY*HdotY) / (1.0f - HdotN*HdotN); - lobe = powf(HdotN, e); - } - else { - lobe = 1.0f; - } - float norm = sqrtf((n_x + 1.0f)*(n_y + 1.0f)) / (8.0f * M_PI_F); - - out = NdotO * norm * lobe * pump; - *pdf = norm * lobe / HdotI; - } - } - - return make_float3(out, out, out); + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; + float3 N = bsdf->N; + + float NdotI = dot(N, I); /* in Cycles/OSL convention I is omega_out */ + float NdotO = dot(N, omega_in); /* and consequently we use for O omaga_in ;) */ + + float out = 0.0f; + + if (fmaxf(bsdf->alpha_x, bsdf->alpha_y) <= 1e-4f) + return make_float3(0.0f, 0.0f, 0.0f); + + if (NdotI > 0.0f && NdotO > 0.0f) { + NdotI = fmaxf(NdotI, 1e-6f); + NdotO = fmaxf(NdotO, 1e-6f); + float3 H = normalize(omega_in + I); + float HdotI = fmaxf(fabsf(dot(H, I)), 1e-6f); + float HdotN = fmaxf(dot(H, N), 1e-6f); + + float pump = + 1.0f / + fmaxf( + 1e-6f, + (HdotI * + fmaxf( + NdotO, + NdotI))); /* pump from original paper (first derivative disc., but cancels the HdotI in the pdf nicely) */ + /*float pump = 1.0f / fmaxf(1e-4f, ((NdotO + NdotI) * (NdotO*NdotI))); */ /* pump from d-brdf paper */ + + float n_x = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_x); + float n_y = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_y); + + if (n_x == n_y) { + /* isotropic */ + float e = n_x; + float lobe = powf(HdotN, e); + float norm = (n_x + 1.0f) / (8.0f * M_PI_F); + + out = NdotO * norm * lobe * pump; + *pdf = + norm * lobe / + HdotI; /* this is p_h / 4(H.I) (conversion from 'wh measure' to 'wi measure', eq. 8 in paper) */ + } + else { + /* anisotropic */ + float3 X, Y; + make_orthonormals_tangent(N, bsdf->T, &X, &Y); + + float HdotX = dot(H, X); + float HdotY = dot(H, Y); + float lobe; + if (HdotN < 1.0f) { + float e = (n_x * HdotX * HdotX + n_y * HdotY * HdotY) / (1.0f - HdotN * HdotN); + lobe = powf(HdotN, e); + } + else { + lobe = 1.0f; + } + float norm = sqrtf((n_x + 1.0f) * (n_y + 1.0f)) / (8.0f * M_PI_F); + + out = NdotO * norm * lobe * pump; + *pdf = norm * lobe / HdotI; + } + } + + return make_float3(out, out, out); } -ccl_device float3 bsdf_ashikhmin_shirley_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_ashikhmin_shirley_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device_inline void bsdf_ashikhmin_shirley_sample_first_quadrant(float n_x, float n_y, float randu, float randv, float *phi, float *cos_theta) +ccl_device_inline void bsdf_ashikhmin_shirley_sample_first_quadrant( + float n_x, float n_y, float randu, float randv, float *phi, float *cos_theta) { - *phi = atanf(sqrtf((n_x + 1.0f) / (n_y + 1.0f)) * tanf(M_PI_2_F * randu)); - float cos_phi = cosf(*phi); - float sin_phi = sinf(*phi); - *cos_theta = powf(randv, 1.0f / (n_x * cos_phi*cos_phi + n_y * sin_phi*sin_phi + 1.0f)); + *phi = atanf(sqrtf((n_x + 1.0f) / (n_y + 1.0f)) * tanf(M_PI_2_F * randu)); + float cos_phi = cosf(*phi); + float sin_phi = sinf(*phi); + *cos_theta = powf(randv, 1.0f / (n_x * cos_phi * cos_phi + n_y * sin_phi * sin_phi + 1.0f)); } -ccl_device int bsdf_ashikhmin_shirley_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) +ccl_device int bsdf_ashikhmin_shirley_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) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; - float3 N = bsdf->N; - int label = LABEL_REFLECT | LABEL_GLOSSY; - - float NdotI = dot(N, I); - if(NdotI > 0.0f) { - - float n_x = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_x); - float n_y = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_y); - - /* get x,y basis on the surface for anisotropy */ - float3 X, Y; - - if(n_x == n_y) - make_orthonormals(N, &X, &Y); - else - make_orthonormals_tangent(N, bsdf->T, &X, &Y); - - /* sample spherical coords for h in tangent space */ - float phi; - float cos_theta; - if(n_x == n_y) { - /* isotropic sampling */ - phi = M_2PI_F * randu; - cos_theta = powf(randv, 1.0f / (n_x + 1.0f)); - } - else { - /* anisotropic sampling */ - if(randu < 0.25f) { /* first quadrant */ - float remapped_randu = 4.0f * randu; - bsdf_ashikhmin_shirley_sample_first_quadrant(n_x, n_y, remapped_randu, randv, &phi, &cos_theta); - } - else if(randu < 0.5f) { /* second quadrant */ - float remapped_randu = 4.0f * (.5f - randu); - bsdf_ashikhmin_shirley_sample_first_quadrant(n_x, n_y, remapped_randu, randv, &phi, &cos_theta); - phi = M_PI_F - phi; - } - else if(randu < 0.75f) { /* third quadrant */ - float remapped_randu = 4.0f * (randu - 0.5f); - bsdf_ashikhmin_shirley_sample_first_quadrant(n_x, n_y, remapped_randu, randv, &phi, &cos_theta); - phi = M_PI_F + phi; - } - else { /* fourth quadrant */ - float remapped_randu = 4.0f * (1.0f - randu); - bsdf_ashikhmin_shirley_sample_first_quadrant(n_x, n_y, remapped_randu, randv, &phi, &cos_theta); - phi = 2.0f * M_PI_F - phi; - } - } - - /* get half vector in tangent space */ - float sin_theta = sqrtf(fmaxf(0.0f, 1.0f - cos_theta*cos_theta)); - float cos_phi = cosf(phi); - float sin_phi = sinf(phi); /* no sqrt(1-cos^2) here b/c it causes artifacts */ - float3 h = make_float3( - sin_theta * cos_phi, - sin_theta * sin_phi, - cos_theta - ); - - /* half vector to world space */ - float3 H = h.x*X + h.y*Y + h.z*N; - float HdotI = dot(H, I); - if(HdotI < 0.0f) H = -H; - - /* reflect I on H to get omega_in */ - *omega_in = -I + (2.0f * HdotI) * H; - - if(fmaxf(bsdf->alpha_x, bsdf->alpha_y) <= 1e-4f) { - /* Some high number for MIS. */ - *pdf = 1e6f; - *eval = make_float3(1e6f, 1e6f, 1e6f); - label = LABEL_REFLECT | LABEL_SINGULAR; - } - else { - /* leave the rest to eval_reflect */ - *eval = bsdf_ashikhmin_shirley_eval_reflect(sc, I, *omega_in, pdf); - } + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; + float3 N = bsdf->N; + int label = LABEL_REFLECT | LABEL_GLOSSY; + + float NdotI = dot(N, I); + if (NdotI > 0.0f) { + + float n_x = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_x); + float n_y = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_y); + + /* get x,y basis on the surface for anisotropy */ + float3 X, Y; + + if (n_x == n_y) + make_orthonormals(N, &X, &Y); + else + make_orthonormals_tangent(N, bsdf->T, &X, &Y); + + /* sample spherical coords for h in tangent space */ + float phi; + float cos_theta; + if (n_x == n_y) { + /* isotropic sampling */ + phi = M_2PI_F * randu; + cos_theta = powf(randv, 1.0f / (n_x + 1.0f)); + } + else { + /* anisotropic sampling */ + if (randu < 0.25f) { /* first quadrant */ + float remapped_randu = 4.0f * randu; + bsdf_ashikhmin_shirley_sample_first_quadrant( + n_x, n_y, remapped_randu, randv, &phi, &cos_theta); + } + else if (randu < 0.5f) { /* second quadrant */ + float remapped_randu = 4.0f * (.5f - randu); + bsdf_ashikhmin_shirley_sample_first_quadrant( + n_x, n_y, remapped_randu, randv, &phi, &cos_theta); + phi = M_PI_F - phi; + } + else if (randu < 0.75f) { /* third quadrant */ + float remapped_randu = 4.0f * (randu - 0.5f); + bsdf_ashikhmin_shirley_sample_first_quadrant( + n_x, n_y, remapped_randu, randv, &phi, &cos_theta); + phi = M_PI_F + phi; + } + else { /* fourth quadrant */ + float remapped_randu = 4.0f * (1.0f - randu); + bsdf_ashikhmin_shirley_sample_first_quadrant( + n_x, n_y, remapped_randu, randv, &phi, &cos_theta); + phi = 2.0f * M_PI_F - phi; + } + } + + /* get half vector in tangent space */ + float sin_theta = sqrtf(fmaxf(0.0f, 1.0f - cos_theta * cos_theta)); + float cos_phi = cosf(phi); + float sin_phi = sinf(phi); /* no sqrt(1-cos^2) here b/c it causes artifacts */ + float3 h = make_float3(sin_theta * cos_phi, sin_theta * sin_phi, cos_theta); + + /* half vector to world space */ + float3 H = h.x * X + h.y * Y + h.z * N; + float HdotI = dot(H, I); + if (HdotI < 0.0f) + H = -H; + + /* reflect I on H to get omega_in */ + *omega_in = -I + (2.0f * HdotI) * H; + + if (fmaxf(bsdf->alpha_x, bsdf->alpha_y) <= 1e-4f) { + /* Some high number for MIS. */ + *pdf = 1e6f; + *eval = make_float3(1e6f, 1e6f, 1e6f); + label = LABEL_REFLECT | LABEL_SINGULAR; + } + else { + /* leave the rest to eval_reflect */ + *eval = bsdf_ashikhmin_shirley_eval_reflect(sc, I, *omega_in, pdf); + } #ifdef __RAY_DIFFERENTIALS__ - /* just do the reflection thing for now */ - *domega_in_dx = (2.0f * dot(N, dIdx)) * N - dIdx; - *domega_in_dy = (2.0f * dot(N, dIdy)) * N - dIdy; + /* just do the reflection thing for now */ + *domega_in_dx = (2.0f * dot(N, dIdx)) * N - dIdx; + *domega_in_dy = (2.0f * dot(N, dIdy)) * N - dIdy; #endif - } + } - return label; + return label; } - CCL_NAMESPACE_END -#endif /* __BSDF_ASHIKHMIN_SHIRLEY_H__ */ +#endif /* __BSDF_ASHIKHMIN_SHIRLEY_H__ */ diff --git a/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h b/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h index 80fd9ba2b37..8122bcc1424 100644 --- a/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h +++ b/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h @@ -36,126 +36,142 @@ CCL_NAMESPACE_BEGIN typedef ccl_addr_space struct VelvetBsdf { - SHADER_CLOSURE_BASE; + SHADER_CLOSURE_BASE; - float sigma; - float invsigma2; + float sigma; + float invsigma2; } VelvetBsdf; ccl_device int bsdf_ashikhmin_velvet_setup(VelvetBsdf *bsdf) { - float sigma = fmaxf(bsdf->sigma, 0.01f); - bsdf->invsigma2 = 1.0f/(sigma * sigma); + float sigma = fmaxf(bsdf->sigma, 0.01f); + bsdf->invsigma2 = 1.0f / (sigma * sigma); - bsdf->type = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID; + bsdf->type = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL; + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device bool bsdf_ashikhmin_velvet_merge(const ShaderClosure *a, const ShaderClosure *b) { - const VelvetBsdf *bsdf_a = (const VelvetBsdf*)a; - const VelvetBsdf *bsdf_b = (const VelvetBsdf*)b; + const VelvetBsdf *bsdf_a = (const VelvetBsdf *)a; + const VelvetBsdf *bsdf_b = (const VelvetBsdf *)b; - return (isequal_float3(bsdf_a->N, bsdf_b->N)) && - (bsdf_a->sigma == bsdf_b->sigma); + return (isequal_float3(bsdf_a->N, bsdf_b->N)) && (bsdf_a->sigma == bsdf_b->sigma); } -ccl_device float3 bsdf_ashikhmin_velvet_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_ashikhmin_velvet_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - const VelvetBsdf *bsdf = (const VelvetBsdf*)sc; - float m_invsigma2 = bsdf->invsigma2; - float3 N = bsdf->N; + const VelvetBsdf *bsdf = (const VelvetBsdf *)sc; + float m_invsigma2 = bsdf->invsigma2; + float3 N = bsdf->N; - float cosNO = dot(N, I); - float cosNI = dot(N, omega_in); - if(cosNO > 0 && cosNI > 0) { - float3 H = normalize(omega_in + I); + float cosNO = dot(N, I); + float cosNI = dot(N, omega_in); + if (cosNO > 0 && cosNI > 0) { + float3 H = normalize(omega_in + I); - float cosNH = dot(N, H); - float cosHO = fabsf(dot(I, H)); + float cosNH = dot(N, H); + float cosHO = fabsf(dot(I, H)); - if(!(fabsf(cosNH) < 1.0f-1e-5f && cosHO > 1e-5f)) - return make_float3(0.0f, 0.0f, 0.0f); + if (!(fabsf(cosNH) < 1.0f - 1e-5f && cosHO > 1e-5f)) + return make_float3(0.0f, 0.0f, 0.0f); - float cosNHdivHO = cosNH / cosHO; - cosNHdivHO = fmaxf(cosNHdivHO, 1e-5f); + float cosNHdivHO = cosNH / cosHO; + cosNHdivHO = fmaxf(cosNHdivHO, 1e-5f); - float fac1 = 2 * fabsf(cosNHdivHO * cosNO); - float fac2 = 2 * fabsf(cosNHdivHO * cosNI); + float fac1 = 2 * fabsf(cosNHdivHO * cosNO); + float fac2 = 2 * fabsf(cosNHdivHO * cosNI); - float sinNH2 = 1 - cosNH * cosNH; - float sinNH4 = sinNH2 * sinNH2; - float cotangent2 = (cosNH * cosNH) / sinNH2; + float sinNH2 = 1 - cosNH * cosNH; + float sinNH4 = sinNH2 * sinNH2; + float cotangent2 = (cosNH * cosNH) / sinNH2; - float D = expf(-cotangent2 * m_invsigma2) * m_invsigma2 * M_1_PI_F / sinNH4; - float G = min(1.0f, min(fac1, fac2)); // TODO: derive G from D analytically + float D = expf(-cotangent2 * m_invsigma2) * m_invsigma2 * M_1_PI_F / sinNH4; + float G = min(1.0f, min(fac1, fac2)); // TODO: derive G from D analytically - float out = 0.25f * (D * G) / cosNO; + float out = 0.25f * (D * G) / cosNO; - *pdf = 0.5f * M_1_PI_F; - return make_float3(out, out, out); - } + *pdf = 0.5f * M_1_PI_F; + return make_float3(out, out, out); + } - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device float3 bsdf_ashikhmin_velvet_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_ashikhmin_velvet_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device int bsdf_ashikhmin_velvet_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) +ccl_device int bsdf_ashikhmin_velvet_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) { - const VelvetBsdf *bsdf = (const VelvetBsdf*)sc; - float m_invsigma2 = bsdf->invsigma2; - float3 N = bsdf->N; + const VelvetBsdf *bsdf = (const VelvetBsdf *)sc; + float m_invsigma2 = bsdf->invsigma2; + float3 N = bsdf->N; - // we are viewing the surface from above - send a ray out with uniform - // distribution over the hemisphere - sample_uniform_hemisphere(N, randu, randv, omega_in, pdf); + // we are viewing the surface from above - send a ray out with uniform + // distribution over the hemisphere + sample_uniform_hemisphere(N, randu, randv, omega_in, pdf); - if(dot(Ng, *omega_in) > 0) { - float3 H = normalize(*omega_in + I); + if (dot(Ng, *omega_in) > 0) { + float3 H = normalize(*omega_in + I); - float cosNI = dot(N, *omega_in); - float cosNO = dot(N, I); - float cosNH = dot(N, H); - float cosHO = fabsf(dot(I, H)); + float cosNI = dot(N, *omega_in); + float cosNO = dot(N, I); + float cosNH = dot(N, H); + float cosHO = fabsf(dot(I, H)); - if(fabsf(cosNO) > 1e-5f && fabsf(cosNH) < 1.0f-1e-5f && cosHO > 1e-5f) { - float cosNHdivHO = cosNH / cosHO; - cosNHdivHO = fmaxf(cosNHdivHO, 1e-5f); + if (fabsf(cosNO) > 1e-5f && fabsf(cosNH) < 1.0f - 1e-5f && cosHO > 1e-5f) { + float cosNHdivHO = cosNH / cosHO; + cosNHdivHO = fmaxf(cosNHdivHO, 1e-5f); - float fac1 = 2 * fabsf(cosNHdivHO * cosNO); - float fac2 = 2 * fabsf(cosNHdivHO * cosNI); + float fac1 = 2 * fabsf(cosNHdivHO * cosNO); + float fac2 = 2 * fabsf(cosNHdivHO * cosNI); - float sinNH2 = 1 - cosNH * cosNH; - float sinNH4 = sinNH2 * sinNH2; - float cotangent2 = (cosNH * cosNH) / sinNH2; + float sinNH2 = 1 - cosNH * cosNH; + float sinNH4 = sinNH2 * sinNH2; + float cotangent2 = (cosNH * cosNH) / sinNH2; - float D = expf(-cotangent2 * m_invsigma2) * m_invsigma2 * M_1_PI_F / sinNH4; - float G = min(1.0f, min(fac1, fac2)); // TODO: derive G from D analytically + float D = expf(-cotangent2 * m_invsigma2) * m_invsigma2 * M_1_PI_F / sinNH4; + float G = min(1.0f, min(fac1, fac2)); // TODO: derive G from D analytically - float power = 0.25f * (D * G) / cosNO; + float power = 0.25f * (D * G) / cosNO; - *eval = make_float3(power, power, power); + *eval = make_float3(power, power, power); #ifdef __RAY_DIFFERENTIALS__ - // TODO: find a better approximation for the retroreflective bounce - *domega_in_dx = (2 * dot(N, dIdx)) * N - dIdx; - *domega_in_dy = (2 * dot(N, dIdy)) * N - dIdy; + // TODO: find a better approximation for the retroreflective bounce + *domega_in_dx = (2 * dot(N, dIdx)) * N - dIdx; + *domega_in_dy = (2 * dot(N, dIdy)) * N - dIdy; #endif - } - else - *pdf = 0.0f; - } - else - *pdf = 0.0f; - - return LABEL_REFLECT|LABEL_DIFFUSE; + } + else + *pdf = 0.0f; + } + else + *pdf = 0.0f; + + return LABEL_REFLECT | LABEL_DIFFUSE; } CCL_NAMESPACE_END -#endif /* __BSDF_ASHIKHMIN_VELVET_H__ */ +#endif /* __BSDF_ASHIKHMIN_VELVET_H__ */ diff --git a/intern/cycles/kernel/closure/bsdf_diffuse.h b/intern/cycles/kernel/closure/bsdf_diffuse.h index 946c460a70e..76b50548455 100644 --- a/intern/cycles/kernel/closure/bsdf_diffuse.h +++ b/intern/cycles/kernel/closure/bsdf_diffuse.h @@ -36,107 +36,141 @@ CCL_NAMESPACE_BEGIN typedef ccl_addr_space struct DiffuseBsdf { - SHADER_CLOSURE_BASE; + SHADER_CLOSURE_BASE; } DiffuseBsdf; /* DIFFUSE */ ccl_device int bsdf_diffuse_setup(DiffuseBsdf *bsdf) { - bsdf->type = CLOSURE_BSDF_DIFFUSE_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL; + bsdf->type = CLOSURE_BSDF_DIFFUSE_ID; + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device bool bsdf_diffuse_merge(const ShaderClosure *a, const ShaderClosure *b) { - const DiffuseBsdf *bsdf_a = (const DiffuseBsdf*)a; - const DiffuseBsdf *bsdf_b = (const DiffuseBsdf*)b; + const DiffuseBsdf *bsdf_a = (const DiffuseBsdf *)a; + const DiffuseBsdf *bsdf_b = (const DiffuseBsdf *)b; - return (isequal_float3(bsdf_a->N, bsdf_b->N)); + return (isequal_float3(bsdf_a->N, bsdf_b->N)); } -ccl_device float3 bsdf_diffuse_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_diffuse_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - const DiffuseBsdf *bsdf = (const DiffuseBsdf*)sc; - float3 N = bsdf->N; + const DiffuseBsdf *bsdf = (const DiffuseBsdf *)sc; + float3 N = bsdf->N; - float cos_pi = fmaxf(dot(N, omega_in), 0.0f) * M_1_PI_F; - *pdf = cos_pi; - return make_float3(cos_pi, cos_pi, cos_pi); + float cos_pi = fmaxf(dot(N, omega_in), 0.0f) * M_1_PI_F; + *pdf = cos_pi; + return make_float3(cos_pi, cos_pi, cos_pi); } -ccl_device float3 bsdf_diffuse_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_diffuse_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device int bsdf_diffuse_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) +ccl_device int bsdf_diffuse_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) { - const DiffuseBsdf *bsdf = (const DiffuseBsdf*)sc; - float3 N = bsdf->N; + const DiffuseBsdf *bsdf = (const DiffuseBsdf *)sc; + float3 N = bsdf->N; - // distribution over the hemisphere - sample_cos_hemisphere(N, randu, randv, omega_in, pdf); + // distribution over the hemisphere + sample_cos_hemisphere(N, randu, randv, omega_in, pdf); - if(dot(Ng, *omega_in) > 0.0f) { - *eval = make_float3(*pdf, *pdf, *pdf); + if (dot(Ng, *omega_in) > 0.0f) { + *eval = make_float3(*pdf, *pdf, *pdf); #ifdef __RAY_DIFFERENTIALS__ - // TODO: find a better approximation for the diffuse bounce - *domega_in_dx = (2 * dot(N, dIdx)) * N - dIdx; - *domega_in_dy = (2 * dot(N, dIdy)) * N - dIdy; + // TODO: find a better approximation for the diffuse bounce + *domega_in_dx = (2 * dot(N, dIdx)) * N - dIdx; + *domega_in_dy = (2 * dot(N, dIdy)) * N - dIdy; #endif - } - else - *pdf = 0.0f; + } + else + *pdf = 0.0f; - return LABEL_REFLECT|LABEL_DIFFUSE; + return LABEL_REFLECT | LABEL_DIFFUSE; } /* TRANSLUCENT */ ccl_device int bsdf_translucent_setup(DiffuseBsdf *bsdf) { - bsdf->type = CLOSURE_BSDF_TRANSLUCENT_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL; + bsdf->type = CLOSURE_BSDF_TRANSLUCENT_ID; + return SD_BSDF | SD_BSDF_HAS_EVAL; } -ccl_device float3 bsdf_translucent_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_translucent_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device float3 bsdf_translucent_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_translucent_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - const DiffuseBsdf *bsdf = (const DiffuseBsdf*)sc; - float3 N = bsdf->N; + const DiffuseBsdf *bsdf = (const DiffuseBsdf *)sc; + float3 N = bsdf->N; - float cos_pi = fmaxf(-dot(N, omega_in), 0.0f) * M_1_PI_F; - *pdf = cos_pi; - return make_float3 (cos_pi, cos_pi, cos_pi); + float cos_pi = fmaxf(-dot(N, omega_in), 0.0f) * M_1_PI_F; + *pdf = cos_pi; + return make_float3(cos_pi, cos_pi, cos_pi); } -ccl_device int bsdf_translucent_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) +ccl_device int bsdf_translucent_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) { - const DiffuseBsdf *bsdf = (const DiffuseBsdf*)sc; - float3 N = bsdf->N; - - // we are viewing the surface from the right side - send a ray out with cosine - // distribution over the hemisphere - sample_cos_hemisphere (-N, randu, randv, omega_in, pdf); - if(dot(Ng, *omega_in) < 0) { - *eval = make_float3(*pdf, *pdf, *pdf); + const DiffuseBsdf *bsdf = (const DiffuseBsdf *)sc; + float3 N = bsdf->N; + + // we are viewing the surface from the right side - send a ray out with cosine + // distribution over the hemisphere + sample_cos_hemisphere(-N, randu, randv, omega_in, pdf); + if (dot(Ng, *omega_in) < 0) { + *eval = make_float3(*pdf, *pdf, *pdf); #ifdef __RAY_DIFFERENTIALS__ - // TODO: find a better approximation for the diffuse bounce - *domega_in_dx = -((2 * dot(N, dIdx)) * N - dIdx); - *domega_in_dy = -((2 * dot(N, dIdy)) * N - dIdy); + // TODO: find a better approximation for the diffuse bounce + *domega_in_dx = -((2 * dot(N, dIdx)) * N - dIdx); + *domega_in_dy = -((2 * dot(N, dIdy)) * N - dIdy); #endif - } - else { - *pdf = 0; - } - return LABEL_TRANSMIT|LABEL_DIFFUSE; + } + else { + *pdf = 0; + } + return LABEL_TRANSMIT | LABEL_DIFFUSE; } CCL_NAMESPACE_END -#endif /* __BSDF_DIFFUSE_H__ */ +#endif /* __BSDF_DIFFUSE_H__ */ diff --git a/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h b/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h index ca33a5b275c..9d13eb8d4e0 100644 --- a/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h +++ b/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h @@ -38,73 +38,90 @@ CCL_NAMESPACE_BEGIN #ifdef __OSL__ typedef ccl_addr_space struct DiffuseRampBsdf { - SHADER_CLOSURE_BASE; + SHADER_CLOSURE_BASE; - float3 *colors; + float3 *colors; } DiffuseRampBsdf; ccl_device float3 bsdf_diffuse_ramp_get_color(const float3 colors[8], float pos) { - int MAXCOLORS = 8; - - float npos = pos * (float)(MAXCOLORS - 1); - int ipos = float_to_int(npos); - if(ipos < 0) - return colors[0]; - if(ipos >= (MAXCOLORS - 1)) - return colors[MAXCOLORS - 1]; - float offset = npos - (float)ipos; - return colors[ipos] * (1.0f - offset) + colors[ipos+1] * offset; + int MAXCOLORS = 8; + + float npos = pos * (float)(MAXCOLORS - 1); + int ipos = float_to_int(npos); + if (ipos < 0) + return colors[0]; + if (ipos >= (MAXCOLORS - 1)) + return colors[MAXCOLORS - 1]; + float offset = npos - (float)ipos; + return colors[ipos] * (1.0f - offset) + colors[ipos + 1] * offset; } ccl_device int bsdf_diffuse_ramp_setup(DiffuseRampBsdf *bsdf) { - bsdf->type = CLOSURE_BSDF_DIFFUSE_RAMP_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL; + bsdf->type = CLOSURE_BSDF_DIFFUSE_RAMP_ID; + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device void bsdf_diffuse_ramp_blur(ShaderClosure *sc, float roughness) { } -ccl_device float3 bsdf_diffuse_ramp_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_diffuse_ramp_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - const DiffuseRampBsdf *bsdf = (const DiffuseRampBsdf*)sc; - float3 N = bsdf->N; + const DiffuseRampBsdf *bsdf = (const DiffuseRampBsdf *)sc; + float3 N = bsdf->N; - float cos_pi = fmaxf(dot(N, omega_in), 0.0f); - *pdf = cos_pi * M_1_PI_F; - return bsdf_diffuse_ramp_get_color(bsdf->colors, cos_pi) * M_1_PI_F; + float cos_pi = fmaxf(dot(N, omega_in), 0.0f); + *pdf = cos_pi * M_1_PI_F; + return bsdf_diffuse_ramp_get_color(bsdf->colors, cos_pi) * M_1_PI_F; } -ccl_device float3 bsdf_diffuse_ramp_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_diffuse_ramp_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device int bsdf_diffuse_ramp_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) +ccl_device int bsdf_diffuse_ramp_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) { - const DiffuseRampBsdf *bsdf = (const DiffuseRampBsdf*)sc; - float3 N = bsdf->N; - - // distribution over the hemisphere - sample_cos_hemisphere(N, randu, randv, omega_in, pdf); - - if(dot(Ng, *omega_in) > 0.0f) { - *eval = bsdf_diffuse_ramp_get_color(bsdf->colors, *pdf * M_PI_F) * M_1_PI_F; -#ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = (2 * dot(N, dIdx)) * N - dIdx; - *domega_in_dy = (2 * dot(N, dIdy)) * N - dIdy; -#endif - } - else - *pdf = 0.0f; - - return LABEL_REFLECT|LABEL_DIFFUSE; + const DiffuseRampBsdf *bsdf = (const DiffuseRampBsdf *)sc; + float3 N = bsdf->N; + + // distribution over the hemisphere + sample_cos_hemisphere(N, randu, randv, omega_in, pdf); + + if (dot(Ng, *omega_in) > 0.0f) { + *eval = bsdf_diffuse_ramp_get_color(bsdf->colors, *pdf * M_PI_F) * M_1_PI_F; +# ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = (2 * dot(N, dIdx)) * N - dIdx; + *domega_in_dy = (2 * dot(N, dIdy)) * N - dIdy; +# endif + } + else + *pdf = 0.0f; + + return LABEL_REFLECT | LABEL_DIFFUSE; } -#endif /* __OSL__ */ +#endif /* __OSL__ */ CCL_NAMESPACE_END -#endif /* __BSDF_DIFFUSE_RAMP_H__ */ +#endif /* __BSDF_DIFFUSE_RAMP_H__ */ diff --git a/intern/cycles/kernel/closure/bsdf_hair.h b/intern/cycles/kernel/closure/bsdf_hair.h index e1a0cfaa3f5..6b2a9a97d30 100644 --- a/intern/cycles/kernel/closure/bsdf_hair.h +++ b/intern/cycles/kernel/closure/bsdf_hair.h @@ -36,245 +36,276 @@ CCL_NAMESPACE_BEGIN typedef ccl_addr_space struct HairBsdf { - SHADER_CLOSURE_BASE; + SHADER_CLOSURE_BASE; - float3 T; - float roughness1; - float roughness2; - float offset; + float3 T; + float roughness1; + float roughness2; + float offset; } HairBsdf; ccl_device int bsdf_hair_reflection_setup(HairBsdf *bsdf) { - bsdf->type = CLOSURE_BSDF_HAIR_REFLECTION_ID; - bsdf->roughness1 = clamp(bsdf->roughness1, 0.001f, 1.0f); - bsdf->roughness2 = clamp(bsdf->roughness2, 0.001f, 1.0f); - return SD_BSDF|SD_BSDF_HAS_EVAL; + bsdf->type = CLOSURE_BSDF_HAIR_REFLECTION_ID; + bsdf->roughness1 = clamp(bsdf->roughness1, 0.001f, 1.0f); + bsdf->roughness2 = clamp(bsdf->roughness2, 0.001f, 1.0f); + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device int bsdf_hair_transmission_setup(HairBsdf *bsdf) { - bsdf->type = CLOSURE_BSDF_HAIR_TRANSMISSION_ID; - bsdf->roughness1 = clamp(bsdf->roughness1, 0.001f, 1.0f); - bsdf->roughness2 = clamp(bsdf->roughness2, 0.001f, 1.0f); - return SD_BSDF|SD_BSDF_HAS_EVAL; + bsdf->type = CLOSURE_BSDF_HAIR_TRANSMISSION_ID; + bsdf->roughness1 = clamp(bsdf->roughness1, 0.001f, 1.0f); + bsdf->roughness2 = clamp(bsdf->roughness2, 0.001f, 1.0f); + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device bool bsdf_hair_merge(const ShaderClosure *a, const ShaderClosure *b) { - const HairBsdf *bsdf_a = (const HairBsdf*)a; - const HairBsdf *bsdf_b = (const HairBsdf*)b; + const HairBsdf *bsdf_a = (const HairBsdf *)a; + const HairBsdf *bsdf_b = (const HairBsdf *)b; - return (isequal_float3(bsdf_a->T, bsdf_b->T)) && - (bsdf_a->roughness1 == bsdf_b->roughness1) && - (bsdf_a->roughness2 == bsdf_b->roughness2) && - (bsdf_a->offset == bsdf_b->offset); + return (isequal_float3(bsdf_a->T, bsdf_b->T)) && (bsdf_a->roughness1 == bsdf_b->roughness1) && + (bsdf_a->roughness2 == bsdf_b->roughness2) && (bsdf_a->offset == bsdf_b->offset); } -ccl_device float3 bsdf_hair_reflection_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_hair_reflection_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - const HairBsdf *bsdf = (const HairBsdf*)sc; - float offset = bsdf->offset; - float3 Tg = bsdf->T; - float roughness1 = bsdf->roughness1; - float roughness2 = bsdf->roughness2; + const HairBsdf *bsdf = (const HairBsdf *)sc; + float offset = bsdf->offset; + float3 Tg = bsdf->T; + float roughness1 = bsdf->roughness1; + float roughness2 = bsdf->roughness2; - float Iz = dot(Tg, I); - float3 locy = normalize(I - Tg * Iz); + float Iz = dot(Tg, I); + float3 locy = normalize(I - Tg * Iz); - float theta_r = M_PI_2_F - fast_acosf(Iz); + float theta_r = M_PI_2_F - fast_acosf(Iz); - float omega_in_z = dot(Tg, omega_in); - float3 omega_in_y = normalize(omega_in - Tg * omega_in_z); + 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 - fast_acosf(omega_in_z); - float cosphi_i = dot(omega_in_y, locy); + float theta_i = M_PI_2_F - fast_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); - } + if (M_PI_2_F - fabsf(theta_i) < 0.001f || cosphi_i < 0.0f) { + *pdf = 0.0f; + return make_float3(*pdf, *pdf, *pdf); + } - float roughness1_inv = 1.0f / roughness1; - float roughness2_inv = 1.0f / roughness2; - float phi_i = fast_acosf(cosphi_i) * roughness2_inv; - phi_i = fabsf(phi_i) < M_PI_F ? phi_i : M_PI_F; - float costheta_i = fast_cosf(theta_i); + float roughness1_inv = 1.0f / roughness1; + float roughness2_inv = 1.0f / roughness2; + float phi_i = fast_acosf(cosphi_i) * roughness2_inv; + phi_i = fabsf(phi_i) < M_PI_F ? phi_i : M_PI_F; + float costheta_i = fast_cosf(theta_i); - float a_R = fast_atan2f(((M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f); - float b_R = fast_atan2f(((-M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f); + float a_R = fast_atan2f(((M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f); + float b_R = fast_atan2f(((-M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f); - float theta_h = (theta_i + theta_r) * 0.5f; - float t = theta_h - offset; + float theta_h = (theta_i + theta_r) * 0.5f; + float t = theta_h - offset; - float phi_pdf = fast_cosf(phi_i * 0.5f) * 0.25f * roughness2_inv; - float theta_pdf = roughness1 / (2 * (t*t + roughness1*roughness1) * (a_R - b_R)* costheta_i); - *pdf = phi_pdf * theta_pdf; + float phi_pdf = fast_cosf(phi_i * 0.5f) * 0.25f * roughness2_inv; + 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); + return make_float3(*pdf, *pdf, *pdf); } -ccl_device float3 bsdf_hair_transmission_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_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); + return make_float3(0.0f, 0.0f, 0.0f); } - -ccl_device float3 bsdf_hair_reflection_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_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); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device float3 bsdf_hair_transmission_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_hair_transmission_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - const HairBsdf *bsdf = (const HairBsdf*)sc; - float offset = bsdf->offset; - float3 Tg = bsdf->T; - float roughness1 = bsdf->roughness1; - float roughness2 = bsdf->roughness2; - float Iz = dot(Tg, I); - float3 locy = normalize(I - Tg * Iz); + const HairBsdf *bsdf = (const HairBsdf *)sc; + float offset = bsdf->offset; + float3 Tg = bsdf->T; + float roughness1 = bsdf->roughness1; + float roughness2 = bsdf->roughness2; + float Iz = dot(Tg, I); + float3 locy = normalize(I - Tg * Iz); - float theta_r = M_PI_2_F - fast_acosf(Iz); + float theta_r = M_PI_2_F - fast_acosf(Iz); - float omega_in_z = dot(Tg, omega_in); - float3 omega_in_y = normalize(omega_in - Tg * omega_in_z); + 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 - fast_acosf(omega_in_z); - float phi_i = fast_acosf(dot(omega_in_y, locy)); + float theta_i = M_PI_2_F - fast_acosf(omega_in_z); + float phi_i = fast_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); - } + if (M_PI_2_F - fabsf(theta_i) < 0.001f) { + *pdf = 0.0f; + return make_float3(*pdf, *pdf, *pdf); + } - float costheta_i = fast_cosf(theta_i); + float costheta_i = fast_cosf(theta_i); - float roughness1_inv = 1.0f / roughness1; - float a_TT = fast_atan2f(((M_PI_2_F + theta_r)/2 - offset) * roughness1_inv, 1.0f); - float b_TT = fast_atan2f(((-M_PI_2_F + theta_r)/2 - offset) * roughness1_inv, 1.0f); - float c_TT = 2 * fast_atan2f(M_PI_2_F / roughness2, 1.0f); + float roughness1_inv = 1.0f / roughness1; + float a_TT = fast_atan2f(((M_PI_2_F + theta_r) / 2 - offset) * roughness1_inv, 1.0f); + float b_TT = fast_atan2f(((-M_PI_2_F + theta_r) / 2 - offset) * roughness1_inv, 1.0f); + float c_TT = 2 * fast_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 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)); + 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); + *pdf = phi_pdf * theta_pdf; + return make_float3(*pdf, *pdf, *pdf); } -ccl_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) +ccl_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) { - const HairBsdf *bsdf = (const HairBsdf*)sc; - float offset = bsdf->offset; - float3 Tg = bsdf->T; - float roughness1 = bsdf->roughness1; - float roughness2 = bsdf->roughness2; - float Iz = dot(Tg, I); - float3 locy = normalize(I - Tg * Iz); - float3 locx = cross(locy, Tg); - float theta_r = M_PI_2_F - fast_acosf(Iz); + const HairBsdf *bsdf = (const HairBsdf *)sc; + float offset = bsdf->offset; + float3 Tg = bsdf->T; + float roughness1 = bsdf->roughness1; + float roughness2 = bsdf->roughness2; + float Iz = dot(Tg, I); + float3 locy = normalize(I - Tg * Iz); + float3 locx = cross(locy, Tg); + float theta_r = M_PI_2_F - fast_acosf(Iz); - float roughness1_inv = 1.0f / roughness1; - float a_R = fast_atan2f(((M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f); - float b_R = fast_atan2f(((-M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f); + float roughness1_inv = 1.0f / roughness1; + float a_R = fast_atan2f(((M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f); + float b_R = fast_atan2f(((-M_PI_2_F + theta_r) * 0.5f - offset) * roughness1_inv, 1.0f); - float t = roughness1 * tanf(randu * (a_R - b_R) + b_R); + 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 theta_h = t + offset; + float theta_i = 2 * theta_h - theta_r; - float costheta_i, sintheta_i; - fast_sincosf(theta_i, &sintheta_i, &costheta_i); + float costheta_i, sintheta_i; + fast_sincosf(theta_i, &sintheta_i, &costheta_i); - float phi = 2 * safe_asinf(1 - 2 * randv) * roughness2; + float phi = 2 * safe_asinf(1 - 2 * randv) * roughness2; - float phi_pdf = fast_cosf(phi * 0.5f) * 0.25f / roughness2; + float phi_pdf = fast_cosf(phi * 0.5f) * 0.25f / roughness2; - float theta_pdf = roughness1 / (2 * (t*t + roughness1*roughness1) * (a_R - b_R)*costheta_i); + float theta_pdf = roughness1 / + (2 * (t * t + roughness1 * roughness1) * (a_R - b_R) * costheta_i); - float sinphi, cosphi; - fast_sincosf(phi, &sinphi, &cosphi); - *omega_in =(cosphi * costheta_i) * locy - - (sinphi * costheta_i) * locx + - ( sintheta_i) * Tg; + float sinphi, cosphi; + fast_sincosf(phi, &sinphi, &cosphi); + *omega_in = (cosphi * costheta_i) * locy - (sinphi * costheta_i) * locx + (sintheta_i)*Tg; - //differentials - TODO: find a better approximation for the reflective bounce + //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; + *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; + *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); + *eval = make_float3(*pdf, *pdf, *pdf); - return LABEL_REFLECT|LABEL_GLOSSY; + return LABEL_REFLECT | LABEL_GLOSSY; } -ccl_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) +ccl_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) { - const HairBsdf *bsdf = (const HairBsdf*)sc; - float offset = bsdf->offset; - float3 Tg = bsdf->T; - float roughness1 = bsdf->roughness1; - float roughness2 = bsdf->roughness2; - float Iz = dot(Tg, I); - float3 locy = normalize(I - Tg * Iz); - float3 locx = cross(locy, Tg); - float theta_r = M_PI_2_F - fast_acosf(Iz); - - float roughness1_inv = 1.0f / roughness1; - float a_TT = fast_atan2f(((M_PI_2_F + theta_r)/2 - offset) * roughness1_inv, 1.0f); - float b_TT = fast_atan2f(((-M_PI_2_F + theta_r)/2 - offset) * roughness1_inv, 1.0f); - float c_TT = 2 * fast_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, sintheta_i; - fast_sincosf(theta_i, &sintheta_i, &costheta_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)); - - float sinphi, cosphi; - fast_sincosf(phi, &sinphi, &cosphi); - *omega_in =(cosphi * costheta_i) * locy - - (sinphi * costheta_i) * locx + - ( sintheta_i) * Tg; - - //differentials - TODO: find a better approximation for the transmission bounce + const HairBsdf *bsdf = (const HairBsdf *)sc; + float offset = bsdf->offset; + float3 Tg = bsdf->T; + float roughness1 = bsdf->roughness1; + float roughness2 = bsdf->roughness2; + float Iz = dot(Tg, I); + float3 locy = normalize(I - Tg * Iz); + float3 locx = cross(locy, Tg); + float theta_r = M_PI_2_F - fast_acosf(Iz); + + float roughness1_inv = 1.0f / roughness1; + float a_TT = fast_atan2f(((M_PI_2_F + theta_r) / 2 - offset) * roughness1_inv, 1.0f); + float b_TT = fast_atan2f(((-M_PI_2_F + theta_r) / 2 - offset) * roughness1_inv, 1.0f); + float c_TT = 2 * fast_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, sintheta_i; + fast_sincosf(theta_i, &sintheta_i, &costheta_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)); + + float sinphi, cosphi; + fast_sincosf(phi, &sinphi, &cosphi); + *omega_in = (cosphi * costheta_i) * locy - (sinphi * 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; + *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; - } + *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); + *eval = make_float3(*pdf, *pdf, *pdf); - /* TODO(sergey): Should always be negative, but seems some precision issue - * is involved here. - */ - kernel_assert(dot(locy, *omega_in) < 1e-4f); + /* TODO(sergey): Should always be negative, but seems some precision issue + * is involved here. + */ + kernel_assert(dot(locy, *omega_in) < 1e-4f); - return LABEL_TRANSMIT|LABEL_GLOSSY; + return LABEL_TRANSMIT | LABEL_GLOSSY; } CCL_NAMESPACE_END -#endif /* __BSDF_HAIR_H__ */ +#endif /* __BSDF_HAIR_H__ */ diff --git a/intern/cycles/kernel/closure/bsdf_hair_principled.h b/intern/cycles/kernel/closure/bsdf_hair_principled.h index 68335ee887a..a4bba2fbf6c 100644 --- a/intern/cycles/kernel/closure/bsdf_hair_principled.h +++ b/intern/cycles/kernel/closure/bsdf_hair_principled.h @@ -15,251 +15,245 @@ */ #ifdef __KERNEL_CPU__ -#include <fenv.h> +# include <fenv.h> #endif #include "kernel/kernel_color.h" #ifndef __BSDF_HAIR_PRINCIPLED_H__ -#define __BSDF_HAIR_PRINCIPLED_H__ +# define __BSDF_HAIR_PRINCIPLED_H__ CCL_NAMESPACE_BEGIN typedef ccl_addr_space struct PrincipledHairExtra { - /* Geometry data. */ - float4 geom; + /* Geometry data. */ + float4 geom; } PrincipledHairExtra; typedef ccl_addr_space struct PrincipledHairBSDF { - SHADER_CLOSURE_BASE; - - /* Absorption coefficient. */ - float3 sigma; - /* Variance of the underlying logistic distribution. */ - float v; - /* Scale factor of the underlying logistic distribution. */ - float s; - /* Cuticle tilt angle. */ - float alpha; - /* IOR. */ - float eta; - /* Effective variance for the diffuse bounce only. */ - float m0_roughness; - - /* Extra closure. */ - PrincipledHairExtra *extra; + SHADER_CLOSURE_BASE; + + /* Absorption coefficient. */ + float3 sigma; + /* Variance of the underlying logistic distribution. */ + float v; + /* Scale factor of the underlying logistic distribution. */ + float s; + /* Cuticle tilt angle. */ + float alpha; + /* IOR. */ + float eta; + /* Effective variance for the diffuse bounce only. */ + float m0_roughness; + + /* Extra closure. */ + PrincipledHairExtra *extra; } PrincipledHairBSDF; -static_assert(sizeof(ShaderClosure) >= sizeof(PrincipledHairBSDF), "PrincipledHairBSDF is too large!"); -static_assert(sizeof(ShaderClosure) >= sizeof(PrincipledHairExtra), "PrincipledHairExtra is too large!"); +static_assert(sizeof(ShaderClosure) >= sizeof(PrincipledHairBSDF), + "PrincipledHairBSDF is too large!"); +static_assert(sizeof(ShaderClosure) >= sizeof(PrincipledHairExtra), + "PrincipledHairExtra is too large!"); ccl_device_inline float cos_from_sin(const float s) { - return safe_sqrtf(1.0f - s*s); + return safe_sqrtf(1.0f - s * s); } /* Gives the change in direction in the normal plane for the given angles and p-th-order scattering. */ ccl_device_inline float delta_phi(int p, float gamma_o, float gamma_t) { - return 2.0f * p * gamma_t - 2.0f * gamma_o + p * M_PI_F; + return 2.0f * p * gamma_t - 2.0f * gamma_o + p * M_PI_F; } /* Remaps the given angle to [-pi, pi]. */ ccl_device_inline float wrap_angle(float a) { - while(a > M_PI_F) { - a -= M_2PI_F; - } - while(a < -M_PI_F) { - a += M_2PI_F; - } - return a; + while (a > M_PI_F) { + a -= M_2PI_F; + } + while (a < -M_PI_F) { + a += M_2PI_F; + } + return a; } /* Logistic distribution function. */ ccl_device_inline float logistic(float x, float s) { - float v = expf(-fabsf(x)/s); - return v / (s * sqr(1.0f + v)); + float v = expf(-fabsf(x) / s); + return v / (s * sqr(1.0f + v)); } /* Logistic cumulative density function. */ ccl_device_inline float logistic_cdf(float x, float s) { - float arg = -x/s; - /* expf() overflows if arg >= 89.0. */ - if(arg > 88.0f) { - return 0.0f; - } - else { - return 1.0f / (1.0f + expf(arg)); - } + float arg = -x / s; + /* expf() overflows if arg >= 89.0. */ + if (arg > 88.0f) { + return 0.0f; + } + else { + return 1.0f / (1.0f + expf(arg)); + } } /* Numerical approximation to the Bessel function of the first kind. */ ccl_device_inline float bessel_I0(float x) { - x = sqr(x); - float val = 1.0f + 0.25f*x; - float pow_x_2i = sqr(x); - uint64_t i_fac_2 = 1; - int pow_4_i = 16; - for(int i = 2; i < 10; i++) { - i_fac_2 *= i*i; - float newval = val + pow_x_2i / (pow_4_i * i_fac_2); - if(val == newval) { - return val; - } - val = newval; - pow_x_2i *= x; - pow_4_i *= 4; - } - return val; + x = sqr(x); + float val = 1.0f + 0.25f * x; + float pow_x_2i = sqr(x); + uint64_t i_fac_2 = 1; + int pow_4_i = 16; + for (int i = 2; i < 10; i++) { + i_fac_2 *= i * i; + float newval = val + pow_x_2i / (pow_4_i * i_fac_2); + if (val == newval) { + return val; + } + val = newval; + pow_x_2i *= x; + pow_4_i *= 4; + } + return val; } /* Logarithm of the Bessel function of the first kind. */ ccl_device_inline float log_bessel_I0(float x) { - if(x > 12.0f) { - /* log(1/x) == -log(x) iff x > 0. - * This is only used with positive cosines */ - return x + 0.5f * (1.f / (8.0f * x) - M_LN_2PI_F - logf(x)); - } - else { - return logf(bessel_I0(x)); - } + if (x > 12.0f) { + /* log(1/x) == -log(x) iff x > 0. + * This is only used with positive cosines */ + return x + 0.5f * (1.f / (8.0f * x) - M_LN_2PI_F - logf(x)); + } + else { + return logf(bessel_I0(x)); + } } /* Logistic distribution limited to the interval [-pi, pi]. */ ccl_device_inline float trimmed_logistic(float x, float s) { - /* The logistic distribution is symmetric and centered around zero, - * so logistic_cdf(x, s) = 1 - logistic_cdf(-x, s). - * Therefore, logistic_cdf(x, s)-logistic_cdf(-x, s) = 1 - 2*logistic_cdf(-x, s) */ - float scaling_fac = 1.0f - 2.0f*logistic_cdf(-M_PI_F, s); - float val = logistic(x, s); - return safe_divide(val, scaling_fac); + /* The logistic distribution is symmetric and centered around zero, + * so logistic_cdf(x, s) = 1 - logistic_cdf(-x, s). + * Therefore, logistic_cdf(x, s)-logistic_cdf(-x, s) = 1 - 2*logistic_cdf(-x, s) */ + float scaling_fac = 1.0f - 2.0f * logistic_cdf(-M_PI_F, s); + float val = logistic(x, s); + return safe_divide(val, scaling_fac); } /* Sampling function for the trimmed logistic function. */ ccl_device_inline float sample_trimmed_logistic(float u, float s) { - float cdf_minuspi = logistic_cdf(-M_PI_F, s); - float x = -s*logf(1.0f / (u*(1.0f - 2.0f*cdf_minuspi) + cdf_minuspi) - 1.0f); - return clamp(x, -M_PI_F, M_PI_F); + float cdf_minuspi = logistic_cdf(-M_PI_F, s); + float x = -s * logf(1.0f / (u * (1.0f - 2.0f * cdf_minuspi) + cdf_minuspi) - 1.0f); + return clamp(x, -M_PI_F, M_PI_F); } /* Azimuthal scattering function Np. */ -ccl_device_inline float azimuthal_scattering(float phi, - int p, - float s, - float gamma_o, - float gamma_t) +ccl_device_inline float azimuthal_scattering( + float phi, int p, float s, float gamma_o, float gamma_t) { - float phi_o = wrap_angle(phi - delta_phi(p, gamma_o, gamma_t)); - float val = trimmed_logistic(phi_o, s); - return val; + float phi_o = wrap_angle(phi - delta_phi(p, gamma_o, gamma_t)); + float val = trimmed_logistic(phi_o, s); + return val; } /* Longitudinal scattering function Mp. */ -ccl_device_inline float longitudinal_scattering(float sin_theta_i, - float cos_theta_i, - float sin_theta_o, - float cos_theta_o, - float v) +ccl_device_inline float longitudinal_scattering( + float sin_theta_i, float cos_theta_i, float sin_theta_o, float cos_theta_o, float v) { - float inv_v = 1.0f/v; - float cos_arg = cos_theta_i * cos_theta_o * inv_v; - float sin_arg = sin_theta_i * sin_theta_o * inv_v; - if(v <= 0.1f) { - float i0 = log_bessel_I0(cos_arg); - float val = expf(i0 - sin_arg - inv_v + 0.6931f + logf(0.5f*inv_v)); - return val; - } - else { - float i0 = bessel_I0(cos_arg); - float val = (expf(-sin_arg) * i0) / (sinhf(inv_v) * 2.0f * v); - return val; - } + float inv_v = 1.0f / v; + float cos_arg = cos_theta_i * cos_theta_o * inv_v; + float sin_arg = sin_theta_i * sin_theta_o * inv_v; + if (v <= 0.1f) { + float i0 = log_bessel_I0(cos_arg); + float val = expf(i0 - sin_arg - inv_v + 0.6931f + logf(0.5f * inv_v)); + return val; + } + else { + float i0 = bessel_I0(cos_arg); + float val = (expf(-sin_arg) * i0) / (sinhf(inv_v) * 2.0f * v); + return val; + } } /* Combine the three values using their luminances. */ ccl_device_inline float4 combine_with_energy(KernelGlobals *kg, float3 c) { - return make_float4(c.x, c.y, c.z, linear_rgb_to_gray(kg, c)); + return make_float4(c.x, c.y, c.z, linear_rgb_to_gray(kg, c)); } -#ifdef __HAIR__ +# ifdef __HAIR__ /* Set up the hair closure. */ ccl_device int bsdf_principled_hair_setup(ShaderData *sd, PrincipledHairBSDF *bsdf) { - bsdf->type = CLOSURE_BSDF_HAIR_PRINCIPLED_ID; - bsdf->v = clamp(bsdf->v, 0.001f, 1.0f); - bsdf->s = clamp(bsdf->s, 0.001f, 1.0f); - /* Apply Primary Reflection Roughness modifier. */ - bsdf->m0_roughness = clamp(bsdf->m0_roughness*bsdf->v, 0.001f, 1.0f); - - /* Map from roughness_u and roughness_v to variance and scale factor. */ - bsdf->v = sqr(0.726f*bsdf->v + 0.812f*sqr(bsdf->v) + 3.700f*pow20(bsdf->v)); - bsdf->s = (0.265f*bsdf->s + 1.194f*sqr(bsdf->s) + 5.372f*pow22(bsdf->s))*M_SQRT_PI_8_F; - bsdf->m0_roughness = sqr(0.726f*bsdf->m0_roughness + 0.812f*sqr(bsdf->m0_roughness) + 3.700f*pow20(bsdf->m0_roughness)); - - /* Compute local frame, aligned to curve tangent and ray direction. */ - float3 X = safe_normalize(sd->dPdu); - float3 Y = safe_normalize(cross(X, sd->I)); - float3 Z = safe_normalize(cross(X, Y)); - /* TODO: the solution below works where sd->Ng is the normal - * pointing from the center of the curve to the shading point. - * It doesn't work for triangles, see https://developer.blender.org/T43625 */ - - /* h -1..0..1 means the rays goes from grazing the hair, to hitting it at - * the center, to grazing the other edge. This is the sine of the angle - * between sd->Ng and Z, as seen from the tangent X. */ - - /* TODO: we convert this value to a cosine later and discard the sign, so - * we could probably save some operations. */ - float h = dot(cross(sd->Ng, X), Z); - - kernel_assert(fabsf(h) < 1.0f + 1e-4f); - kernel_assert(isfinite3_safe(Y)); - kernel_assert(isfinite_safe(h)); - - bsdf->extra->geom = make_float4(Y.x, Y.y, Y.z, h); - - return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG; + bsdf->type = CLOSURE_BSDF_HAIR_PRINCIPLED_ID; + bsdf->v = clamp(bsdf->v, 0.001f, 1.0f); + bsdf->s = clamp(bsdf->s, 0.001f, 1.0f); + /* Apply Primary Reflection Roughness modifier. */ + bsdf->m0_roughness = clamp(bsdf->m0_roughness * bsdf->v, 0.001f, 1.0f); + + /* Map from roughness_u and roughness_v to variance and scale factor. */ + bsdf->v = sqr(0.726f * bsdf->v + 0.812f * sqr(bsdf->v) + 3.700f * pow20(bsdf->v)); + bsdf->s = (0.265f * bsdf->s + 1.194f * sqr(bsdf->s) + 5.372f * pow22(bsdf->s)) * M_SQRT_PI_8_F; + bsdf->m0_roughness = sqr(0.726f * bsdf->m0_roughness + 0.812f * sqr(bsdf->m0_roughness) + + 3.700f * pow20(bsdf->m0_roughness)); + + /* Compute local frame, aligned to curve tangent and ray direction. */ + float3 X = safe_normalize(sd->dPdu); + float3 Y = safe_normalize(cross(X, sd->I)); + float3 Z = safe_normalize(cross(X, Y)); + /* TODO: the solution below works where sd->Ng is the normal + * pointing from the center of the curve to the shading point. + * It doesn't work for triangles, see https://developer.blender.org/T43625 */ + + /* h -1..0..1 means the rays goes from grazing the hair, to hitting it at + * the center, to grazing the other edge. This is the sine of the angle + * between sd->Ng and Z, as seen from the tangent X. */ + + /* TODO: we convert this value to a cosine later and discard the sign, so + * we could probably save some operations. */ + float h = dot(cross(sd->Ng, X), Z); + + kernel_assert(fabsf(h) < 1.0f + 1e-4f); + kernel_assert(isfinite3_safe(Y)); + kernel_assert(isfinite_safe(h)); + + bsdf->extra->geom = make_float4(Y.x, Y.y, Y.z, h); + + return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG; } -#endif /* __HAIR__ */ +# endif /* __HAIR__ */ /* Given the Fresnel term and transmittance, generate the attenuation terms for each bounce. */ -ccl_device_inline void hair_attenuation(KernelGlobals *kg, - float f, - float3 T, - float4 *Ap) +ccl_device_inline void hair_attenuation(KernelGlobals *kg, float f, float3 T, float4 *Ap) { - /* Primary specular (R). */ - Ap[0] = make_float4(f, f, f, f); + /* Primary specular (R). */ + Ap[0] = make_float4(f, f, f, f); - /* Transmission (TT). */ - float3 col = sqr(1.0f - f) * T; - Ap[1] = combine_with_energy(kg, col); + /* Transmission (TT). */ + float3 col = sqr(1.0f - f) * T; + Ap[1] = combine_with_energy(kg, col); - /* Secondary specular (TRT). */ - col *= T*f; - Ap[2] = combine_with_energy(kg, col); + /* Secondary specular (TRT). */ + col *= T * f; + Ap[2] = combine_with_energy(kg, col); - /* Residual component (TRRT+). */ - col *= safe_divide_color(T*f, make_float3(1.0f, 1.0f, 1.0f) - T*f); - Ap[3] = combine_with_energy(kg, col); + /* Residual component (TRRT+). */ + col *= safe_divide_color(T * f, make_float3(1.0f, 1.0f, 1.0f) - T * f); + Ap[3] = combine_with_energy(kg, col); - /* Normalize sampling weights. */ - float totweight = Ap[0].w + Ap[1].w + Ap[2].w + Ap[3].w; - float fac = safe_divide(1.0f, totweight); + /* Normalize sampling weights. */ + float totweight = Ap[0].w + Ap[1].w + Ap[2].w + Ap[3].w; + float fac = safe_divide(1.0f, totweight); - Ap[0].w *= fac; - Ap[1].w *= fac; - Ap[2].w *= fac; - Ap[3].w *= fac; + Ap[0].w *= fac; + Ap[1].w *= fac; + Ap[2].w *= fac; + Ap[3].w *= fac; } /* Given the tilt angle, generate the rotated theta_i for the different bounces. */ @@ -268,19 +262,19 @@ ccl_device_inline void hair_alpha_angles(float sin_theta_i, float alpha, float *angles) { - float sin_1alpha = sinf(alpha); - float cos_1alpha = cos_from_sin(sin_1alpha); - float sin_2alpha = 2.0f*sin_1alpha*cos_1alpha; - float cos_2alpha = sqr(cos_1alpha) - sqr(sin_1alpha); - float sin_4alpha = 2.0f*sin_2alpha*cos_2alpha; - float cos_4alpha = sqr(cos_2alpha) - sqr(sin_2alpha); - - angles[0] = sin_theta_i*cos_2alpha + cos_theta_i*sin_2alpha; - angles[1] = fabsf(cos_theta_i*cos_2alpha - sin_theta_i*sin_2alpha); - angles[2] = sin_theta_i*cos_1alpha - cos_theta_i*sin_1alpha; - angles[3] = fabsf(cos_theta_i*cos_1alpha + sin_theta_i*sin_1alpha); - angles[4] = sin_theta_i*cos_4alpha - cos_theta_i*sin_4alpha; - angles[5] = fabsf(cos_theta_i*cos_4alpha + sin_theta_i*sin_4alpha); + float sin_1alpha = sinf(alpha); + float cos_1alpha = cos_from_sin(sin_1alpha); + float sin_2alpha = 2.0f * sin_1alpha * cos_1alpha; + float cos_2alpha = sqr(cos_1alpha) - sqr(sin_1alpha); + float sin_4alpha = 2.0f * sin_2alpha * cos_2alpha; + float cos_4alpha = sqr(cos_2alpha) - sqr(sin_2alpha); + + angles[0] = sin_theta_i * cos_2alpha + cos_theta_i * sin_2alpha; + angles[1] = fabsf(cos_theta_i * cos_2alpha - sin_theta_i * sin_2alpha); + angles[2] = sin_theta_i * cos_1alpha - cos_theta_i * sin_1alpha; + angles[3] = fabsf(cos_theta_i * cos_1alpha + sin_theta_i * sin_1alpha); + angles[4] = sin_theta_i * cos_4alpha - cos_theta_i * sin_4alpha; + angles[5] = fabsf(cos_theta_i * cos_4alpha + sin_theta_i * sin_4alpha); } /* Evaluation function for our shader. */ @@ -290,75 +284,75 @@ ccl_device float3 bsdf_principled_hair_eval(KernelGlobals *kg, const float3 omega_in, float *pdf) { - kernel_assert(isfinite3_safe(sd->P) && isfinite_safe(sd->ray_length)); + kernel_assert(isfinite3_safe(sd->P) && isfinite_safe(sd->ray_length)); - const PrincipledHairBSDF *bsdf = (const PrincipledHairBSDF*) sc; - float3 Y = float4_to_float3(bsdf->extra->geom); + const PrincipledHairBSDF *bsdf = (const PrincipledHairBSDF *)sc; + float3 Y = float4_to_float3(bsdf->extra->geom); - float3 X = safe_normalize(sd->dPdu); - kernel_assert(fabsf(dot(X, Y)) < 1e-3f); - float3 Z = safe_normalize(cross(X, Y)); + float3 X = safe_normalize(sd->dPdu); + kernel_assert(fabsf(dot(X, Y)) < 1e-3f); + float3 Z = safe_normalize(cross(X, Y)); - float3 wo = make_float3(dot(sd->I, X), dot(sd->I, Y), dot(sd->I, Z)); - float3 wi = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + float3 wo = make_float3(dot(sd->I, X), dot(sd->I, Y), dot(sd->I, Z)); + float3 wi = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); - float sin_theta_o = wo.x; - float cos_theta_o = cos_from_sin(sin_theta_o); - float phi_o = atan2f(wo.z, wo.y); + float sin_theta_o = wo.x; + float cos_theta_o = cos_from_sin(sin_theta_o); + float phi_o = atan2f(wo.z, wo.y); - float sin_theta_t = sin_theta_o / bsdf->eta; - float cos_theta_t = cos_from_sin(sin_theta_t); + float sin_theta_t = sin_theta_o / bsdf->eta; + float cos_theta_t = cos_from_sin(sin_theta_t); - float sin_gamma_o = bsdf->extra->geom.w; - float cos_gamma_o = cos_from_sin(sin_gamma_o); - float gamma_o = safe_asinf(sin_gamma_o); + float sin_gamma_o = bsdf->extra->geom.w; + float cos_gamma_o = cos_from_sin(sin_gamma_o); + float gamma_o = safe_asinf(sin_gamma_o); - float sin_gamma_t = sin_gamma_o * cos_theta_o / sqrtf(sqr(bsdf->eta) - sqr(sin_theta_o)); - float cos_gamma_t = cos_from_sin(sin_gamma_t); - float gamma_t = safe_asinf(sin_gamma_t); + float sin_gamma_t = sin_gamma_o * cos_theta_o / sqrtf(sqr(bsdf->eta) - sqr(sin_theta_o)); + float cos_gamma_t = cos_from_sin(sin_gamma_t); + float gamma_t = safe_asinf(sin_gamma_t); - float3 T = exp3(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t)); - float4 Ap[4]; - hair_attenuation(kg, fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta), T, Ap); + float3 T = exp3(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t)); + float4 Ap[4]; + hair_attenuation(kg, fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta), T, Ap); - float sin_theta_i = wi.x; - float cos_theta_i = cos_from_sin(sin_theta_i); - float phi_i = atan2f(wi.z, wi.y); + float sin_theta_i = wi.x; + float cos_theta_i = cos_from_sin(sin_theta_i); + float phi_i = atan2f(wi.z, wi.y); - float phi = phi_i - phi_o; + float phi = phi_i - phi_o; - float angles[6]; - hair_alpha_angles(sin_theta_i, cos_theta_i, bsdf->alpha, angles); + float angles[6]; + hair_alpha_angles(sin_theta_i, cos_theta_i, bsdf->alpha, angles); - float4 F; - float Mp, Np; + float4 F; + float Mp, Np; - /* Primary specular (R). */ - Mp = longitudinal_scattering(angles[0], angles[1], sin_theta_o, cos_theta_o, bsdf->m0_roughness); - Np = azimuthal_scattering(phi, 0, bsdf->s, gamma_o, gamma_t); - F = Ap[0] * Mp * Np; - kernel_assert(isfinite3_safe(float4_to_float3(F))); + /* Primary specular (R). */ + Mp = longitudinal_scattering(angles[0], angles[1], sin_theta_o, cos_theta_o, bsdf->m0_roughness); + Np = azimuthal_scattering(phi, 0, bsdf->s, gamma_o, gamma_t); + F = Ap[0] * Mp * Np; + kernel_assert(isfinite3_safe(float4_to_float3(F))); - /* Transmission (TT). */ - Mp = longitudinal_scattering(angles[2], angles[3], sin_theta_o, cos_theta_o, 0.25f*bsdf->v); - Np = azimuthal_scattering(phi, 1, bsdf->s, gamma_o, gamma_t); - F += Ap[1] * Mp * Np; - kernel_assert(isfinite3_safe(float4_to_float3(F))); + /* Transmission (TT). */ + Mp = longitudinal_scattering(angles[2], angles[3], sin_theta_o, cos_theta_o, 0.25f * bsdf->v); + Np = azimuthal_scattering(phi, 1, bsdf->s, gamma_o, gamma_t); + F += Ap[1] * Mp * Np; + kernel_assert(isfinite3_safe(float4_to_float3(F))); - /* Secondary specular (TRT). */ - Mp = longitudinal_scattering(angles[4], angles[5], sin_theta_o, cos_theta_o, 4.0f*bsdf->v); - Np = azimuthal_scattering(phi, 2, bsdf->s, gamma_o, gamma_t); - F += Ap[2] * Mp * Np; - kernel_assert(isfinite3_safe(float4_to_float3(F))); + /* Secondary specular (TRT). */ + Mp = longitudinal_scattering(angles[4], angles[5], sin_theta_o, cos_theta_o, 4.0f * bsdf->v); + Np = azimuthal_scattering(phi, 2, bsdf->s, gamma_o, gamma_t); + F += Ap[2] * Mp * Np; + kernel_assert(isfinite3_safe(float4_to_float3(F))); - /* Residual component (TRRT+). */ - Mp = longitudinal_scattering(sin_theta_i, cos_theta_i, sin_theta_o, cos_theta_o, 4.0f*bsdf->v); - Np = M_1_2PI_F; - F += Ap[3] * Mp * Np; - kernel_assert(isfinite3_safe(float4_to_float3(F))); + /* Residual component (TRRT+). */ + Mp = longitudinal_scattering(sin_theta_i, cos_theta_i, sin_theta_o, cos_theta_o, 4.0f * bsdf->v); + Np = M_1_2PI_F; + F += Ap[3] * Mp * Np; + kernel_assert(isfinite3_safe(float4_to_float3(F))); - *pdf = F.w; - return float4_to_float3(F); + *pdf = F.w; + return float4_to_float3(F); } /* Sampling function for the hair shader. */ @@ -373,130 +367,131 @@ ccl_device int bsdf_principled_hair_sample(KernelGlobals *kg, float3 *domega_in_dy, float *pdf) { - PrincipledHairBSDF *bsdf = (PrincipledHairBSDF*) sc; - - float3 Y = float4_to_float3(bsdf->extra->geom); - - float3 X = safe_normalize(sd->dPdu); - kernel_assert(fabsf(dot(X, Y)) < 1e-3f); - float3 Z = safe_normalize(cross(X, Y)); - - float3 wo = make_float3(dot(sd->I, X), dot(sd->I, Y), dot(sd->I, Z)); - - float2 u[2]; - u[0] = make_float2(randu, randv); - u[1].x = lcg_step_float_addrspace(&sd->lcg_state); - u[1].y = lcg_step_float_addrspace(&sd->lcg_state); - - float sin_theta_o = wo.x; - float cos_theta_o = cos_from_sin(sin_theta_o); - float phi_o = atan2f(wo.z, wo.y); - - float sin_theta_t = sin_theta_o / bsdf->eta; - float cos_theta_t = cos_from_sin(sin_theta_t); - - float sin_gamma_o = bsdf->extra->geom.w; - float cos_gamma_o = cos_from_sin(sin_gamma_o); - float gamma_o = safe_asinf(sin_gamma_o); - - float sin_gamma_t = sin_gamma_o * cos_theta_o / sqrtf(sqr(bsdf->eta) - sqr(sin_theta_o)); - float cos_gamma_t = cos_from_sin(sin_gamma_t); - float gamma_t = safe_asinf(sin_gamma_t); - - float3 T = exp3(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t)); - float4 Ap[4]; - hair_attenuation(kg, fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta), T, Ap); - - int p = 0; - for(; p < 3; p++) { - if(u[0].x < Ap[p].w) { - break; - } - u[0].x -= Ap[p].w; - } - - float v = bsdf->v; - if(p == 1) { - v *= 0.25f; - } - if(p >= 2) { - v *= 4.0f; - } - - u[1].x = max(u[1].x, 1e-5f); - float fac = 1.0f + v*logf(u[1].x + (1.0f - u[1].x)*expf(-2.0f/v)); - float sin_theta_i = -fac * sin_theta_o + cos_from_sin(fac) * cosf(M_2PI_F * u[1].y) * cos_theta_o; - float cos_theta_i = cos_from_sin(sin_theta_i); - - float angles[6]; - if(p < 3) { - hair_alpha_angles(sin_theta_i, cos_theta_i, -bsdf->alpha, angles); - sin_theta_i = angles[2*p]; - cos_theta_i = angles[2*p+1]; - } - - float phi; - if(p < 3) { - phi = delta_phi(p, gamma_o, gamma_t) + sample_trimmed_logistic(u[0].y, bsdf->s); - } - else { - phi = M_2PI_F*u[0].y; - } - float phi_i = phi_o + phi; - - hair_alpha_angles(sin_theta_i, cos_theta_i, bsdf->alpha, angles); - - float4 F; - float Mp, Np; - - /* Primary specular (R). */ - Mp = longitudinal_scattering(angles[0], angles[1], sin_theta_o, cos_theta_o, bsdf->m0_roughness); - Np = azimuthal_scattering(phi, 0, bsdf->s, gamma_o, gamma_t); - F = Ap[0] * Mp * Np; - kernel_assert(isfinite3_safe(float4_to_float3(F))); - - /* Transmission (TT). */ - Mp = longitudinal_scattering(angles[2], angles[3], sin_theta_o, cos_theta_o, 0.25f*bsdf->v); - Np = azimuthal_scattering(phi, 1, bsdf->s, gamma_o, gamma_t); - F += Ap[1] * Mp * Np; - kernel_assert(isfinite3_safe(float4_to_float3(F))); - - /* Secondary specular (TRT). */ - Mp = longitudinal_scattering(angles[4], angles[5], sin_theta_o, cos_theta_o, 4.0f*bsdf->v); - Np = azimuthal_scattering(phi, 2, bsdf->s, gamma_o, gamma_t); - F += Ap[2] * Mp * Np; - kernel_assert(isfinite3_safe(float4_to_float3(F))); - - /* Residual component (TRRT+). */ - Mp = longitudinal_scattering(sin_theta_i, cos_theta_i, sin_theta_o, cos_theta_o, 4.0f*bsdf->v); - Np = M_1_2PI_F; - F += Ap[3] * Mp * Np; - kernel_assert(isfinite3_safe(float4_to_float3(F))); - - *eval = float4_to_float3(F); - *pdf = F.w; - - *omega_in = X*sin_theta_i + Y*cos_theta_i*cosf(phi_i) + Z*cos_theta_i*sinf(phi_i); - -#ifdef __RAY_DIFFERENTIALS__ - float3 N = safe_normalize(sd->I + *omega_in); - *domega_in_dx = (2 * dot(N, sd->dI.dx)) * N - sd->dI.dx; - *domega_in_dy = (2 * dot(N, sd->dI.dy)) * N - sd->dI.dy; -#endif - - return LABEL_GLOSSY|((p == 0)? LABEL_REFLECT : LABEL_TRANSMIT); + PrincipledHairBSDF *bsdf = (PrincipledHairBSDF *)sc; + + float3 Y = float4_to_float3(bsdf->extra->geom); + + float3 X = safe_normalize(sd->dPdu); + kernel_assert(fabsf(dot(X, Y)) < 1e-3f); + float3 Z = safe_normalize(cross(X, Y)); + + float3 wo = make_float3(dot(sd->I, X), dot(sd->I, Y), dot(sd->I, Z)); + + float2 u[2]; + u[0] = make_float2(randu, randv); + u[1].x = lcg_step_float_addrspace(&sd->lcg_state); + u[1].y = lcg_step_float_addrspace(&sd->lcg_state); + + float sin_theta_o = wo.x; + float cos_theta_o = cos_from_sin(sin_theta_o); + float phi_o = atan2f(wo.z, wo.y); + + float sin_theta_t = sin_theta_o / bsdf->eta; + float cos_theta_t = cos_from_sin(sin_theta_t); + + float sin_gamma_o = bsdf->extra->geom.w; + float cos_gamma_o = cos_from_sin(sin_gamma_o); + float gamma_o = safe_asinf(sin_gamma_o); + + float sin_gamma_t = sin_gamma_o * cos_theta_o / sqrtf(sqr(bsdf->eta) - sqr(sin_theta_o)); + float cos_gamma_t = cos_from_sin(sin_gamma_t); + float gamma_t = safe_asinf(sin_gamma_t); + + float3 T = exp3(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t)); + float4 Ap[4]; + hair_attenuation(kg, fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta), T, Ap); + + int p = 0; + for (; p < 3; p++) { + if (u[0].x < Ap[p].w) { + break; + } + u[0].x -= Ap[p].w; + } + + float v = bsdf->v; + if (p == 1) { + v *= 0.25f; + } + if (p >= 2) { + v *= 4.0f; + } + + u[1].x = max(u[1].x, 1e-5f); + float fac = 1.0f + v * logf(u[1].x + (1.0f - u[1].x) * expf(-2.0f / v)); + float sin_theta_i = -fac * sin_theta_o + + cos_from_sin(fac) * cosf(M_2PI_F * u[1].y) * cos_theta_o; + float cos_theta_i = cos_from_sin(sin_theta_i); + + float angles[6]; + if (p < 3) { + hair_alpha_angles(sin_theta_i, cos_theta_i, -bsdf->alpha, angles); + sin_theta_i = angles[2 * p]; + cos_theta_i = angles[2 * p + 1]; + } + + float phi; + if (p < 3) { + phi = delta_phi(p, gamma_o, gamma_t) + sample_trimmed_logistic(u[0].y, bsdf->s); + } + else { + phi = M_2PI_F * u[0].y; + } + float phi_i = phi_o + phi; + + hair_alpha_angles(sin_theta_i, cos_theta_i, bsdf->alpha, angles); + + float4 F; + float Mp, Np; + + /* Primary specular (R). */ + Mp = longitudinal_scattering(angles[0], angles[1], sin_theta_o, cos_theta_o, bsdf->m0_roughness); + Np = azimuthal_scattering(phi, 0, bsdf->s, gamma_o, gamma_t); + F = Ap[0] * Mp * Np; + kernel_assert(isfinite3_safe(float4_to_float3(F))); + + /* Transmission (TT). */ + Mp = longitudinal_scattering(angles[2], angles[3], sin_theta_o, cos_theta_o, 0.25f * bsdf->v); + Np = azimuthal_scattering(phi, 1, bsdf->s, gamma_o, gamma_t); + F += Ap[1] * Mp * Np; + kernel_assert(isfinite3_safe(float4_to_float3(F))); + + /* Secondary specular (TRT). */ + Mp = longitudinal_scattering(angles[4], angles[5], sin_theta_o, cos_theta_o, 4.0f * bsdf->v); + Np = azimuthal_scattering(phi, 2, bsdf->s, gamma_o, gamma_t); + F += Ap[2] * Mp * Np; + kernel_assert(isfinite3_safe(float4_to_float3(F))); + + /* Residual component (TRRT+). */ + Mp = longitudinal_scattering(sin_theta_i, cos_theta_i, sin_theta_o, cos_theta_o, 4.0f * bsdf->v); + Np = M_1_2PI_F; + F += Ap[3] * Mp * Np; + kernel_assert(isfinite3_safe(float4_to_float3(F))); + + *eval = float4_to_float3(F); + *pdf = F.w; + + *omega_in = X * sin_theta_i + Y * cos_theta_i * cosf(phi_i) + Z * cos_theta_i * sinf(phi_i); + +# ifdef __RAY_DIFFERENTIALS__ + float3 N = safe_normalize(sd->I + *omega_in); + *domega_in_dx = (2 * dot(N, sd->dI.dx)) * N - sd->dI.dx; + *domega_in_dy = (2 * dot(N, sd->dI.dy)) * N - sd->dI.dy; +# endif + + return LABEL_GLOSSY | ((p == 0) ? LABEL_REFLECT : LABEL_TRANSMIT); } /* Implements Filter Glossy by capping the effective roughness. */ ccl_device void bsdf_principled_hair_blur(ShaderClosure *sc, float roughness) { - PrincipledHairBSDF *bsdf = (PrincipledHairBSDF*)sc; + PrincipledHairBSDF *bsdf = (PrincipledHairBSDF *)sc; - bsdf->v = fmaxf(roughness, bsdf->v); - bsdf->s = fmaxf(roughness, bsdf->s); - bsdf->m0_roughness = fmaxf(roughness, bsdf->m0_roughness); + bsdf->v = fmaxf(roughness, bsdf->v); + bsdf->s = fmaxf(roughness, bsdf->s); + bsdf->m0_roughness = fmaxf(roughness, bsdf->m0_roughness); } CCL_NAMESPACE_END -#endif /* __BSDF_HAIR_PRINCIPLED_H__ */ +#endif /* __BSDF_HAIR_PRINCIPLED_H__ */ diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h index 32b6e50b09a..b4da3123f28 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet.h @@ -36,95 +36,98 @@ CCL_NAMESPACE_BEGIN typedef ccl_addr_space struct MicrofacetExtra { - float3 color, cspec0; - float clearcoat; + float3 color, cspec0; + float clearcoat; } MicrofacetExtra; typedef ccl_addr_space struct MicrofacetBsdf { - SHADER_CLOSURE_BASE; + SHADER_CLOSURE_BASE; - float alpha_x, alpha_y, ior; - MicrofacetExtra *extra; - float3 T; + float alpha_x, alpha_y, ior; + MicrofacetExtra *extra; + float3 T; } MicrofacetBsdf; /* Beckmann and GGX microfacet importance sampling. */ -ccl_device_inline void microfacet_beckmann_sample_slopes( - KernelGlobals *kg, - const float cos_theta_i, const float sin_theta_i, - float randu, float randv, float *slope_x, float *slope_y, - float *G1i) +ccl_device_inline void microfacet_beckmann_sample_slopes(KernelGlobals *kg, + const float cos_theta_i, + const float sin_theta_i, + float randu, + float randv, + float *slope_x, + float *slope_y, + float *G1i) { - /* special case (normal incidence) */ - if(cos_theta_i >= 0.99999f) { - const float r = sqrtf(-logf(randu)); - const float phi = M_2PI_F * randv; - *slope_x = r * cosf(phi); - *slope_y = r * sinf(phi); - *G1i = 1.0f; - return; - } - - /* precomputations */ - const float tan_theta_i = sin_theta_i/cos_theta_i; - const float inv_a = tan_theta_i; - const float cot_theta_i = 1.0f/tan_theta_i; - const float erf_a = fast_erff(cot_theta_i); - const float exp_a2 = expf(-cot_theta_i*cot_theta_i); - const float SQRT_PI_INV = 0.56418958354f; - const float Lambda = 0.5f*(erf_a - 1.0f) + (0.5f*SQRT_PI_INV)*(exp_a2*inv_a); - const float G1 = 1.0f/(1.0f + Lambda); /* masking */ - - *G1i = G1; + /* special case (normal incidence) */ + if (cos_theta_i >= 0.99999f) { + const float r = sqrtf(-logf(randu)); + const float phi = M_2PI_F * randv; + *slope_x = r * cosf(phi); + *slope_y = r * sinf(phi); + *G1i = 1.0f; + return; + } + + /* precomputations */ + const float tan_theta_i = sin_theta_i / cos_theta_i; + const float inv_a = tan_theta_i; + const float cot_theta_i = 1.0f / tan_theta_i; + const float erf_a = fast_erff(cot_theta_i); + const float exp_a2 = expf(-cot_theta_i * cot_theta_i); + const float SQRT_PI_INV = 0.56418958354f; + const float Lambda = 0.5f * (erf_a - 1.0f) + (0.5f * SQRT_PI_INV) * (exp_a2 * inv_a); + const float G1 = 1.0f / (1.0f + Lambda); /* masking */ + + *G1i = G1; #if defined(__KERNEL_GPU__) - /* Based on paper from Wenzel Jakob - * An Improved Visible Normal Sampling Routine for the Beckmann Distribution - * - * http://www.mitsuba-renderer.org/~wenzel/files/visnormal.pdf - * - * Reformulation from OpenShadingLanguage which avoids using inverse - * trigonometric functions. - */ - - /* Sample slope X. - * - * Compute a coarse approximation using the approximation: - * exp(-ierf(x)^2) ~= 1 - x * x - * solve y = 1 + b + K * (1 - b * b) - */ - float K = tan_theta_i * SQRT_PI_INV; - float y_approx = randu * (1.0f + erf_a + K * (1 - erf_a * erf_a)); - float y_exact = randu * (1.0f + erf_a + K * exp_a2); - float b = K > 0 ? (0.5f - sqrtf(K * (K - y_approx + 1.0f) + 0.25f)) / K : y_approx - 1.0f; - - /* Perform newton step to refine toward the true root. */ - float inv_erf = fast_ierff(b); - float value = 1.0f + b + K * expf(-inv_erf * inv_erf) - y_exact; - /* Check if we are close enough already, - * this also avoids NaNs as we get close to the root. - */ - if(fabsf(value) > 1e-6f) { - b -= value / (1.0f - inv_erf * tan_theta_i); /* newton step 1. */ - inv_erf = fast_ierff(b); - value = 1.0f + b + K * expf(-inv_erf * inv_erf) - y_exact; - b -= value / (1.0f - inv_erf * tan_theta_i); /* newton step 2. */ - /* Compute the slope from the refined value. */ - *slope_x = fast_ierff(b); - } - else { - /* We are close enough already. */ - *slope_x = inv_erf; - } - *slope_y = fast_ierff(2.0f*randv - 1.0f); + /* Based on paper from Wenzel Jakob + * An Improved Visible Normal Sampling Routine for the Beckmann Distribution + * + * http://www.mitsuba-renderer.org/~wenzel/files/visnormal.pdf + * + * Reformulation from OpenShadingLanguage which avoids using inverse + * trigonometric functions. + */ + + /* Sample slope X. + * + * Compute a coarse approximation using the approximation: + * exp(-ierf(x)^2) ~= 1 - x * x + * solve y = 1 + b + K * (1 - b * b) + */ + float K = tan_theta_i * SQRT_PI_INV; + float y_approx = randu * (1.0f + erf_a + K * (1 - erf_a * erf_a)); + float y_exact = randu * (1.0f + erf_a + K * exp_a2); + float b = K > 0 ? (0.5f - sqrtf(K * (K - y_approx + 1.0f) + 0.25f)) / K : y_approx - 1.0f; + + /* Perform newton step to refine toward the true root. */ + float inv_erf = fast_ierff(b); + float value = 1.0f + b + K * expf(-inv_erf * inv_erf) - y_exact; + /* Check if we are close enough already, + * this also avoids NaNs as we get close to the root. + */ + if (fabsf(value) > 1e-6f) { + b -= value / (1.0f - inv_erf * tan_theta_i); /* newton step 1. */ + inv_erf = fast_ierff(b); + value = 1.0f + b + K * expf(-inv_erf * inv_erf) - y_exact; + b -= value / (1.0f - inv_erf * tan_theta_i); /* newton step 2. */ + /* Compute the slope from the refined value. */ + *slope_x = fast_ierff(b); + } + else { + /* We are close enough already. */ + *slope_x = inv_erf; + } + *slope_y = fast_ierff(2.0f * randv - 1.0f); #else - /* Use precomputed table on CPU, it gives better perfomance. */ - int beckmann_table_offset = kernel_data.tables.beckmann_offset; + /* Use precomputed table on CPU, it gives better perfomance. */ + int beckmann_table_offset = kernel_data.tables.beckmann_offset; - *slope_x = lookup_table_read_2D(kg, randu, cos_theta_i, - beckmann_table_offset, BECKMANN_TABLE_SIZE, BECKMANN_TABLE_SIZE); - *slope_y = fast_ierff(2.0f*randv - 1.0f); + *slope_x = lookup_table_read_2D( + kg, randu, cos_theta_i, beckmann_table_offset, BECKMANN_TABLE_SIZE, BECKMANN_TABLE_SIZE); + *slope_y = fast_ierff(2.0f * randv - 1.0f); #endif } @@ -134,103 +137,109 @@ ccl_device_inline void microfacet_beckmann_sample_slopes( * E. Heitz and E. d'Eon, EGSR 2014 */ -ccl_device_inline void microfacet_ggx_sample_slopes( - const float cos_theta_i, const float sin_theta_i, - float randu, float randv, float *slope_x, float *slope_y, - float *G1i) +ccl_device_inline void microfacet_ggx_sample_slopes(const float cos_theta_i, + const float sin_theta_i, + float randu, + float randv, + float *slope_x, + float *slope_y, + float *G1i) { - /* special case (normal incidence) */ - if(cos_theta_i >= 0.99999f) { - const float r = sqrtf(randu/(1.0f - randu)); - const float phi = M_2PI_F * randv; - *slope_x = r * cosf(phi); - *slope_y = r * sinf(phi); - *G1i = 1.0f; - - return; - } - - /* precomputations */ - const float tan_theta_i = sin_theta_i/cos_theta_i; - const float G1_inv = 0.5f * (1.0f + safe_sqrtf(1.0f + tan_theta_i*tan_theta_i)); - - *G1i = 1.0f/G1_inv; - - /* sample slope_x */ - const float A = 2.0f*randu*G1_inv - 1.0f; - const float AA = A*A; - const float tmp = 1.0f/(AA - 1.0f); - const float B = tan_theta_i; - const float BB = B*B; - const float D = safe_sqrtf(BB*(tmp*tmp) - (AA - BB)*tmp); - const float slope_x_1 = B*tmp - D; - const float slope_x_2 = B*tmp + D; - *slope_x = (A < 0.0f || slope_x_2*tan_theta_i > 1.0f)? slope_x_1: slope_x_2; - - /* sample slope_y */ - float S; - - if(randv > 0.5f) { - S = 1.0f; - randv = 2.0f*(randv - 0.5f); - } - else { - S = -1.0f; - randv = 2.0f*(0.5f - randv); - } - - const float z = (randv*(randv*(randv*0.27385f - 0.73369f) + 0.46341f)) / (randv*(randv*(randv*0.093073f + 0.309420f) - 1.000000f) + 0.597999f); - *slope_y = S * z * safe_sqrtf(1.0f + (*slope_x)*(*slope_x)); + /* special case (normal incidence) */ + if (cos_theta_i >= 0.99999f) { + const float r = sqrtf(randu / (1.0f - randu)); + const float phi = M_2PI_F * randv; + *slope_x = r * cosf(phi); + *slope_y = r * sinf(phi); + *G1i = 1.0f; + + return; + } + + /* precomputations */ + const float tan_theta_i = sin_theta_i / cos_theta_i; + const float G1_inv = 0.5f * (1.0f + safe_sqrtf(1.0f + tan_theta_i * tan_theta_i)); + + *G1i = 1.0f / G1_inv; + + /* sample slope_x */ + const float A = 2.0f * randu * G1_inv - 1.0f; + const float AA = A * A; + const float tmp = 1.0f / (AA - 1.0f); + const float B = tan_theta_i; + const float BB = B * B; + const float D = safe_sqrtf(BB * (tmp * tmp) - (AA - BB) * tmp); + const float slope_x_1 = B * tmp - D; + const float slope_x_2 = B * tmp + D; + *slope_x = (A < 0.0f || slope_x_2 * tan_theta_i > 1.0f) ? slope_x_1 : slope_x_2; + + /* sample slope_y */ + float S; + + if (randv > 0.5f) { + S = 1.0f; + randv = 2.0f * (randv - 0.5f); + } + else { + S = -1.0f; + randv = 2.0f * (0.5f - randv); + } + + const float z = (randv * (randv * (randv * 0.27385f - 0.73369f) + 0.46341f)) / + (randv * (randv * (randv * 0.093073f + 0.309420f) - 1.000000f) + 0.597999f); + *slope_y = S * z * safe_sqrtf(1.0f + (*slope_x) * (*slope_x)); } -ccl_device_forceinline float3 microfacet_sample_stretched( - KernelGlobals *kg, const float3 omega_i, - const float alpha_x, const float alpha_y, - const float randu, const float randv, - bool beckmann, float *G1i) +ccl_device_forceinline float3 microfacet_sample_stretched(KernelGlobals *kg, + const float3 omega_i, + const float alpha_x, + const float alpha_y, + const float randu, + const float randv, + bool beckmann, + float *G1i) { - /* 1. stretch omega_i */ - float3 omega_i_ = make_float3(alpha_x * omega_i.x, alpha_y * omega_i.y, omega_i.z); - omega_i_ = normalize(omega_i_); - - /* get polar coordinates of omega_i_ */ - float costheta_ = 1.0f; - float sintheta_ = 0.0f; - float cosphi_ = 1.0f; - float sinphi_ = 0.0f; - - if(omega_i_.z < 0.99999f) { - costheta_ = omega_i_.z; - sintheta_ = safe_sqrtf(1.0f - costheta_*costheta_); - - float invlen = 1.0f/sintheta_; - cosphi_ = omega_i_.x * invlen; - sinphi_ = omega_i_.y * invlen; - } - - /* 2. sample P22_{omega_i}(x_slope, y_slope, 1, 1) */ - float slope_x, slope_y; - - if(beckmann) { - microfacet_beckmann_sample_slopes(kg, costheta_, sintheta_, - randu, randv, &slope_x, &slope_y, G1i); - } - else { - microfacet_ggx_sample_slopes(costheta_, sintheta_, - randu, randv, &slope_x, &slope_y, G1i); - } - - /* 3. rotate */ - float tmp = cosphi_*slope_x - sinphi_*slope_y; - slope_y = sinphi_*slope_x + cosphi_*slope_y; - slope_x = tmp; - - /* 4. unstretch */ - slope_x = alpha_x * slope_x; - slope_y = alpha_y * slope_y; - - /* 5. compute normal */ - return normalize(make_float3(-slope_x, -slope_y, 1.0f)); + /* 1. stretch omega_i */ + float3 omega_i_ = make_float3(alpha_x * omega_i.x, alpha_y * omega_i.y, omega_i.z); + omega_i_ = normalize(omega_i_); + + /* get polar coordinates of omega_i_ */ + float costheta_ = 1.0f; + float sintheta_ = 0.0f; + float cosphi_ = 1.0f; + float sinphi_ = 0.0f; + + if (omega_i_.z < 0.99999f) { + costheta_ = omega_i_.z; + sintheta_ = safe_sqrtf(1.0f - costheta_ * costheta_); + + float invlen = 1.0f / sintheta_; + cosphi_ = omega_i_.x * invlen; + sinphi_ = omega_i_.y * invlen; + } + + /* 2. sample P22_{omega_i}(x_slope, y_slope, 1, 1) */ + float slope_x, slope_y; + + if (beckmann) { + microfacet_beckmann_sample_slopes( + kg, costheta_, sintheta_, randu, randv, &slope_x, &slope_y, G1i); + } + else { + microfacet_ggx_sample_slopes(costheta_, sintheta_, randu, randv, &slope_x, &slope_y, G1i); + } + + /* 3. rotate */ + float tmp = cosphi_ * slope_x - sinphi_ * slope_y; + slope_y = sinphi_ * slope_x + cosphi_ * slope_y; + slope_x = tmp; + + /* 4. unstretch */ + slope_x = alpha_x * slope_x; + slope_y = alpha_y * slope_y; + + /* 5. compute normal */ + return normalize(make_float3(-slope_x, -slope_y, 1.0f)); } /* Calculate the reflection color @@ -240,27 +249,29 @@ ccl_device_forceinline float3 microfacet_sample_stretched( * * Else it is simply white */ -ccl_device_forceinline float3 reflection_color(const MicrofacetBsdf *bsdf, float3 L, float3 H) { - float3 F = make_float3(1.0f, 1.0f, 1.0f); - bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID - || bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID - || bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID); +ccl_device_forceinline float3 reflection_color(const MicrofacetBsdf *bsdf, float3 L, float3 H) +{ + float3 F = make_float3(1.0f, 1.0f, 1.0f); + bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID || + bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID || + bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID); - if(use_fresnel) { - float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); + if (use_fresnel) { + float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); - F = interpolate_fresnel_color(L, H, bsdf->ior, F0, bsdf->extra->cspec0); - } + F = interpolate_fresnel_color(L, H, bsdf->ior, F0, bsdf->extra->cspec0); + } - return F; + return F; } ccl_device_forceinline float D_GTR1(float NdotH, float alpha) { - if(alpha >= 1.0f) return M_1_PI_F; - float alpha2 = alpha*alpha; - float t = 1.0f + (alpha2 - 1.0f) * NdotH*NdotH; - return (alpha2 - 1.0f) / (M_PI_F * logf(alpha2) * t); + if (alpha >= 1.0f) + return M_1_PI_F; + float alpha2 = alpha * alpha; + float t = 1.0f + (alpha2 - 1.0f) * NdotH * NdotH; + return (alpha2 - 1.0f) / (M_PI_F * logf(alpha2) * t); } /* GGX microfacet with Smith shadow-masking from: @@ -278,483 +289,511 @@ ccl_device_forceinline float D_GTR1(float NdotH, float alpha) ccl_device int bsdf_microfacet_ggx_setup(MicrofacetBsdf *bsdf) { - bsdf->extra = NULL; + bsdf->extra = NULL; - bsdf->alpha_x = saturate(bsdf->alpha_x); - bsdf->alpha_y = bsdf->alpha_x; + bsdf->alpha_x = saturate(bsdf->alpha_x); + bsdf->alpha_y = bsdf->alpha_x; - bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL; + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device int bsdf_microfacet_ggx_fresnel_setup(MicrofacetBsdf *bsdf, const ShaderData *sd) { - bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); - bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); - bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); + bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); + bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); + bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); - float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); - float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0)); - bsdf->sample_weight *= F; + float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); + float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0)); + bsdf->sample_weight *= F; - bsdf->alpha_x = saturate(bsdf->alpha_x); - bsdf->alpha_y = bsdf->alpha_x; + bsdf->alpha_x = saturate(bsdf->alpha_x); + bsdf->alpha_y = bsdf->alpha_x; - bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL; + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device int bsdf_microfacet_ggx_clearcoat_setup(MicrofacetBsdf *bsdf, const ShaderData *sd) { - bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); - bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); - bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); + bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); + bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); + bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); - float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); - float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0)); - bsdf->sample_weight *= 0.25f * bsdf->extra->clearcoat * F; + float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); + float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0)); + bsdf->sample_weight *= 0.25f * bsdf->extra->clearcoat * F; - bsdf->alpha_x = saturate(bsdf->alpha_x); - bsdf->alpha_y = bsdf->alpha_x; + bsdf->alpha_x = saturate(bsdf->alpha_x); + bsdf->alpha_y = bsdf->alpha_x; - bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL; + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device bool bsdf_microfacet_merge(const ShaderClosure *a, const ShaderClosure *b) { - const MicrofacetBsdf *bsdf_a = (const MicrofacetBsdf*)a; - const MicrofacetBsdf *bsdf_b = (const MicrofacetBsdf*)b; - - return (isequal_float3(bsdf_a->N, bsdf_b->N)) && - (bsdf_a->alpha_x == bsdf_b->alpha_x) && - (bsdf_a->alpha_y == bsdf_b->alpha_y) && - (isequal_float3(bsdf_a->T, bsdf_b->T)) && - (bsdf_a->ior == bsdf_b->ior) && - ((bsdf_a->extra == NULL && bsdf_b->extra == NULL) || - ((bsdf_a->extra && bsdf_b->extra) && - (isequal_float3(bsdf_a->extra->color, bsdf_b->extra->color)) && - (isequal_float3(bsdf_a->extra->cspec0, bsdf_b->extra->cspec0)) && - (bsdf_a->extra->clearcoat == bsdf_b->extra->clearcoat))); + const MicrofacetBsdf *bsdf_a = (const MicrofacetBsdf *)a; + const MicrofacetBsdf *bsdf_b = (const MicrofacetBsdf *)b; + + return (isequal_float3(bsdf_a->N, bsdf_b->N)) && (bsdf_a->alpha_x == bsdf_b->alpha_x) && + (bsdf_a->alpha_y == bsdf_b->alpha_y) && (isequal_float3(bsdf_a->T, bsdf_b->T)) && + (bsdf_a->ior == bsdf_b->ior) && + ((bsdf_a->extra == NULL && bsdf_b->extra == NULL) || + ((bsdf_a->extra && bsdf_b->extra) && + (isequal_float3(bsdf_a->extra->color, bsdf_b->extra->color)) && + (isequal_float3(bsdf_a->extra->cspec0, bsdf_b->extra->cspec0)) && + (bsdf_a->extra->clearcoat == bsdf_b->extra->clearcoat))); } ccl_device int bsdf_microfacet_ggx_aniso_setup(MicrofacetBsdf *bsdf) { - bsdf->extra = NULL; + bsdf->extra = NULL; - bsdf->alpha_x = saturate(bsdf->alpha_x); - bsdf->alpha_y = saturate(bsdf->alpha_y); + bsdf->alpha_x = saturate(bsdf->alpha_x); + bsdf->alpha_y = saturate(bsdf->alpha_y); - bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL; + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device int bsdf_microfacet_ggx_aniso_fresnel_setup(MicrofacetBsdf *bsdf, const ShaderData *sd) { - bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); - bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); - bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); + bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); + bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); + bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); - float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); - float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0)); - bsdf->sample_weight *= F; + float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); + float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0)); + bsdf->sample_weight *= F; - bsdf->alpha_x = saturate(bsdf->alpha_x); - bsdf->alpha_y = saturate(bsdf->alpha_y); + bsdf->alpha_x = saturate(bsdf->alpha_x); + bsdf->alpha_y = saturate(bsdf->alpha_y); - bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL; + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device int bsdf_microfacet_ggx_refraction_setup(MicrofacetBsdf *bsdf) { - bsdf->extra = NULL; + bsdf->extra = NULL; - bsdf->alpha_x = saturate(bsdf->alpha_x); - bsdf->alpha_y = bsdf->alpha_x; + bsdf->alpha_x = saturate(bsdf->alpha_x); + bsdf->alpha_y = bsdf->alpha_x; - bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL; + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device void bsdf_microfacet_ggx_blur(ShaderClosure *sc, float roughness) { - MicrofacetBsdf *bsdf = (MicrofacetBsdf*)sc; + MicrofacetBsdf *bsdf = (MicrofacetBsdf *)sc; - bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x); - bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); + bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x); + bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); } -ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; - float alpha_x = bsdf->alpha_x; - float alpha_y = bsdf->alpha_y; - bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; - float3 N = bsdf->N; - - if(m_refractive || alpha_x*alpha_y <= 1e-7f) - return make_float3(0.0f, 0.0f, 0.0f); - - float cosNO = dot(N, I); - float cosNI = dot(N, omega_in); - - if(cosNI > 0 && cosNO > 0) { - /* get half vector */ - float3 m = normalize(omega_in + I); - float alpha2 = alpha_x * alpha_y; - float D, G1o, G1i; - - if(alpha_x == alpha_y) { - /* isotropic - * eq. 20: (F*G*D)/(4*in*on) - * eq. 33: first we calculate D(m) */ - float cosThetaM = dot(N, m); - float cosThetaM2 = cosThetaM * cosThetaM; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; - - if(bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { - /* use GTR1 for clearcoat */ - D = D_GTR1(cosThetaM, bsdf->alpha_x); - - /* the alpha value for clearcoat is a fixed 0.25 => alpha2 = 0.25 * 0.25 */ - alpha2 = 0.0625f; - } - else { - /* use GTR2 otherwise */ - D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); - } - - /* eq. 34: now calculate G1(i,m) and G1(o,m) */ - G1o = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); - G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); - } - else { - /* anisotropic */ - float3 X, Y, Z = N; - make_orthonormals_tangent(Z, bsdf->T, &X, &Y); - - /* distribution */ - float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); - float slope_x = -local_m.x/(local_m.z*alpha_x); - float slope_y = -local_m.y/(local_m.z*alpha_y); - float slope_len = 1 + slope_x*slope_x + slope_y*slope_y; - - float cosThetaM = local_m.z; - float cosThetaM2 = cosThetaM * cosThetaM; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - - D = 1 / ((slope_len * slope_len) * M_PI_F * alpha2 * cosThetaM4); - - /* G1(i,m) and G1(o,m) */ - float tanThetaO2 = (1 - cosNO * cosNO) / (cosNO * cosNO); - float cosPhiO = dot(I, X); - float sinPhiO = dot(I, Y); - - float alphaO2 = (cosPhiO*cosPhiO)*(alpha_x*alpha_x) + (sinPhiO*sinPhiO)*(alpha_y*alpha_y); - alphaO2 /= cosPhiO*cosPhiO + sinPhiO*sinPhiO; - - G1o = 2 / (1 + safe_sqrtf(1 + alphaO2 * tanThetaO2)); - - float tanThetaI2 = (1 - cosNI * cosNI) / (cosNI * cosNI); - float cosPhiI = dot(omega_in, X); - float sinPhiI = dot(omega_in, Y); - - float alphaI2 = (cosPhiI*cosPhiI)*(alpha_x*alpha_x) + (sinPhiI*sinPhiI)*(alpha_y*alpha_y); - alphaI2 /= cosPhiI*cosPhiI + sinPhiI*sinPhiI; - - G1i = 2 / (1 + safe_sqrtf(1 + alphaI2 * tanThetaI2)); - } - - float G = G1o * G1i; - - /* eq. 20 */ - float common = D * 0.25f / cosNO; - - float3 F = reflection_color(bsdf, omega_in, m); - if(bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { - F *= 0.25f * bsdf->extra->clearcoat; - } - - float3 out = F * G * common; - - /* eq. 2 in distribution of visible normals sampling - * pm = Dw = G1o * dot(m, I) * D / dot(N, I); */ - - /* eq. 38 - but see also: - * eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf - * pdf = pm * 0.25 / dot(m, I); */ - *pdf = G1o * common; - - return out; - } - - return make_float3(0.0f, 0.0f, 0.0f); + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; + float alpha_x = bsdf->alpha_x; + float alpha_y = bsdf->alpha_y; + bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + float3 N = bsdf->N; + + if (m_refractive || alpha_x * alpha_y <= 1e-7f) + return make_float3(0.0f, 0.0f, 0.0f); + + float cosNO = dot(N, I); + float cosNI = dot(N, omega_in); + + if (cosNI > 0 && cosNO > 0) { + /* get half vector */ + float3 m = normalize(omega_in + I); + float alpha2 = alpha_x * alpha_y; + float D, G1o, G1i; + + if (alpha_x == alpha_y) { + /* isotropic + * eq. 20: (F*G*D)/(4*in*on) + * eq. 33: first we calculate D(m) */ + float cosThetaM = dot(N, m); + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + + if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { + /* use GTR1 for clearcoat */ + D = D_GTR1(cosThetaM, bsdf->alpha_x); + + /* the alpha value for clearcoat is a fixed 0.25 => alpha2 = 0.25 * 0.25 */ + alpha2 = 0.0625f; + } + else { + /* use GTR2 otherwise */ + D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + } + + /* eq. 34: now calculate G1(i,m) and G1(o,m) */ + G1o = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); + G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); + } + else { + /* anisotropic */ + float3 X, Y, Z = N; + make_orthonormals_tangent(Z, bsdf->T, &X, &Y); + + /* distribution */ + float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); + float slope_x = -local_m.x / (local_m.z * alpha_x); + float slope_y = -local_m.y / (local_m.z * alpha_y); + float slope_len = 1 + slope_x * slope_x + slope_y * slope_y; + + float cosThetaM = local_m.z; + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + + D = 1 / ((slope_len * slope_len) * M_PI_F * alpha2 * cosThetaM4); + + /* G1(i,m) and G1(o,m) */ + float tanThetaO2 = (1 - cosNO * cosNO) / (cosNO * cosNO); + float cosPhiO = dot(I, X); + float sinPhiO = dot(I, Y); + + float alphaO2 = (cosPhiO * cosPhiO) * (alpha_x * alpha_x) + + (sinPhiO * sinPhiO) * (alpha_y * alpha_y); + alphaO2 /= cosPhiO * cosPhiO + sinPhiO * sinPhiO; + + G1o = 2 / (1 + safe_sqrtf(1 + alphaO2 * tanThetaO2)); + + float tanThetaI2 = (1 - cosNI * cosNI) / (cosNI * cosNI); + float cosPhiI = dot(omega_in, X); + float sinPhiI = dot(omega_in, Y); + + float alphaI2 = (cosPhiI * cosPhiI) * (alpha_x * alpha_x) + + (sinPhiI * sinPhiI) * (alpha_y * alpha_y); + alphaI2 /= cosPhiI * cosPhiI + sinPhiI * sinPhiI; + + G1i = 2 / (1 + safe_sqrtf(1 + alphaI2 * tanThetaI2)); + } + + float G = G1o * G1i; + + /* eq. 20 */ + float common = D * 0.25f / cosNO; + + float3 F = reflection_color(bsdf, omega_in, m); + if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { + F *= 0.25f * bsdf->extra->clearcoat; + } + + float3 out = F * G * common; + + /* eq. 2 in distribution of visible normals sampling + * pm = Dw = G1o * dot(m, I) * D / dot(N, I); */ + + /* eq. 38 - but see also: + * eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf + * pdf = pm * 0.25 / dot(m, I); */ + *pdf = G1o * common; + + return out; + } + + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; - float alpha_x = bsdf->alpha_x; - float alpha_y = bsdf->alpha_y; - float m_eta = bsdf->ior; - bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; - float3 N = bsdf->N; + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; + float alpha_x = bsdf->alpha_x; + float alpha_y = bsdf->alpha_y; + float m_eta = bsdf->ior; + bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + float3 N = bsdf->N; - if(!m_refractive || alpha_x*alpha_y <= 1e-7f) - return make_float3(0.0f, 0.0f, 0.0f); + if (!m_refractive || alpha_x * alpha_y <= 1e-7f) + return make_float3(0.0f, 0.0f, 0.0f); - float cosNO = dot(N, I); - float cosNI = dot(N, omega_in); + float cosNO = dot(N, I); + float cosNI = dot(N, omega_in); - if(cosNO <= 0 || cosNI >= 0) - return make_float3(0.0f, 0.0f, 0.0f); /* vectors on same side -- not possible */ + if (cosNO <= 0 || cosNI >= 0) + return make_float3(0.0f, 0.0f, 0.0f); /* vectors on same side -- not possible */ - /* compute half-vector of the refraction (eq. 16) */ - float3 ht = -(m_eta * omega_in + I); - float3 Ht = normalize(ht); - float cosHO = dot(Ht, I); - float cosHI = dot(Ht, omega_in); + /* compute half-vector of the refraction (eq. 16) */ + float3 ht = -(m_eta * omega_in + I); + float3 Ht = normalize(ht); + float cosHO = dot(Ht, I); + float cosHI = dot(Ht, omega_in); - float D, G1o, G1i; + float D, G1o, G1i; - /* eq. 33: first we calculate D(m) with m=Ht: */ - float alpha2 = alpha_x * alpha_y; - float cosThetaM = dot(N, Ht); - float cosThetaM2 = cosThetaM * cosThetaM; - float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + /* eq. 33: first we calculate D(m) with m=Ht: */ + float alpha2 = alpha_x * alpha_y; + float cosThetaM = dot(N, Ht); + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); - /* eq. 34: now calculate G1(i,m) and G1(o,m) */ - G1o = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); - G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); + /* eq. 34: now calculate G1(i,m) and G1(o,m) */ + G1o = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); + G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); - float G = G1o * G1i; + float G = G1o * G1i; - /* probability */ - float Ht2 = dot(ht, ht); + /* probability */ + float Ht2 = dot(ht, ht); - /* eq. 2 in distribution of visible normals sampling - * pm = Dw = G1o * dot(m, I) * D / dot(N, I); */ + /* eq. 2 in distribution of visible normals sampling + * pm = Dw = G1o * dot(m, I) * D / dot(N, I); */ - /* out = fabsf(cosHI * cosHO) * (m_eta * m_eta) * G * D / (cosNO * Ht2) - * pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2 */ - float common = D * (m_eta * m_eta) / (cosNO * Ht2); - float out = G * fabsf(cosHI * cosHO) * common; - *pdf = G1o * fabsf(cosHO * cosHI) * common; + /* out = fabsf(cosHI * cosHO) * (m_eta * m_eta) * G * D / (cosNO * Ht2) + * pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2 */ + float common = D * (m_eta * m_eta) / (cosNO * Ht2); + float out = G * fabsf(cosHI * cosHO) * common; + *pdf = G1o * fabsf(cosHO * cosHI) * common; - return make_float3(out, out, out); + return make_float3(out, out, out); } -ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, 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) +ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, + 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) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; - float alpha_x = bsdf->alpha_x; - float alpha_y = bsdf->alpha_y; - bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; - float3 N = bsdf->N; - int label; - - float cosNO = dot(N, I); - if(cosNO > 0) { - float3 X, Y, Z = N; - - if(alpha_x == alpha_y) - make_orthonormals(Z, &X, &Y); - else - make_orthonormals_tangent(Z, bsdf->T, &X, &Y); - - /* importance sampling with distribution of visible normals. vectors are - * transformed to local space before and after */ - float3 local_I = make_float3(dot(X, I), dot(Y, I), cosNO); - float3 local_m; - float G1o; - - local_m = microfacet_sample_stretched(kg, local_I, alpha_x, alpha_y, - randu, randv, false, &G1o); - - float3 m = X*local_m.x + Y*local_m.y + Z*local_m.z; - float cosThetaM = local_m.z; - - /* reflection or refraction? */ - if(!m_refractive) { - float cosMO = dot(m, I); - label = LABEL_REFLECT | LABEL_GLOSSY; - - if(cosMO > 0) { - /* eq. 39 - compute actual reflected direction */ - *omega_in = 2 * cosMO * m - I; - - if(dot(Ng, *omega_in) > 0) { - if(alpha_x*alpha_y <= 1e-7f) { - /* some high number for MIS */ - *pdf = 1e6f; - *eval = make_float3(1e6f, 1e6f, 1e6f); - - bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID - || bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID - || bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID); - - /* if fresnel is used, calculate the color with reflection_color(...) */ - if(use_fresnel) { - *eval *= reflection_color(bsdf, *omega_in, m); - } - - label = LABEL_REFLECT | LABEL_SINGULAR; - } - else { - /* microfacet normal is visible to this ray */ - /* eq. 33 */ - float alpha2 = alpha_x * alpha_y; - float D, G1i; - - if(alpha_x == alpha_y) { - /* isotropic */ - float cosThetaM2 = cosThetaM * cosThetaM; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - float tanThetaM2 = 1/(cosThetaM2) - 1; - - /* eval BRDF*cosNI */ - float cosNI = dot(N, *omega_in); - - if(bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { - /* use GTR1 for clearcoat */ - D = D_GTR1(cosThetaM, bsdf->alpha_x); - - /* the alpha value for clearcoat is a fixed 0.25 => alpha2 = 0.25 * 0.25 */ - alpha2 = 0.0625f; - - /* recalculate G1o */ - G1o = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); - } - else { - /* use GTR2 otherwise */ - D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); - } - - /* eq. 34: now calculate G1(i,m) */ - G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); - } - else { - /* anisotropic distribution */ - float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); - float slope_x = -local_m.x/(local_m.z*alpha_x); - float slope_y = -local_m.y/(local_m.z*alpha_y); - float slope_len = 1 + slope_x*slope_x + slope_y*slope_y; - - float cosThetaM = local_m.z; - float cosThetaM2 = cosThetaM * cosThetaM; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - - D = 1 / ((slope_len * slope_len) * M_PI_F * alpha2 * cosThetaM4); - - /* calculate G1(i,m) */ - float cosNI = dot(N, *omega_in); - - float tanThetaI2 = (1 - cosNI * cosNI) / (cosNI * cosNI); - float cosPhiI = dot(*omega_in, X); - float sinPhiI = dot(*omega_in, Y); - - float alphaI2 = (cosPhiI*cosPhiI)*(alpha_x*alpha_x) + (sinPhiI*sinPhiI)*(alpha_y*alpha_y); - alphaI2 /= cosPhiI*cosPhiI + sinPhiI*sinPhiI; - - G1i = 2 / (1 + safe_sqrtf(1 + alphaI2 * tanThetaI2)); - } - - /* see eval function for derivation */ - float common = (G1o * D) * 0.25f / cosNO; - *pdf = common; - - float3 F = reflection_color(bsdf, *omega_in, m); - - *eval = G1i * common * F; - } - - if(bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { - *eval *= 0.25f * bsdf->extra->clearcoat; - } + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; + float alpha_x = bsdf->alpha_x; + float alpha_y = bsdf->alpha_y; + bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + float3 N = bsdf->N; + int label; + + float cosNO = dot(N, I); + if (cosNO > 0) { + float3 X, Y, Z = N; + + if (alpha_x == alpha_y) + make_orthonormals(Z, &X, &Y); + else + make_orthonormals_tangent(Z, bsdf->T, &X, &Y); + + /* importance sampling with distribution of visible normals. vectors are + * transformed to local space before and after */ + float3 local_I = make_float3(dot(X, I), dot(Y, I), cosNO); + float3 local_m; + float G1o; + + local_m = microfacet_sample_stretched( + kg, local_I, alpha_x, alpha_y, randu, randv, false, &G1o); + + float3 m = X * local_m.x + Y * local_m.y + Z * local_m.z; + float cosThetaM = local_m.z; + + /* reflection or refraction? */ + if (!m_refractive) { + float cosMO = dot(m, I); + label = LABEL_REFLECT | LABEL_GLOSSY; + + if (cosMO > 0) { + /* eq. 39 - compute actual reflected direction */ + *omega_in = 2 * cosMO * m - I; + + if (dot(Ng, *omega_in) > 0) { + if (alpha_x * alpha_y <= 1e-7f) { + /* some high number for MIS */ + *pdf = 1e6f; + *eval = make_float3(1e6f, 1e6f, 1e6f); + + bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID || + bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID || + bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID); + + /* if fresnel is used, calculate the color with reflection_color(...) */ + if (use_fresnel) { + *eval *= reflection_color(bsdf, *omega_in, m); + } + + label = LABEL_REFLECT | LABEL_SINGULAR; + } + else { + /* microfacet normal is visible to this ray */ + /* eq. 33 */ + float alpha2 = alpha_x * alpha_y; + float D, G1i; + + if (alpha_x == alpha_y) { + /* isotropic */ + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float tanThetaM2 = 1 / (cosThetaM2)-1; + + /* eval BRDF*cosNI */ + float cosNI = dot(N, *omega_in); + + if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { + /* use GTR1 for clearcoat */ + D = D_GTR1(cosThetaM, bsdf->alpha_x); + + /* the alpha value for clearcoat is a fixed 0.25 => alpha2 = 0.25 * 0.25 */ + alpha2 = 0.0625f; + + /* recalculate G1o */ + G1o = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); + } + else { + /* use GTR2 otherwise */ + D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + } + + /* eq. 34: now calculate G1(i,m) */ + G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); + } + else { + /* anisotropic distribution */ + float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); + float slope_x = -local_m.x / (local_m.z * alpha_x); + float slope_y = -local_m.y / (local_m.z * alpha_y); + float slope_len = 1 + slope_x * slope_x + slope_y * slope_y; + + float cosThetaM = local_m.z; + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + + D = 1 / ((slope_len * slope_len) * M_PI_F * alpha2 * cosThetaM4); + + /* calculate G1(i,m) */ + float cosNI = dot(N, *omega_in); + + float tanThetaI2 = (1 - cosNI * cosNI) / (cosNI * cosNI); + float cosPhiI = dot(*omega_in, X); + float sinPhiI = dot(*omega_in, Y); + + float alphaI2 = (cosPhiI * cosPhiI) * (alpha_x * alpha_x) + + (sinPhiI * sinPhiI) * (alpha_y * alpha_y); + alphaI2 /= cosPhiI * cosPhiI + sinPhiI * sinPhiI; + + G1i = 2 / (1 + safe_sqrtf(1 + alphaI2 * tanThetaI2)); + } + + /* see eval function for derivation */ + float common = (G1o * D) * 0.25f / cosNO; + *pdf = common; + + float3 F = reflection_color(bsdf, *omega_in, m); + + *eval = G1i * common * F; + } + + if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { + *eval *= 0.25f * bsdf->extra->clearcoat; + } #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = (2 * dot(m, dIdx)) * m - dIdx; - *domega_in_dy = (2 * dot(m, dIdy)) * m - dIdy; + *domega_in_dx = (2 * dot(m, dIdx)) * m - dIdx; + *domega_in_dy = (2 * dot(m, dIdy)) * m - dIdy; #endif - } - } - } - else { - label = LABEL_TRANSMIT | LABEL_GLOSSY; - - /* CAUTION: the i and o variables are inverted relative to the paper - * eq. 39 - compute actual refractive direction */ - float3 R, T; + } + } + } + else { + label = LABEL_TRANSMIT | LABEL_GLOSSY; + + /* CAUTION: the i and o variables are inverted relative to the paper + * eq. 39 - compute actual refractive direction */ + float3 R, T; #ifdef __RAY_DIFFERENTIALS__ - float3 dRdx, dRdy, dTdx, dTdy; + float3 dRdx, dRdy, dTdx, dTdy; #endif - float m_eta = bsdf->ior, fresnel; - bool inside; - - fresnel = fresnel_dielectric(m_eta, m, I, &R, &T, + float m_eta = bsdf->ior, fresnel; + bool inside; + + fresnel = fresnel_dielectric(m_eta, + m, + I, + &R, + &T, #ifdef __RAY_DIFFERENTIALS__ - dIdx, dIdy, &dRdx, &dRdy, &dTdx, &dTdy, + dIdx, + dIdy, + &dRdx, + &dRdy, + &dTdx, + &dTdy, #endif - &inside); + &inside); - if(!inside && fresnel != 1.0f) { + if (!inside && fresnel != 1.0f) { - *omega_in = T; + *omega_in = T; #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = dTdx; - *domega_in_dy = dTdy; + *domega_in_dx = dTdx; + *domega_in_dy = dTdy; #endif - if(alpha_x*alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) { - /* some high number for MIS */ - *pdf = 1e6f; - *eval = make_float3(1e6f, 1e6f, 1e6f); - label = LABEL_TRANSMIT | LABEL_SINGULAR; - } - else { - /* eq. 33 */ - float alpha2 = alpha_x * alpha_y; - float cosThetaM2 = cosThetaM * cosThetaM; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - float tanThetaM2 = 1/(cosThetaM2) - 1; - float D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); - - /* eval BRDF*cosNI */ - float cosNI = dot(N, *omega_in); - - /* eq. 34: now calculate G1(i,m) */ - float G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); - - /* eq. 21 */ - float cosHI = dot(m, *omega_in); - float cosHO = dot(m, I); - float Ht2 = m_eta * cosHI + cosHO; - Ht2 *= Ht2; - - /* see eval function for derivation */ - float common = (G1o * D) * (m_eta * m_eta) / (cosNO * Ht2); - float out = G1i * fabsf(cosHI * cosHO) * common; - *pdf = cosHO * fabsf(cosHI) * common; - - *eval = make_float3(out, out, out); - } - } - } - } - else { - label = (m_refractive) ? LABEL_TRANSMIT|LABEL_GLOSSY : LABEL_REFLECT|LABEL_GLOSSY; - } - return label; + if (alpha_x * alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) { + /* some high number for MIS */ + *pdf = 1e6f; + *eval = make_float3(1e6f, 1e6f, 1e6f); + label = LABEL_TRANSMIT | LABEL_SINGULAR; + } + else { + /* eq. 33 */ + float alpha2 = alpha_x * alpha_y; + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float tanThetaM2 = 1 / (cosThetaM2)-1; + float D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + + /* eval BRDF*cosNI */ + float cosNI = dot(N, *omega_in); + + /* eq. 34: now calculate G1(i,m) */ + float G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); + + /* eq. 21 */ + float cosHI = dot(m, *omega_in); + float cosHO = dot(m, I); + float Ht2 = m_eta * cosHI + cosHO; + Ht2 *= Ht2; + + /* see eval function for derivation */ + float common = (G1o * D) * (m_eta * m_eta) / (cosNO * Ht2); + float out = G1i * fabsf(cosHI * cosHO) * common; + *pdf = cosHO * fabsf(cosHI) * common; + + *eval = make_float3(out, out, out); + } + } + } + } + else { + label = (m_refractive) ? LABEL_TRANSMIT | LABEL_GLOSSY : LABEL_REFLECT | LABEL_GLOSSY; + } + return label; } /* Beckmann microfacet with Smith shadow-masking from: @@ -764,364 +803,392 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure ccl_device int bsdf_microfacet_beckmann_setup(MicrofacetBsdf *bsdf) { - bsdf->alpha_x = saturate(bsdf->alpha_x); - bsdf->alpha_y = bsdf->alpha_x; + bsdf->alpha_x = saturate(bsdf->alpha_x); + bsdf->alpha_y = bsdf->alpha_x; - bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL; + bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ID; + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device int bsdf_microfacet_beckmann_aniso_setup(MicrofacetBsdf *bsdf) { - bsdf->alpha_x = saturate(bsdf->alpha_x); - bsdf->alpha_y = saturate(bsdf->alpha_y); + bsdf->alpha_x = saturate(bsdf->alpha_x); + bsdf->alpha_y = saturate(bsdf->alpha_y); - bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL; + bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID; + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device int bsdf_microfacet_beckmann_refraction_setup(MicrofacetBsdf *bsdf) { - bsdf->alpha_x = saturate(bsdf->alpha_x); - bsdf->alpha_y = bsdf->alpha_x; + bsdf->alpha_x = saturate(bsdf->alpha_x); + bsdf->alpha_y = bsdf->alpha_x; - bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL; + bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device void bsdf_microfacet_beckmann_blur(ShaderClosure *sc, float roughness) { - MicrofacetBsdf *bsdf = (MicrofacetBsdf*)sc; + MicrofacetBsdf *bsdf = (MicrofacetBsdf *)sc; - bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x); - bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); + bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x); + bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); } ccl_device_inline float bsdf_beckmann_G1(float alpha, float cos_n) { - cos_n *= cos_n; - float invA = alpha * safe_sqrtf((1.0f - cos_n) / cos_n); - if(invA < 0.625f) { - return 1.0f; - } - - float a = 1.0f / invA; - return ((2.181f*a + 3.535f)*a) / ((2.577f*a + 2.276f)*a + 1.0f); + cos_n *= cos_n; + float invA = alpha * safe_sqrtf((1.0f - cos_n) / cos_n); + if (invA < 0.625f) { + return 1.0f; + } + + float a = 1.0f / invA; + return ((2.181f * a + 3.535f) * a) / ((2.577f * a + 2.276f) * a + 1.0f); } -ccl_device_inline float bsdf_beckmann_aniso_G1(float alpha_x, float alpha_y, float cos_n, float cos_phi, float sin_phi) +ccl_device_inline float bsdf_beckmann_aniso_G1( + float alpha_x, float alpha_y, float cos_n, float cos_phi, float sin_phi) { - cos_n *= cos_n; - sin_phi *= sin_phi; - cos_phi *= cos_phi; - alpha_x *= alpha_x; - alpha_y *= alpha_y; - - float alphaO2 = (cos_phi*alpha_x + sin_phi*alpha_y) / (cos_phi + sin_phi); - float invA = safe_sqrtf(alphaO2 * (1 - cos_n) / cos_n); - if(invA < 0.625f) { - return 1.0f; - } - - float a = 1.0f / invA; - return ((2.181f*a + 3.535f)*a) / ((2.577f*a + 2.276f)*a + 1.0f); + cos_n *= cos_n; + sin_phi *= sin_phi; + cos_phi *= cos_phi; + alpha_x *= alpha_x; + alpha_y *= alpha_y; + + float alphaO2 = (cos_phi * alpha_x + sin_phi * alpha_y) / (cos_phi + sin_phi); + float invA = safe_sqrtf(alphaO2 * (1 - cos_n) / cos_n); + if (invA < 0.625f) { + return 1.0f; + } + + float a = 1.0f / invA; + return ((2.181f * a + 3.535f) * a) / ((2.577f * a + 2.276f) * a + 1.0f); } -ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; - float alpha_x = bsdf->alpha_x; - float alpha_y = bsdf->alpha_y; - bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; - float3 N = bsdf->N; - - if(m_refractive || alpha_x*alpha_y <= 1e-7f) - return make_float3(0.0f, 0.0f, 0.0f); - - float cosNO = dot(N, I); - float cosNI = dot(N, omega_in); - - if(cosNO > 0 && cosNI > 0) { - /* get half vector */ - float3 m = normalize(omega_in + I); - - float alpha2 = alpha_x * alpha_y; - float D, G1o, G1i; - - if(alpha_x == alpha_y) { - /* isotropic - * eq. 20: (F*G*D)/(4*in*on) - * eq. 25: first we calculate D(m) */ - float cosThetaM = dot(N, m); - float cosThetaM2 = cosThetaM * cosThetaM; - float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); - - /* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */ - G1o = bsdf_beckmann_G1(alpha_x, cosNO); - G1i = bsdf_beckmann_G1(alpha_x, cosNI); - } - else { - /* anisotropic */ - float3 X, Y, Z = N; - make_orthonormals_tangent(Z, bsdf->T, &X, &Y); - - /* distribution */ - float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); - float slope_x = -local_m.x/(local_m.z*alpha_x); - float slope_y = -local_m.y/(local_m.z*alpha_y); - - float cosThetaM = local_m.z; - float cosThetaM2 = cosThetaM * cosThetaM; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - - D = expf(-slope_x*slope_x - slope_y*slope_y) / (M_PI_F * alpha2 * cosThetaM4); - - /* G1(i,m) and G1(o,m) */ - G1o = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, cosNO, dot(I, X), dot(I, Y)); - G1i = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, cosNI, dot(omega_in, X), dot(omega_in, Y)); - } - - float G = G1o * G1i; - - /* eq. 20 */ - float common = D * 0.25f / cosNO; - float out = G * common; - - /* eq. 2 in distribution of visible normals sampling - * pm = Dw = G1o * dot(m, I) * D / dot(N, I); */ - - /* eq. 38 - but see also: - * eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf - * pdf = pm * 0.25 / dot(m, I); */ - *pdf = G1o * common; - - return make_float3(out, out, out); - } - - return make_float3(0.0f, 0.0f, 0.0f); + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; + float alpha_x = bsdf->alpha_x; + float alpha_y = bsdf->alpha_y; + bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + float3 N = bsdf->N; + + if (m_refractive || alpha_x * alpha_y <= 1e-7f) + return make_float3(0.0f, 0.0f, 0.0f); + + float cosNO = dot(N, I); + float cosNI = dot(N, omega_in); + + if (cosNO > 0 && cosNI > 0) { + /* get half vector */ + float3 m = normalize(omega_in + I); + + float alpha2 = alpha_x * alpha_y; + float D, G1o, G1i; + + if (alpha_x == alpha_y) { + /* isotropic + * eq. 20: (F*G*D)/(4*in*on) + * eq. 25: first we calculate D(m) */ + float cosThetaM = dot(N, m); + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); + + /* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */ + G1o = bsdf_beckmann_G1(alpha_x, cosNO); + G1i = bsdf_beckmann_G1(alpha_x, cosNI); + } + else { + /* anisotropic */ + float3 X, Y, Z = N; + make_orthonormals_tangent(Z, bsdf->T, &X, &Y); + + /* distribution */ + float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); + float slope_x = -local_m.x / (local_m.z * alpha_x); + float slope_y = -local_m.y / (local_m.z * alpha_y); + + float cosThetaM = local_m.z; + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + + D = expf(-slope_x * slope_x - slope_y * slope_y) / (M_PI_F * alpha2 * cosThetaM4); + + /* G1(i,m) and G1(o,m) */ + G1o = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, cosNO, dot(I, X), dot(I, Y)); + G1i = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, cosNI, dot(omega_in, X), dot(omega_in, Y)); + } + + float G = G1o * G1i; + + /* eq. 20 */ + float common = D * 0.25f / cosNO; + float out = G * common; + + /* eq. 2 in distribution of visible normals sampling + * pm = Dw = G1o * dot(m, I) * D / dot(N, I); */ + + /* eq. 38 - but see also: + * eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf + * pdf = pm * 0.25 / dot(m, I); */ + *pdf = G1o * common; + + return make_float3(out, out, out); + } + + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; - float alpha_x = bsdf->alpha_x; - float alpha_y = bsdf->alpha_y; - float m_eta = bsdf->ior; - bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; - float3 N = bsdf->N; - - if(!m_refractive || alpha_x*alpha_y <= 1e-7f) - return make_float3(0.0f, 0.0f, 0.0f); - - float cosNO = dot(N, I); - float cosNI = dot(N, omega_in); - - if(cosNO <= 0 || cosNI >= 0) - return make_float3(0.0f, 0.0f, 0.0f); - - /* compute half-vector of the refraction (eq. 16) */ - float3 ht = -(m_eta * omega_in + I); - float3 Ht = normalize(ht); - float cosHO = dot(Ht, I); - float cosHI = dot(Ht, omega_in); - - /* eq. 25: first we calculate D(m) with m=Ht: */ - float alpha2 = alpha_x * alpha_y; - float cosThetaM = min(dot(N, Ht), 1.0f); - float cosThetaM2 = cosThetaM * cosThetaM; - float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); - - /* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */ - float G1o = bsdf_beckmann_G1(alpha_x, cosNO); - float G1i = bsdf_beckmann_G1(alpha_x, cosNI); - float G = G1o * G1i; - - /* probability */ - float Ht2 = dot(ht, ht); - - /* eq. 2 in distribution of visible normals sampling - * pm = Dw = G1o * dot(m, I) * D / dot(N, I); */ - - /* out = fabsf(cosHI * cosHO) * (m_eta * m_eta) * G * D / (cosNO * Ht2) - * pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2 */ - float common = D * (m_eta * m_eta) / (cosNO * Ht2); - float out = G * fabsf(cosHI * cosHO) * common; - *pdf = G1o * fabsf(cosHO * cosHI) * common; - - return make_float3(out, out, out); + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; + float alpha_x = bsdf->alpha_x; + float alpha_y = bsdf->alpha_y; + float m_eta = bsdf->ior; + bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + float3 N = bsdf->N; + + if (!m_refractive || alpha_x * alpha_y <= 1e-7f) + return make_float3(0.0f, 0.0f, 0.0f); + + float cosNO = dot(N, I); + float cosNI = dot(N, omega_in); + + if (cosNO <= 0 || cosNI >= 0) + return make_float3(0.0f, 0.0f, 0.0f); + + /* compute half-vector of the refraction (eq. 16) */ + float3 ht = -(m_eta * omega_in + I); + float3 Ht = normalize(ht); + float cosHO = dot(Ht, I); + float cosHI = dot(Ht, omega_in); + + /* eq. 25: first we calculate D(m) with m=Ht: */ + float alpha2 = alpha_x * alpha_y; + float cosThetaM = min(dot(N, Ht), 1.0f); + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); + + /* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */ + float G1o = bsdf_beckmann_G1(alpha_x, cosNO); + float G1i = bsdf_beckmann_G1(alpha_x, cosNI); + float G = G1o * G1i; + + /* probability */ + float Ht2 = dot(ht, ht); + + /* eq. 2 in distribution of visible normals sampling + * pm = Dw = G1o * dot(m, I) * D / dot(N, I); */ + + /* out = fabsf(cosHI * cosHO) * (m_eta * m_eta) * G * D / (cosNO * Ht2) + * pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2 */ + float common = D * (m_eta * m_eta) / (cosNO * Ht2); + float out = G * fabsf(cosHI * cosHO) * common; + *pdf = G1o * fabsf(cosHO * cosHI) * common; + + return make_float3(out, out, out); } -ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, 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) +ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, + 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) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; - float alpha_x = bsdf->alpha_x; - float alpha_y = bsdf->alpha_y; - bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; - float3 N = bsdf->N; - int label; - - float cosNO = dot(N, I); - if(cosNO > 0) { - float3 X, Y, Z = N; - - if(alpha_x == alpha_y) - make_orthonormals(Z, &X, &Y); - else - make_orthonormals_tangent(Z, bsdf->T, &X, &Y); - - /* importance sampling with distribution of visible normals. vectors are - * transformed to local space before and after */ - float3 local_I = make_float3(dot(X, I), dot(Y, I), cosNO); - float3 local_m; - float G1o; - - local_m = microfacet_sample_stretched(kg, local_I, alpha_x, alpha_x, - randu, randv, true, &G1o); - - float3 m = X*local_m.x + Y*local_m.y + Z*local_m.z; - float cosThetaM = local_m.z; - - /* reflection or refraction? */ - if(!m_refractive) { - label = LABEL_REFLECT | LABEL_GLOSSY; - float cosMO = dot(m, I); - - if(cosMO > 0) { - /* eq. 39 - compute actual reflected direction */ - *omega_in = 2 * cosMO * m - I; - - if(dot(Ng, *omega_in) > 0) { - if(alpha_x*alpha_y <= 1e-7f) { - /* some high number for MIS */ - *pdf = 1e6f; - *eval = make_float3(1e6f, 1e6f, 1e6f); - label = LABEL_REFLECT | LABEL_SINGULAR; - } - else { - /* microfacet normal is visible to this ray - * eq. 25 */ - float alpha2 = alpha_x * alpha_y; - float D, G1i; - - if(alpha_x == alpha_y) { - /* istropic distribution */ - float cosThetaM2 = cosThetaM * cosThetaM; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - float tanThetaM2 = 1/(cosThetaM2) - 1; - D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); - - /* eval BRDF*cosNI */ - float cosNI = dot(N, *omega_in); - - /* eq. 26, 27: now calculate G1(i,m) */ - G1i = bsdf_beckmann_G1(alpha_x, cosNI); - } - else { - /* anisotropic distribution */ - float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); - float slope_x = -local_m.x/(local_m.z*alpha_x); - float slope_y = -local_m.y/(local_m.z*alpha_y); - - float cosThetaM = local_m.z; - float cosThetaM2 = cosThetaM * cosThetaM; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - - D = expf(-slope_x*slope_x - slope_y*slope_y) / (M_PI_F * alpha2 * cosThetaM4); - - /* G1(i,m) */ - G1i = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, dot(*omega_in, N), dot(*omega_in, X), dot(*omega_in, Y)); - } - - float G = G1o * G1i; - - /* see eval function for derivation */ - float common = D * 0.25f / cosNO; - float out = G * common; - *pdf = G1o * common; - - *eval = make_float3(out, out, out); - } + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; + float alpha_x = bsdf->alpha_x; + float alpha_y = bsdf->alpha_y; + bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + float3 N = bsdf->N; + int label; + + float cosNO = dot(N, I); + if (cosNO > 0) { + float3 X, Y, Z = N; + + if (alpha_x == alpha_y) + make_orthonormals(Z, &X, &Y); + else + make_orthonormals_tangent(Z, bsdf->T, &X, &Y); + + /* importance sampling with distribution of visible normals. vectors are + * transformed to local space before and after */ + float3 local_I = make_float3(dot(X, I), dot(Y, I), cosNO); + float3 local_m; + float G1o; + + local_m = microfacet_sample_stretched(kg, local_I, alpha_x, alpha_x, randu, randv, true, &G1o); + + float3 m = X * local_m.x + Y * local_m.y + Z * local_m.z; + float cosThetaM = local_m.z; + + /* reflection or refraction? */ + if (!m_refractive) { + label = LABEL_REFLECT | LABEL_GLOSSY; + float cosMO = dot(m, I); + + if (cosMO > 0) { + /* eq. 39 - compute actual reflected direction */ + *omega_in = 2 * cosMO * m - I; + + if (dot(Ng, *omega_in) > 0) { + if (alpha_x * alpha_y <= 1e-7f) { + /* some high number for MIS */ + *pdf = 1e6f; + *eval = make_float3(1e6f, 1e6f, 1e6f); + label = LABEL_REFLECT | LABEL_SINGULAR; + } + else { + /* microfacet normal is visible to this ray + * eq. 25 */ + float alpha2 = alpha_x * alpha_y; + float D, G1i; + + if (alpha_x == alpha_y) { + /* istropic distribution */ + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float tanThetaM2 = 1 / (cosThetaM2)-1; + D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); + + /* eval BRDF*cosNI */ + float cosNI = dot(N, *omega_in); + + /* eq. 26, 27: now calculate G1(i,m) */ + G1i = bsdf_beckmann_G1(alpha_x, cosNI); + } + else { + /* anisotropic distribution */ + float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); + float slope_x = -local_m.x / (local_m.z * alpha_x); + float slope_y = -local_m.y / (local_m.z * alpha_y); + + float cosThetaM = local_m.z; + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + + D = expf(-slope_x * slope_x - slope_y * slope_y) / (M_PI_F * alpha2 * cosThetaM4); + + /* G1(i,m) */ + G1i = bsdf_beckmann_aniso_G1( + alpha_x, alpha_y, dot(*omega_in, N), dot(*omega_in, X), dot(*omega_in, Y)); + } + + float G = G1o * G1i; + + /* see eval function for derivation */ + float common = D * 0.25f / cosNO; + float out = G * common; + *pdf = G1o * common; + + *eval = make_float3(out, out, out); + } #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = (2 * dot(m, dIdx)) * m - dIdx; - *domega_in_dy = (2 * dot(m, dIdy)) * m - dIdy; + *domega_in_dx = (2 * dot(m, dIdx)) * m - dIdx; + *domega_in_dy = (2 * dot(m, dIdy)) * m - dIdy; #endif - } - } - } - else { - label = LABEL_TRANSMIT | LABEL_GLOSSY; - - /* CAUTION: the i and o variables are inverted relative to the paper - * eq. 39 - compute actual refractive direction */ - float3 R, T; + } + } + } + else { + label = LABEL_TRANSMIT | LABEL_GLOSSY; + + /* CAUTION: the i and o variables are inverted relative to the paper + * eq. 39 - compute actual refractive direction */ + float3 R, T; #ifdef __RAY_DIFFERENTIALS__ - float3 dRdx, dRdy, dTdx, dTdy; + float3 dRdx, dRdy, dTdx, dTdy; #endif - float m_eta = bsdf->ior, fresnel; - bool inside; - - fresnel = fresnel_dielectric(m_eta, m, I, &R, &T, + float m_eta = bsdf->ior, fresnel; + bool inside; + + fresnel = fresnel_dielectric(m_eta, + m, + I, + &R, + &T, #ifdef __RAY_DIFFERENTIALS__ - dIdx, dIdy, &dRdx, &dRdy, &dTdx, &dTdy, + dIdx, + dIdy, + &dRdx, + &dRdy, + &dTdx, + &dTdy, #endif - &inside); + &inside); - if(!inside && fresnel != 1.0f) { - *omega_in = T; + if (!inside && fresnel != 1.0f) { + *omega_in = T; #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = dTdx; - *domega_in_dy = dTdy; + *domega_in_dx = dTdx; + *domega_in_dy = dTdy; #endif - if(alpha_x*alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) { - /* some high number for MIS */ - *pdf = 1e6f; - *eval = make_float3(1e6f, 1e6f, 1e6f); - label = LABEL_TRANSMIT | LABEL_SINGULAR; - } - else { - /* eq. 33 */ - float alpha2 = alpha_x * alpha_y; - float cosThetaM2 = cosThetaM * cosThetaM; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - float tanThetaM2 = 1/(cosThetaM2) - 1; - float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); - - /* eval BRDF*cosNI */ - float cosNI = dot(N, *omega_in); - - /* eq. 26, 27: now calculate G1(i,m) */ - float G1i = bsdf_beckmann_G1(alpha_x, cosNI); - float G = G1o * G1i; - - /* eq. 21 */ - float cosHI = dot(m, *omega_in); - float cosHO = dot(m, I); - float Ht2 = m_eta * cosHI + cosHO; - Ht2 *= Ht2; - - /* see eval function for derivation */ - float common = D * (m_eta * m_eta) / (cosNO * Ht2); - float out = G * fabsf(cosHI * cosHO) * common; - *pdf = G1o * cosHO * fabsf(cosHI) * common; - - *eval = make_float3(out, out, out); - } - } - } - } - else { - label = (m_refractive) ? LABEL_TRANSMIT|LABEL_GLOSSY : LABEL_REFLECT|LABEL_GLOSSY; - } - return label; + if (alpha_x * alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) { + /* some high number for MIS */ + *pdf = 1e6f; + *eval = make_float3(1e6f, 1e6f, 1e6f); + label = LABEL_TRANSMIT | LABEL_SINGULAR; + } + else { + /* eq. 33 */ + float alpha2 = alpha_x * alpha_y; + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float tanThetaM2 = 1 / (cosThetaM2)-1; + float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); + + /* eval BRDF*cosNI */ + float cosNI = dot(N, *omega_in); + + /* eq. 26, 27: now calculate G1(i,m) */ + float G1i = bsdf_beckmann_G1(alpha_x, cosNI); + float G = G1o * G1i; + + /* eq. 21 */ + float cosHI = dot(m, *omega_in); + float cosHO = dot(m, I); + float Ht2 = m_eta * cosHI + cosHO; + Ht2 *= Ht2; + + /* see eval function for derivation */ + float common = D * (m_eta * m_eta) / (cosNO * Ht2); + float out = G * fabsf(cosHI * cosHO) * common; + *pdf = G1o * cosHO * fabsf(cosHI) * common; + + *eval = make_float3(out, out, out); + } + } + } + } + else { + label = (m_refractive) ? LABEL_TRANSMIT | LABEL_GLOSSY : LABEL_REFLECT | LABEL_GLOSSY; + } + return label; } CCL_NAMESPACE_END -#endif /* __BSDF_MICROFACET_H__ */ +#endif /* __BSDF_MICROFACET_H__ */ diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h index 2f2c35d5d1f..2cc1a9c5299 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h @@ -23,149 +23,168 @@ CCL_NAMESPACE_BEGIN /* Isotropic GGX microfacet distribution */ ccl_device_forceinline float D_ggx(float3 wm, float alpha) { - wm.z *= wm.z; - alpha *= alpha; - float tmp = (1.0f - wm.z) + alpha * wm.z; - return alpha / max(M_PI_F * tmp*tmp, 1e-7f); + wm.z *= wm.z; + alpha *= alpha; + float tmp = (1.0f - wm.z) + alpha * wm.z; + return alpha / max(M_PI_F * tmp * tmp, 1e-7f); } /* Anisotropic GGX microfacet distribution */ ccl_device_forceinline float D_ggx_aniso(const float3 wm, const float2 alpha) { - float slope_x = -wm.x/alpha.x; - float slope_y = -wm.y/alpha.y; - float tmp = wm.z*wm.z + slope_x*slope_x + slope_y*slope_y; + float slope_x = -wm.x / alpha.x; + float slope_y = -wm.y / alpha.y; + float tmp = wm.z * wm.z + slope_x * slope_x + slope_y * slope_y; - return 1.0f / max(M_PI_F * tmp*tmp * alpha.x*alpha.y, 1e-7f); + return 1.0f / max(M_PI_F * tmp * tmp * alpha.x * alpha.y, 1e-7f); } /* Sample slope distribution (based on page 14 of the supplemental implementation). */ -ccl_device_forceinline float2 mf_sampleP22_11(const float cosI, const float randx, const float randy) -{ - if(cosI > 0.9999f || fabsf(cosI) < 1e-6f) { - const float r = sqrtf(randx / max(1.0f - randx, 1e-7f)); - const float phi = M_2PI_F * randy; - return make_float2(r*cosf(phi), r*sinf(phi)); - } - - const float sinI = safe_sqrtf(1.0f - cosI*cosI); - const float tanI = sinI/cosI; - const float projA = 0.5f * (cosI + 1.0f); - if(projA < 0.0001f) - return make_float2(0.0f, 0.0f); - const float A = 2.0f*randx*projA / cosI - 1.0f; - float tmp = A*A-1.0f; - if(fabsf(tmp) < 1e-7f) - return make_float2(0.0f, 0.0f); - tmp = 1.0f / tmp; - const float D = safe_sqrtf(tanI*tanI*tmp*tmp - (A*A-tanI*tanI)*tmp); - - const float slopeX2 = tanI*tmp + D; - const float slopeX = (A < 0.0f || slopeX2 > 1.0f/tanI)? (tanI*tmp - D) : slopeX2; - - float U2; - if(randy >= 0.5f) - U2 = 2.0f*(randy - 0.5f); - else - U2 = 2.0f*(0.5f - randy); - const float z = (U2*(U2*(U2*0.27385f-0.73369f)+0.46341f)) / (U2*(U2*(U2*0.093073f+0.309420f)-1.0f)+0.597999f); - const float slopeY = z * sqrtf(1.0f + slopeX*slopeX); - - if(randy >= 0.5f) - return make_float2(slopeX, slopeY); - else - return make_float2(slopeX, -slopeY); +ccl_device_forceinline float2 mf_sampleP22_11(const float cosI, + const float randx, + const float randy) +{ + if (cosI > 0.9999f || fabsf(cosI) < 1e-6f) { + const float r = sqrtf(randx / max(1.0f - randx, 1e-7f)); + const float phi = M_2PI_F * randy; + return make_float2(r * cosf(phi), r * sinf(phi)); + } + + const float sinI = safe_sqrtf(1.0f - cosI * cosI); + const float tanI = sinI / cosI; + const float projA = 0.5f * (cosI + 1.0f); + if (projA < 0.0001f) + return make_float2(0.0f, 0.0f); + const float A = 2.0f * randx * projA / cosI - 1.0f; + float tmp = A * A - 1.0f; + if (fabsf(tmp) < 1e-7f) + return make_float2(0.0f, 0.0f); + tmp = 1.0f / tmp; + const float D = safe_sqrtf(tanI * tanI * tmp * tmp - (A * A - tanI * tanI) * tmp); + + const float slopeX2 = tanI * tmp + D; + const float slopeX = (A < 0.0f || slopeX2 > 1.0f / tanI) ? (tanI * tmp - D) : slopeX2; + + float U2; + if (randy >= 0.5f) + U2 = 2.0f * (randy - 0.5f); + else + U2 = 2.0f * (0.5f - randy); + const float z = (U2 * (U2 * (U2 * 0.27385f - 0.73369f) + 0.46341f)) / + (U2 * (U2 * (U2 * 0.093073f + 0.309420f) - 1.0f) + 0.597999f); + const float slopeY = z * sqrtf(1.0f + slopeX * slopeX); + + if (randy >= 0.5f) + return make_float2(slopeX, slopeY); + else + return make_float2(slopeX, -slopeY); } /* Visible normal sampling for the GGX distribution (based on page 7 of the supplemental implementation). */ -ccl_device_forceinline float3 mf_sample_vndf(const float3 wi, const float2 alpha, const float randx, const float randy) +ccl_device_forceinline float3 mf_sample_vndf(const float3 wi, + const float2 alpha, + const float randx, + const float randy) { - const float3 wi_11 = normalize(make_float3(alpha.x*wi.x, alpha.y*wi.y, wi.z)); - const float2 slope_11 = mf_sampleP22_11(wi_11.z, randx, randy); + const float3 wi_11 = normalize(make_float3(alpha.x * wi.x, alpha.y * wi.y, wi.z)); + const float2 slope_11 = mf_sampleP22_11(wi_11.z, randx, randy); - const float3 cossin_phi = safe_normalize(make_float3(wi_11.x, wi_11.y, 0.0f)); - const float slope_x = alpha.x*(cossin_phi.x * slope_11.x - cossin_phi.y * slope_11.y); - const float slope_y = alpha.y*(cossin_phi.y * slope_11.x + cossin_phi.x * slope_11.y); + const float3 cossin_phi = safe_normalize(make_float3(wi_11.x, wi_11.y, 0.0f)); + const float slope_x = alpha.x * (cossin_phi.x * slope_11.x - cossin_phi.y * slope_11.y); + const float slope_y = alpha.y * (cossin_phi.y * slope_11.x + cossin_phi.x * slope_11.y); - kernel_assert(isfinite(slope_x)); - return normalize(make_float3(-slope_x, -slope_y, 1.0f)); + kernel_assert(isfinite(slope_x)); + return normalize(make_float3(-slope_x, -slope_y, 1.0f)); } /* === Phase functions: Glossy and Glass === */ /* Phase function for reflective materials. */ -ccl_device_forceinline float3 mf_sample_phase_glossy(const float3 wi, float3 *weight, const float3 wm) +ccl_device_forceinline float3 mf_sample_phase_glossy(const float3 wi, + float3 *weight, + const float3 wm) { - return -wi + 2.0f * wm * dot(wi, wm); + return -wi + 2.0f * wm * dot(wi, wm); } -ccl_device_forceinline float3 mf_eval_phase_glossy(const float3 w, const float lambda, const float3 wo, const float2 alpha) +ccl_device_forceinline float3 mf_eval_phase_glossy(const float3 w, + const float lambda, + const float3 wo, + const float2 alpha) { - if(w.z > 0.9999f) - return make_float3(0.0f, 0.0f, 0.0f); + if (w.z > 0.9999f) + return make_float3(0.0f, 0.0f, 0.0f); - const float3 wh = normalize(wo - w); - if(wh.z < 0.0f) - return make_float3(0.0f, 0.0f, 0.0f); + const float3 wh = normalize(wo - w); + if (wh.z < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); - float pArea = (w.z < -0.9999f)? 1.0f: lambda*w.z; + float pArea = (w.z < -0.9999f) ? 1.0f : lambda * w.z; - const float dotW_WH = dot(-w, wh); - if(dotW_WH < 0.0f) - return make_float3(0.0f, 0.0f, 0.0f); + const float dotW_WH = dot(-w, wh); + if (dotW_WH < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); - float phase = max(0.0f, dotW_WH) * 0.25f / max(pArea * dotW_WH, 1e-7f); - if(alpha.x == alpha.y) - phase *= D_ggx(wh, alpha.x); - else - phase *= D_ggx_aniso(wh, alpha); + float phase = max(0.0f, dotW_WH) * 0.25f / max(pArea * dotW_WH, 1e-7f); + if (alpha.x == alpha.y) + phase *= D_ggx(wh, alpha.x); + else + phase *= D_ggx_aniso(wh, alpha); - return make_float3(phase, phase, phase); + return make_float3(phase, phase, phase); } /* Phase function for dielectric transmissive materials, including both reflection and refraction according to the dielectric fresnel term. */ -ccl_device_forceinline float3 mf_sample_phase_glass(const float3 wi, const float eta, const float3 wm, const float randV, bool *outside) -{ - float cosI = dot(wi, wm); - float f = fresnel_dielectric_cos(cosI, eta); - if(randV < f) { - *outside = true; - return -wi + 2.0f * wm * cosI; - } - *outside = false; - float inv_eta = 1.0f/eta; - float cosT = -safe_sqrtf(1.0f - (1.0f - cosI*cosI) * inv_eta*inv_eta); - return normalize(wm*(cosI*inv_eta + cosT) - wi*inv_eta); -} - -ccl_device_forceinline float3 mf_eval_phase_glass(const float3 w, const float lambda, const float3 wo, const bool wo_outside, const float2 alpha, const float eta) -{ - if(w.z > 0.9999f) - return make_float3(0.0f, 0.0f, 0.0f); - - float pArea = (w.z < -0.9999f)? 1.0f: lambda*w.z; - float v; - if(wo_outside) { - const float3 wh = normalize(wo - w); - if(wh.z < 0.0f) - return make_float3(0.0f, 0.0f, 0.0f); - - const float dotW_WH = dot(-w, wh); - v = fresnel_dielectric_cos(dotW_WH, eta) * max(0.0f, dotW_WH) * D_ggx(wh, alpha.x) * 0.25f / (pArea * dotW_WH); - } - else { - float3 wh = normalize(wo*eta - w); - if(wh.z < 0.0f) - wh = -wh; - const float dotW_WH = dot(-w, wh), dotWO_WH = dot(wo, wh); - if(dotW_WH < 0.0f) - return make_float3(0.0f, 0.0f, 0.0f); - - float temp = dotW_WH + eta*dotWO_WH; - v = (1.0f - fresnel_dielectric_cos(dotW_WH, eta)) * max(0.0f, dotW_WH) * max(0.0f, -dotWO_WH) * D_ggx(wh, alpha.x) / (pArea * temp * temp); - } - - return make_float3(v, v, v); +ccl_device_forceinline float3 mf_sample_phase_glass( + const float3 wi, const float eta, const float3 wm, const float randV, bool *outside) +{ + float cosI = dot(wi, wm); + float f = fresnel_dielectric_cos(cosI, eta); + if (randV < f) { + *outside = true; + return -wi + 2.0f * wm * cosI; + } + *outside = false; + float inv_eta = 1.0f / eta; + float cosT = -safe_sqrtf(1.0f - (1.0f - cosI * cosI) * inv_eta * inv_eta); + return normalize(wm * (cosI * inv_eta + cosT) - wi * inv_eta); +} + +ccl_device_forceinline float3 mf_eval_phase_glass(const float3 w, + const float lambda, + const float3 wo, + const bool wo_outside, + const float2 alpha, + const float eta) +{ + if (w.z > 0.9999f) + return make_float3(0.0f, 0.0f, 0.0f); + + float pArea = (w.z < -0.9999f) ? 1.0f : lambda * w.z; + float v; + if (wo_outside) { + const float3 wh = normalize(wo - w); + if (wh.z < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + const float dotW_WH = dot(-w, wh); + v = fresnel_dielectric_cos(dotW_WH, eta) * max(0.0f, dotW_WH) * D_ggx(wh, alpha.x) * 0.25f / + (pArea * dotW_WH); + } + else { + float3 wh = normalize(wo * eta - w); + if (wh.z < 0.0f) + wh = -wh; + const float dotW_WH = dot(-w, wh), dotWO_WH = dot(wo, wh); + if (dotW_WH < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + float temp = dotW_WH + eta * dotWO_WH; + v = (1.0f - fresnel_dielectric_cos(dotW_WH, eta)) * max(0.0f, dotW_WH) * max(0.0f, -dotWO_WH) * + D_ggx(wh, alpha.x) / (pArea * temp * temp); + } + + return make_float3(v, v, v); } /* === Utility functions for the random walks === */ @@ -173,64 +192,65 @@ ccl_device_forceinline float3 mf_eval_phase_glass(const float3 w, const float la /* Smith Lambda function for GGX (based on page 12 of the supplemental implementation). */ ccl_device_forceinline float mf_lambda(const float3 w, const float2 alpha) { - if(w.z > 0.9999f) - return 0.0f; - else if(w.z < -0.9999f) - return -0.9999f; + if (w.z > 0.9999f) + return 0.0f; + else if (w.z < -0.9999f) + return -0.9999f; - const float inv_wz2 = 1.0f / max(w.z*w.z, 1e-7f); - const float2 wa = make_float2(w.x, w.y)*alpha; - float v = sqrtf(1.0f + dot(wa, wa) * inv_wz2); - if(w.z <= 0.0f) - v = -v; + const float inv_wz2 = 1.0f / max(w.z * w.z, 1e-7f); + const float2 wa = make_float2(w.x, w.y) * alpha; + float v = sqrtf(1.0f + dot(wa, wa) * inv_wz2); + if (w.z <= 0.0f) + v = -v; - return 0.5f*(v - 1.0f); + return 0.5f * (v - 1.0f); } /* Height distribution CDF (based on page 4 of the supplemental implementation). */ ccl_device_forceinline float mf_invC1(const float h) { - return 2.0f * saturate(h) - 1.0f; + return 2.0f * saturate(h) - 1.0f; } ccl_device_forceinline float mf_C1(const float h) { - return saturate(0.5f * (h + 1.0f)); + return saturate(0.5f * (h + 1.0f)); } /* Masking function (based on page 16 of the supplemental implementation). */ ccl_device_forceinline float mf_G1(const float3 w, const float C1, const float lambda) { - if(w.z > 0.9999f) - return 1.0f; - if(w.z < 1e-5f) - return 0.0f; - return powf(C1, lambda); + if (w.z > 0.9999f) + return 1.0f; + if (w.z < 1e-5f) + return 0.0f; + return powf(C1, lambda); } /* Sampling from the visible height distribution (based on page 17 of the supplemental implementation). */ -ccl_device_forceinline bool mf_sample_height(const float3 w, float *h, float *C1, float *G1, float *lambda, const float U) -{ - if(w.z > 0.9999f) - return false; - if(w.z < -0.9999f) { - *C1 *= U; - *h = mf_invC1(*C1); - *G1 = mf_G1(w, *C1, *lambda); - } - else if(fabsf(w.z) >= 0.0001f) { - if(U > 1.0f - *G1) - return false; - if(*lambda >= 0.0f) { - *C1 = 1.0f; - } - else { - *C1 *= powf(1.0f-U, -1.0f / *lambda); - } - *h = mf_invC1(*C1); - *G1 = mf_G1(w, *C1, *lambda); - } - return true; +ccl_device_forceinline bool mf_sample_height( + const float3 w, float *h, float *C1, float *G1, float *lambda, const float U) +{ + if (w.z > 0.9999f) + return false; + if (w.z < -0.9999f) { + *C1 *= U; + *h = mf_invC1(*C1); + *G1 = mf_G1(w, *C1, *lambda); + } + else if (fabsf(w.z) >= 0.0001f) { + if (U > 1.0f - *G1) + return false; + if (*lambda >= 0.0f) { + *C1 = 1.0f; + } + else { + *C1 *= powf(1.0f - U, -1.0f / *lambda); + } + *h = mf_invC1(*C1); + *G1 = mf_G1(w, *C1, *lambda); + } + return true; } /* === PDF approximations for the different phase functions. === @@ -240,80 +260,92 @@ ccl_device_forceinline bool mf_sample_height(const float3 w, float *h, float *C1 * the missing energy is then approximated as a diffuse reflection for the PDF. */ ccl_device_forceinline float mf_ggx_albedo(float r) { - float albedo = 0.806495f*expf(-1.98712f*r*r) + 0.199531f; - albedo -= ((((((1.76741f*r - 8.43891f)*r + 15.784f)*r - 14.398f)*r + 6.45221f)*r - 1.19722f)*r + 0.027803f)*r + 0.00568739f; - return saturate(albedo); + float albedo = 0.806495f * expf(-1.98712f * r * r) + 0.199531f; + albedo -= ((((((1.76741f * r - 8.43891f) * r + 15.784f) * r - 14.398f) * r + 6.45221f) * r - + 1.19722f) * + r + + 0.027803f) * + r + + 0.00568739f; + return saturate(albedo); } ccl_device_inline float mf_ggx_transmission_albedo(float a, float ior) { - if(ior < 1.0f) { - ior = 1.0f/ior; - } - a = saturate(a); - ior = clamp(ior, 1.0f, 3.0f); - float I_1 = 0.0476898f*expf(-0.978352f*(ior-0.65657f)*(ior-0.65657f)) - 0.033756f*ior + 0.993261f; - float R_1 = (((0.116991f*a - 0.270369f)*a + 0.0501366f)*a - 0.00411511f)*a + 1.00008f; - float I_2 = (((-2.08704f*ior + 26.3298f)*ior - 127.906f)*ior + 292.958f)*ior - 287.946f + 199.803f/(ior*ior) - 101.668f/(ior*ior*ior); - float R_2 = ((((5.3725f*a -24.9307f)*a + 22.7437f)*a - 3.40751f)*a + 0.0986325f)*a + 0.00493504f; - - return saturate(1.0f + I_2*R_2*0.0019127f - (1.0f - I_1)*(1.0f - R_1)*9.3205f); + if (ior < 1.0f) { + ior = 1.0f / ior; + } + a = saturate(a); + ior = clamp(ior, 1.0f, 3.0f); + float I_1 = 0.0476898f * expf(-0.978352f * (ior - 0.65657f) * (ior - 0.65657f)) - + 0.033756f * ior + 0.993261f; + float R_1 = (((0.116991f * a - 0.270369f) * a + 0.0501366f) * a - 0.00411511f) * a + 1.00008f; + float I_2 = (((-2.08704f * ior + 26.3298f) * ior - 127.906f) * ior + 292.958f) * ior - 287.946f + + 199.803f / (ior * ior) - 101.668f / (ior * ior * ior); + float R_2 = ((((5.3725f * a - 24.9307f) * a + 22.7437f) * a - 3.40751f) * a + 0.0986325f) * a + + 0.00493504f; + + return saturate(1.0f + I_2 * R_2 * 0.0019127f - (1.0f - I_1) * (1.0f - R_1) * 9.3205f); } ccl_device_forceinline float mf_ggx_pdf(const float3 wi, const float3 wo, const float alpha) { - float D = D_ggx(normalize(wi+wo), alpha); - float lambda = mf_lambda(wi, make_float2(alpha, alpha)); - float singlescatter = 0.25f * D / max((1.0f + lambda) * wi.z, 1e-7f); + float D = D_ggx(normalize(wi + wo), alpha); + float lambda = mf_lambda(wi, make_float2(alpha, alpha)); + float singlescatter = 0.25f * D / max((1.0f + lambda) * wi.z, 1e-7f); - float multiscatter = wo.z * M_1_PI_F; + float multiscatter = wo.z * M_1_PI_F; - float albedo = mf_ggx_albedo(alpha); - return albedo*singlescatter + (1.0f - albedo)*multiscatter; + float albedo = mf_ggx_albedo(alpha); + return albedo * singlescatter + (1.0f - albedo) * multiscatter; } ccl_device_forceinline float mf_ggx_aniso_pdf(const float3 wi, const float3 wo, const float2 alpha) { - float D = D_ggx_aniso(normalize(wi+wo), alpha); - float lambda = mf_lambda(wi, alpha); - float singlescatter = 0.25f * D / max((1.0f + lambda) * wi.z, 1e-7f); + float D = D_ggx_aniso(normalize(wi + wo), alpha); + float lambda = mf_lambda(wi, alpha); + float singlescatter = 0.25f * D / max((1.0f + lambda) * wi.z, 1e-7f); - float multiscatter = wo.z * M_1_PI_F; + float multiscatter = wo.z * M_1_PI_F; - float albedo = mf_ggx_albedo(sqrtf(alpha.x*alpha.y)); - return albedo*singlescatter + (1.0f - albedo)*multiscatter; + float albedo = mf_ggx_albedo(sqrtf(alpha.x * alpha.y)); + return albedo * singlescatter + (1.0f - albedo) * multiscatter; } -ccl_device_forceinline float mf_glass_pdf(const float3 wi, const float3 wo, const float alpha, const float eta) +ccl_device_forceinline float mf_glass_pdf(const float3 wi, + const float3 wo, + const float alpha, + const float eta) { - bool reflective = (wi.z*wo.z > 0.0f); - - float wh_len; - float3 wh = normalize_len(wi + (reflective? wo : (wo*eta)), &wh_len); - if(wh.z < 0.0f) - wh = -wh; - float3 r_wi = (wi.z < 0.0f)? -wi: wi; - float lambda = mf_lambda(r_wi, make_float2(alpha, alpha)); - float D = D_ggx(wh, alpha); - float fresnel = fresnel_dielectric_cos(dot(r_wi, wh), eta); - - float multiscatter = fabsf(wo.z * M_1_PI_F); - if(reflective) { - float singlescatter = 0.25f * D / max((1.0f + lambda) * r_wi.z, 1e-7f); - float albedo = mf_ggx_albedo(alpha); - return fresnel * (albedo*singlescatter + (1.0f - albedo)*multiscatter); - } - else { - float singlescatter = fabsf(dot(r_wi, wh)*dot(wo, wh) * D * eta*eta / max((1.0f + lambda) * r_wi.z * wh_len*wh_len, 1e-7f)); - float albedo = mf_ggx_transmission_albedo(alpha, eta); - return (1.0f - fresnel) * (albedo*singlescatter + (1.0f - albedo)*multiscatter); - } + bool reflective = (wi.z * wo.z > 0.0f); + + float wh_len; + float3 wh = normalize_len(wi + (reflective ? wo : (wo * eta)), &wh_len); + if (wh.z < 0.0f) + wh = -wh; + float3 r_wi = (wi.z < 0.0f) ? -wi : wi; + float lambda = mf_lambda(r_wi, make_float2(alpha, alpha)); + float D = D_ggx(wh, alpha); + float fresnel = fresnel_dielectric_cos(dot(r_wi, wh), eta); + + float multiscatter = fabsf(wo.z * M_1_PI_F); + if (reflective) { + float singlescatter = 0.25f * D / max((1.0f + lambda) * r_wi.z, 1e-7f); + float albedo = mf_ggx_albedo(alpha); + return fresnel * (albedo * singlescatter + (1.0f - albedo) * multiscatter); + } + else { + float singlescatter = fabsf(dot(r_wi, wh) * dot(wo, wh) * D * eta * eta / + max((1.0f + lambda) * r_wi.z * wh_len * wh_len, 1e-7f)); + float albedo = mf_ggx_transmission_albedo(alpha, eta); + return (1.0f - fresnel) * (albedo * singlescatter + (1.0f - albedo) * multiscatter); + } } /* === Actual random walk implementations, one version of mf_eval and mf_sample per phase function. === */ -#define MF_NAME_JOIN(x,y) x ## _ ## y -#define MF_NAME_EVAL(x,y) MF_NAME_JOIN(x,y) +#define MF_NAME_JOIN(x, y) x##_##y +#define MF_NAME_EVAL(x, y) MF_NAME_JOIN(x, y) #define MF_FUNCTION_FULL_NAME(prefix) MF_NAME_EVAL(prefix, MF_PHASE_FUNCTION) #define MF_PHASE_FUNCTION glass @@ -326,10 +358,10 @@ ccl_device_forceinline float mf_glass_pdf(const float3 wi, const float3 wo, cons ccl_device void bsdf_microfacet_multi_ggx_blur(ShaderClosure *sc, float roughness) { - MicrofacetBsdf *bsdf = (MicrofacetBsdf*)sc; + MicrofacetBsdf *bsdf = (MicrofacetBsdf *)sc; - bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x); - bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); + bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x); + bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); } /* === Closure implementations === */ @@ -338,293 +370,395 @@ ccl_device void bsdf_microfacet_multi_ggx_blur(ShaderClosure *sc, float roughnes ccl_device int bsdf_microfacet_multi_ggx_common_setup(MicrofacetBsdf *bsdf) { - bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); - bsdf->alpha_y = clamp(bsdf->alpha_y, 1e-4f, 1.0f); - bsdf->extra->color.x = saturate(bsdf->extra->color.x); - bsdf->extra->color.y = saturate(bsdf->extra->color.y); - bsdf->extra->color.z = saturate(bsdf->extra->color.z); - bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); - bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); - bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); + bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); + bsdf->alpha_y = clamp(bsdf->alpha_y, 1e-4f, 1.0f); + bsdf->extra->color.x = saturate(bsdf->extra->color.x); + bsdf->extra->color.y = saturate(bsdf->extra->color.y); + bsdf->extra->color.z = saturate(bsdf->extra->color.z); + bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); + bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); + bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); - return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG; + return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG; } ccl_device int bsdf_microfacet_multi_ggx_aniso_setup(MicrofacetBsdf *bsdf) { - if(is_zero(bsdf->T)) - bsdf->T = make_float3(1.0f, 0.0f, 0.0f); + if (is_zero(bsdf->T)) + bsdf->T = make_float3(1.0f, 0.0f, 0.0f); - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; - return bsdf_microfacet_multi_ggx_common_setup(bsdf); + return bsdf_microfacet_multi_ggx_common_setup(bsdf); } -ccl_device int bsdf_microfacet_multi_ggx_aniso_fresnel_setup(MicrofacetBsdf *bsdf, const ShaderData *sd) +ccl_device int bsdf_microfacet_multi_ggx_aniso_fresnel_setup(MicrofacetBsdf *bsdf, + const ShaderData *sd) { - if(is_zero(bsdf->T)) - bsdf->T = make_float3(1.0f, 0.0f, 0.0f); + if (is_zero(bsdf->T)) + bsdf->T = make_float3(1.0f, 0.0f, 0.0f); - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID; - float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); - float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0)); - bsdf->sample_weight *= F; + float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); + float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0)); + bsdf->sample_weight *= F; - return bsdf_microfacet_multi_ggx_common_setup(bsdf); + return bsdf_microfacet_multi_ggx_common_setup(bsdf); } ccl_device int bsdf_microfacet_multi_ggx_setup(MicrofacetBsdf *bsdf) { - bsdf->alpha_y = bsdf->alpha_x; + bsdf->alpha_y = bsdf->alpha_x; - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; - return bsdf_microfacet_multi_ggx_common_setup(bsdf); + return bsdf_microfacet_multi_ggx_common_setup(bsdf); } ccl_device int bsdf_microfacet_multi_ggx_fresnel_setup(MicrofacetBsdf *bsdf, const ShaderData *sd) { - bsdf->alpha_y = bsdf->alpha_x; + bsdf->alpha_y = bsdf->alpha_x; - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID; - float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); - float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0)); - bsdf->sample_weight *= F; + float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); + float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0)); + bsdf->sample_weight *= F; - return bsdf_microfacet_multi_ggx_common_setup(bsdf); + return bsdf_microfacet_multi_ggx_common_setup(bsdf); } ccl_device int bsdf_microfacet_multi_ggx_refraction_setup(MicrofacetBsdf *bsdf) { - bsdf->alpha_y = bsdf->alpha_x; - - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; + bsdf->alpha_y = bsdf->alpha_x; - return bsdf_microfacet_multi_ggx_common_setup(bsdf); -} + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; -ccl_device float3 bsdf_microfacet_multi_ggx_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { - *pdf = 0.0f; - return make_float3(0.0f, 0.0f, 0.0f); + return bsdf_microfacet_multi_ggx_common_setup(bsdf); } -ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; - - if(bsdf->alpha_x*bsdf->alpha_y < 1e-7f) { - return make_float3(0.0f, 0.0f, 0.0f); - } - - bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID); - - bool is_aniso = (bsdf->alpha_x != bsdf->alpha_y); - float3 X, Y, Z; - Z = bsdf->N; - if(is_aniso) - make_orthonormals_tangent(Z, bsdf->T, &X, &Y); - else - make_orthonormals(Z, &X, &Y); - - float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); - float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); - - if(is_aniso) - *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(bsdf->alpha_x, bsdf->alpha_y)); - else - *pdf = mf_ggx_pdf(localI, localO, bsdf->alpha_x); - return mf_eval_glossy(localI, localO, true, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior, use_fresnel, bsdf->extra->cspec0); +ccl_device float3 bsdf_microfacet_multi_ggx_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf, + ccl_addr_space uint *lcg_state) +{ + *pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, 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, ccl_addr_space uint *lcg_state) +ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf, + ccl_addr_space uint *lcg_state) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; + + if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) { + return make_float3(0.0f, 0.0f, 0.0f); + } + + bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID); + + bool is_aniso = (bsdf->alpha_x != bsdf->alpha_y); + float3 X, Y, Z; + Z = bsdf->N; + if (is_aniso) + make_orthonormals_tangent(Z, bsdf->T, &X, &Y); + else + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + if (is_aniso) + *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(bsdf->alpha_x, bsdf->alpha_y)); + else + *pdf = mf_ggx_pdf(localI, localO, bsdf->alpha_x); + return mf_eval_glossy(localI, + localO, + true, + bsdf->extra->color, + bsdf->alpha_x, + bsdf->alpha_y, + lcg_state, + bsdf->ior, + use_fresnel, + bsdf->extra->cspec0); +} + +ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, + 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, + ccl_addr_space uint *lcg_state) +{ + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; - float3 X, Y, Z; - Z = bsdf->N; + float3 X, Y, Z; + Z = bsdf->N; - if(bsdf->alpha_x*bsdf->alpha_y < 1e-7f) { - *omega_in = 2*dot(Z, I)*Z - I; - *pdf = 1e6f; - *eval = make_float3(1e6f, 1e6f, 1e6f); + if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) { + *omega_in = 2 * dot(Z, I) * Z - I; + *pdf = 1e6f; + *eval = make_float3(1e6f, 1e6f, 1e6f); #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx; - *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy; + *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx; + *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy; #endif - return LABEL_REFLECT|LABEL_SINGULAR; - } - - bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID); - - bool is_aniso = (bsdf->alpha_x != bsdf->alpha_y); - if(is_aniso) - make_orthonormals_tangent(Z, bsdf->T, &X, &Y); - else - make_orthonormals(Z, &X, &Y); - - float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); - float3 localO; - - *eval = mf_sample_glossy(localI, &localO, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior, use_fresnel, bsdf->extra->cspec0); - if(is_aniso) - *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(bsdf->alpha_x, bsdf->alpha_y)); - else - *pdf = mf_ggx_pdf(localI, localO, bsdf->alpha_x); - *eval *= *pdf; - - *omega_in = X*localO.x + Y*localO.y + Z*localO.z; + return LABEL_REFLECT | LABEL_SINGULAR; + } + + bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID); + + bool is_aniso = (bsdf->alpha_x != bsdf->alpha_y); + if (is_aniso) + make_orthonormals_tangent(Z, bsdf->T, &X, &Y); + else + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO; + + *eval = mf_sample_glossy(localI, + &localO, + bsdf->extra->color, + bsdf->alpha_x, + bsdf->alpha_y, + lcg_state, + bsdf->ior, + use_fresnel, + bsdf->extra->cspec0); + if (is_aniso) + *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(bsdf->alpha_x, bsdf->alpha_y)); + else + *pdf = mf_ggx_pdf(localI, localO, bsdf->alpha_x); + *eval *= *pdf; + + *omega_in = X * localO.x + Y * localO.y + Z * localO.z; #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx; - *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy; + *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx; + *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy; #endif - return LABEL_REFLECT|LABEL_GLOSSY; + return LABEL_REFLECT | LABEL_GLOSSY; } /* Multiscattering GGX Glass closure */ ccl_device int bsdf_microfacet_multi_ggx_glass_setup(MicrofacetBsdf *bsdf) { - bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); - bsdf->alpha_y = bsdf->alpha_x; - bsdf->ior = max(0.0f, bsdf->ior); - bsdf->extra->color.x = saturate(bsdf->extra->color.x); - bsdf->extra->color.y = saturate(bsdf->extra->color.y); - bsdf->extra->color.z = saturate(bsdf->extra->color.z); + bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); + bsdf->alpha_y = bsdf->alpha_x; + bsdf->ior = max(0.0f, bsdf->ior); + bsdf->extra->color.x = saturate(bsdf->extra->color.x); + bsdf->extra->color.y = saturate(bsdf->extra->color.y); + bsdf->extra->color.z = saturate(bsdf->extra->color.z); - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG; + return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG; } -ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(MicrofacetBsdf *bsdf, const ShaderData *sd) +ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(MicrofacetBsdf *bsdf, + const ShaderData *sd) { - bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); - bsdf->alpha_y = bsdf->alpha_x; - bsdf->ior = max(0.0f, bsdf->ior); - bsdf->extra->color.x = saturate(bsdf->extra->color.x); - bsdf->extra->color.y = saturate(bsdf->extra->color.y); - bsdf->extra->color.z = saturate(bsdf->extra->color.z); - bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); - bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); - bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); - - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID; - - float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); - float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0)); - bsdf->sample_weight *= F; - - return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG; -} - -ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; - - if(bsdf->alpha_x*bsdf->alpha_y < 1e-7f) { - return make_float3(0.0f, 0.0f, 0.0f); - } - - float3 X, Y, Z; - Z = bsdf->N; - make_orthonormals(Z, &X, &Y); - - float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); - float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); - - *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); - return mf_eval_glass(localI, localO, false, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior, false, bsdf->extra->color); -} - -ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; - - if(bsdf->alpha_x*bsdf->alpha_y < 1e-7f) { - return make_float3(0.0f, 0.0f, 0.0f); - } - - bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID); - - float3 X, Y, Z; - Z = bsdf->N; - make_orthonormals(Z, &X, &Y); - - float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); - float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); - - *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); - return mf_eval_glass(localI, localO, true, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior, use_fresnel, bsdf->extra->cspec0); -} - -ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg, 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, ccl_addr_space uint *lcg_state) + bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); + bsdf->alpha_y = bsdf->alpha_x; + bsdf->ior = max(0.0f, bsdf->ior); + bsdf->extra->color.x = saturate(bsdf->extra->color.x); + bsdf->extra->color.y = saturate(bsdf->extra->color.y); + bsdf->extra->color.z = saturate(bsdf->extra->color.z); + bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); + bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); + bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); + + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID; + + float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); + float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0)); + bsdf->sample_weight *= F; + + return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG; +} + +ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf, + ccl_addr_space uint *lcg_state) +{ + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; + + if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) { + return make_float3(0.0f, 0.0f, 0.0f); + } + + float3 X, Y, Z; + Z = bsdf->N; + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); + return mf_eval_glass(localI, + localO, + false, + bsdf->extra->color, + bsdf->alpha_x, + bsdf->alpha_y, + lcg_state, + bsdf->ior, + false, + bsdf->extra->color); +} + +ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf, + ccl_addr_space uint *lcg_state) +{ + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; + + if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) { + return make_float3(0.0f, 0.0f, 0.0f); + } + + bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID); + + float3 X, Y, Z; + Z = bsdf->N; + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); + return mf_eval_glass(localI, + localO, + true, + bsdf->extra->color, + bsdf->alpha_x, + bsdf->alpha_y, + lcg_state, + bsdf->ior, + use_fresnel, + bsdf->extra->cspec0); +} + +ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg, + 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, + ccl_addr_space uint *lcg_state) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; - float3 X, Y, Z; - Z = bsdf->N; + float3 X, Y, Z; + Z = bsdf->N; - if(bsdf->alpha_x*bsdf->alpha_y < 1e-7f) { - float3 R, T; + if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) { + float3 R, T; #ifdef __RAY_DIFFERENTIALS__ - float3 dRdx, dRdy, dTdx, dTdy; + float3 dRdx, dRdy, dTdx, dTdy; #endif - bool inside; - float fresnel = fresnel_dielectric(bsdf->ior, Z, I, &R, &T, + bool inside; + float fresnel = fresnel_dielectric(bsdf->ior, + Z, + I, + &R, + &T, #ifdef __RAY_DIFFERENTIALS__ - dIdx, dIdy, &dRdx, &dRdy, &dTdx, &dTdy, + dIdx, + dIdy, + &dRdx, + &dRdy, + &dTdx, + &dTdy, #endif - &inside); + &inside); - *pdf = 1e6f; - *eval = make_float3(1e6f, 1e6f, 1e6f); - if(randu < fresnel) { - *omega_in = R; + *pdf = 1e6f; + *eval = make_float3(1e6f, 1e6f, 1e6f); + if (randu < fresnel) { + *omega_in = R; #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = dRdx; - *domega_in_dy = dRdy; + *domega_in_dx = dRdx; + *domega_in_dy = dRdy; #endif - return LABEL_REFLECT|LABEL_SINGULAR; - } - else { - *omega_in = T; + return LABEL_REFLECT | LABEL_SINGULAR; + } + else { + *omega_in = T; #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = dTdx; - *domega_in_dy = dTdy; + *domega_in_dx = dTdx; + *domega_in_dy = dTdy; #endif - return LABEL_TRANSMIT|LABEL_SINGULAR; - } - } - - bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID); - - make_orthonormals(Z, &X, &Y); - - float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); - float3 localO; - - *eval = mf_sample_glass(localI, &localO, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior, use_fresnel, bsdf->extra->cspec0); - *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); - *eval *= *pdf; - - *omega_in = X*localO.x + Y*localO.y + Z*localO.z; - if(localO.z*localI.z > 0.0f) { + return LABEL_TRANSMIT | LABEL_SINGULAR; + } + } + + bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID); + + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO; + + *eval = mf_sample_glass(localI, + &localO, + bsdf->extra->color, + bsdf->alpha_x, + bsdf->alpha_y, + lcg_state, + bsdf->ior, + use_fresnel, + bsdf->extra->cspec0); + *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); + *eval *= *pdf; + + *omega_in = X * localO.x + Y * localO.y + Z * localO.z; + if (localO.z * localI.z > 0.0f) { #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx; - *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy; + *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx; + *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy; #endif - return LABEL_REFLECT|LABEL_GLOSSY; - } - else { + return LABEL_REFLECT | LABEL_GLOSSY; + } + else { #ifdef __RAY_DIFFERENTIALS__ - float cosI = dot(Z, I); - float dnp = max(sqrtf(1.0f - (bsdf->ior * bsdf->ior * (1.0f - cosI*cosI))), 1e-7f); - *domega_in_dx = -(bsdf->ior * dIdx) + ((bsdf->ior - bsdf->ior * bsdf->ior * cosI / dnp) * dot(dIdx, Z)) * Z; - *domega_in_dy = -(bsdf->ior * dIdy) + ((bsdf->ior - bsdf->ior * bsdf->ior * cosI / dnp) * dot(dIdy, Z)) * Z; + float cosI = dot(Z, I); + float dnp = max(sqrtf(1.0f - (bsdf->ior * bsdf->ior * (1.0f - cosI * cosI))), 1e-7f); + *domega_in_dx = -(bsdf->ior * dIdx) + + ((bsdf->ior - bsdf->ior * bsdf->ior * cosI / dnp) * dot(dIdx, Z)) * Z; + *domega_in_dy = -(bsdf->ior * dIdy) + + ((bsdf->ior - bsdf->ior * bsdf->ior * cosI / dnp) * dot(dIdy, Z)) * Z; #endif - return LABEL_TRANSMIT|LABEL_GLOSSY; - } + return LABEL_TRANSMIT | LABEL_GLOSSY; + } } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h index 5d300ef6db5..79247ee8057 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h @@ -25,247 +25,251 @@ * energy is used. In combination with MIS, that is enough to produce an unbiased result, although * the balance heuristic isn't necessarily optimal anymore. */ -ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)( - float3 wi, - float3 wo, - const bool wo_outside, - const float3 color, - const float alpha_x, - const float alpha_y, - ccl_addr_space uint *lcg_state, - const float eta, - bool use_fresnel, - const float3 cspec0) +ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(float3 wi, + float3 wo, + const bool wo_outside, + const float3 color, + const float alpha_x, + const float alpha_y, + ccl_addr_space uint *lcg_state, + const float eta, + bool use_fresnel, + const float3 cspec0) { - /* Evaluating for a shallower incoming direction produces less noise, and the properties of the BSDF guarantee reciprocity. */ - bool swapped = false; + /* Evaluating for a shallower incoming direction produces less noise, and the properties of the BSDF guarantee reciprocity. */ + bool swapped = false; #ifdef MF_MULTI_GLASS - if(wi.z*wo.z < 0.0f) { - /* Glass transmission is a special case and requires the directions to change hemisphere. */ - if(-wo.z < wi.z) { - swapped = true; - float3 tmp = -wo; - wo = -wi; - wi = tmp; - } - } - else + if (wi.z * wo.z < 0.0f) { + /* Glass transmission is a special case and requires the directions to change hemisphere. */ + if (-wo.z < wi.z) { + swapped = true; + float3 tmp = -wo; + wo = -wi; + wi = tmp; + } + } + else #endif - if(wo.z < wi.z) { - swapped = true; - float3 tmp = wo; - wo = wi; - wi = tmp; - } + if (wo.z < wi.z) { + swapped = true; + float3 tmp = wo; + wo = wi; + wi = tmp; + } - if(wi.z < 1e-5f || (wo.z < 1e-5f && wo_outside) || (wo.z > -1e-5f && !wo_outside)) - return make_float3(0.0f, 0.0f, 0.0f); + if (wi.z < 1e-5f || (wo.z < 1e-5f && wo_outside) || (wo.z > -1e-5f && !wo_outside)) + return make_float3(0.0f, 0.0f, 0.0f); - const float2 alpha = make_float2(alpha_x, alpha_y); + const float2 alpha = make_float2(alpha_x, alpha_y); - float lambda_r = mf_lambda(-wi, alpha); - float shadowing_lambda = mf_lambda(wo_outside? wo: -wo, alpha); + float lambda_r = mf_lambda(-wi, alpha); + float shadowing_lambda = mf_lambda(wo_outside ? wo : -wo, alpha); - /* Analytically compute single scattering for lower noise. */ - float3 eval; - float3 throughput = make_float3(1.0f, 1.0f, 1.0f); - const float3 wh = normalize(wi+wo); + /* Analytically compute single scattering for lower noise. */ + float3 eval; + float3 throughput = make_float3(1.0f, 1.0f, 1.0f); + const float3 wh = normalize(wi + wo); #ifdef MF_MULTI_GLASS - eval = mf_eval_phase_glass(-wi, lambda_r, wo, wo_outside, alpha, eta); - if(wo_outside) - eval *= -lambda_r / (shadowing_lambda - lambda_r); - else - eval *= -lambda_r * beta(-lambda_r, shadowing_lambda+1.0f); -#else /* MF_MULTI_GLOSSY */ - const float G2 = 1.0f / (1.0f - (lambda_r + 1.0f) + shadowing_lambda); - float val = G2 * 0.25f / wi.z; - if(alpha.x == alpha.y) - val *= D_ggx(wh, alpha.x); - else - val *= D_ggx_aniso(wh, alpha); - eval = make_float3(val, val, val); + eval = mf_eval_phase_glass(-wi, lambda_r, wo, wo_outside, alpha, eta); + if (wo_outside) + eval *= -lambda_r / (shadowing_lambda - lambda_r); + else + eval *= -lambda_r * beta(-lambda_r, shadowing_lambda + 1.0f); +#else /* MF_MULTI_GLOSSY */ + const float G2 = 1.0f / (1.0f - (lambda_r + 1.0f) + shadowing_lambda); + float val = G2 * 0.25f / wi.z; + if (alpha.x == alpha.y) + val *= D_ggx(wh, alpha.x); + else + val *= D_ggx_aniso(wh, alpha); + eval = make_float3(val, val, val); #endif - float F0 = fresnel_dielectric_cos(1.0f, eta); - if(use_fresnel) { - throughput = interpolate_fresnel_color(wi, wh, eta, F0, cspec0); + float F0 = fresnel_dielectric_cos(1.0f, eta); + if (use_fresnel) { + throughput = interpolate_fresnel_color(wi, wh, eta, F0, cspec0); - eval *= throughput; - } + eval *= throughput; + } - float3 wr = -wi; - float hr = 1.0f; - float C1_r = 1.0f; - float G1_r = 0.0f; - bool outside = true; + float3 wr = -wi; + float hr = 1.0f; + float C1_r = 1.0f; + float G1_r = 0.0f; + bool outside = true; - for(int order = 0; order < 10; order++) { - /* Sample microfacet height. */ - float height_rand = lcg_step_float_addrspace(lcg_state); - if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, height_rand)) - break; - /* Sample microfacet normal. */ - float vndf_rand_y = lcg_step_float_addrspace(lcg_state); - float vndf_rand_x = lcg_step_float_addrspace(lcg_state); - float3 wm = mf_sample_vndf(-wr, alpha, vndf_rand_x, vndf_rand_y); + for (int order = 0; order < 10; order++) { + /* Sample microfacet height. */ + float height_rand = lcg_step_float_addrspace(lcg_state); + if (!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, height_rand)) + break; + /* Sample microfacet normal. */ + float vndf_rand_y = lcg_step_float_addrspace(lcg_state); + float vndf_rand_x = lcg_step_float_addrspace(lcg_state); + float3 wm = mf_sample_vndf(-wr, alpha, vndf_rand_x, vndf_rand_y); #ifdef MF_MULTI_GLASS - if(order == 0 && use_fresnel) { - /* Evaluate amount of scattering towards wo on this microfacet. */ - float3 phase; - if(outside) - phase = mf_eval_phase_glass(wr, lambda_r, wo, wo_outside, alpha, eta); - else - phase = mf_eval_phase_glass(wr, lambda_r, -wo, !wo_outside, alpha, 1.0f / eta); + if (order == 0 && use_fresnel) { + /* Evaluate amount of scattering towards wo on this microfacet. */ + float3 phase; + if (outside) + phase = mf_eval_phase_glass(wr, lambda_r, wo, wo_outside, alpha, eta); + else + phase = mf_eval_phase_glass(wr, lambda_r, -wo, !wo_outside, alpha, 1.0f / eta); - eval = throughput * phase * mf_G1(wo_outside ? wo : -wo, mf_C1((outside == wo_outside) ? hr : -hr), shadowing_lambda); - } + eval = throughput * phase * + mf_G1(wo_outside ? wo : -wo, + mf_C1((outside == wo_outside) ? hr : -hr), + shadowing_lambda); + } #endif - if(order > 0) { - /* Evaluate amount of scattering towards wo on this microfacet. */ - float3 phase; + if (order > 0) { + /* Evaluate amount of scattering towards wo on this microfacet. */ + float3 phase; #ifdef MF_MULTI_GLASS - if(outside) - phase = mf_eval_phase_glass(wr, lambda_r, wo, wo_outside, alpha, eta); - else - phase = mf_eval_phase_glass(wr, lambda_r, -wo, !wo_outside, alpha, 1.0f/eta); -#else /* MF_MULTI_GLOSSY */ - phase = mf_eval_phase_glossy(wr, lambda_r, wo, alpha) * throughput; + if (outside) + phase = mf_eval_phase_glass(wr, lambda_r, wo, wo_outside, alpha, eta); + else + phase = mf_eval_phase_glass(wr, lambda_r, -wo, !wo_outside, alpha, 1.0f / eta); +#else /* MF_MULTI_GLOSSY */ + phase = mf_eval_phase_glossy(wr, lambda_r, wo, alpha) * throughput; #endif - eval += throughput * phase * mf_G1(wo_outside? wo: -wo, mf_C1((outside == wo_outside)? hr: -hr), shadowing_lambda); - } - if(order+1 < 10) { - /* Bounce from the microfacet. */ + eval += throughput * phase * + mf_G1(wo_outside ? wo : -wo, + mf_C1((outside == wo_outside) ? hr : -hr), + shadowing_lambda); + } + if (order + 1 < 10) { + /* Bounce from the microfacet. */ #ifdef MF_MULTI_GLASS - bool next_outside; - float3 wi_prev = -wr; - float phase_rand = lcg_step_float_addrspace(lcg_state); - wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, phase_rand, &next_outside); - if(!next_outside) { - outside = !outside; - wr = -wr; - hr = -hr; - } + bool next_outside; + float3 wi_prev = -wr; + float phase_rand = lcg_step_float_addrspace(lcg_state); + wr = mf_sample_phase_glass(-wr, outside ? eta : 1.0f / eta, wm, phase_rand, &next_outside); + if (!next_outside) { + outside = !outside; + wr = -wr; + hr = -hr; + } - if(use_fresnel && !next_outside) { - throughput *= color; - } - else if(use_fresnel && order > 0) { - throughput *= interpolate_fresnel_color(wi_prev, wm, eta, F0, cspec0); - } -#else /* MF_MULTI_GLOSSY */ - if(use_fresnel && order > 0) { - throughput *= interpolate_fresnel_color(-wr, wm, eta, F0, cspec0); - } - wr = mf_sample_phase_glossy(-wr, &throughput, wm); + if (use_fresnel && !next_outside) { + throughput *= color; + } + else if (use_fresnel && order > 0) { + throughput *= interpolate_fresnel_color(wi_prev, wm, eta, F0, cspec0); + } +#else /* MF_MULTI_GLOSSY */ + if (use_fresnel && order > 0) { + throughput *= interpolate_fresnel_color(-wr, wm, eta, F0, cspec0); + } + wr = mf_sample_phase_glossy(-wr, &throughput, wm); #endif - lambda_r = mf_lambda(wr, alpha); + lambda_r = mf_lambda(wr, alpha); - if(!use_fresnel) - throughput *= color; + if (!use_fresnel) + throughput *= color; - C1_r = mf_C1(hr); - G1_r = mf_G1(wr, C1_r, lambda_r); - } - } + C1_r = mf_C1(hr); + G1_r = mf_G1(wr, C1_r, lambda_r); + } + } - if(swapped) - eval *= fabsf(wi.z / wo.z); - return eval; + if (swapped) + eval *= fabsf(wi.z / wo.z); + return eval; } /* Perform a random walk on the microsurface starting from wi, returning the direction in which the walk * escaped the surface in wo. The function returns the throughput between wi and wo. * Without reflection losses due to coloring or fresnel absorption in conductors, the sampling is optimal. */ -ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)( - float3 wi, - float3 *wo, - const float3 color, - const float alpha_x, - const float alpha_y, - ccl_addr_space uint *lcg_state, - const float eta, - bool use_fresnel, - const float3 cspec0) +ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, + float3 *wo, + const float3 color, + const float alpha_x, + const float alpha_y, + ccl_addr_space uint *lcg_state, + const float eta, + bool use_fresnel, + const float3 cspec0) { - const float2 alpha = make_float2(alpha_x, alpha_y); + const float2 alpha = make_float2(alpha_x, alpha_y); - float3 throughput = make_float3(1.0f, 1.0f, 1.0f); - float3 wr = -wi; - float lambda_r = mf_lambda(wr, alpha); - float hr = 1.0f; - float C1_r = 1.0f; - float G1_r = 0.0f; - bool outside = true; + float3 throughput = make_float3(1.0f, 1.0f, 1.0f); + float3 wr = -wi; + float lambda_r = mf_lambda(wr, alpha); + float hr = 1.0f; + float C1_r = 1.0f; + float G1_r = 0.0f; + bool outside = true; - float F0 = fresnel_dielectric_cos(1.0f, eta); - if(use_fresnel) { - throughput = interpolate_fresnel_color(wi, normalize(wi + wr), eta, F0, cspec0); - } + float F0 = fresnel_dielectric_cos(1.0f, eta); + if (use_fresnel) { + throughput = interpolate_fresnel_color(wi, normalize(wi + wr), eta, F0, cspec0); + } - int order; - for(order = 0; order < 10; order++) { - /* Sample microfacet height. */ - float height_rand = lcg_step_float_addrspace(lcg_state); - if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, height_rand)) { - /* The random walk has left the surface. */ - *wo = outside? wr: -wr; - return throughput; - } - /* Sample microfacet normal. */ - float vndf_rand_y = lcg_step_float_addrspace(lcg_state); - float vndf_rand_x = lcg_step_float_addrspace(lcg_state); - float3 wm = mf_sample_vndf(-wr, alpha, vndf_rand_x, vndf_rand_y); + int order; + for (order = 0; order < 10; order++) { + /* Sample microfacet height. */ + float height_rand = lcg_step_float_addrspace(lcg_state); + if (!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, height_rand)) { + /* The random walk has left the surface. */ + *wo = outside ? wr : -wr; + return throughput; + } + /* Sample microfacet normal. */ + float vndf_rand_y = lcg_step_float_addrspace(lcg_state); + float vndf_rand_x = lcg_step_float_addrspace(lcg_state); + float3 wm = mf_sample_vndf(-wr, alpha, vndf_rand_x, vndf_rand_y); - /* First-bounce color is already accounted for in mix weight. */ - if(!use_fresnel && order > 0) - throughput *= color; + /* First-bounce color is already accounted for in mix weight. */ + if (!use_fresnel && order > 0) + throughput *= color; - /* Bounce from the microfacet. */ + /* Bounce from the microfacet. */ #ifdef MF_MULTI_GLASS - bool next_outside; - float3 wi_prev = -wr; - float phase_rand = lcg_step_float_addrspace(lcg_state); - wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, phase_rand, &next_outside); - if(!next_outside) { - hr = -hr; - wr = -wr; - outside = !outside; - } + bool next_outside; + float3 wi_prev = -wr; + float phase_rand = lcg_step_float_addrspace(lcg_state); + wr = mf_sample_phase_glass(-wr, outside ? eta : 1.0f / eta, wm, phase_rand, &next_outside); + if (!next_outside) { + hr = -hr; + wr = -wr; + outside = !outside; + } - if(use_fresnel) { - if(!next_outside) { - throughput *= color; - } - else { - float3 t_color = interpolate_fresnel_color(wi_prev, wm, eta, F0, cspec0); + if (use_fresnel) { + if (!next_outside) { + throughput *= color; + } + else { + float3 t_color = interpolate_fresnel_color(wi_prev, wm, eta, F0, cspec0); - if(order == 0) - throughput = t_color; - else - throughput *= t_color; - } - } -#else /* MF_MULTI_GLOSSY */ - if(use_fresnel) { - float3 t_color = interpolate_fresnel_color(-wr, wm, eta, F0, cspec0); + if (order == 0) + throughput = t_color; + else + throughput *= t_color; + } + } +#else /* MF_MULTI_GLOSSY */ + if (use_fresnel) { + float3 t_color = interpolate_fresnel_color(-wr, wm, eta, F0, cspec0); - if(order == 0) - throughput = t_color; - else - throughput *= t_color; - } - wr = mf_sample_phase_glossy(-wr, &throughput, wm); + if (order == 0) + throughput = t_color; + else + throughput *= t_color; + } + wr = mf_sample_phase_glossy(-wr, &throughput, wm); #endif - /* Update random walk parameters. */ - lambda_r = mf_lambda(wr, alpha); - G1_r = mf_G1(wr, C1_r, lambda_r); - } - *wo = make_float3(0.0f, 0.0f, 1.0f); - return make_float3(0.0f, 0.0f, 0.0f); + /* Update random walk parameters. */ + lambda_r = mf_lambda(wr, alpha); + G1_r = mf_G1(wr, C1_r, lambda_r); + } + *wo = make_float3(0.0f, 0.0f, 1.0f); + return make_float3(0.0f, 0.0f, 0.0f); } #undef MF_MULTI_GLASS diff --git a/intern/cycles/kernel/closure/bsdf_oren_nayar.h b/intern/cycles/kernel/closure/bsdf_oren_nayar.h index 3446d1609d9..104ed5b2818 100644 --- a/intern/cycles/kernel/closure/bsdf_oren_nayar.h +++ b/intern/cycles/kernel/closure/bsdf_oren_nayar.h @@ -20,92 +20,110 @@ CCL_NAMESPACE_BEGIN typedef ccl_addr_space struct OrenNayarBsdf { - SHADER_CLOSURE_BASE; + SHADER_CLOSURE_BASE; - float roughness; - float a; - float b; + float roughness; + float a; + float b; } OrenNayarBsdf; -ccl_device float3 bsdf_oren_nayar_get_intensity(const ShaderClosure *sc, float3 n, float3 v, float3 l) +ccl_device float3 bsdf_oren_nayar_get_intensity(const ShaderClosure *sc, + float3 n, + float3 v, + float3 l) { - const OrenNayarBsdf *bsdf = (const OrenNayarBsdf*)sc; - float nl = max(dot(n, l), 0.0f); - float nv = max(dot(n, v), 0.0f); - float t = dot(l, v) - nl * nv; - - if(t > 0.0f) - t /= max(nl, nv) + FLT_MIN; - float is = nl * (bsdf->a + bsdf->b * t); - return make_float3(is, is, is); + const OrenNayarBsdf *bsdf = (const OrenNayarBsdf *)sc; + float nl = max(dot(n, l), 0.0f); + float nv = max(dot(n, v), 0.0f); + float t = dot(l, v) - nl * nv; + + if (t > 0.0f) + t /= max(nl, nv) + FLT_MIN; + float is = nl * (bsdf->a + bsdf->b * t); + return make_float3(is, is, is); } ccl_device int bsdf_oren_nayar_setup(OrenNayarBsdf *bsdf) { - float sigma = bsdf->roughness; + float sigma = bsdf->roughness; - bsdf->type = CLOSURE_BSDF_OREN_NAYAR_ID; + bsdf->type = CLOSURE_BSDF_OREN_NAYAR_ID; - sigma = saturate(sigma); + sigma = saturate(sigma); - float div = 1.0f / (M_PI_F + ((3.0f * M_PI_F - 4.0f) / 6.0f) * sigma); + float div = 1.0f / (M_PI_F + ((3.0f * M_PI_F - 4.0f) / 6.0f) * sigma); - bsdf->a = 1.0f * div; - bsdf->b = sigma * div; + bsdf->a = 1.0f * div; + bsdf->b = sigma * div; - return SD_BSDF|SD_BSDF_HAS_EVAL; + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device bool bsdf_oren_nayar_merge(const ShaderClosure *a, const ShaderClosure *b) { - const OrenNayarBsdf *bsdf_a = (const OrenNayarBsdf*)a; - const OrenNayarBsdf *bsdf_b = (const OrenNayarBsdf*)b; + const OrenNayarBsdf *bsdf_a = (const OrenNayarBsdf *)a; + const OrenNayarBsdf *bsdf_b = (const OrenNayarBsdf *)b; - return (isequal_float3(bsdf_a->N, bsdf_b->N)) && - (bsdf_a->roughness == bsdf_b->roughness); + return (isequal_float3(bsdf_a->N, bsdf_b->N)) && (bsdf_a->roughness == bsdf_b->roughness); } -ccl_device float3 bsdf_oren_nayar_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_oren_nayar_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - const OrenNayarBsdf *bsdf = (const OrenNayarBsdf*)sc; - if(dot(bsdf->N, omega_in) > 0.0f) { - *pdf = 0.5f * M_1_PI_F; - return bsdf_oren_nayar_get_intensity(sc, bsdf->N, I, omega_in); - } - else { - *pdf = 0.0f; - return make_float3(0.0f, 0.0f, 0.0f); - } + const OrenNayarBsdf *bsdf = (const OrenNayarBsdf *)sc; + if (dot(bsdf->N, omega_in) > 0.0f) { + *pdf = 0.5f * M_1_PI_F; + return bsdf_oren_nayar_get_intensity(sc, bsdf->N, I, omega_in); + } + else { + *pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); + } } -ccl_device float3 bsdf_oren_nayar_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_oren_nayar_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device int bsdf_oren_nayar_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) +ccl_device int bsdf_oren_nayar_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) { - const OrenNayarBsdf *bsdf = (const OrenNayarBsdf*)sc; - sample_uniform_hemisphere(bsdf->N, randu, randv, omega_in, pdf); + const OrenNayarBsdf *bsdf = (const OrenNayarBsdf *)sc; + sample_uniform_hemisphere(bsdf->N, randu, randv, omega_in, pdf); - if(dot(Ng, *omega_in) > 0.0f) { - *eval = bsdf_oren_nayar_get_intensity(sc, bsdf->N, I, *omega_in); + if (dot(Ng, *omega_in) > 0.0f) { + *eval = bsdf_oren_nayar_get_intensity(sc, bsdf->N, I, *omega_in); #ifdef __RAY_DIFFERENTIALS__ - // TODO: find a better approximation for the bounce - *domega_in_dx = (2.0f * dot(bsdf->N, dIdx)) * bsdf->N - dIdx; - *domega_in_dy = (2.0f * dot(bsdf->N, dIdy)) * bsdf->N - dIdy; + // TODO: find a better approximation for the bounce + *domega_in_dx = (2.0f * dot(bsdf->N, dIdx)) * bsdf->N - dIdx; + *domega_in_dy = (2.0f * dot(bsdf->N, dIdy)) * bsdf->N - dIdy; #endif - } - else { - *pdf = 0.0f; - *eval = make_float3(0.0f, 0.0f, 0.0f); - } + } + else { + *pdf = 0.0f; + *eval = make_float3(0.0f, 0.0f, 0.0f); + } - return LABEL_REFLECT|LABEL_DIFFUSE; + return LABEL_REFLECT | LABEL_DIFFUSE; } - CCL_NAMESPACE_END -#endif /* __BSDF_OREN_NAYAR_H__ */ +#endif /* __BSDF_OREN_NAYAR_H__ */ diff --git a/intern/cycles/kernel/closure/bsdf_phong_ramp.h b/intern/cycles/kernel/closure/bsdf_phong_ramp.h index 83da05ac435..b6fd0e68681 100644 --- a/intern/cycles/kernel/closure/bsdf_phong_ramp.h +++ b/intern/cycles/kernel/closure/bsdf_phong_ramp.h @@ -38,105 +38,118 @@ CCL_NAMESPACE_BEGIN #ifdef __OSL__ typedef ccl_addr_space struct PhongRampBsdf { - SHADER_CLOSURE_BASE; + SHADER_CLOSURE_BASE; - float exponent; - float3 *colors; + float exponent; + float3 *colors; } PhongRampBsdf; ccl_device float3 bsdf_phong_ramp_get_color(const float3 colors[8], float pos) { - int MAXCOLORS = 8; - - float npos = pos * (float)(MAXCOLORS - 1); - int ipos = float_to_int(npos); - if(ipos < 0) - return colors[0]; - if(ipos >= (MAXCOLORS - 1)) - return colors[MAXCOLORS - 1]; - float offset = npos - (float)ipos; - return colors[ipos] * (1.0f - offset) + colors[ipos+1] * offset; + int MAXCOLORS = 8; + + float npos = pos * (float)(MAXCOLORS - 1); + int ipos = float_to_int(npos); + if (ipos < 0) + return colors[0]; + if (ipos >= (MAXCOLORS - 1)) + return colors[MAXCOLORS - 1]; + float offset = npos - (float)ipos; + return colors[ipos] * (1.0f - offset) + colors[ipos + 1] * offset; } ccl_device int bsdf_phong_ramp_setup(PhongRampBsdf *bsdf) { - bsdf->type = CLOSURE_BSDF_PHONG_RAMP_ID; - bsdf->exponent = max(bsdf->exponent, 0.0f); - return SD_BSDF|SD_BSDF_HAS_EVAL; + bsdf->type = CLOSURE_BSDF_PHONG_RAMP_ID; + bsdf->exponent = max(bsdf->exponent, 0.0f); + return SD_BSDF | SD_BSDF_HAS_EVAL; } -ccl_device float3 bsdf_phong_ramp_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_phong_ramp_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - const PhongRampBsdf *bsdf = (const PhongRampBsdf*)sc; - float m_exponent = bsdf->exponent; - float cosNI = dot(bsdf->N, omega_in); - float cosNO = dot(bsdf->N, I); - - if(cosNI > 0 && cosNO > 0) { - // reflect the view vector - float3 R = (2 * cosNO) * bsdf->N - I; - float cosRI = dot(R, omega_in); - if(cosRI > 0) { - float cosp = powf(cosRI, m_exponent); - float common = 0.5f * M_1_PI_F * cosp; - float out = cosNI * (m_exponent + 2) * common; - *pdf = (m_exponent + 1) * common; - return bsdf_phong_ramp_get_color(bsdf->colors, cosp) * out; - } - } - - return make_float3(0.0f, 0.0f, 0.0f); + const PhongRampBsdf *bsdf = (const PhongRampBsdf *)sc; + float m_exponent = bsdf->exponent; + float cosNI = dot(bsdf->N, omega_in); + float cosNO = dot(bsdf->N, I); + + if (cosNI > 0 && cosNO > 0) { + // reflect the view vector + float3 R = (2 * cosNO) * bsdf->N - I; + float cosRI = dot(R, omega_in); + if (cosRI > 0) { + float cosp = powf(cosRI, m_exponent); + float common = 0.5f * M_1_PI_F * cosp; + float out = cosNI * (m_exponent + 2) * common; + *pdf = (m_exponent + 1) * common; + return bsdf_phong_ramp_get_color(bsdf->colors, cosp) * out; + } + } + + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device float3 bsdf_phong_ramp_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_phong_ramp_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device int bsdf_phong_ramp_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) +ccl_device int bsdf_phong_ramp_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) { - const PhongRampBsdf *bsdf = (const PhongRampBsdf*)sc; - float cosNO = dot(bsdf->N, I); - float m_exponent = bsdf->exponent; - - if(cosNO > 0) { - // reflect the view vector - float3 R = (2 * cosNO) * bsdf->N - I; - -#ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = (2 * dot(bsdf->N, dIdx)) * bsdf->N - dIdx; - *domega_in_dy = (2 * dot(bsdf->N, dIdy)) * bsdf->N - dIdy; -#endif - - float3 T, B; - make_orthonormals (R, &T, &B); - float phi = M_2PI_F * randu; - float cosTheta = powf(randv, 1 / (m_exponent + 1)); - float sinTheta2 = 1 - cosTheta * cosTheta; - float sinTheta = sinTheta2 > 0 ? sqrtf(sinTheta2) : 0; - *omega_in = (cosf(phi) * sinTheta) * T + - (sinf(phi) * sinTheta) * B + - ( cosTheta) * R; - if(dot(Ng, *omega_in) > 0.0f) - { - // common terms for pdf and eval - float cosNI = dot(bsdf->N, *omega_in); - // make sure the direction we chose is still in the right hemisphere - if(cosNI > 0) - { - float cosp = powf(cosTheta, m_exponent); - float common = 0.5f * M_1_PI_F * cosp; - *pdf = (m_exponent + 1) * common; - float out = cosNI * (m_exponent + 2) * common; - *eval = bsdf_phong_ramp_get_color(bsdf->colors, cosp) * out; - } - } - } - return LABEL_REFLECT|LABEL_GLOSSY; + const PhongRampBsdf *bsdf = (const PhongRampBsdf *)sc; + float cosNO = dot(bsdf->N, I); + float m_exponent = bsdf->exponent; + + if (cosNO > 0) { + // reflect the view vector + float3 R = (2 * cosNO) * bsdf->N - I; + +# ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = (2 * dot(bsdf->N, dIdx)) * bsdf->N - dIdx; + *domega_in_dy = (2 * dot(bsdf->N, dIdy)) * bsdf->N - dIdy; +# endif + + float3 T, B; + make_orthonormals(R, &T, &B); + float phi = M_2PI_F * randu; + float cosTheta = powf(randv, 1 / (m_exponent + 1)); + float sinTheta2 = 1 - cosTheta * cosTheta; + float sinTheta = sinTheta2 > 0 ? sqrtf(sinTheta2) : 0; + *omega_in = (cosf(phi) * sinTheta) * T + (sinf(phi) * sinTheta) * B + (cosTheta)*R; + if (dot(Ng, *omega_in) > 0.0f) { + // common terms for pdf and eval + float cosNI = dot(bsdf->N, *omega_in); + // make sure the direction we chose is still in the right hemisphere + if (cosNI > 0) { + float cosp = powf(cosTheta, m_exponent); + float common = 0.5f * M_1_PI_F * cosp; + *pdf = (m_exponent + 1) * common; + float out = cosNI * (m_exponent + 2) * common; + *eval = bsdf_phong_ramp_get_color(bsdf->colors, cosp) * out; + } + } + } + return LABEL_REFLECT | LABEL_GLOSSY; } -#endif /* __OSL__ */ +#endif /* __OSL__ */ CCL_NAMESPACE_END -#endif /* __BSDF_PHONG_RAMP_H__ */ +#endif /* __BSDF_PHONG_RAMP_H__ */ diff --git a/intern/cycles/kernel/closure/bsdf_principled_diffuse.h b/intern/cycles/kernel/closure/bsdf_principled_diffuse.h index 2f65fd54be2..d7795974ef5 100644 --- a/intern/cycles/kernel/closure/bsdf_principled_diffuse.h +++ b/intern/cycles/kernel/closure/bsdf_principled_diffuse.h @@ -25,101 +25,113 @@ CCL_NAMESPACE_BEGIN typedef ccl_addr_space struct PrincipledDiffuseBsdf { - SHADER_CLOSURE_BASE; + SHADER_CLOSURE_BASE; - float roughness; + float roughness; } PrincipledDiffuseBsdf; -ccl_device float3 calculate_principled_diffuse_brdf(const PrincipledDiffuseBsdf *bsdf, - float3 N, float3 V, float3 L, float3 H, float *pdf) +ccl_device float3 calculate_principled_diffuse_brdf( + const PrincipledDiffuseBsdf *bsdf, float3 N, float3 V, float3 L, float3 H, float *pdf) { - float NdotL = max(dot(N, L), 0.0f); - float NdotV = max(dot(N, V), 0.0f); + float NdotL = max(dot(N, L), 0.0f); + float NdotV = max(dot(N, V), 0.0f); - if(NdotL < 0 || NdotV < 0) { - *pdf = 0.0f; - return make_float3(0.0f, 0.0f, 0.0f); - } + if (NdotL < 0 || NdotV < 0) { + *pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); + } - float LdotH = dot(L, H); + float LdotH = dot(L, H); - float FL = schlick_fresnel(NdotL), FV = schlick_fresnel(NdotV); - const float Fd90 = 0.5f + 2.0f * LdotH*LdotH * bsdf->roughness; - float Fd = (1.0f * (1.0f - FL) + Fd90 * FL) * (1.0f * (1.0f - FV) + Fd90 * FV); + float FL = schlick_fresnel(NdotL), FV = schlick_fresnel(NdotV); + const float Fd90 = 0.5f + 2.0f * LdotH * LdotH * bsdf->roughness; + float Fd = (1.0f * (1.0f - FL) + Fd90 * FL) * (1.0f * (1.0f - FV) + Fd90 * FV); - float value = M_1_PI_F * NdotL * Fd; + float value = M_1_PI_F * NdotL * Fd; - return make_float3(value, value, value); + return make_float3(value, value, value); } ccl_device int bsdf_principled_diffuse_setup(PrincipledDiffuseBsdf *bsdf) { - bsdf->type = CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL; + bsdf->type = CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID; + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device bool bsdf_principled_diffuse_merge(const ShaderClosure *a, const ShaderClosure *b) { - const PrincipledDiffuseBsdf *bsdf_a = (const PrincipledDiffuseBsdf*)a; - const PrincipledDiffuseBsdf *bsdf_b = (const PrincipledDiffuseBsdf*)b; + const PrincipledDiffuseBsdf *bsdf_a = (const PrincipledDiffuseBsdf *)a; + const PrincipledDiffuseBsdf *bsdf_b = (const PrincipledDiffuseBsdf *)b; - return (isequal_float3(bsdf_a->N, bsdf_b->N) && bsdf_a->roughness == bsdf_b->roughness); + return (isequal_float3(bsdf_a->N, bsdf_b->N) && bsdf_a->roughness == bsdf_b->roughness); } -ccl_device float3 bsdf_principled_diffuse_eval_reflect(const ShaderClosure *sc, const float3 I, - const float3 omega_in, float *pdf) +ccl_device float3 bsdf_principled_diffuse_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - const PrincipledDiffuseBsdf *bsdf = (const PrincipledDiffuseBsdf *)sc; - - float3 N = bsdf->N; - float3 V = I; // outgoing - float3 L = omega_in; // incoming - float3 H = normalize(L + V); - - if(dot(N, omega_in) > 0.0f) { - *pdf = fmaxf(dot(N, omega_in), 0.0f) * M_1_PI_F; - return calculate_principled_diffuse_brdf(bsdf, N, V, L, H, pdf); - } - else { - *pdf = 0.0f; - return make_float3(0.0f, 0.0f, 0.0f); - } + const PrincipledDiffuseBsdf *bsdf = (const PrincipledDiffuseBsdf *)sc; + + float3 N = bsdf->N; + float3 V = I; // outgoing + float3 L = omega_in; // incoming + float3 H = normalize(L + V); + + if (dot(N, omega_in) > 0.0f) { + *pdf = fmaxf(dot(N, omega_in), 0.0f) * M_1_PI_F; + return calculate_principled_diffuse_brdf(bsdf, N, V, L, H, pdf); + } + else { + *pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); + } } -ccl_device float3 bsdf_principled_diffuse_eval_transmit(const ShaderClosure *sc, const float3 I, - const float3 omega_in, float *pdf) +ccl_device float3 bsdf_principled_diffuse_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } ccl_device int bsdf_principled_diffuse_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) + 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) { - const PrincipledDiffuseBsdf *bsdf = (const PrincipledDiffuseBsdf *)sc; + const PrincipledDiffuseBsdf *bsdf = (const PrincipledDiffuseBsdf *)sc; - float3 N = bsdf->N; + float3 N = bsdf->N; - sample_cos_hemisphere(N, randu, randv, omega_in, pdf); + sample_cos_hemisphere(N, randu, randv, omega_in, pdf); - if(dot(Ng, *omega_in) > 0) { - float3 H = normalize(I + *omega_in); + if (dot(Ng, *omega_in) > 0) { + float3 H = normalize(I + *omega_in); - *eval = calculate_principled_diffuse_brdf(bsdf, N, I, *omega_in, H, pdf); + *eval = calculate_principled_diffuse_brdf(bsdf, N, I, *omega_in, H, pdf); #ifdef __RAY_DIFFERENTIALS__ - // TODO: find a better approximation for the diffuse bounce - *domega_in_dx = -((2 * dot(N, dIdx)) * N - dIdx); - *domega_in_dy = -((2 * dot(N, dIdy)) * N - dIdy); + // TODO: find a better approximation for the diffuse bounce + *domega_in_dx = -((2 * dot(N, dIdx)) * N - dIdx); + *domega_in_dy = -((2 * dot(N, dIdy)) * N - dIdy); #endif - } - else { - *pdf = 0.0f; - } - return LABEL_REFLECT|LABEL_DIFFUSE; + } + else { + *pdf = 0.0f; + } + return LABEL_REFLECT | LABEL_DIFFUSE; } CCL_NAMESPACE_END -#endif /* __BSDF_PRINCIPLED_DIFFUSE_H__ */ +#endif /* __BSDF_PRINCIPLED_DIFFUSE_H__ */ diff --git a/intern/cycles/kernel/closure/bsdf_principled_sheen.h b/intern/cycles/kernel/closure/bsdf_principled_sheen.h index ccdcb1babd2..bc522095b3b 100644 --- a/intern/cycles/kernel/closure/bsdf_principled_sheen.h +++ b/intern/cycles/kernel/closure/bsdf_principled_sheen.h @@ -25,87 +25,99 @@ CCL_NAMESPACE_BEGIN typedef ccl_addr_space struct PrincipledSheenBsdf { - SHADER_CLOSURE_BASE; + SHADER_CLOSURE_BASE; } PrincipledSheenBsdf; -ccl_device float3 calculate_principled_sheen_brdf(const PrincipledSheenBsdf *bsdf, - float3 N, float3 V, float3 L, float3 H, float *pdf) +ccl_device float3 calculate_principled_sheen_brdf( + const PrincipledSheenBsdf *bsdf, float3 N, float3 V, float3 L, float3 H, float *pdf) { - float NdotL = dot(N, L); - float NdotV = dot(N, V); + float NdotL = dot(N, L); + float NdotV = dot(N, V); - if(NdotL < 0 || NdotV < 0) { - *pdf = 0.0f; - return make_float3(0.0f, 0.0f, 0.0f); - } + if (NdotL < 0 || NdotV < 0) { + *pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); + } - float LdotH = dot(L, H); + float LdotH = dot(L, H); - float value = schlick_fresnel(LdotH) * NdotL; + float value = schlick_fresnel(LdotH) * NdotL; - return make_float3(value, value, value); + return make_float3(value, value, value); } ccl_device int bsdf_principled_sheen_setup(PrincipledSheenBsdf *bsdf) { - bsdf->type = CLOSURE_BSDF_PRINCIPLED_SHEEN_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL; + bsdf->type = CLOSURE_BSDF_PRINCIPLED_SHEEN_ID; + return SD_BSDF | SD_BSDF_HAS_EVAL; } -ccl_device float3 bsdf_principled_sheen_eval_reflect(const ShaderClosure *sc, const float3 I, - const float3 omega_in, float *pdf) +ccl_device float3 bsdf_principled_sheen_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - const PrincipledSheenBsdf *bsdf = (const PrincipledSheenBsdf *)sc; - - float3 N = bsdf->N; - float3 V = I; // outgoing - float3 L = omega_in; // incoming - float3 H = normalize(L + V); - - if(dot(N, omega_in) > 0.0f) { - *pdf = fmaxf(dot(N, omega_in), 0.0f) * M_1_PI_F; - return calculate_principled_sheen_brdf(bsdf, N, V, L, H, pdf); - } - else { - *pdf = 0.0f; - return make_float3(0.0f, 0.0f, 0.0f); - } + const PrincipledSheenBsdf *bsdf = (const PrincipledSheenBsdf *)sc; + + float3 N = bsdf->N; + float3 V = I; // outgoing + float3 L = omega_in; // incoming + float3 H = normalize(L + V); + + if (dot(N, omega_in) > 0.0f) { + *pdf = fmaxf(dot(N, omega_in), 0.0f) * M_1_PI_F; + return calculate_principled_sheen_brdf(bsdf, N, V, L, H, pdf); + } + else { + *pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); + } } -ccl_device float3 bsdf_principled_sheen_eval_transmit(const ShaderClosure *sc, const float3 I, - const float3 omega_in, float *pdf) +ccl_device float3 bsdf_principled_sheen_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } ccl_device int bsdf_principled_sheen_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) + 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) { - const PrincipledSheenBsdf *bsdf = (const PrincipledSheenBsdf *)sc; + const PrincipledSheenBsdf *bsdf = (const PrincipledSheenBsdf *)sc; - float3 N = bsdf->N; + float3 N = bsdf->N; - sample_cos_hemisphere(N, randu, randv, omega_in, pdf); + sample_cos_hemisphere(N, randu, randv, omega_in, pdf); - if(dot(Ng, *omega_in) > 0) { - float3 H = normalize(I + *omega_in); + if (dot(Ng, *omega_in) > 0) { + float3 H = normalize(I + *omega_in); - *eval = calculate_principled_sheen_brdf(bsdf, N, I, *omega_in, H, pdf); + *eval = calculate_principled_sheen_brdf(bsdf, N, I, *omega_in, H, pdf); #ifdef __RAY_DIFFERENTIALS__ - // TODO: find a better approximation for the diffuse bounce - *domega_in_dx = -((2 * dot(N, dIdx)) * N - dIdx); - *domega_in_dy = -((2 * dot(N, dIdy)) * N - dIdy); + // TODO: find a better approximation for the diffuse bounce + *domega_in_dx = -((2 * dot(N, dIdx)) * N - dIdx); + *domega_in_dy = -((2 * dot(N, dIdy)) * N - dIdy); #endif - } - else { - *pdf = 0.0f; - } - return LABEL_REFLECT|LABEL_DIFFUSE; + } + else { + *pdf = 0.0f; + } + return LABEL_REFLECT | LABEL_DIFFUSE; } CCL_NAMESPACE_END -#endif /* __BSDF_PRINCIPLED_SHEEN_H__ */ +#endif /* __BSDF_PRINCIPLED_SHEEN_H__ */ diff --git a/intern/cycles/kernel/closure/bsdf_reflection.h b/intern/cycles/kernel/closure/bsdf_reflection.h index 94f1c283af7..c24ba170915 100644 --- a/intern/cycles/kernel/closure/bsdf_reflection.h +++ b/intern/cycles/kernel/closure/bsdf_reflection.h @@ -39,42 +39,59 @@ CCL_NAMESPACE_BEGIN ccl_device int bsdf_reflection_setup(MicrofacetBsdf *bsdf) { - bsdf->type = CLOSURE_BSDF_REFLECTION_ID; - return SD_BSDF; + bsdf->type = CLOSURE_BSDF_REFLECTION_ID; + return SD_BSDF; } -ccl_device float3 bsdf_reflection_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_reflection_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device float3 bsdf_reflection_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_reflection_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device int bsdf_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) +ccl_device int bsdf_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) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; - float3 N = bsdf->N; + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; + float3 N = bsdf->N; - // only one direction is possible - float cosNO = dot(N, I); - if(cosNO > 0) { - *omega_in = (2 * cosNO) * N - I; - if(dot(Ng, *omega_in) > 0) { + // only one direction is possible + float cosNO = dot(N, I); + if (cosNO > 0) { + *omega_in = (2 * cosNO) * N - I; + if (dot(Ng, *omega_in) > 0) { #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = 2 * dot(N, dIdx) * N - dIdx; - *domega_in_dy = 2 * dot(N, dIdy) * N - dIdy; + *domega_in_dx = 2 * dot(N, dIdx) * N - dIdx; + *domega_in_dy = 2 * dot(N, dIdy) * N - dIdy; #endif - /* Some high number for MIS. */ - *pdf = 1e6f; - *eval = make_float3(1e6f, 1e6f, 1e6f); - } - } - return LABEL_REFLECT|LABEL_SINGULAR; + /* Some high number for MIS. */ + *pdf = 1e6f; + *eval = make_float3(1e6f, 1e6f, 1e6f); + } + } + return LABEL_REFLECT | LABEL_SINGULAR; } CCL_NAMESPACE_END -#endif /* __BSDF_REFLECTION_H__ */ +#endif /* __BSDF_REFLECTION_H__ */ diff --git a/intern/cycles/kernel/closure/bsdf_refraction.h b/intern/cycles/kernel/closure/bsdf_refraction.h index abdd01c7a1d..d4fbe86dac0 100644 --- a/intern/cycles/kernel/closure/bsdf_refraction.h +++ b/intern/cycles/kernel/closure/bsdf_refraction.h @@ -39,51 +39,77 @@ CCL_NAMESPACE_BEGIN ccl_device int bsdf_refraction_setup(MicrofacetBsdf *bsdf) { - bsdf->type = CLOSURE_BSDF_REFRACTION_ID; - return SD_BSDF; + bsdf->type = CLOSURE_BSDF_REFRACTION_ID; + return SD_BSDF; } -ccl_device float3 bsdf_refraction_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_refraction_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device float3 bsdf_refraction_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_refraction_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device int bsdf_refraction_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) +ccl_device int bsdf_refraction_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) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; - float m_eta = bsdf->ior; - float3 N = bsdf->N; + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; + float m_eta = bsdf->ior; + float3 N = bsdf->N; - float3 R, T; + float3 R, T; #ifdef __RAY_DIFFERENTIALS__ - float3 dRdx, dRdy, dTdx, dTdy; + float3 dRdx, dRdy, dTdx, dTdy; #endif - bool inside; - float fresnel; - fresnel = fresnel_dielectric(m_eta, N, I, &R, &T, + bool inside; + float fresnel; + fresnel = fresnel_dielectric(m_eta, + N, + I, + &R, + &T, #ifdef __RAY_DIFFERENTIALS__ - dIdx, dIdy, &dRdx, &dRdy, &dTdx, &dTdy, + dIdx, + dIdy, + &dRdx, + &dRdy, + &dTdx, + &dTdy, #endif - &inside); + &inside); - if(!inside && fresnel != 1.0f) { - /* Some high number for MIS. */ - *pdf = 1e6f; - *eval = make_float3(1e6f, 1e6f, 1e6f); - *omega_in = T; + if (!inside && fresnel != 1.0f) { + /* Some high number for MIS. */ + *pdf = 1e6f; + *eval = make_float3(1e6f, 1e6f, 1e6f); + *omega_in = T; #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = dTdx; - *domega_in_dy = dTdy; + *domega_in_dx = dTdx; + *domega_in_dy = dTdy; #endif - } - return LABEL_TRANSMIT|LABEL_SINGULAR; + } + return LABEL_TRANSMIT | LABEL_SINGULAR; } CCL_NAMESPACE_END -#endif /* __BSDF_REFRACTION_H__ */ +#endif /* __BSDF_REFRACTION_H__ */ diff --git a/intern/cycles/kernel/closure/bsdf_toon.h b/intern/cycles/kernel/closure/bsdf_toon.h index 097a56f22eb..f37fd228087 100644 --- a/intern/cycles/kernel/closure/bsdf_toon.h +++ b/intern/cycles/kernel/closure/bsdf_toon.h @@ -36,183 +36,215 @@ CCL_NAMESPACE_BEGIN typedef ccl_addr_space struct ToonBsdf { - SHADER_CLOSURE_BASE; + SHADER_CLOSURE_BASE; - float size; - float smooth; + float size; + float smooth; } ToonBsdf; /* DIFFUSE TOON */ ccl_device int bsdf_diffuse_toon_setup(ToonBsdf *bsdf) { - bsdf->type = CLOSURE_BSDF_DIFFUSE_TOON_ID; - bsdf->size = saturate(bsdf->size); - bsdf->smooth = saturate(bsdf->smooth); + bsdf->type = CLOSURE_BSDF_DIFFUSE_TOON_ID; + bsdf->size = saturate(bsdf->size); + bsdf->smooth = saturate(bsdf->smooth); - return SD_BSDF|SD_BSDF_HAS_EVAL; + return SD_BSDF | SD_BSDF_HAS_EVAL; } ccl_device bool bsdf_toon_merge(const ShaderClosure *a, const ShaderClosure *b) { - const ToonBsdf *bsdf_a = (const ToonBsdf*)a; - const ToonBsdf *bsdf_b = (const ToonBsdf*)b; + const ToonBsdf *bsdf_a = (const ToonBsdf *)a; + const ToonBsdf *bsdf_b = (const ToonBsdf *)b; - return (isequal_float3(bsdf_a->N, bsdf_b->N)) && - (bsdf_a->size == bsdf_b->size) && - (bsdf_a->smooth == bsdf_b->smooth); + return (isequal_float3(bsdf_a->N, bsdf_b->N)) && (bsdf_a->size == bsdf_b->size) && + (bsdf_a->smooth == bsdf_b->smooth); } ccl_device float3 bsdf_toon_get_intensity(float max_angle, float smooth, float angle) { - float is; + float is; - if(angle < max_angle) - is = 1.0f; - else if(angle < (max_angle + smooth) && smooth != 0.0f) - is = (1.0f - (angle - max_angle)/smooth); - else - is = 0.0f; + if (angle < max_angle) + is = 1.0f; + else if (angle < (max_angle + smooth) && smooth != 0.0f) + is = (1.0f - (angle - max_angle) / smooth); + else + is = 0.0f; - return make_float3(is, is, is); + return make_float3(is, is, is); } ccl_device float bsdf_toon_get_sample_angle(float max_angle, float smooth) { - return fminf(max_angle + smooth, M_PI_2_F); + return fminf(max_angle + smooth, M_PI_2_F); } -ccl_device float3 bsdf_diffuse_toon_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_diffuse_toon_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - const ToonBsdf *bsdf = (const ToonBsdf*)sc; - float max_angle = bsdf->size*M_PI_2_F; - float smooth = bsdf->smooth*M_PI_2_F; - float angle = safe_acosf(fmaxf(dot(bsdf->N, omega_in), 0.0f)); + const ToonBsdf *bsdf = (const ToonBsdf *)sc; + float max_angle = bsdf->size * M_PI_2_F; + float smooth = bsdf->smooth * M_PI_2_F; + float angle = safe_acosf(fmaxf(dot(bsdf->N, omega_in), 0.0f)); - float3 eval = bsdf_toon_get_intensity(max_angle, smooth, angle); + float3 eval = bsdf_toon_get_intensity(max_angle, smooth, angle); - if(eval.x > 0.0f) { - float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth); + if (eval.x > 0.0f) { + float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth); - *pdf = 0.5f * M_1_PI_F / (1.0f - cosf(sample_angle)); - return *pdf * eval; - } + *pdf = 0.5f * M_1_PI_F / (1.0f - cosf(sample_angle)); + return *pdf * eval; + } - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device float3 bsdf_diffuse_toon_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_diffuse_toon_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device int bsdf_diffuse_toon_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) +ccl_device int bsdf_diffuse_toon_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) { - const ToonBsdf *bsdf = (const ToonBsdf*)sc; - float max_angle = bsdf->size*M_PI_2_F; - float smooth = bsdf->smooth*M_PI_2_F; - float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth); - float angle = sample_angle*randu; + const ToonBsdf *bsdf = (const ToonBsdf *)sc; + float max_angle = bsdf->size * M_PI_2_F; + float smooth = bsdf->smooth * M_PI_2_F; + float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth); + float angle = sample_angle * randu; - if(sample_angle > 0.0f) { - sample_uniform_cone(bsdf->N, sample_angle, randu, randv, omega_in, pdf); + if (sample_angle > 0.0f) { + sample_uniform_cone(bsdf->N, sample_angle, randu, randv, omega_in, pdf); - if(dot(Ng, *omega_in) > 0.0f) { - *eval = *pdf * bsdf_toon_get_intensity(max_angle, smooth, angle); + if (dot(Ng, *omega_in) > 0.0f) { + *eval = *pdf * bsdf_toon_get_intensity(max_angle, smooth, angle); #ifdef __RAY_DIFFERENTIALS__ - // TODO: find a better approximation for the bounce - *domega_in_dx = (2.0f * dot(bsdf->N, dIdx)) * bsdf->N - dIdx; - *domega_in_dy = (2.0f * dot(bsdf->N, dIdy)) * bsdf->N - dIdy; + // TODO: find a better approximation for the bounce + *domega_in_dx = (2.0f * dot(bsdf->N, dIdx)) * bsdf->N - dIdx; + *domega_in_dy = (2.0f * dot(bsdf->N, dIdy)) * bsdf->N - dIdy; #endif - } - else - *pdf = 0.0f; - } - - return LABEL_REFLECT | LABEL_DIFFUSE; + } + else + *pdf = 0.0f; + } + return LABEL_REFLECT | LABEL_DIFFUSE; } /* GLOSSY TOON */ ccl_device int bsdf_glossy_toon_setup(ToonBsdf *bsdf) { - bsdf->type = CLOSURE_BSDF_GLOSSY_TOON_ID; - bsdf->size = saturate(bsdf->size); - bsdf->smooth = saturate(bsdf->smooth); + bsdf->type = CLOSURE_BSDF_GLOSSY_TOON_ID; + bsdf->size = saturate(bsdf->size); + bsdf->smooth = saturate(bsdf->smooth); - return SD_BSDF|SD_BSDF_HAS_EVAL; + return SD_BSDF | SD_BSDF_HAS_EVAL; } -ccl_device float3 bsdf_glossy_toon_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_glossy_toon_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - const ToonBsdf *bsdf = (const ToonBsdf*)sc; - float max_angle = bsdf->size*M_PI_2_F; - float smooth = bsdf->smooth*M_PI_2_F; - float cosNI = dot(bsdf->N, omega_in); - float cosNO = dot(bsdf->N, I); + const ToonBsdf *bsdf = (const ToonBsdf *)sc; + float max_angle = bsdf->size * M_PI_2_F; + float smooth = bsdf->smooth * M_PI_2_F; + float cosNI = dot(bsdf->N, omega_in); + float cosNO = dot(bsdf->N, I); - if(cosNI > 0 && cosNO > 0) { - /* reflect the view vector */ - float3 R = (2 * cosNO) * bsdf->N - I; - float cosRI = dot(R, omega_in); + if (cosNI > 0 && cosNO > 0) { + /* reflect the view vector */ + float3 R = (2 * cosNO) * bsdf->N - I; + float cosRI = dot(R, omega_in); - float angle = safe_acosf(fmaxf(cosRI, 0.0f)); + float angle = safe_acosf(fmaxf(cosRI, 0.0f)); - float3 eval = bsdf_toon_get_intensity(max_angle, smooth, angle); - float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth); + float3 eval = bsdf_toon_get_intensity(max_angle, smooth, angle); + float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth); - *pdf = 0.5f * M_1_PI_F / (1.0f - cosf(sample_angle)); - return *pdf * eval; - } + *pdf = 0.5f * M_1_PI_F / (1.0f - cosf(sample_angle)); + return *pdf * eval; + } - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device float3 bsdf_glossy_toon_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_glossy_toon_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device int bsdf_glossy_toon_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) +ccl_device int bsdf_glossy_toon_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) { - const ToonBsdf *bsdf = (const ToonBsdf*)sc; - float max_angle = bsdf->size*M_PI_2_F; - float smooth = bsdf->smooth*M_PI_2_F; - float cosNO = dot(bsdf->N, I); + const ToonBsdf *bsdf = (const ToonBsdf *)sc; + float max_angle = bsdf->size * M_PI_2_F; + float smooth = bsdf->smooth * M_PI_2_F; + float cosNO = dot(bsdf->N, I); - if(cosNO > 0) { - /* reflect the view vector */ - float3 R = (2 * cosNO) * bsdf->N - I; + if (cosNO > 0) { + /* reflect the view vector */ + float3 R = (2 * cosNO) * bsdf->N - I; - float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth); - float angle = sample_angle*randu; + float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth); + float angle = sample_angle * randu; - sample_uniform_cone(R, sample_angle, randu, randv, omega_in, pdf); + sample_uniform_cone(R, sample_angle, randu, randv, omega_in, pdf); - if(dot(Ng, *omega_in) > 0.0f) { - float cosNI = dot(bsdf->N, *omega_in); + if (dot(Ng, *omega_in) > 0.0f) { + float cosNI = dot(bsdf->N, *omega_in); - /* make sure the direction we chose is still in the right hemisphere */ - if(cosNI > 0) { - *eval = *pdf * bsdf_toon_get_intensity(max_angle, smooth, angle); + /* make sure the direction we chose is still in the right hemisphere */ + if (cosNI > 0) { + *eval = *pdf * bsdf_toon_get_intensity(max_angle, smooth, angle); #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = (2 * dot(bsdf->N, dIdx)) * bsdf->N - dIdx; - *domega_in_dy = (2 * dot(bsdf->N, dIdy)) * bsdf->N - dIdy; + *domega_in_dx = (2 * dot(bsdf->N, dIdx)) * bsdf->N - dIdx; + *domega_in_dy = (2 * dot(bsdf->N, dIdy)) * bsdf->N - dIdy; #endif - } - else - *pdf = 0.0f; - } - else - *pdf = 0.0f; - } - - return LABEL_GLOSSY | LABEL_REFLECT; + } + else + *pdf = 0.0f; + } + else + *pdf = 0.0f; + } + + return LABEL_GLOSSY | LABEL_REFLECT; } CCL_NAMESPACE_END -#endif /* __BSDF_TOON_H__ */ +#endif /* __BSDF_TOON_H__ */ diff --git a/intern/cycles/kernel/closure/bsdf_transparent.h b/intern/cycles/kernel/closure/bsdf_transparent.h index 060dff69f52..4e5513499e8 100644 --- a/intern/cycles/kernel/closure/bsdf_transparent.h +++ b/intern/cycles/kernel/closure/bsdf_transparent.h @@ -37,73 +37,91 @@ CCL_NAMESPACE_BEGIN ccl_device void bsdf_transparent_setup(ShaderData *sd, const float3 weight, int path_flag) { - /* Check cutoff weight. */ - float sample_weight = fabsf(average(weight)); - if(!(sample_weight >= CLOSURE_WEIGHT_CUTOFF)) { - return; - } + /* Check cutoff weight. */ + float sample_weight = fabsf(average(weight)); + if (!(sample_weight >= CLOSURE_WEIGHT_CUTOFF)) { + return; + } - if(sd->flag & SD_TRANSPARENT) { - sd->closure_transparent_extinction += weight; + if (sd->flag & SD_TRANSPARENT) { + sd->closure_transparent_extinction += weight; - /* Add weight to existing transparent BSDF. */ - for(int i = 0; i < sd->num_closure; i++) { - ShaderClosure *sc = &sd->closure[i]; + /* Add weight to existing transparent BSDF. */ + for (int i = 0; i < sd->num_closure; i++) { + ShaderClosure *sc = &sd->closure[i]; - if(sc->type == CLOSURE_BSDF_TRANSPARENT_ID) { - sc->weight += weight; - sc->sample_weight += sample_weight; - break; - } - } - } - else { - sd->flag |= SD_BSDF|SD_TRANSPARENT; - sd->closure_transparent_extinction = weight; + if (sc->type == CLOSURE_BSDF_TRANSPARENT_ID) { + sc->weight += weight; + sc->sample_weight += sample_weight; + break; + } + } + } + else { + sd->flag |= SD_BSDF | SD_TRANSPARENT; + sd->closure_transparent_extinction = weight; - if(path_flag & PATH_RAY_TERMINATE) { - /* In this case the number of closures is set to zero to disable - * all others, but we still want to get transparency so increase - * the number just for this. */ - sd->num_closure_left = 1; - } + if (path_flag & PATH_RAY_TERMINATE) { + /* In this case the number of closures is set to zero to disable + * all others, but we still want to get transparency so increase + * the number just for this. */ + sd->num_closure_left = 1; + } - /* Create new transparent BSDF. */ - ShaderClosure *bsdf = closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_BSDF_TRANSPARENT_ID, weight); + /* Create new transparent BSDF. */ + ShaderClosure *bsdf = closure_alloc( + sd, sizeof(ShaderClosure), CLOSURE_BSDF_TRANSPARENT_ID, weight); - if(bsdf) { - bsdf->sample_weight = sample_weight; - bsdf->N = sd->N; - } - else if(path_flag & PATH_RAY_TERMINATE) { - sd->num_closure_left = 0; - } - } + if (bsdf) { + bsdf->sample_weight = sample_weight; + bsdf->N = sd->N; + } + else if (path_flag & PATH_RAY_TERMINATE) { + sd->num_closure_left = 0; + } + } } -ccl_device float3 bsdf_transparent_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_transparent_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device float3 bsdf_transparent_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_transparent_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf) { - return make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device int bsdf_transparent_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) +ccl_device int bsdf_transparent_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) { - // only one direction is possible - *omega_in = -I; + // only one direction is possible + *omega_in = -I; #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = -dIdx; - *domega_in_dy = -dIdy; + *domega_in_dx = -dIdx; + *domega_in_dy = -dIdy; #endif - *pdf = 1; - *eval = make_float3(1, 1, 1); - return LABEL_TRANSMIT|LABEL_TRANSPARENT; + *pdf = 1; + *eval = make_float3(1, 1, 1); + return LABEL_TRANSMIT | LABEL_TRANSPARENT; } CCL_NAMESPACE_END -#endif /* __BSDF_TRANSPARENT_H__ */ +#endif /* __BSDF_TRANSPARENT_H__ */ diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h index 4f3453675c7..a9a27edd7de 100644 --- a/intern/cycles/kernel/closure/bsdf_util.h +++ b/intern/cycles/kernel/closure/bsdf_util.h @@ -35,127 +35,134 @@ CCL_NAMESPACE_BEGIN -ccl_device float fresnel_dielectric( - float eta, const float3 N, - const float3 I, float3 *R, float3 *T, +ccl_device float fresnel_dielectric(float eta, + const float3 N, + const float3 I, + float3 *R, + float3 *T, #ifdef __RAY_DIFFERENTIALS__ - const float3 dIdx, const float3 dIdy, - float3 *dRdx, float3 *dRdy, - float3 *dTdx, float3 *dTdy, + const float3 dIdx, + const float3 dIdy, + float3 *dRdx, + float3 *dRdy, + float3 *dTdx, + float3 *dTdy, #endif - bool *is_inside) + bool *is_inside) { - float cos = dot(N, I), neta; - float3 Nn; + float cos = dot(N, I), neta; + float3 Nn; - // check which side of the surface we are on - if(cos > 0) { - // we are on the outside of the surface, going in - neta = 1 / eta; - Nn = N; - *is_inside = false; - } - else { - // we are inside the surface - cos = -cos; - neta = eta; - Nn = -N; - *is_inside = true; - } + // check which side of the surface we are on + if (cos > 0) { + // we are on the outside of the surface, going in + neta = 1 / eta; + Nn = N; + *is_inside = false; + } + else { + // we are inside the surface + cos = -cos; + neta = eta; + Nn = -N; + *is_inside = true; + } - // compute reflection - *R = (2 * cos)* Nn - I; + // compute reflection + *R = (2 * cos) * Nn - I; #ifdef __RAY_DIFFERENTIALS__ - *dRdx = (2 * dot(Nn, dIdx)) * Nn - dIdx; - *dRdy = (2 * dot(Nn, dIdy)) * Nn - dIdy; + *dRdx = (2 * dot(Nn, dIdx)) * Nn - dIdx; + *dRdy = (2 * dot(Nn, dIdy)) * Nn - dIdy; #endif - float arg = 1 -(neta * neta *(1 -(cos * cos))); - if(arg < 0) { - *T = make_float3(0.0f, 0.0f, 0.0f); + float arg = 1 - (neta * neta * (1 - (cos * cos))); + if (arg < 0) { + *T = make_float3(0.0f, 0.0f, 0.0f); #ifdef __RAY_DIFFERENTIALS__ - *dTdx = make_float3(0.0f, 0.0f, 0.0f); - *dTdy = make_float3(0.0f, 0.0f, 0.0f); + *dTdx = make_float3(0.0f, 0.0f, 0.0f); + *dTdy = make_float3(0.0f, 0.0f, 0.0f); #endif - return 1; // total internal reflection - } - else { - float dnp = max(sqrtf(arg), 1e-7f); - float nK = (neta * cos)- dnp; - *T = -(neta * I)+(nK * Nn); + return 1; // total internal reflection + } + else { + float dnp = max(sqrtf(arg), 1e-7f); + float nK = (neta * cos) - dnp; + *T = -(neta * I) + (nK * Nn); #ifdef __RAY_DIFFERENTIALS__ - *dTdx = -(neta * dIdx) + ((neta - neta * neta * cos / dnp) * dot(dIdx, Nn)) * Nn; - *dTdy = -(neta * dIdy) + ((neta - neta * neta * cos / dnp) * dot(dIdy, Nn)) * Nn; + *dTdx = -(neta * dIdx) + ((neta - neta * neta * cos / dnp) * dot(dIdx, Nn)) * Nn; + *dTdy = -(neta * dIdy) + ((neta - neta * neta * cos / dnp) * dot(dIdy, Nn)) * Nn; #endif - // compute Fresnel terms - float cosTheta1 = cos; // N.R - float cosTheta2 = -dot(Nn, *T); - float pPara = (cosTheta1 - eta * cosTheta2)/(cosTheta1 + eta * cosTheta2); - float pPerp = (eta * cosTheta1 - cosTheta2)/(eta * cosTheta1 + cosTheta2); - return 0.5f * (pPara * pPara + pPerp * pPerp); - } + // compute Fresnel terms + float cosTheta1 = cos; // N.R + float cosTheta2 = -dot(Nn, *T); + float pPara = (cosTheta1 - eta * cosTheta2) / (cosTheta1 + eta * cosTheta2); + float pPerp = (eta * cosTheta1 - cosTheta2) / (eta * cosTheta1 + cosTheta2); + return 0.5f * (pPara * pPara + pPerp * pPerp); + } } ccl_device float fresnel_dielectric_cos(float cosi, float eta) { - // compute fresnel reflectance without explicitly computing - // the refracted direction - float c = fabsf(cosi); - float g = eta * eta - 1 + c * c; - if(g > 0) { - g = sqrtf(g); - float A = (g - c)/(g + c); - float B = (c *(g + c)- 1)/(c *(g - c)+ 1); - return 0.5f * A * A *(1 + B * B); - } - return 1.0f; // TIR(no refracted component) + // compute fresnel reflectance without explicitly computing + // the refracted direction + float c = fabsf(cosi); + float g = eta * eta - 1 + c * c; + if (g > 0) { + g = sqrtf(g); + float A = (g - c) / (g + c); + float B = (c * (g + c) - 1) / (c * (g - c) + 1); + return 0.5f * A * A * (1 + B * B); + } + return 1.0f; // TIR(no refracted component) } ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k) { - float3 cosi2 = make_float3(cosi*cosi, cosi*cosi, cosi*cosi); - float3 one = make_float3(1.0f, 1.0f, 1.0f); - float3 tmp_f = eta * eta + k * k; - float3 tmp = tmp_f * cosi2; - float3 Rparl2 = (tmp - (2.0f * eta * cosi) + one) / - (tmp + (2.0f * eta * cosi) + one); - float3 Rperp2 = (tmp_f - (2.0f * eta * cosi) + cosi2) / - (tmp_f + (2.0f * eta * cosi) + cosi2); - return(Rparl2 + Rperp2) * 0.5f; + float3 cosi2 = make_float3(cosi * cosi, cosi * cosi, cosi * cosi); + float3 one = make_float3(1.0f, 1.0f, 1.0f); + float3 tmp_f = eta * eta + k * k; + float3 tmp = tmp_f * cosi2; + float3 Rparl2 = (tmp - (2.0f * eta * cosi) + one) / (tmp + (2.0f * eta * cosi) + one); + float3 Rperp2 = (tmp_f - (2.0f * eta * cosi) + cosi2) / (tmp_f + (2.0f * eta * cosi) + cosi2); + return (Rparl2 + Rperp2) * 0.5f; } ccl_device float schlick_fresnel(float u) { - float m = clamp(1.0f - u, 0.0f, 1.0f); - float m2 = m * m; - return m2 * m2 * m; // pow(m, 5) + float m = clamp(1.0f - u, 0.0f, 1.0f); + float m2 = m * m; + return m2 * m2 * m; // pow(m, 5) } ccl_device float smooth_step(float edge0, float edge1, float x) { - float result; - if(x < edge0) result = 0.0f; - else if(x >= edge1) result = 1.0f; - else { - float t = (x - edge0)/(edge1 - edge0); - result = (3.0f-2.0f*t)*(t*t); - } - return result; + float result; + if (x < edge0) + result = 0.0f; + else if (x >= edge1) + result = 1.0f; + else { + float t = (x - edge0) / (edge1 - edge0); + result = (3.0f - 2.0f * t) * (t * t); + } + return result; } /* Calculate the fresnel color which is a blend between white and the F0 color (cspec0) */ -ccl_device_forceinline float3 interpolate_fresnel_color(float3 L, float3 H, float ior, float F0, float3 cspec0) { - /* Calculate the fresnel interpolation factor - * The value from fresnel_dielectric_cos(...) has to be normalized because - * the cspec0 keeps the F0 color - */ - float F0_norm = 1.0f / (1.0f - F0); - float FH = (fresnel_dielectric_cos(dot(L, H), ior) - F0) * F0_norm; +ccl_device_forceinline float3 +interpolate_fresnel_color(float3 L, float3 H, float ior, float F0, float3 cspec0) +{ + /* Calculate the fresnel interpolation factor + * The value from fresnel_dielectric_cos(...) has to be normalized because + * the cspec0 keeps the F0 color + */ + float F0_norm = 1.0f / (1.0f - F0); + float FH = (fresnel_dielectric_cos(dot(L, H), ior) - F0) * F0_norm; - /* Blend between white and a specular color with respect to the fresnel */ - return cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; + /* Blend between white and a specular color with respect to the fresnel */ + return cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; } CCL_NAMESPACE_END -#endif /* __BSDF_UTIL_H__ */ +#endif /* __BSDF_UTIL_H__ */ diff --git a/intern/cycles/kernel/closure/bssrdf.h b/intern/cycles/kernel/closure/bssrdf.h index 98c7f23c288..57804eca269 100644 --- a/intern/cycles/kernel/closure/bssrdf.h +++ b/intern/cycles/kernel/closure/bssrdf.h @@ -20,14 +20,14 @@ CCL_NAMESPACE_BEGIN typedef ccl_addr_space struct Bssrdf { - SHADER_CLOSURE_BASE; - - float3 radius; - float3 albedo; - float sharpness; - float texture_blur; - float roughness; - float channels; + SHADER_CLOSURE_BASE; + + float3 radius; + float3 albedo; + float sharpness; + float texture_blur; + float roughness; + float channels; } Bssrdf; /* Planar Truncated Gaussian @@ -41,41 +41,41 @@ typedef ccl_addr_space struct Bssrdf { ccl_device float bssrdf_gaussian_eval(const float radius, float r) { - /* integrate (2*pi*r * exp(-r*r/(2*v)))/(2*pi*v)) from 0 to Rm - * = 1 - exp(-Rm*Rm/(2*v)) */ - const float v = radius*radius*(0.25f*0.25f); - const float Rm = sqrtf(v*GAUSS_TRUNCATE); + /* integrate (2*pi*r * exp(-r*r/(2*v)))/(2*pi*v)) from 0 to Rm + * = 1 - exp(-Rm*Rm/(2*v)) */ + const float v = radius * radius * (0.25f * 0.25f); + const float Rm = sqrtf(v * GAUSS_TRUNCATE); - if(r >= Rm) - return 0.0f; + if (r >= Rm) + return 0.0f; - return expf(-r*r/(2.0f*v))/(2.0f*M_PI_F*v); + return expf(-r * r / (2.0f * v)) / (2.0f * M_PI_F * v); } ccl_device float bssrdf_gaussian_pdf(const float radius, float r) { - /* 1.0 - expf(-Rm*Rm/(2*v)) simplified */ - const float area_truncated = 1.0f - expf(-0.5f*GAUSS_TRUNCATE); + /* 1.0 - expf(-Rm*Rm/(2*v)) simplified */ + const float area_truncated = 1.0f - expf(-0.5f * GAUSS_TRUNCATE); - return bssrdf_gaussian_eval(radius, r) * (1.0f/(area_truncated)); + return bssrdf_gaussian_eval(radius, r) * (1.0f / (area_truncated)); } ccl_device void bssrdf_gaussian_sample(const float radius, float xi, float *r, float *h) { - /* xi = integrate (2*pi*r * exp(-r*r/(2*v)))/(2*pi*v)) = -exp(-r^2/(2*v)) - * r = sqrt(-2*v*logf(xi)) */ - const float v = radius*radius*(0.25f*0.25f); - const float Rm = sqrtf(v*GAUSS_TRUNCATE); + /* xi = integrate (2*pi*r * exp(-r*r/(2*v)))/(2*pi*v)) = -exp(-r^2/(2*v)) + * r = sqrt(-2*v*logf(xi)) */ + const float v = radius * radius * (0.25f * 0.25f); + const float Rm = sqrtf(v * GAUSS_TRUNCATE); - /* 1.0 - expf(-Rm*Rm/(2*v)) simplified */ - const float area_truncated = 1.0f - expf(-0.5f*GAUSS_TRUNCATE); + /* 1.0 - expf(-Rm*Rm/(2*v)) simplified */ + const float area_truncated = 1.0f - expf(-0.5f * GAUSS_TRUNCATE); - /* r(xi) */ - const float r_squared = -2.0f*v*logf(1.0f - xi*area_truncated); - *r = sqrtf(r_squared); + /* r(xi) */ + const float r_squared = -2.0f * v * logf(1.0f - xi * area_truncated); + *r = sqrtf(r_squared); - /* h^2 + r^2 = Rm^2 */ - *h = safe_sqrtf(Rm*Rm - r_squared); + /* h^2 + r^2 = Rm^2 */ + *h = safe_sqrtf(Rm * Rm - r_squared); } /* Planar Cubic BSSRDF falloff @@ -87,97 +87,97 @@ ccl_device void bssrdf_gaussian_sample(const float radius, float xi, float *r, f ccl_device float bssrdf_cubic_eval(const float radius, const float sharpness, float r) { - if(sharpness == 0.0f) { - const float Rm = radius; - - if(r >= Rm) - return 0.0f; - - /* integrate (2*pi*r * 10*(R - r)^3)/(pi * R^5) from 0 to R = 1 */ - const float Rm5 = (Rm*Rm) * (Rm*Rm) * Rm; - const float f = Rm - r; - const float num = f*f*f; - - return (10.0f * num) / (Rm5 * M_PI_F); - - } - else { - float Rm = radius*(1.0f + sharpness); - - if(r >= Rm) - return 0.0f; - - /* custom variation with extra sharpness, to match the previous code */ - const float y = 1.0f/(1.0f + sharpness); - float Rmy, ry, ryinv; - - if(sharpness == 1.0f) { - Rmy = sqrtf(Rm); - ry = sqrtf(r); - ryinv = (ry > 0.0f)? 1.0f/ry: 0.0f; - } - else { - Rmy = powf(Rm, y); - ry = powf(r, y); - ryinv = (r > 0.0f)? powf(r, y - 1.0f): 0.0f; - } - - const float Rmy5 = (Rmy*Rmy) * (Rmy*Rmy) * Rmy; - const float f = Rmy - ry; - const float num = f*(f*f)*(y*ryinv); - - return (10.0f * num) / (Rmy5 * M_PI_F); - } + if (sharpness == 0.0f) { + const float Rm = radius; + + if (r >= Rm) + return 0.0f; + + /* integrate (2*pi*r * 10*(R - r)^3)/(pi * R^5) from 0 to R = 1 */ + const float Rm5 = (Rm * Rm) * (Rm * Rm) * Rm; + const float f = Rm - r; + const float num = f * f * f; + + return (10.0f * num) / (Rm5 * M_PI_F); + } + else { + float Rm = radius * (1.0f + sharpness); + + if (r >= Rm) + return 0.0f; + + /* custom variation with extra sharpness, to match the previous code */ + const float y = 1.0f / (1.0f + sharpness); + float Rmy, ry, ryinv; + + if (sharpness == 1.0f) { + Rmy = sqrtf(Rm); + ry = sqrtf(r); + ryinv = (ry > 0.0f) ? 1.0f / ry : 0.0f; + } + else { + Rmy = powf(Rm, y); + ry = powf(r, y); + ryinv = (r > 0.0f) ? powf(r, y - 1.0f) : 0.0f; + } + + const float Rmy5 = (Rmy * Rmy) * (Rmy * Rmy) * Rmy; + const float f = Rmy - ry; + const float num = f * (f * f) * (y * ryinv); + + return (10.0f * num) / (Rmy5 * M_PI_F); + } } ccl_device float bssrdf_cubic_pdf(const float radius, const float sharpness, float r) { - return bssrdf_cubic_eval(radius, sharpness, r); + return bssrdf_cubic_eval(radius, sharpness, r); } /* solve 10x^2 - 20x^3 + 15x^4 - 4x^5 - xi == 0 */ ccl_device_forceinline float bssrdf_cubic_quintic_root_find(float xi) { - /* newton-raphson iteration, usually succeeds in 2-4 iterations, except - * outside 0.02 ... 0.98 where it can go up to 10, so overall performance - * should not be too bad */ - const float tolerance = 1e-6f; - const int max_iteration_count = 10; - float x = 0.25f; - int i; + /* newton-raphson iteration, usually succeeds in 2-4 iterations, except + * outside 0.02 ... 0.98 where it can go up to 10, so overall performance + * should not be too bad */ + const float tolerance = 1e-6f; + const int max_iteration_count = 10; + float x = 0.25f; + int i; - for(i = 0; i < max_iteration_count; i++) { - float x2 = x*x; - float x3 = x2*x; - float nx = (1.0f - x); + for (i = 0; i < max_iteration_count; i++) { + float x2 = x * x; + float x3 = x2 * x; + float nx = (1.0f - x); - float f = 10.0f*x2 - 20.0f*x3 + 15.0f*x2*x2 - 4.0f*x2*x3 - xi; - float f_ = 20.0f*(x*nx)*(nx*nx); + float f = 10.0f * x2 - 20.0f * x3 + 15.0f * x2 * x2 - 4.0f * x2 * x3 - xi; + float f_ = 20.0f * (x * nx) * (nx * nx); - if(fabsf(f) < tolerance || f_ == 0.0f) - break; + if (fabsf(f) < tolerance || f_ == 0.0f) + break; - x = saturate(x - f/f_); - } + x = saturate(x - f / f_); + } - return x; + return x; } -ccl_device void bssrdf_cubic_sample(const float radius, const float sharpness, float xi, float *r, float *h) +ccl_device void bssrdf_cubic_sample( + const float radius, const float sharpness, float xi, float *r, float *h) { - float Rm = radius; - float r_ = bssrdf_cubic_quintic_root_find(xi); + float Rm = radius; + float r_ = bssrdf_cubic_quintic_root_find(xi); - if(sharpness != 0.0f) { - r_ = powf(r_, 1.0f + sharpness); - Rm *= (1.0f + sharpness); - } + if (sharpness != 0.0f) { + r_ = powf(r_, 1.0f + sharpness); + Rm *= (1.0f + sharpness); + } - r_ *= Rm; - *r = r_; + r_ *= Rm; + *r = r_; - /* h^2 + r^2 = Rm^2 */ - *h = safe_sqrtf(Rm*Rm - r_*r_); + /* h^2 + r^2 = Rm^2 */ + *h = safe_sqrtf(Rm * Rm - r_ * r_); } /* Approximate Reflectance Profiles @@ -188,13 +188,13 @@ ccl_device void bssrdf_cubic_sample(const float radius, const float sharpness, f * the mean free length, but still not too big so sampling is still * effective. Might need some further tweaks. */ -#define BURLEY_TRUNCATE 16.0f -#define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE) +#define BURLEY_TRUNCATE 16.0f +#define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE) ccl_device_inline float bssrdf_burley_fitting(float A) { - /* Diffuse surface transmission, equation (6). */ - return 1.9f - A + 3.5f * (A - 0.8f) * (A - 0.8f); + /* Diffuse surface transmission, equation (6). */ + return 1.9f - A + 3.5f * (A - 0.8f) * (A - 0.8f); } /* Scale mean free path length so it gives similar looking result @@ -202,45 +202,44 @@ ccl_device_inline float bssrdf_burley_fitting(float A) */ ccl_device_inline float3 bssrdf_burley_compatible_mfp(float3 r) { - return 0.25f * M_1_PI_F * r; + return 0.25f * M_1_PI_F * r; } ccl_device void bssrdf_burley_setup(Bssrdf *bssrdf) { - /* Mean free path length. */ - const float3 l = bssrdf_burley_compatible_mfp(bssrdf->radius); - /* Surface albedo. */ - const float3 A = bssrdf->albedo; - const float3 s = make_float3(bssrdf_burley_fitting(A.x), - bssrdf_burley_fitting(A.y), - bssrdf_burley_fitting(A.z)); - - bssrdf->radius = l / s; + /* Mean free path length. */ + const float3 l = bssrdf_burley_compatible_mfp(bssrdf->radius); + /* Surface albedo. */ + const float3 A = bssrdf->albedo; + const float3 s = make_float3( + bssrdf_burley_fitting(A.x), bssrdf_burley_fitting(A.y), bssrdf_burley_fitting(A.z)); + + bssrdf->radius = l / s; } ccl_device float bssrdf_burley_eval(const float d, float r) { - const float Rm = BURLEY_TRUNCATE * d; - - if(r >= Rm) - return 0.0f; - - /* Burley refletance profile, equation (3). - * - * NOTES: - * - Surface albedo is already included into sc->weight, no need to - * multiply by this term here. - * - This is normalized diffuse model, so the equation is mutliplied - * by 2*pi, which also matches cdf(). - */ - float exp_r_3_d = expf(-r / (3.0f * d)); - float exp_r_d = exp_r_3_d * exp_r_3_d * exp_r_3_d; - return (exp_r_d + exp_r_3_d) / (4.0f*d); + const float Rm = BURLEY_TRUNCATE * d; + + if (r >= Rm) + return 0.0f; + + /* Burley refletance profile, equation (3). + * + * NOTES: + * - Surface albedo is already included into sc->weight, no need to + * multiply by this term here. + * - This is normalized diffuse model, so the equation is mutliplied + * by 2*pi, which also matches cdf(). + */ + float exp_r_3_d = expf(-r / (3.0f * d)); + float exp_r_d = exp_r_3_d * exp_r_3_d * exp_r_3_d; + return (exp_r_d + exp_r_3_d) / (4.0f * d); } ccl_device float bssrdf_burley_pdf(const float d, float r) { - return bssrdf_burley_eval(d, r) * (1.0f/BURLEY_TRUNCATE_CDF); + return bssrdf_burley_eval(d, r) * (1.0f / BURLEY_TRUNCATE_CDF); } /* Find the radius for desired CDF value. @@ -249,52 +248,49 @@ ccl_device float bssrdf_burley_pdf(const float d, float r) */ ccl_device_forceinline float bssrdf_burley_root_find(float xi) { - const float tolerance = 1e-6f; - const int max_iteration_count = 10; - /* Do initial guess based on manual curve fitting, this allows us to reduce - * number of iterations to maximum 4 across the [0..1] range. We keep maximum - * number of iteration higher just to be sure we didn't miss root in some - * corner case. - */ - float r; - if(xi <= 0.9f) { - r = expf(xi * xi * 2.4f) - 1.0f; - } - else { - /* TODO(sergey): Some nicer curve fit is possible here. */ - r = 15.0f; - } - /* Solve against scaled radius. */ - for(int i = 0; i < max_iteration_count; i++) { - float exp_r_3 = expf(-r / 3.0f); - float exp_r = exp_r_3 * exp_r_3 * exp_r_3; - float f = 1.0f - 0.25f * exp_r - 0.75f * exp_r_3 - xi; - float f_ = 0.25f * exp_r + 0.25f * exp_r_3; - - if(fabsf(f) < tolerance || f_ == 0.0f) { - break; - } - - r = r - f/f_; - if(r < 0.0f) { - r = 0.0f; - } - } - return r; + const float tolerance = 1e-6f; + const int max_iteration_count = 10; + /* Do initial guess based on manual curve fitting, this allows us to reduce + * number of iterations to maximum 4 across the [0..1] range. We keep maximum + * number of iteration higher just to be sure we didn't miss root in some + * corner case. + */ + float r; + if (xi <= 0.9f) { + r = expf(xi * xi * 2.4f) - 1.0f; + } + else { + /* TODO(sergey): Some nicer curve fit is possible here. */ + r = 15.0f; + } + /* Solve against scaled radius. */ + for (int i = 0; i < max_iteration_count; i++) { + float exp_r_3 = expf(-r / 3.0f); + float exp_r = exp_r_3 * exp_r_3 * exp_r_3; + float f = 1.0f - 0.25f * exp_r - 0.75f * exp_r_3 - xi; + float f_ = 0.25f * exp_r + 0.25f * exp_r_3; + + if (fabsf(f) < tolerance || f_ == 0.0f) { + break; + } + + r = r - f / f_; + if (r < 0.0f) { + r = 0.0f; + } + } + return r; } -ccl_device void bssrdf_burley_sample(const float d, - float xi, - float *r, - float *h) +ccl_device void bssrdf_burley_sample(const float d, float xi, float *r, float *h) { - const float Rm = BURLEY_TRUNCATE * d; - const float r_ = bssrdf_burley_root_find(xi * BURLEY_TRUNCATE_CDF) * d; + const float Rm = BURLEY_TRUNCATE * d; + const float r_ = bssrdf_burley_root_find(xi * BURLEY_TRUNCATE_CDF) * d; - *r = r_; + *r = r_; - /* h^2 + r^2 = Rm^2 */ - *h = safe_sqrtf(Rm*Rm - r_*r_); + /* h^2 + r^2 = Rm^2 */ + *h = safe_sqrtf(Rm * Rm - r_ * r_); } /* None BSSRDF falloff @@ -303,200 +299,195 @@ ccl_device void bssrdf_burley_sample(const float d, ccl_device float bssrdf_none_eval(const float radius, float r) { - const float Rm = radius; - return (r < Rm)? 1.0f: 0.0f; + const float Rm = radius; + return (r < Rm) ? 1.0f : 0.0f; } ccl_device float bssrdf_none_pdf(const float radius, float r) { - /* integrate (2*pi*r)/(pi*Rm*Rm) from 0 to Rm = 1 */ - const float Rm = radius; - const float area = (M_PI_F*Rm*Rm); + /* integrate (2*pi*r)/(pi*Rm*Rm) from 0 to Rm = 1 */ + const float Rm = radius; + const float area = (M_PI_F * Rm * Rm); - return bssrdf_none_eval(radius, r) / area; + return bssrdf_none_eval(radius, r) / area; } ccl_device void bssrdf_none_sample(const float radius, float xi, float *r, float *h) { - /* xi = integrate (2*pi*r)/(pi*Rm*Rm) = r^2/Rm^2 - * r = sqrt(xi)*Rm */ - const float Rm = radius; - const float r_ = sqrtf(xi)*Rm; + /* xi = integrate (2*pi*r)/(pi*Rm*Rm) = r^2/Rm^2 + * r = sqrt(xi)*Rm */ + const float Rm = radius; + const float r_ = sqrtf(xi) * Rm; - *r = r_; + *r = r_; - /* h^2 + r^2 = Rm^2 */ - *h = safe_sqrtf(Rm*Rm - r_*r_); + /* h^2 + r^2 = Rm^2 */ + *h = safe_sqrtf(Rm * Rm - r_ * r_); } /* Generic */ ccl_device_inline Bssrdf *bssrdf_alloc(ShaderData *sd, float3 weight) { - Bssrdf *bssrdf = (Bssrdf*)closure_alloc(sd, sizeof(Bssrdf), CLOSURE_NONE_ID, weight); + Bssrdf *bssrdf = (Bssrdf *)closure_alloc(sd, sizeof(Bssrdf), CLOSURE_NONE_ID, weight); - if(bssrdf == NULL) { - return NULL; - } + if (bssrdf == NULL) { + return NULL; + } - float sample_weight = fabsf(average(weight)); - bssrdf->sample_weight = sample_weight; - return (sample_weight >= CLOSURE_WEIGHT_CUTOFF) ? bssrdf : NULL; + float sample_weight = fabsf(average(weight)); + bssrdf->sample_weight = sample_weight; + return (sample_weight >= CLOSURE_WEIGHT_CUTOFF) ? bssrdf : NULL; } ccl_device int bssrdf_setup(ShaderData *sd, Bssrdf *bssrdf, ClosureType type) { - int flag = 0; - int bssrdf_channels = 3; - float3 diffuse_weight = make_float3(0.0f, 0.0f, 0.0f); - - /* Verify if the radii are large enough to sample without precision issues. */ - if(bssrdf->radius.x < BSSRDF_MIN_RADIUS) { - diffuse_weight.x = bssrdf->weight.x; - bssrdf->weight.x = 0.0f; - bssrdf->radius.x = 0.0f; - bssrdf_channels--; - } - if(bssrdf->radius.y < BSSRDF_MIN_RADIUS) { - diffuse_weight.y = bssrdf->weight.y; - bssrdf->weight.y = 0.0f; - bssrdf->radius.y = 0.0f; - bssrdf_channels--; - } - if(bssrdf->radius.z < BSSRDF_MIN_RADIUS) { - diffuse_weight.z = bssrdf->weight.z; - bssrdf->weight.z = 0.0f; - bssrdf->radius.z = 0.0f; - bssrdf_channels--; - } - - if(bssrdf_channels < 3) { - /* Add diffuse BSDF if any radius too small. */ + int flag = 0; + int bssrdf_channels = 3; + float3 diffuse_weight = make_float3(0.0f, 0.0f, 0.0f); + + /* Verify if the radii are large enough to sample without precision issues. */ + if (bssrdf->radius.x < BSSRDF_MIN_RADIUS) { + diffuse_weight.x = bssrdf->weight.x; + bssrdf->weight.x = 0.0f; + bssrdf->radius.x = 0.0f; + bssrdf_channels--; + } + if (bssrdf->radius.y < BSSRDF_MIN_RADIUS) { + diffuse_weight.y = bssrdf->weight.y; + bssrdf->weight.y = 0.0f; + bssrdf->radius.y = 0.0f; + bssrdf_channels--; + } + if (bssrdf->radius.z < BSSRDF_MIN_RADIUS) { + diffuse_weight.z = bssrdf->weight.z; + bssrdf->weight.z = 0.0f; + bssrdf->radius.z = 0.0f; + bssrdf_channels--; + } + + if (bssrdf_channels < 3) { + /* Add diffuse BSDF if any radius too small. */ #ifdef __PRINCIPLED__ - if(type == CLOSURE_BSSRDF_PRINCIPLED_ID || - type == CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID) - { - float roughness = bssrdf->roughness; - float3 N = bssrdf->N; - - PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf*)bsdf_alloc(sd, sizeof(PrincipledDiffuseBsdf), diffuse_weight); - - if(bsdf) { - bsdf->type = CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID; - bsdf->N = N; - bsdf->roughness = roughness; - flag |= bsdf_principled_diffuse_setup(bsdf); - } - } - else -#endif /* __PRINCIPLED__ */ - { - DiffuseBsdf *bsdf = (DiffuseBsdf*)bsdf_alloc(sd, sizeof(DiffuseBsdf), diffuse_weight); - - if(bsdf) { - bsdf->type = CLOSURE_BSDF_BSSRDF_ID; - bsdf->N = bssrdf->N; - flag |= bsdf_diffuse_setup(bsdf); - } - } - } - - /* Setup BSSRDF if radius is large enough. */ - if(bssrdf_channels > 0) { - bssrdf->type = type; - bssrdf->channels = bssrdf_channels; - bssrdf->sample_weight = fabsf(average(bssrdf->weight)) * bssrdf->channels; - bssrdf->texture_blur = saturate(bssrdf->texture_blur); - bssrdf->sharpness = saturate(bssrdf->sharpness); - - if(type == CLOSURE_BSSRDF_BURLEY_ID || - type == CLOSURE_BSSRDF_PRINCIPLED_ID || - type == CLOSURE_BSSRDF_RANDOM_WALK_ID || - type == CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID) - { - bssrdf_burley_setup(bssrdf); - } - - flag |= SD_BSSRDF; - } - else { - bssrdf->type = type; - bssrdf->sample_weight = 0.0f; - } - - return flag; + if (type == CLOSURE_BSSRDF_PRINCIPLED_ID || type == CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID) { + float roughness = bssrdf->roughness; + float3 N = bssrdf->N; + + PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf *)bsdf_alloc( + sd, sizeof(PrincipledDiffuseBsdf), diffuse_weight); + + if (bsdf) { + bsdf->type = CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID; + bsdf->N = N; + bsdf->roughness = roughness; + flag |= bsdf_principled_diffuse_setup(bsdf); + } + } + else +#endif /* __PRINCIPLED__ */ + { + DiffuseBsdf *bsdf = (DiffuseBsdf *)bsdf_alloc(sd, sizeof(DiffuseBsdf), diffuse_weight); + + if (bsdf) { + bsdf->type = CLOSURE_BSDF_BSSRDF_ID; + bsdf->N = bssrdf->N; + flag |= bsdf_diffuse_setup(bsdf); + } + } + } + + /* Setup BSSRDF if radius is large enough. */ + if (bssrdf_channels > 0) { + bssrdf->type = type; + bssrdf->channels = bssrdf_channels; + bssrdf->sample_weight = fabsf(average(bssrdf->weight)) * bssrdf->channels; + bssrdf->texture_blur = saturate(bssrdf->texture_blur); + bssrdf->sharpness = saturate(bssrdf->sharpness); + + if (type == CLOSURE_BSSRDF_BURLEY_ID || type == CLOSURE_BSSRDF_PRINCIPLED_ID || + type == CLOSURE_BSSRDF_RANDOM_WALK_ID || + type == CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID) { + bssrdf_burley_setup(bssrdf); + } + + flag |= SD_BSSRDF; + } + else { + bssrdf->type = type; + bssrdf->sample_weight = 0.0f; + } + + return flag; } ccl_device void bssrdf_sample(const ShaderClosure *sc, float xi, float *r, float *h) { - const Bssrdf *bssrdf = (const Bssrdf*)sc; - float radius; - - /* Sample color channel and reuse random number. Only a subset of channels - * may be used if their radius was too small to handle as BSSRDF. */ - xi *= bssrdf->channels; - - if(xi < 1.0f) { - radius = (bssrdf->radius.x > 0.0f)? bssrdf->radius.x: - (bssrdf->radius.y > 0.0f)? bssrdf->radius.y: - bssrdf->radius.z; - } - else if(xi < 2.0f) { - xi -= 1.0f; - radius = (bssrdf->radius.x > 0.0f)? bssrdf->radius.y: - bssrdf->radius.z; - } - else { - xi -= 2.0f; - radius = bssrdf->radius.z; - } - - /* Sample BSSRDF. */ - if(bssrdf->type == CLOSURE_BSSRDF_CUBIC_ID) { - bssrdf_cubic_sample(radius, bssrdf->sharpness, xi, r, h); - } - else if(bssrdf->type == CLOSURE_BSSRDF_GAUSSIAN_ID){ - bssrdf_gaussian_sample(radius, xi, r, h); - } - else { /*if(bssrdf->type == CLOSURE_BSSRDF_BURLEY_ID || bssrdf->type == CLOSURE_BSSRDF_PRINCIPLED_ID)*/ - bssrdf_burley_sample(radius, xi, r, h); - } + const Bssrdf *bssrdf = (const Bssrdf *)sc; + float radius; + + /* Sample color channel and reuse random number. Only a subset of channels + * may be used if their radius was too small to handle as BSSRDF. */ + xi *= bssrdf->channels; + + if (xi < 1.0f) { + radius = (bssrdf->radius.x > 0.0f) ? + bssrdf->radius.x : + (bssrdf->radius.y > 0.0f) ? bssrdf->radius.y : bssrdf->radius.z; + } + else if (xi < 2.0f) { + xi -= 1.0f; + radius = (bssrdf->radius.x > 0.0f) ? bssrdf->radius.y : bssrdf->radius.z; + } + else { + xi -= 2.0f; + radius = bssrdf->radius.z; + } + + /* Sample BSSRDF. */ + if (bssrdf->type == CLOSURE_BSSRDF_CUBIC_ID) { + bssrdf_cubic_sample(radius, bssrdf->sharpness, xi, r, h); + } + else if (bssrdf->type == CLOSURE_BSSRDF_GAUSSIAN_ID) { + bssrdf_gaussian_sample(radius, xi, r, h); + } + else { /*if(bssrdf->type == CLOSURE_BSSRDF_BURLEY_ID || bssrdf->type == CLOSURE_BSSRDF_PRINCIPLED_ID)*/ + bssrdf_burley_sample(radius, xi, r, h); + } } ccl_device float bssrdf_channel_pdf(const Bssrdf *bssrdf, float radius, float r) { - if(radius == 0.0f) { - return 0.0f; - } - else if(bssrdf->type == CLOSURE_BSSRDF_CUBIC_ID) { - return bssrdf_cubic_pdf(radius, bssrdf->sharpness, r); - } - else if(bssrdf->type == CLOSURE_BSSRDF_GAUSSIAN_ID) { - return bssrdf_gaussian_pdf(radius, r); - } - else { /*if(bssrdf->type == CLOSURE_BSSRDF_BURLEY_ID || bssrdf->type == CLOSURE_BSSRDF_PRINCIPLED_ID)*/ - return bssrdf_burley_pdf(radius, r); - } + if (radius == 0.0f) { + return 0.0f; + } + else if (bssrdf->type == CLOSURE_BSSRDF_CUBIC_ID) { + return bssrdf_cubic_pdf(radius, bssrdf->sharpness, r); + } + else if (bssrdf->type == CLOSURE_BSSRDF_GAUSSIAN_ID) { + return bssrdf_gaussian_pdf(radius, r); + } + else { /*if(bssrdf->type == CLOSURE_BSSRDF_BURLEY_ID || bssrdf->type == CLOSURE_BSSRDF_PRINCIPLED_ID)*/ + return bssrdf_burley_pdf(radius, r); + } } ccl_device_forceinline float3 bssrdf_eval(const ShaderClosure *sc, float r) { - const Bssrdf *bssrdf = (const Bssrdf*)sc; + const Bssrdf *bssrdf = (const Bssrdf *)sc; - return make_float3( - bssrdf_channel_pdf(bssrdf, bssrdf->radius.x, r), - bssrdf_channel_pdf(bssrdf, bssrdf->radius.y, r), - bssrdf_channel_pdf(bssrdf, bssrdf->radius.z, r)); + return make_float3(bssrdf_channel_pdf(bssrdf, bssrdf->radius.x, r), + bssrdf_channel_pdf(bssrdf, bssrdf->radius.y, r), + bssrdf_channel_pdf(bssrdf, bssrdf->radius.z, r)); } ccl_device_forceinline float bssrdf_pdf(const ShaderClosure *sc, float r) { - const Bssrdf *bssrdf = (const Bssrdf*)sc; - float3 pdf = bssrdf_eval(sc, r); + const Bssrdf *bssrdf = (const Bssrdf *)sc; + float3 pdf = bssrdf_eval(sc, r); - return (pdf.x + pdf.y + pdf.z) / bssrdf->channels; + return (pdf.x + pdf.y + pdf.z) / bssrdf->channels; } CCL_NAMESPACE_END -#endif /* __KERNEL_BSSRDF_H__ */ +#endif /* __KERNEL_BSSRDF_H__ */ diff --git a/intern/cycles/kernel/closure/emissive.h b/intern/cycles/kernel/closure/emissive.h index a7f4a2a7327..911382e6865 100644 --- a/intern/cycles/kernel/closure/emissive.h +++ b/intern/cycles/kernel/closure/emissive.h @@ -36,26 +36,26 @@ CCL_NAMESPACE_BEGIN ccl_device void background_setup(ShaderData *sd, const float3 weight) { - if(sd->flag & SD_EMISSION) { - sd->closure_emission_background += weight; - } - else { - sd->flag |= SD_EMISSION; - sd->closure_emission_background = weight; - } + if (sd->flag & SD_EMISSION) { + sd->closure_emission_background += weight; + } + else { + sd->flag |= SD_EMISSION; + sd->closure_emission_background = weight; + } } /* EMISSION CLOSURE */ ccl_device void emission_setup(ShaderData *sd, const float3 weight) { - if(sd->flag & SD_EMISSION) { - sd->closure_emission_background += weight; - } - else { - sd->flag |= SD_EMISSION; - sd->closure_emission_background = weight; - } + if (sd->flag & SD_EMISSION) { + sd->closure_emission_background += weight; + } + else { + sd->flag |= SD_EMISSION; + sd->closure_emission_background = weight; + } } /* return the probability distribution function in the direction I, @@ -63,21 +63,21 @@ ccl_device void emission_setup(ShaderData *sd, const float3 weight) * the PDF computed by sample(). */ ccl_device float emissive_pdf(const float3 Ng, const float3 I) { - float cosNO = fabsf(dot(Ng, I)); - return (cosNO > 0.0f)? 1.0f: 0.0f; + float cosNO = fabsf(dot(Ng, I)); + return (cosNO > 0.0f) ? 1.0f : 0.0f; } -ccl_device void emissive_sample(const float3 Ng, float randu, float randv, - float3 *omega_out, float *pdf) +ccl_device void emissive_sample( + const float3 Ng, float randu, float randv, float3 *omega_out, float *pdf) { - /* todo: not implemented and used yet */ + /* todo: not implemented and used yet */ } ccl_device float3 emissive_simple_eval(const float3 Ng, const float3 I) { - float res = emissive_pdf(Ng, I); + float res = emissive_pdf(Ng, I); - return make_float3(res, res, res); + return make_float3(res, res, res); } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/closure/volume.h b/intern/cycles/kernel/closure/volume.h index 872d06c936a..473bc0e8a82 100644 --- a/intern/cycles/kernel/closure/volume.h +++ b/intern/cycles/kernel/closure/volume.h @@ -23,21 +23,21 @@ CCL_NAMESPACE_BEGIN ccl_device void volume_extinction_setup(ShaderData *sd, float3 weight) { - if(sd->flag & SD_EXTINCTION) { - sd->closure_transparent_extinction += weight; - } - else { - sd->flag |= SD_EXTINCTION; - sd->closure_transparent_extinction = weight; - } + if (sd->flag & SD_EXTINCTION) { + sd->closure_transparent_extinction += weight; + } + else { + sd->flag |= SD_EXTINCTION; + sd->closure_transparent_extinction = weight; + } } /* HENYEY-GREENSTEIN CLOSURE */ typedef ccl_addr_space struct HenyeyGreensteinVolume { - SHADER_CLOSURE_BASE; + SHADER_CLOSURE_BASE; - float g; + float g; } HenyeyGreensteinVolume; /* Given cosine between rays, return probability density that a photon bounces @@ -45,119 +45,152 @@ typedef ccl_addr_space struct HenyeyGreensteinVolume { * uniform sphere. g=0 uniform diffuse-like, g=1 close to sharp single ray. */ ccl_device float single_peaked_henyey_greenstein(float cos_theta, float g) { - return ((1.0f - g * g) / safe_powf(1.0f + g * g - 2.0f * g * cos_theta, 1.5f)) * (M_1_PI_F * 0.25f); + return ((1.0f - g * g) / safe_powf(1.0f + g * g - 2.0f * g * cos_theta, 1.5f)) * + (M_1_PI_F * 0.25f); }; ccl_device int volume_henyey_greenstein_setup(HenyeyGreensteinVolume *volume) { - volume->type = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; + volume->type = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; - /* clamp anisotropy to avoid delta function */ - volume->g = signf(volume->g) * min(fabsf(volume->g), 1.0f - 1e-3f); + /* clamp anisotropy to avoid delta function */ + volume->g = signf(volume->g) * min(fabsf(volume->g), 1.0f - 1e-3f); - return SD_SCATTER; + return SD_SCATTER; } ccl_device bool volume_henyey_greenstein_merge(const ShaderClosure *a, const ShaderClosure *b) { - const HenyeyGreensteinVolume *volume_a = (const HenyeyGreensteinVolume*)a; - const HenyeyGreensteinVolume *volume_b = (const HenyeyGreensteinVolume*)b; + const HenyeyGreensteinVolume *volume_a = (const HenyeyGreensteinVolume *)a; + const HenyeyGreensteinVolume *volume_b = (const HenyeyGreensteinVolume *)b; - return (volume_a->g == volume_b->g); + return (volume_a->g == volume_b->g); } -ccl_device float3 volume_henyey_greenstein_eval_phase(const ShaderClosure *sc, const float3 I, float3 omega_in, float *pdf) +ccl_device float3 volume_henyey_greenstein_eval_phase(const ShaderClosure *sc, + const float3 I, + float3 omega_in, + float *pdf) { - const HenyeyGreensteinVolume *volume = (const HenyeyGreensteinVolume*)sc; - float g = volume->g; - - /* note that I points towards the viewer */ - if(fabsf(g) < 1e-3f) { - *pdf = M_1_PI_F * 0.25f; - } - else { - float cos_theta = dot(-I, omega_in); - *pdf = single_peaked_henyey_greenstein(cos_theta, g); - } - - return make_float3(*pdf, *pdf, *pdf); + const HenyeyGreensteinVolume *volume = (const HenyeyGreensteinVolume *)sc; + float g = volume->g; + + /* note that I points towards the viewer */ + if (fabsf(g) < 1e-3f) { + *pdf = M_1_PI_F * 0.25f; + } + else { + float cos_theta = dot(-I, omega_in); + *pdf = single_peaked_henyey_greenstein(cos_theta, g); + } + + return make_float3(*pdf, *pdf, *pdf); } -ccl_device float3 henyey_greenstrein_sample(float3 D, float g, float randu, float randv, float *pdf) +ccl_device float3 +henyey_greenstrein_sample(float3 D, float g, float randu, float randv, float *pdf) { - /* match pdf for small g */ - float cos_theta; - bool isotropic = fabsf(g) < 1e-3f; - - if(isotropic) { - cos_theta = (1.0f - 2.0f * randu); - if(pdf) { - *pdf = M_1_PI_F * 0.25f; - } - } - else { - float k = (1.0f - g * g) / (1.0f - g + 2.0f * g * randu); - cos_theta = (1.0f + g * g - k * k) / (2.0f * g); - if(pdf) { - *pdf = single_peaked_henyey_greenstein(cos_theta, g); - } - } - - float sin_theta = safe_sqrtf(1.0f - cos_theta * cos_theta); - float phi = M_2PI_F * randv; - float3 dir = make_float3(sin_theta * cosf(phi), sin_theta * sinf(phi), cos_theta); - - float3 T, B; - make_orthonormals(D, &T, &B); - dir = dir.x * T + dir.y * B + dir.z * D; - - return dir; + /* match pdf for small g */ + float cos_theta; + bool isotropic = fabsf(g) < 1e-3f; + + if (isotropic) { + cos_theta = (1.0f - 2.0f * randu); + if (pdf) { + *pdf = M_1_PI_F * 0.25f; + } + } + else { + float k = (1.0f - g * g) / (1.0f - g + 2.0f * g * randu); + cos_theta = (1.0f + g * g - k * k) / (2.0f * g); + if (pdf) { + *pdf = single_peaked_henyey_greenstein(cos_theta, g); + } + } + + float sin_theta = safe_sqrtf(1.0f - cos_theta * cos_theta); + float phi = M_2PI_F * randv; + float3 dir = make_float3(sin_theta * cosf(phi), sin_theta * sinf(phi), cos_theta); + + float3 T, B; + make_orthonormals(D, &T, &B); + dir = dir.x * T + dir.y * B + dir.z * D; + + return dir; } -ccl_device int volume_henyey_greenstein_sample(const ShaderClosure *sc, 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) +ccl_device int volume_henyey_greenstein_sample(const ShaderClosure *sc, + 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) { - const HenyeyGreensteinVolume *volume = (const HenyeyGreensteinVolume*)sc; - float g = volume->g; + const HenyeyGreensteinVolume *volume = (const HenyeyGreensteinVolume *)sc; + float g = volume->g; - /* note that I points towards the viewer and so is used negated */ - *omega_in = henyey_greenstrein_sample(-I, g, randu, randv, pdf); - *eval = make_float3(*pdf, *pdf, *pdf); /* perfect importance sampling */ + /* note that I points towards the viewer and so is used negated */ + *omega_in = henyey_greenstrein_sample(-I, g, randu, randv, pdf); + *eval = make_float3(*pdf, *pdf, *pdf); /* perfect importance sampling */ #ifdef __RAY_DIFFERENTIALS__ - /* todo: implement ray differential estimation */ - *domega_in_dx = make_float3(0.0f, 0.0f, 0.0f); - *domega_in_dy = make_float3(0.0f, 0.0f, 0.0f); + /* todo: implement ray differential estimation */ + *domega_in_dx = make_float3(0.0f, 0.0f, 0.0f); + *domega_in_dy = make_float3(0.0f, 0.0f, 0.0f); #endif - return LABEL_VOLUME_SCATTER; + return LABEL_VOLUME_SCATTER; } /* VOLUME CLOSURE */ -ccl_device float3 volume_phase_eval(const ShaderData *sd, const ShaderClosure *sc, float3 omega_in, float *pdf) +ccl_device float3 volume_phase_eval(const ShaderData *sd, + const ShaderClosure *sc, + float3 omega_in, + float *pdf) { - kernel_assert(sc->type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID); + kernel_assert(sc->type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID); - return volume_henyey_greenstein_eval_phase(sc, sd->I, omega_in, pdf); + return volume_henyey_greenstein_eval_phase(sc, sd->I, omega_in, pdf); } -ccl_device int volume_phase_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, - float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf) +ccl_device int volume_phase_sample(const 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_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; - default: - *eval = make_float3(0.0f, 0.0f, 0.0f); - label = LABEL_NONE; - break; - } - - return label; + int label; + + switch (sc->type) { + 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; + default: + *eval = make_float3(0.0f, 0.0f, 0.0f); + label = LABEL_NONE; + break; + } + + return label; } CCL_NAMESPACE_END |