Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/cycles/kernel/closure')
-rw-r--r--intern/cycles/kernel/closure/alloc.h90
-rw-r--r--intern/cycles/kernel/closure/bsdf.h116
-rw-r--r--intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h54
-rw-r--r--intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h35
-rw-r--r--intern/cycles/kernel/closure/bsdf_diffuse.h33
-rw-r--r--intern/cycles/kernel/closure/bsdf_diffuse_ramp.h35
-rw-r--r--intern/cycles/kernel/closure/bsdf_disney_clearcoat.h34
-rw-r--r--intern/cycles/kernel/closure/bsdf_disney_diffuse.h31
-rw-r--r--intern/cycles/kernel/closure/bsdf_disney_sheen.h37
-rw-r--r--intern/cycles/kernel/closure/bsdf_disney_specular.h79
-rw-r--r--intern/cycles/kernel/closure/bsdf_hair.h71
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet.h336
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet_multi.h507
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h226
-rw-r--r--intern/cycles/kernel/closure/bsdf_oren_nayar.h45
-rw-r--r--intern/cycles/kernel/closure/bsdf_phong_ramp.h56
-rw-r--r--intern/cycles/kernel/closure/bsdf_reflection.h7
-rw-r--r--intern/cycles/kernel/closure/bsdf_refraction.h9
-rw-r--r--intern/cycles/kernel/closure/bsdf_toon.h78
-rw-r--r--intern/cycles/kernel/closure/bsdf_util.h6
-rw-r--r--intern/cycles/kernel/closure/bssrdf.h125
-rw-r--r--intern/cycles/kernel/closure/volume.h26
22 files changed, 1617 insertions, 419 deletions
diff --git a/intern/cycles/kernel/closure/alloc.h b/intern/cycles/kernel/closure/alloc.h
new file mode 100644
index 00000000000..b7abc1ec507
--- /dev/null
+++ b/intern/cycles/kernel/closure/alloc.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device ShaderClosure *closure_alloc(ShaderData *sd, int size, ClosureType type, float3 weight)
+{
+ kernel_assert(size <= sizeof(ShaderClosure));
+
+ int num_closure = ccl_fetch(sd, num_closure);
+ int num_closure_extra = ccl_fetch(sd, num_closure_extra);
+ if(num_closure + num_closure_extra >= MAX_CLOSURE)
+ return NULL;
+
+ ShaderClosure *sc = &ccl_fetch(sd, closure)[num_closure];
+
+ sc->type = type;
+ sc->weight = weight;
+
+ ccl_fetch(sd, num_closure)++;
+
+ 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));
+ int num_closure = ccl_fetch(sd, num_closure);
+ int num_closure_extra = ccl_fetch(sd, num_closure_extra) + num_extra;
+
+ if(num_closure + num_closure_extra > MAX_CLOSURE) {
+ /* Remove previous closure. */
+ ccl_fetch(sd, num_closure)--;
+ ccl_fetch(sd, num_closure_extra)++;
+ return NULL;
+ }
+
+ ccl_fetch(sd, num_closure_extra) = num_closure_extra;
+ return (ccl_addr_space void*)(ccl_fetch(sd, closure) + MAX_CLOSURE - num_closure_extra);
+}
+
+ccl_device_inline ShaderClosure *bsdf_alloc(ShaderData *sd, int size, float3 weight)
+{
+ ShaderClosure *sc = closure_alloc(sd, size, CLOSURE_NONE_ID, weight);
+
+ if(!sc)
+ return 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)
+{
+ ShaderClosure *sc = closure_alloc(sd, size, CLOSURE_NONE_ID, weight);
+
+ if(!sc)
+ return NULL;
+
+ memcpy(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;
+}
+#endif
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h
index 1f225e1e96c..72096f4d873 100644
--- a/intern/cycles/kernel/closure/bsdf.h
+++ b/intern/cycles/kernel/closure/bsdf.h
@@ -20,6 +20,7 @@
#include "../closure/bsdf_phong_ramp.h"
#include "../closure/bsdf_diffuse_ramp.h"
#include "../closure/bsdf_microfacet.h"
+#include "../closure/bsdf_microfacet_multi.h"
#include "../closure/bsdf_reflection.h"
#include "../closure/bsdf_refraction.h"
#include "../closure/bsdf_transparent.h"
@@ -39,15 +40,10 @@
CCL_NAMESPACE_BEGIN
-ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf)
+ccl_device int bsdf_sample(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf)
{
int label;
-#ifdef __OSL__
- if(kg->osl && sc->prim)
- return OSLShader::bsdf_sample(sd, sc, randu, randv, *eval, *omega_in, *domega_in, *pdf);
-#endif
-
switch(sc->type) {
case CLOSURE_BSDF_DIFFUSE_ID:
case CLOSURE_BSDF_BSSRDF_ID:
@@ -59,14 +55,16 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader
label = bsdf_oren_nayar_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
- /*case CLOSURE_BSDF_PHONG_RAMP_ID:
+#ifdef __OSL__
+ case CLOSURE_BSDF_PHONG_RAMP_ID:
label = bsdf_phong_ramp_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(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, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
- break;*/
+ break;
+#endif
case CLOSURE_BSDF_TRANSLUCENT_ID:
label = bsdf_translucent_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
@@ -89,6 +87,14 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader
label = bsdf_microfacet_ggx_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
+ label = bsdf_microfacet_multi_ggx_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
+ eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &ccl_fetch(sd, lcg_state));
+ break;
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
+ label = bsdf_microfacet_multi_ggx_glass_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
+ eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &ccl_fetch(sd, lcg_state));
+ break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
@@ -129,10 +135,10 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader
label = bsdf_disney_sheen_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
- case CLOSURE_BSDF_DISNEY_SPECULAR_ID:
+ /*case CLOSURE_BSDF_DISNEY_SPECULAR_ID:
label = bsdf_disney_specular_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
- break;
+ break;*/
case CLOSURE_BSDF_DISNEY_CLEARCOAT_ID:
label = bsdf_disney_clearcoat_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
@@ -151,15 +157,10 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader
return label;
}
-ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, float *pdf)
+ccl_device float3 bsdf_eval(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, float *pdf)
{
float3 eval;
-#ifdef __OSL__
- if(kg->osl && sc->prim)
- return OSLShader::bsdf_eval(sd, sc, omega_in, *pdf);
-#endif
-
if(dot(ccl_fetch(sd, Ng), omega_in) >= 0.0f) {
switch(sc->type) {
case CLOSURE_BSDF_DIFFUSE_ID:
@@ -170,12 +171,14 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade
case CLOSURE_BSDF_OREN_NAYAR_ID:
eval = bsdf_oren_nayar_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
- /*case CLOSURE_BSDF_PHONG_RAMP_ID:
+#ifdef __OSL__
+ case CLOSURE_BSDF_PHONG_RAMP_ID:
eval = bsdf_phong_ramp_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_DIFFUSE_RAMP_ID:
eval = bsdf_diffuse_ramp_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
- break;*/
+ break;
+#endif
case CLOSURE_BSDF_TRANSLUCENT_ID:
eval = bsdf_translucent_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
@@ -193,6 +196,12 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
eval = bsdf_microfacet_ggx_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
+ eval = bsdf_microfacet_multi_ggx_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state));
+ break;
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
+ eval = bsdf_microfacet_multi_ggx_glass_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state));
+ break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
@@ -224,9 +233,9 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade
case CLOSURE_BSDF_DISNEY_SHEEN_ID:
eval = bsdf_disney_sheen_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
- case CLOSURE_BSDF_DISNEY_SPECULAR_ID:
+ /*case CLOSURE_BSDF_DISNEY_SPECULAR_ID:
eval = bsdf_disney_specular_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
- break;
+ break;*/
case CLOSURE_BSDF_DISNEY_CLEARCOAT_ID:
eval = bsdf_disney_clearcoat_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
@@ -268,6 +277,12 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
eval = bsdf_microfacet_ggx_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
+ eval = bsdf_microfacet_multi_ggx_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state));
+ break;
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
+ eval = bsdf_microfacet_multi_ggx_glass_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state));
+ break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
@@ -299,9 +314,9 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade
case CLOSURE_BSDF_DISNEY_SHEEN_ID:
eval = bsdf_disney_sheen_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
- case CLOSURE_BSDF_DISNEY_SPECULAR_ID:
+ /*case CLOSURE_BSDF_DISNEY_SPECULAR_ID:
eval = bsdf_disney_specular_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
- break;
+ break;*/
case CLOSURE_BSDF_DISNEY_CLEARCOAT_ID:
eval = bsdf_disney_clearcoat_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
@@ -322,17 +337,13 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade
ccl_device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness)
{
-/* ToDo: do we want to blur volume closures? */
-
-#ifdef __OSL__
- if(kg->osl && sc->prim) {
- OSLShader::bsdf_blur(sc, roughness);
- return;
- }
-#endif
-
+ /* 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_GLASS_ID:
+ bsdf_microfacet_multi_ggx_blur(sc, roughness);
+ break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
@@ -353,5 +364,48 @@ ccl_device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness)
#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_ANISO_ID:
+ case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
+ case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_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 __VOLUME__
+ case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID:
+ return volume_henyey_greenstein_merge(a, b);
+#endif
+ default:
+ return false;
+ }
+#endif
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h b/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h
index 8d7d533d6f8..8ed76bea525 100644
--- a/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h
+++ b/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h
@@ -31,28 +31,30 @@ Other than that, the implementation directly follows the paper.
CCL_NAMESPACE_BEGIN
-ccl_device int bsdf_ashikhmin_shirley_setup(ShaderClosure *sc)
+ccl_device int bsdf_ashikhmin_shirley_setup(MicrofacetBsdf *bsdf)
{
- sc->data0 = clamp(sc->data0, 1e-4f, 1.0f);
- sc->data1 = sc->data0;
+ bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
+ bsdf->alpha_y = bsdf->alpha_x;
- sc->type = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID;
+ bsdf->type = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
-ccl_device int bsdf_ashikhmin_shirley_aniso_setup(ShaderClosure *sc)
+ccl_device int bsdf_ashikhmin_shirley_aniso_setup(MicrofacetBsdf *bsdf)
{
- sc->data0 = clamp(sc->data0, 1e-4f, 1.0f);
- sc->data1 = clamp(sc->data1, 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);
- sc->type = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID;
+ 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)
{
- sc->data0 = fmaxf(roughness, sc->data0); /* clamp roughness */
- sc->data1 = fmaxf(roughness, sc->data1);
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf*)sc;
+
+ 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)
@@ -62,14 +64,15 @@ ccl_device_inline float bsdf_ashikhmin_shirley_roughness_to_exponent(float rough
ccl_device float3 bsdf_ashikhmin_shirley_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float3 N = sc->N;
+ 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(sc->data0, sc->data1) <= 1e-4f)
+ 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) {
@@ -82,8 +85,8 @@ ccl_device float3 bsdf_ashikhmin_shirley_eval_reflect(const ShaderClosure *sc, c
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(sc->data0);
- float n_y = bsdf_ashikhmin_shirley_roughness_to_exponent(sc->data1);
+ 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 */
@@ -97,12 +100,18 @@ ccl_device float3 bsdf_ashikhmin_shirley_eval_reflect(const ShaderClosure *sc, c
else {
/* anisotropic */
float3 X, Y;
- make_orthonormals_tangent(N, sc->T, &X, &Y);
+ make_orthonormals_tangent(N, bsdf->T, &X, &Y);
float HdotX = dot(H, X);
float HdotY = dot(H, Y);
- float e = (n_x * HdotX*HdotX + n_y * HdotY*HdotY) / (1.0f - HdotN*HdotN);
- float lobe = powf(HdotN, e);
+ 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;
@@ -128,13 +137,14 @@ ccl_device_inline void bsdf_ashikhmin_shirley_sample_first_quadrant(float n_x, f
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)
{
- float3 N = sc->N;
+ const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+ float3 N = bsdf->N;
float NdotI = dot(N, I);
if(NdotI > 0.0f) {
- float n_x = bsdf_ashikhmin_shirley_roughness_to_exponent(sc->data0);
- float n_y = bsdf_ashikhmin_shirley_roughness_to_exponent(sc->data1);
+ 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;
@@ -142,7 +152,7 @@ ccl_device int bsdf_ashikhmin_shirley_sample(const ShaderClosure *sc, float3 Ng,
if(n_x == n_y)
make_orthonormals(N, &X, &Y);
else
- make_orthonormals_tangent(N, sc->T, &X, &Y);
+ make_orthonormals_tangent(N, bsdf->T, &X, &Y);
/* sample spherical coords for h in tangent space */
float phi;
@@ -193,7 +203,7 @@ ccl_device int bsdf_ashikhmin_shirley_sample(const ShaderClosure *sc, float3 Ng,
/* reflect I on H to get omega_in */
*omega_in = -I + (2.0f * HdotI) * H;
- if(fmaxf(sc->data0, sc->data1) <= 1e-4f) {
+ if(fmaxf(bsdf->alpha_x, bsdf->alpha_y) <= 1e-4f) {
/* Some high number for MIS. */
*pdf = 1e6f;
*eval = make_float3(1e6f, 1e6f, 1e6f);
diff --git a/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h b/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h
index f1a26650078..7e0f5a7ec75 100644
--- a/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h
+++ b/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h
@@ -35,20 +35,38 @@
CCL_NAMESPACE_BEGIN
-ccl_device int bsdf_ashikhmin_velvet_setup(ShaderClosure *sc)
+typedef ccl_addr_space struct VelvetBsdf {
+ SHADER_CLOSURE_BASE;
+
+ float sigma;
+ float invsigma2;
+ float3 N;
+} VelvetBsdf;
+
+ccl_device int bsdf_ashikhmin_velvet_setup(VelvetBsdf *bsdf)
{
- float sigma = fmaxf(sc->data0, 0.01f);
- sc->data0 = 1.0f/(sigma * sigma); /* m_invsigma2 */
+ float sigma = fmaxf(bsdf->sigma, 0.01f);
+ bsdf->invsigma2 = 1.0f/(sigma * sigma);
- sc->type = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID;
+ bsdf->type = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID;
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;
+
+ 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)
{
- float m_invsigma2 = sc->data0;
- float3 N = sc->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);
@@ -90,8 +108,9 @@ ccl_device float3 bsdf_ashikhmin_velvet_eval_transmit(const ShaderClosure *sc, c
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)
{
- float m_invsigma2 = sc->data0;
- float3 N = sc->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
diff --git a/intern/cycles/kernel/closure/bsdf_diffuse.h b/intern/cycles/kernel/closure/bsdf_diffuse.h
index 4b29bb096d1..dcd187f9305 100644
--- a/intern/cycles/kernel/closure/bsdf_diffuse.h
+++ b/intern/cycles/kernel/closure/bsdf_diffuse.h
@@ -35,17 +35,31 @@
CCL_NAMESPACE_BEGIN
+typedef ccl_addr_space struct DiffuseBsdf {
+ SHADER_CLOSURE_BASE;
+ float3 N;
+} DiffuseBsdf;
+
/* DIFFUSE */
-ccl_device int bsdf_diffuse_setup(ShaderClosure *sc)
+ccl_device int bsdf_diffuse_setup(DiffuseBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_DIFFUSE_ID;
+ 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;
+
+ 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)
{
- float3 N = sc->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;
@@ -59,7 +73,8 @@ ccl_device float3 bsdf_diffuse_eval_transmit(const ShaderClosure *sc, const floa
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)
{
- float3 N = sc->N;
+ const DiffuseBsdf *bsdf = (const DiffuseBsdf*)sc;
+ float3 N = bsdf->N;
// distribution over the hemisphere
sample_cos_hemisphere(N, randu, randv, omega_in, pdf);
@@ -80,9 +95,9 @@ ccl_device int bsdf_diffuse_sample(const ShaderClosure *sc, float3 Ng, float3 I,
/* TRANSLUCENT */
-ccl_device int bsdf_translucent_setup(ShaderClosure *sc)
+ccl_device int bsdf_translucent_setup(DiffuseBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_TRANSLUCENT_ID;
+ bsdf->type = CLOSURE_BSDF_TRANSLUCENT_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
@@ -93,7 +108,8 @@ ccl_device float3 bsdf_translucent_eval_reflect(const ShaderClosure *sc, const f
ccl_device float3 bsdf_translucent_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float3 N = sc->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;
@@ -102,7 +118,8 @@ ccl_device float3 bsdf_translucent_eval_transmit(const ShaderClosure *sc, const
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)
{
- float3 N = sc->N;
+ 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
diff --git a/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h b/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h
index e0287e7655a..2d982a95fe4 100644
--- a/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h
+++ b/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h
@@ -35,7 +35,16 @@
CCL_NAMESPACE_BEGIN
-ccl_device float3 bsdf_diffuse_ramp_get_color(const ShaderClosure *sc, const float3 colors[8], float pos)
+#ifdef __OSL__
+
+typedef ccl_addr_space struct DiffuseRampBsdf {
+ SHADER_CLOSURE_BASE;
+
+ float3 N;
+ float3 *colors;
+} DiffuseRampBsdf;
+
+ccl_device float3 bsdf_diffuse_ramp_get_color(const float3 colors[8], float pos)
{
int MAXCOLORS = 8;
@@ -49,11 +58,9 @@ ccl_device float3 bsdf_diffuse_ramp_get_color(const ShaderClosure *sc, const flo
return colors[ipos] * (1.0f - offset) + colors[ipos+1] * offset;
}
-ccl_device int bsdf_diffuse_ramp_setup(ShaderClosure *sc)
+ccl_device int bsdf_diffuse_ramp_setup(DiffuseRampBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_DIFFUSE_RAMP_ID;
- sc->data0 = 0.0f;
- sc->data1 = 0.0f;
+ bsdf->type = CLOSURE_BSDF_DIFFUSE_RAMP_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
@@ -61,29 +68,31 @@ ccl_device void bsdf_diffuse_ramp_blur(ShaderClosure *sc, float roughness)
{
}
-ccl_device float3 bsdf_diffuse_ramp_eval_reflect(const ShaderClosure *sc, const float3 colors[8], 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)
{
- float3 N = sc->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(sc, colors, 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 colors[8], 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);
}
-ccl_device int bsdf_diffuse_ramp_sample(const ShaderClosure *sc, const float3 colors[8], 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)
{
- float3 N = sc->N;
+ 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(sc, colors, *pdf * M_PI_F) * M_1_PI_F;
+ *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;
@@ -95,6 +104,8 @@ ccl_device int bsdf_diffuse_ramp_sample(const ShaderClosure *sc, const float3 co
return LABEL_REFLECT|LABEL_DIFFUSE;
}
+#endif /* __OSL__ */
+
CCL_NAMESPACE_END
#endif /* __BSDF_DIFFUSE_RAMP_H__ */
diff --git a/intern/cycles/kernel/closure/bsdf_disney_clearcoat.h b/intern/cycles/kernel/closure/bsdf_disney_clearcoat.h
index 377d21939b7..cdb8b3e0cff 100644
--- a/intern/cycles/kernel/closure/bsdf_disney_clearcoat.h
+++ b/intern/cycles/kernel/closure/bsdf_disney_clearcoat.h
@@ -35,22 +35,30 @@
CCL_NAMESPACE_BEGIN
+typedef ccl_addr_space struct DisneyClearcoatBsdf {
+ SHADER_CLOSURE_BASE;
-ccl_device int bsdf_disney_clearcoat_setup(ShaderClosure *sc)
+ float clearcoat, clearcoatGloss, clearcoatRoughness;
+ float3 N;
+} DisneyClearcoatBsdf;
+
+ccl_device int bsdf_disney_clearcoat_setup(DisneyClearcoatBsdf *bsdf)
{
/* clearcoat roughness */
- sc->custom1 = 0.1f * (1.0f - sc->data1/*clearcoatGloss*/) + 0.001f * sc->data1/*clearcoatGloss*/; // lerp(0.1f, 0.001f, sc->data1/*clearcoatGloss*/); //
+ bsdf->clearcoatRoughness = 0.1f * (1.0f - bsdf->clearcoatGloss) + 0.001f * bsdf->clearcoatGloss; // lerp(0.1f, 0.001f, sc->data1/*clearcoatGloss*/); //
- sc->type = CLOSURE_BSDF_DISNEY_CLEARCOAT_ID;
+ bsdf->type = CLOSURE_BSDF_DISNEY_CLEARCOAT_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
ccl_device float3 bsdf_disney_clearcoat_eval_reflect(const ShaderClosure *sc, const float3 I,
const float3 omega_in, float *pdf)
{
- if (sc->data0 > 0.0f) {
- float alpha = sc->custom1;
- float3 N = sc->N;
+ const DisneyClearcoatBsdf *bsdf = (const DisneyClearcoatBsdf *)sc;
+
+ if (bsdf->clearcoat > 0.0f) {
+ float alpha = bsdf->clearcoatRoughness;
+ float3 N = bsdf->N;
if (alpha <= 1e-4f)
return make_float3(0.0f, 0.0f, 0.0f);
@@ -81,7 +89,7 @@ ccl_device float3 bsdf_disney_clearcoat_eval_reflect(const ShaderClosure *sc, co
float common = D * 0.25f / cosNO;
float FH = schlick_fresnel(dot(omega_in, m));
- float3 F = (0.04f * (1.0f - FH) + 1.0f * FH) * 0.25f * sc->data0/*clearcoat*/ * make_float3(1.0f, 1.0f, 1.0f); // lerp(make_float3(0.04f, 0.04f, 0.04f), make_float3(1.0f, 1.0f, 1.0f), FH);
+ float3 F = (0.04f * (1.0f - FH) + 1.0f * FH) * 0.25f * bsdf->clearcoat * make_float3(1.0f, 1.0f, 1.0f); // lerp(make_float3(0.04f, 0.04f, 0.04f), make_float3(1.0f, 1.0f, 1.0f), FH);
float3 out = F * G * common;
@@ -110,9 +118,11 @@ ccl_device int bsdf_disney_clearcoat_sample(const ShaderClosure *sc,
float3 *eval, float3 *omega_in, float3 *domega_in_dx,
float3 *domega_in_dy, float *pdf)
{
- if (sc->data0 > 0.0f) {
- float alpha = sc->custom1;
- float3 N = sc->N;
+ const DisneyClearcoatBsdf *bsdf = (const DisneyClearcoatBsdf *)sc;
+
+ if (bsdf->clearcoat > 0.0f) {
+ float alpha = bsdf->clearcoatRoughness;
+ float3 N = bsdf->N;
float cosNO = dot(N, I);
if (cosNO > 0) {
@@ -168,8 +178,8 @@ ccl_device int bsdf_disney_clearcoat_sample(const ShaderClosure *sc,
float FH = schlick_fresnel(dot(*omega_in, m));
float3 F = make_float3(0.04f, 0.04f, 0.04f) * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; // lerp(make_float3(0.04f, 0.04f, 0.04f), make_float3(1.0f, 1.0f, 1.0f), FH);
-
- *eval = G1i * common * F * 0.25f * sc->data0/*clearcoat*/;
+
+ *eval = G1i * common * F * 0.25f * bsdf->clearcoat;
}
#ifdef __RAY_DIFFERENTIALS__
diff --git a/intern/cycles/kernel/closure/bsdf_disney_diffuse.h b/intern/cycles/kernel/closure/bsdf_disney_diffuse.h
index ac5032f3377..faeb00197c7 100644
--- a/intern/cycles/kernel/closure/bsdf_disney_diffuse.h
+++ b/intern/cycles/kernel/closure/bsdf_disney_diffuse.h
@@ -36,8 +36,15 @@
CCL_NAMESPACE_BEGIN
+typedef ccl_addr_space struct DisneyDiffuseBsdf {
+ SHADER_CLOSURE_BASE;
-ccl_device float3 calculate_disney_diffuse_brdf(const ShaderClosure *sc,
+ float roughness;
+ float3 N;
+ float3 baseColor;
+} DisneyDiffuseBsdf;
+
+ccl_device float3 calculate_disney_diffuse_brdf(const DisneyDiffuseBsdf *bsdf,
float3 N, float3 V, float3 L, float3 H, float *pdf)
{
float NdotL = max(dot(N, L), 0.0f);
@@ -51,10 +58,10 @@ ccl_device float3 calculate_disney_diffuse_brdf(const ShaderClosure *sc,
float LdotH = dot(L, H);
float FL = schlick_fresnel(NdotL), FV = schlick_fresnel(NdotV);
- const float Fd90 = 0.5f + 2.0f * LdotH*LdotH * sc->data0/*roughness*/;
+ 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); //lerp(1.0f, Fd90, FL) * lerp(1.0f, Fd90, FV);
- float3 value = M_1_PI_F * Fd * sc->color0/*baseColor*/;
+ float3 value = M_1_PI_F * Fd * bsdf->baseColor;
*pdf = M_1_PI_F * 0.5f;
@@ -63,22 +70,24 @@ ccl_device float3 calculate_disney_diffuse_brdf(const ShaderClosure *sc,
return value;
}
-ccl_device int bsdf_disney_diffuse_setup(ShaderClosure *sc)
+ccl_device int bsdf_disney_diffuse_setup(DisneyDiffuseBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_DISNEY_DIFFUSE_ID;
+ bsdf->type = CLOSURE_BSDF_DISNEY_DIFFUSE_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
ccl_device float3 bsdf_disney_diffuse_eval_reflect(const ShaderClosure *sc, const float3 I,
const float3 omega_in, float *pdf)
{
- float3 N = normalize(sc->N);
+ const DisneyDiffuseBsdf *bsdf = (const DisneyDiffuseBsdf *)sc;
+
+ float3 N = normalize(bsdf->N);
float3 V = I; // outgoing
float3 L = omega_in; // incoming
float3 H = normalize(L + V);
- if (dot(sc->N, omega_in) > 0.0f) {
- float3 value = calculate_disney_diffuse_brdf(sc, N, V, L, H, pdf);
+ if (dot(bsdf->N, omega_in) > 0.0f) {
+ float3 value = calculate_disney_diffuse_brdf(bsdf, N, V, L, H, pdf);
return value;
}
@@ -99,14 +108,16 @@ ccl_device int bsdf_disney_diffuse_sample(const ShaderClosure *sc,
float3 *eval, float3 *omega_in, float3 *domega_in_dx,
float3 *domega_in_dy, float *pdf)
{
- float3 N = normalize(sc->N);
+ const DisneyDiffuseBsdf *bsdf = (const DisneyDiffuseBsdf *)sc;
+
+ float3 N = normalize(bsdf->N);
sample_uniform_hemisphere(N, randu, randv, omega_in, pdf);
if (dot(Ng, *omega_in) > 0) {
float3 H = normalize(I + *omega_in);
- *eval = calculate_disney_diffuse_brdf(sc, N, I, *omega_in, H, pdf);
+ *eval = calculate_disney_diffuse_brdf(bsdf, N, I, *omega_in, H, pdf);
#ifdef __RAY_DIFFERENTIALS__
// TODO: find a better approximation for the diffuse bounce
diff --git a/intern/cycles/kernel/closure/bsdf_disney_sheen.h b/intern/cycles/kernel/closure/bsdf_disney_sheen.h
index 2806ecfc951..478ecaba324 100644
--- a/intern/cycles/kernel/closure/bsdf_disney_sheen.h
+++ b/intern/cycles/kernel/closure/bsdf_disney_sheen.h
@@ -36,14 +36,21 @@
CCL_NAMESPACE_BEGIN
+typedef ccl_addr_space struct DisneySheenBsdf {
+ SHADER_CLOSURE_BASE;
-ccl_device float3 calculate_disney_sheen_brdf(const ShaderClosure *sc,
+ float sheen, sheenTint;
+ float3 N;
+ float3 baseColor, csheen0;
+} DisneySheenBsdf;
+
+ccl_device float3 calculate_disney_sheen_brdf(const DisneySheenBsdf *bsdf,
float3 N, float3 V, float3 L, float3 H, float *pdf)
{
float NdotL = dot(N, L);
float NdotV = dot(N, V);
- if (NdotL < 0 || NdotV < 0 || sc->data0 == 0.0f) {
+ if (NdotL < 0 || NdotV < 0 || bsdf->sheen == 0.0f) {
*pdf = 0.0f;
return make_float3(0.0f, 0.0f, 0.0f);
}
@@ -54,36 +61,38 @@ ccl_device float3 calculate_disney_sheen_brdf(const ShaderClosure *sc,
float FH = schlick_fresnel(LdotH);
- float3 value = FH * sc->data0/*sheen*/ * sc->custom_color0/*csheen0*/;
+ float3 value = FH * bsdf->sheen * bsdf->csheen0;
value *= NdotL;
return value;
}
-ccl_device int bsdf_disney_sheen_setup(ShaderClosure *sc)
+ccl_device int bsdf_disney_sheen_setup(DisneySheenBsdf *bsdf)
{
- float m_cdlum = 0.3f * sc->color0.x + 0.6f * sc->color0.y + 0.1f * sc->color0.z; // luminance approx.
+ float m_cdlum = 0.3f * bsdf->baseColor.x + 0.6f * bsdf->baseColor.y + 0.1f * bsdf->baseColor.z; // luminance approx.
- float3 m_ctint = m_cdlum > 0.0f ? sc->color0 / m_cdlum : make_float3(1.0f, 1.0f, 1.0f); // normalize lum. to isolate hue+sat
+ float3 m_ctint = m_cdlum > 0.0f ? bsdf->baseColor / m_cdlum : make_float3(1.0f, 1.0f, 1.0f); // normalize lum. to isolate hue+sat
/* csheen0 */
- sc->custom_color0 = make_float3(1.0f, 1.0f, 1.0f) * (1.0f - sc->data1/*sheenTint*/) + m_ctint * sc->data1/*sheenTint*/; // lerp(make_float3(1.0f, 1.0f, 1.0f), m_ctint, sc->data1/*sheenTint*/);
+ bsdf->csheen0 = make_float3(1.0f, 1.0f, 1.0f) * (1.0f - bsdf->sheenTint) + m_ctint * bsdf->sheenTint; // lerp(make_float3(1.0f, 1.0f, 1.0f), m_ctint, sc->data1/*sheenTint*/);
- sc->type = CLOSURE_BSDF_DISNEY_SHEEN_ID;
+ bsdf->type = CLOSURE_BSDF_DISNEY_SHEEN_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
ccl_device float3 bsdf_disney_sheen_eval_reflect(const ShaderClosure *sc, const float3 I,
const float3 omega_in, float *pdf)
{
- float3 N = normalize(sc->N);
+ const DisneySheenBsdf *bsdf = (const DisneySheenBsdf *)sc;
+
+ float3 N = normalize(bsdf->N);
float3 V = I; // outgoing
float3 L = omega_in; // incoming
float3 H = normalize(L + V);
- if (dot(sc->N, omega_in) > 0.0f) {
- float3 value = calculate_disney_sheen_brdf(sc, N, V, L, H, pdf);
+ if (dot(bsdf->N, omega_in) > 0.0f) {
+ float3 value = calculate_disney_sheen_brdf(bsdf, N, V, L, H, pdf);
return value;
}
@@ -104,14 +113,16 @@ ccl_device int bsdf_disney_sheen_sample(const ShaderClosure *sc,
float3 *eval, float3 *omega_in, float3 *domega_in_dx,
float3 *domega_in_dy, float *pdf)
{
- float3 N = normalize(sc->N);
+ const DisneySheenBsdf *bsdf = (const DisneySheenBsdf *)sc;
+
+ float3 N = normalize(bsdf->N);
sample_uniform_hemisphere(N, randu, randv, omega_in, pdf);
if (dot(Ng, *omega_in) > 0) {
float3 H = normalize(I + *omega_in);
- *eval = calculate_disney_sheen_brdf(sc, N, I, *omega_in, H, pdf);
+ *eval = calculate_disney_sheen_brdf(bsdf, N, I, *omega_in, H, pdf);
#ifdef __RAY_DIFFERENTIALS__
// TODO: find a better approximation for the diffuse bounce
diff --git a/intern/cycles/kernel/closure/bsdf_disney_specular.h b/intern/cycles/kernel/closure/bsdf_disney_specular.h
index cbcfc4106c5..7e8139fd040 100644
--- a/intern/cycles/kernel/closure/bsdf_disney_specular.h
+++ b/intern/cycles/kernel/closure/bsdf_disney_specular.h
@@ -35,40 +35,47 @@
CCL_NAMESPACE_BEGIN
+typedef ccl_addr_space struct DisneySpecularBsdf {
+ SHADER_CLOSURE_BASE;
-ccl_device int bsdf_disney_specular_setup(ShaderClosure *sc)
+ float specular, specularTint, roughness, metallic, anisotropic, alpha_x, alpha_y, rough_g;
+ float3 N, T;
+ float3 baseColor, cspec0;
+} DisneySpecularBsdf;
+
+ccl_device int bsdf_disney_specular_setup(DisneySpecularBsdf *bsdf)
{
- float m_cdlum = 0.3f * sc->color0.x + 0.6f * sc->color0.y + 0.1f * sc->color0.z; // luminance approx.
+ float m_cdlum = 0.3f * bsdf->baseColor.x + 0.6f * bsdf->baseColor.y + 0.1f * bsdf->baseColor.z; // luminance approx.
- float3 m_ctint = m_cdlum > 0.0f ? sc->color0/*baseColor*/ / m_cdlum : make_float3(1.0f, 1.0f, 1.0f); // normalize lum. to isolate hue+sat
+ float3 m_ctint = m_cdlum > 0.0f ? bsdf->baseColor / m_cdlum : make_float3(1.0f, 1.0f, 1.0f); // normalize lum. to isolate hue+sat
- float3 tmp_col = make_float3(1.0f, 1.0f, 1.0f) * (1.0f - sc->data2/*specularTint*/) + m_ctint * sc->data2/*specularTint*/; // lerp(make_float3(1.0f, 1.0f, 1.0f), m_ctint, sc->data2/*specularTint*/);
- sc->custom_color0/*cspec0*/ = (sc->data1/*specular*/ * 0.08f * tmp_col) * (1.0f - sc->data0/*metallic*/) + sc->color0/*baseColor*/ * sc->data0/*metallic*/; // lerp(sc->data1/*specular*/ * 0.08f * tmp_col, sc->color0/*baseColor*/, sc->data0/*metallic*/);
+ float3 tmp_col = make_float3(1.0f, 1.0f, 1.0f) * (1.0f - bsdf->specularTint) + m_ctint * bsdf->specularTint; // lerp(make_float3(1.0f, 1.0f, 1.0f), m_ctint, sc->data2/*specularTint*/);
+ bsdf->cspec0 = (bsdf->specular * 0.08f * tmp_col) * (1.0f - bsdf->metallic) + bsdf->baseColor * bsdf->metallic; // lerp(sc->data1/*specular*/ * 0.08f * tmp_col, sc->color0/*baseColor*/, sc->data0/*metallic*/);
- float aspect = safe_sqrtf(1.0f - sc->data4/*anisotropic*/ * 0.9f);
- float r2 = sqr(sc->data3/*roughness*/);
+ float aspect = safe_sqrtf(1.0f - bsdf->anisotropic * 0.9f);
+ float r2 = sqr(bsdf->roughness);
/* ax */
- sc->custom1 = fmaxf(0.001f, r2 / aspect);
+ bsdf->alpha_x = fmaxf(0.001f, r2 / aspect);
/* ay */
- sc->custom2 = fmaxf(0.001f, r2 * aspect);
+ bsdf->alpha_y = fmaxf(0.001f, r2 * aspect);
/* rough_g */
- sc->custom3 = sqr(sc->data3/*roughness*/ * 0.5f + 0.5f);
+ bsdf->rough_g = sqr(bsdf->roughness * 0.5f + 0.5f);
- sc->type = CLOSURE_BSDF_DISNEY_SPECULAR_ID;
+ bsdf->type = CLOSURE_BSDF_DISNEY_SPECULAR_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
ccl_device float3 bsdf_disney_specular_eval_reflect(const ShaderClosure *sc, const float3 I,
const float3 omega_in, float *pdf)
{
- float alpha_x = sc->custom1;
- float alpha_y = sc->custom2;
- float3 N = sc->N;
+ const DisneySpecularBsdf *bsdf = (const DisneySpecularBsdf *)sc;
+
+ float3 N = bsdf->N;
- if (fmaxf(alpha_x, alpha_y) <= 1e-4f)
+ if (fmaxf(bsdf->alpha_x, bsdf->alpha_y) <= 1e-4f)
return make_float3(0.0f, 0.0f, 0.0f);
float cosNO = dot(N, I);
@@ -77,10 +84,10 @@ ccl_device float3 bsdf_disney_specular_eval_reflect(const ShaderClosure *sc, con
if (cosNI > 0 && cosNO > 0) {
/* get half vector */
float3 m = normalize(omega_in + I);
- float alpha2 = alpha_x * alpha_y;
+ float alpha2 = bsdf->alpha_x * bsdf->alpha_y;
float D, G1o, G1i;
- if (alpha_x == alpha_y) {
+ if (bsdf->alpha_x == bsdf->alpha_y) {
/* isotropic
* eq. 20: (F*G*D)/(4*in*on)
* eq. 33: first we calculate D(m) */
@@ -97,12 +104,12 @@ ccl_device float3 bsdf_disney_specular_eval_reflect(const ShaderClosure *sc, con
else {
/* anisotropic */
float3 X, Y, Z = N;
- make_orthonormals_tangent(Z, sc->T, &X, &Y);
+ 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_x = -local_m.x/(local_m.z*bsdf->alpha_x);
+ float slope_y = -local_m.y/(local_m.z*bsdf->alpha_y);
float slope_len = 1 + slope_x*slope_x + slope_y*slope_y;
float cosThetaM = local_m.z;
@@ -116,7 +123,7 @@ ccl_device float3 bsdf_disney_specular_eval_reflect(const ShaderClosure *sc, con
float cosPhiO = dot(I, X);
float sinPhiO = dot(I, Y);
- float alphaO2 = (cosPhiO*cosPhiO)*(alpha_x*alpha_x) + (sinPhiO*sinPhiO)*(alpha_y*alpha_y);
+ float alphaO2 = (cosPhiO*cosPhiO)*(bsdf->alpha_x*bsdf->alpha_x) + (sinPhiO*sinPhiO)*(bsdf->alpha_y*bsdf->alpha_y);
alphaO2 /= cosPhiO*cosPhiO + sinPhiO*sinPhiO;
G1o = 2 / (1 + safe_sqrtf(1 + alphaO2 * tanThetaO2));
@@ -125,7 +132,7 @@ ccl_device float3 bsdf_disney_specular_eval_reflect(const ShaderClosure *sc, con
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);
+ float alphaI2 = (cosPhiI*cosPhiI)*(bsdf->alpha_x*bsdf->alpha_x) + (sinPhiI*sinPhiI)*(bsdf->alpha_y*bsdf->alpha_y);
alphaI2 /= cosPhiI*cosPhiI + sinPhiI*sinPhiI;
G1i = 2 / (1 + safe_sqrtf(1 + alphaI2 * tanThetaI2));
@@ -137,7 +144,7 @@ ccl_device float3 bsdf_disney_specular_eval_reflect(const ShaderClosure *sc, con
float common = D * 0.25f / cosNO;
float FH = schlick_fresnel(dot(omega_in, m));
- float3 F = sc->custom_color0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; // lerp(sc->custom_color0, make_float3(1.0f, 1.0f, 1.0f), FH);
+ float3 F = bsdf->cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; // lerp(sc->custom_color0, make_float3(1.0f, 1.0f, 1.0f), FH);
float3 out = F * G * common;
@@ -166,18 +173,18 @@ ccl_device int bsdf_disney_specular_sample(const ShaderClosure *sc,
float3 *eval, float3 *omega_in, float3 *domega_in_dx,
float3 *domega_in_dy, float *pdf)
{
- float alpha_x = sc->custom1;
- float alpha_y = sc->custom2;
- float3 N = sc->N;
+ const DisneySpecularBsdf *bsdf = (const DisneySpecularBsdf *)sc;
+
+ float3 N = bsdf->N;
float cosNO = dot(N, I);
if(cosNO > 0) {
float3 X, Y, Z = N;
- if(alpha_x == alpha_y)
+ if (bsdf->alpha_x == bsdf->alpha_y)
make_orthonormals(Z, &X, &Y);
else
- make_orthonormals_tangent(Z, sc->T, &X, &Y);
+ make_orthonormals_tangent(Z, bsdf->T, &X, &Y);
/* importance sampling with distribution of visible normals. vectors are
* transformed to local space before and after */
@@ -186,7 +193,7 @@ ccl_device int bsdf_disney_specular_sample(const ShaderClosure *sc,
float3 m;
float G1o;
- local_m = importance_sample_microfacet_stretched(local_I, alpha_x, alpha_y,
+ local_m = importance_sample_microfacet_stretched(local_I, bsdf->alpha_x, bsdf->alpha_y,
randu, randv, false, &G1o);
m = X*local_m.x + Y*local_m.y + Z*local_m.z;
@@ -200,7 +207,7 @@ ccl_device int bsdf_disney_specular_sample(const ShaderClosure *sc,
*omega_in = 2 * cosMO * m - I;
if(dot(Ng, *omega_in) > 0) {
- if(fmaxf(alpha_x, alpha_y) <= 1e-4f) {
+ if (fmaxf(bsdf->alpha_x, bsdf->alpha_y) <= 1e-4f) {
/* some high number for MIS */
*pdf = 1e6f;
*eval = make_float3(1e6f, 1e6f, 1e6f);
@@ -208,10 +215,10 @@ ccl_device int bsdf_disney_specular_sample(const ShaderClosure *sc,
else {
/* microfacet normal is visible to this ray */
/* eq. 33 */
- float alpha2 = alpha_x * alpha_y;
+ float alpha2 = bsdf->alpha_x * bsdf->alpha_y;
float D, G1i;
- if(alpha_x == alpha_y) {
+ if (bsdf->alpha_x == bsdf->alpha_y) {
float cosThetaM2 = cosThetaM * cosThetaM;
float cosThetaM4 = cosThetaM2 * cosThetaM2;
float tanThetaM2 = 1/(cosThetaM2) - 1;
@@ -225,8 +232,8 @@ ccl_device int bsdf_disney_specular_sample(const ShaderClosure *sc,
}
else {
/* anisotropic distribution */
- float slope_x = -local_m.x/(local_m.z*alpha_x);
- float slope_y = -local_m.y/(local_m.z*alpha_y);
+ float slope_x = -local_m.x / (local_m.z*bsdf->alpha_x);
+ float slope_y = -local_m.y / (local_m.z*bsdf->alpha_y);
float slope_len = 1 + slope_x*slope_x + slope_y*slope_y;
float cosThetaM = local_m.z;
@@ -242,7 +249,7 @@ ccl_device int bsdf_disney_specular_sample(const ShaderClosure *sc,
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);
+ float alphaI2 = (cosPhiI*cosPhiI)*(bsdf->alpha_x*bsdf->alpha_x) + (sinPhiI*sinPhiI)*(bsdf->alpha_y*bsdf->alpha_y);
alphaI2 /= cosPhiI*cosPhiI + sinPhiI*sinPhiI;
G1i = 2 / (1 + safe_sqrtf(1 + alphaI2 * tanThetaI2));
@@ -253,7 +260,7 @@ ccl_device int bsdf_disney_specular_sample(const ShaderClosure *sc,
*pdf = common;
float FH = schlick_fresnel(dot(*omega_in, m));
- float3 F = sc->custom_color0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; // lerp(sc->custom_color0, make_float3(1.0f, 1.0f, 1.0f), FH);
+ float3 F = bsdf->cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; // lerp(sc->custom_color0, make_float3(1.0f, 1.0f, 1.0f), FH);
*eval = G1i * common * F;
}
diff --git a/intern/cycles/kernel/closure/bsdf_hair.h b/intern/cycles/kernel/closure/bsdf_hair.h
index 1e81617a7d3..bede5f45e7e 100644
--- a/intern/cycles/kernel/closure/bsdf_hair.h
+++ b/intern/cycles/kernel/closure/bsdf_hair.h
@@ -35,29 +35,49 @@
CCL_NAMESPACE_BEGIN
+typedef ccl_addr_space struct HairBsdf {
+ SHADER_CLOSURE_BASE;
-ccl_device int bsdf_hair_reflection_setup(ShaderClosure *sc)
+ float3 T;
+ float roughness1;
+ float roughness2;
+ float offset;
+} HairBsdf;
+
+ccl_device int bsdf_hair_reflection_setup(HairBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_HAIR_REFLECTION_ID;
- sc->data0 = clamp(sc->data0, 0.001f, 1.0f);
- sc->data1 = clamp(sc->data1, 0.001f, 1.0f);
+ 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(ShaderClosure *sc)
+ccl_device int bsdf_hair_transmission_setup(HairBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_HAIR_TRANSMISSION_ID;
- sc->data0 = clamp(sc->data0, 0.001f, 1.0f);
- sc->data1 = clamp(sc->data1, 0.001f, 1.0f);
+ 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;
+
+ 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)
{
- float offset = sc->data2;
- float3 Tg = sc->T;
- float roughness1 = sc->data0;
- float roughness2 = sc->data1;
+ 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);
@@ -107,10 +127,11 @@ ccl_device float3 bsdf_hair_reflection_eval_transmit(const ShaderClosure *sc, co
ccl_device float3 bsdf_hair_transmission_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float offset = sc->data2;
- float3 Tg = sc->T;
- float roughness1 = sc->data0;
- float roughness2 = sc->data1;
+ 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);
@@ -148,10 +169,11 @@ ccl_device float3 bsdf_hair_transmission_eval_transmit(const ShaderClosure *sc,
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)
{
- float offset = sc->data2;
- float3 Tg = sc->T;
- float roughness1 = sc->data0;
- float roughness2 = sc->data1;
+ 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);
@@ -198,10 +220,11 @@ ccl_device int bsdf_hair_reflection_sample(const ShaderClosure *sc, float3 Ng, f
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)
{
- float offset = sc->data2;
- float3 Tg = sc->T;
- float roughness1 = sc->data0;
- float roughness2 = sc->data1;
+ 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);
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h
index 2a0e8f62e7c..7173ecd64de 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet.h
@@ -35,6 +35,20 @@
CCL_NAMESPACE_BEGIN
+typedef ccl_addr_space struct MicrofacetExtra {
+ float3 color, cspec0;
+ bool use_fresnel;
+} MicrofacetExtra;
+
+typedef ccl_addr_space struct MicrofacetBsdf {
+ SHADER_CLOSURE_BASE;
+
+ float alpha_x, alpha_y, ior;
+ MicrofacetExtra *extra;
+ float3 T;
+ float3 N;
+} MicrofacetBsdf;
+
/* Beckmann and GGX microfacet importance sampling. */
ccl_device_inline void microfacet_beckmann_sample_slopes(
@@ -233,50 +247,92 @@ ccl_device_inline float3 microfacet_sample_stretched(
* Anisotropy is only supported for reflection currently, but adding it for
* transmission is just a matter of copying code from reflection if needed. */
-ccl_device int bsdf_microfacet_ggx_setup(ShaderClosure *sc)
+ccl_device int bsdf_microfacet_ggx_setup(MicrofacetBsdf *bsdf, bool use_fresnel = false)
{
- sc->data0 = saturate(sc->data0); /* alpha_x */
- sc->data1 = sc->data0; /* alpha_y */
+ if (bsdf->extra) {
+ bsdf->extra->use_fresnel = use_fresnel;
+
+ 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 = saturate(bsdf->alpha_x);
+ bsdf->alpha_y = bsdf->alpha_x;
- sc->type = CLOSURE_BSDF_MICROFACET_GGX_ID;
+ bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
-ccl_device int bsdf_microfacet_ggx_aniso_setup(ShaderClosure *sc)
+ccl_device bool bsdf_microfacet_merge(const ShaderClosure *a, const ShaderClosure *b)
{
- sc->data0 = saturate(sc->data0); /* alpha_x */
- sc->data1 = saturate(sc->data1); /* alpha_y */
+ 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 && !bsdf_b->extra) ||
+ ((bsdf_a->extra && bsdf_b->extra) &&
+ (isequal_float3(bsdf_a->extra->color, bsdf_b->extra->color))));
+}
+
+ccl_device int bsdf_microfacet_ggx_aniso_setup(MicrofacetBsdf *bsdf, bool use_fresnel = false)
+{
+ if (bsdf->extra) {
+ bsdf->extra->use_fresnel = use_fresnel;
+
+ 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 = saturate(bsdf->alpha_x);
+ bsdf->alpha_y = saturate(bsdf->alpha_y);
- sc->type = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
+ bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
-ccl_device int bsdf_microfacet_ggx_refraction_setup(ShaderClosure *sc)
+ccl_device int bsdf_microfacet_ggx_refraction_setup(MicrofacetBsdf *bsdf, bool use_fresnel = false)
{
- sc->data0 = saturate(sc->data0); /* alpha_x */
- sc->data1 = sc->data0; /* alpha_y */
+ if (bsdf->extra) {
+ bsdf->extra->use_fresnel = use_fresnel;
+
+ 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 = saturate(bsdf->alpha_x);
+ bsdf->alpha_y = bsdf->alpha_x;
- sc->type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
+ bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
ccl_device void bsdf_microfacet_ggx_blur(ShaderClosure *sc, float roughness)
{
- sc->data0 = fmaxf(roughness, sc->data0); /* alpha_x */
- sc->data1 = fmaxf(roughness, sc->data1); /* alpha_y */
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf*)sc;
+
+ 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)
{
- float alpha_x = sc->data0;
- float alpha_y = sc->data1;
- bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
- float3 N = sc->N;
+ 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 || fmaxf(alpha_x, alpha_y) <= 1e-4f)
+ if(m_refractive || alpha_x*alpha_y <= 1e-7f)
return make_float3(0.0f, 0.0f, 0.0f);
float cosNO = dot(N, I);
@@ -305,7 +361,7 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons
else {
/* anisotropic */
float3 X, Y, Z = N;
- make_orthonormals_tangent(Z, sc->T, &X, &Y);
+ make_orthonormals_tangent(Z, bsdf->T, &X, &Y);
/* distribution */
float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m));
@@ -343,7 +399,17 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons
/* eq. 20 */
float common = D * 0.25f / cosNO;
- float out = G * common;
+
+ float3 F = make_float3(1.0f, 1.0f, 1.0f);
+ if (bsdf->extra) {
+ if (bsdf->extra->use_fresnel) {
+ float FH = schlick_fresnel(dot(omega_in, m));
+
+ F = bsdf->extra->cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; // lerp(sc->custom_color0, make_float3(1.0f, 1.0f, 1.0f), FH);
+ }
+ }
+
+ float3 out = F * G * common;
/* eq. 2 in distribution of visible normals sampling
* pm = Dw = G1o * dot(m, I) * D / dot(N, I); */
@@ -353,7 +419,7 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons
* pdf = pm * 0.25 / dot(m, I); */
*pdf = G1o * common;
- return make_float3(out, out, out);
+ return out;
}
return make_float3(0.0f, 0.0f, 0.0f);
@@ -361,13 +427,14 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons
ccl_device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float alpha_x = sc->data0;
- float alpha_y = sc->data1;
- float m_eta = sc->data2;
- bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
- float3 N = sc->N;
-
- if(!m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f)
+ 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);
float cosNO = dot(N, I);
@@ -407,18 +474,29 @@ ccl_device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderClosure *sc, con
/* 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;
+
+ float3 F = make_float3(1.0f, 1.0f, 1.0f);
+ if (bsdf->extra) {
+ if (bsdf->extra->use_fresnel) {
+ float FH = schlick_fresnel(dot(omega_in, Ht));
+
+ F = bsdf->extra->cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; // lerp(sc->custom_color0, make_float3(1.0f, 1.0f, 1.0f), FH);
+ }
+ }
+
+ float3 out = G * fabsf(cosHI * cosHO) * common * F;
*pdf = G1o * fabsf(cosHO * cosHI) * common;
- return make_float3(out, out, out);
+ return 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)
{
- float alpha_x = sc->data0;
- float alpha_y = sc->data1;
- bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
- float3 N = sc->N;
+ 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;
float cosNO = dot(N, I);
if(cosNO > 0) {
@@ -427,7 +505,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure
if(alpha_x == alpha_y)
make_orthonormals(Z, &X, &Y);
else
- make_orthonormals_tangent(Z, sc->T, &X, &Y);
+ make_orthonormals_tangent(Z, bsdf->T, &X, &Y);
/* importance sampling with distribution of visible normals. vectors are
* transformed to local space before and after */
@@ -450,7 +528,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure
*omega_in = 2 * cosMO * m - I;
if(dot(Ng, *omega_in) > 0) {
- if(fmaxf(alpha_x, alpha_y) <= 1e-4f) {
+ if(alpha_x*alpha_y <= 1e-7f) {
/* some high number for MIS */
*pdf = 1e6f;
*eval = make_float3(1e6f, 1e6f, 1e6f);
@@ -502,10 +580,18 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure
/* see eval function for derivation */
float common = (G1o * D) * 0.25f / cosNO;
- float out = G1i * common;
*pdf = common;
- *eval = make_float3(out, out, out);
+ float3 F = make_float3(1.0f, 1.0f, 1.0f);
+ if (bsdf->extra) {
+ if (bsdf->extra->use_fresnel) {
+ float FH = schlick_fresnel(dot(*omega_in, m));
+
+ F = bsdf->extra->cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; // lerp(sc->custom_color0, make_float3(1.0f, 1.0f, 1.0f), FH);
+ }
+ }
+
+ *eval = G1i * common * F;
}
#ifdef __RAY_DIFFERENTIALS__
@@ -522,7 +608,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure
#ifdef __RAY_DIFFERENTIALS__
float3 dRdx, dRdy, dTdx, dTdy;
#endif
- float m_eta = sc->data2, fresnel;
+ float m_eta = bsdf->ior, fresnel;
bool inside;
fresnel = fresnel_dielectric(m_eta, m, I, &R, &T,
@@ -539,7 +625,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure
*domega_in_dy = dTdy;
#endif
- if(fmaxf(alpha_x, alpha_y) <= 1e-4f || fabsf(m_eta - 1.0f) < 1e-4f) {
+ 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);
@@ -566,10 +652,20 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure
/* see eval function for derivation */
float common = (G1o * D) * (m_eta * m_eta) / (cosNO * Ht2);
- float out = G1i * fabsf(cosHI * cosHO) * common;
+
+ float3 F = make_float3(1.0f, 1.0f, 1.0f);
+ if (bsdf->extra) {
+ if (bsdf->extra->use_fresnel) {
+ float FH = schlick_fresnel(dot(*omega_in, m));
+
+ F = bsdf->extra->cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; // lerp(sc->custom_color0, make_float3(1.0f, 1.0f, 1.0f), FH);
+ }
+ }
+
+ float3 out = G1i * fabsf(cosHI * cosHO) * common * F;
*pdf = cosHO * fabsf(cosHI) * common;
- *eval = make_float3(out, out, out);
+ *eval = out;
}
}
}
@@ -582,47 +678,80 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure
* Microfacet Models for Refraction through Rough Surfaces
* B. Walter, S. R. Marschner, H. Li, K. E. Torrance, EGSR 2007 */
-ccl_device int bsdf_microfacet_beckmann_setup(ShaderClosure *sc)
+ccl_device int bsdf_microfacet_beckmann_setup(MicrofacetBsdf *bsdf)
{
- sc->data0 = saturate(sc->data0); /* alpha_x */
- sc->data1 = sc->data0; /* alpha_y */
+ bsdf->alpha_x = saturate(bsdf->alpha_x);
+ bsdf->alpha_y = bsdf->alpha_x;
- sc->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ID;
+ bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
-ccl_device int bsdf_microfacet_beckmann_aniso_setup(ShaderClosure *sc)
+ccl_device int bsdf_microfacet_beckmann_aniso_setup(MicrofacetBsdf *bsdf)
{
- sc->data0 = saturate(sc->data0); /* alpha_x */
- sc->data1 = saturate(sc->data1); /* alpha_y */
+ bsdf->alpha_x = saturate(bsdf->alpha_x);
+ bsdf->alpha_y = saturate(bsdf->alpha_y);
- sc->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID;
+ bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
-ccl_device int bsdf_microfacet_beckmann_refraction_setup(ShaderClosure *sc)
+ccl_device int bsdf_microfacet_beckmann_refraction_setup(MicrofacetBsdf *bsdf)
{
- sc->data0 = saturate(sc->data0); /* alpha_x */
- sc->data1 = sc->data0; /* alpha_y */
+ bsdf->alpha_x = saturate(bsdf->alpha_x);
+ bsdf->alpha_y = bsdf->alpha_x;
- sc->type = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
+ 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)
{
- sc->data0 = fmaxf(roughness, sc->data0); /* alpha_x */
- sc->data1 = fmaxf(roughness, sc->data1); /* alpha_y */
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf*)sc;
+
+ 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);
+}
+
+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);
}
ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float alpha_x = sc->data0;
- float alpha_y = sc->data1;
- bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
- float3 N = sc->N;
+ 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 || fmaxf(alpha_x, alpha_y) <= 1e-4f)
+ if(m_refractive || alpha_x*alpha_y <= 1e-7f)
return make_float3(0.0f, 0.0f, 0.0f);
float cosNO = dot(N, I);
@@ -646,15 +775,13 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc,
D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4);
/* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */
- float ao = 1 / (alpha_x * safe_sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
- float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
- G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
- G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ 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, sc->T, &X, &Y);
+ make_orthonormals_tangent(Z, bsdf->T, &X, &Y);
/* distribution */
float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m));
@@ -668,24 +795,8 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc,
D = expf(-slope_x*slope_x - slope_y*slope_y) / (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;
-
- 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;
-
- float ao = 1 / (safe_sqrtf(alphaO2 * tanThetaO2));
- float ai = 1 / (safe_sqrtf(alphaI2 * tanThetaI2));
- G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
- G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ 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;
@@ -710,13 +821,14 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc,
ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float alpha_x = sc->data0;
- float alpha_y = sc->data1;
- float m_eta = sc->data2;
- bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
- float3 N = sc->N;
-
- if(!m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f)
+ 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);
@@ -740,10 +852,8 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc
float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4);
/* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */
- float ao = 1 / (alpha_x * safe_sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
- float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
- float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
- float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ float G1o = bsdf_beckmann_G1(alpha_x, cosNO);
+ float G1i = bsdf_beckmann_G1(alpha_x, cosNI);
float G = G1o * G1i;
/* probability */
@@ -763,10 +873,11 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc
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)
{
- float alpha_x = sc->data0;
- float alpha_y = sc->data1;
- bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
- float3 N = sc->N;
+ 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;
float cosNO = dot(N, I);
if(cosNO > 0) {
@@ -775,7 +886,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl
if(alpha_x == alpha_y)
make_orthonormals(Z, &X, &Y);
else
- make_orthonormals_tangent(Z, sc->T, &X, &Y);
+ make_orthonormals_tangent(Z, bsdf->T, &X, &Y);
/* importance sampling with distribution of visible normals. vectors are
* transformed to local space before and after */
@@ -798,7 +909,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl
*omega_in = 2 * cosMO * m - I;
if(dot(Ng, *omega_in) > 0) {
- if(fmaxf(alpha_x, alpha_y) <= 1e-4f) {
+ if(alpha_x*alpha_y <= 1e-7f) {
/* some high number for MIS */
*pdf = 1e6f;
*eval = make_float3(1e6f, 1e6f, 1e6f);
@@ -820,8 +931,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl
float cosNI = dot(N, *omega_in);
/* eq. 26, 27: now calculate G1(i,m) */
- float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
- G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ G1i = bsdf_beckmann_G1(alpha_x, cosNI);
}
else {
/* anisotropic distribution */
@@ -836,16 +946,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl
D = expf(-slope_x*slope_x - slope_y*slope_y) / (M_PI_F * alpha2 * cosThetaM4);
/* 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;
-
- float ai = 1 / (safe_sqrtf(alphaI2 * tanThetaI2));
- G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ 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;
@@ -872,7 +973,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl
#ifdef __RAY_DIFFERENTIALS__
float3 dRdx, dRdy, dTdx, dTdy;
#endif
- float m_eta = sc->data2, fresnel;
+ float m_eta = bsdf->ior, fresnel;
bool inside;
fresnel = fresnel_dielectric(m_eta, m, I, &R, &T,
@@ -889,7 +990,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl
*domega_in_dy = dTdy;
#endif
- if(fmaxf(alpha_x, alpha_y) <= 1e-4f || fabsf(m_eta - 1.0f) < 1e-4f) {
+ 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);
@@ -906,8 +1007,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl
float cosNI = dot(N, *omega_in);
/* eq. 26, 27: now calculate G1(i,m) */
- float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
- float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ float G1i = bsdf_beckmann_G1(alpha_x, cosNI);
float G = G1o * G1i;
/* eq. 21 */
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
new file mode 100644
index 00000000000..38c645cba87
--- /dev/null
+++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
@@ -0,0 +1,507 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Most of the code is based on the supplemental implementations from https://eheitzresearch.wordpress.com/240-2/. */
+
+/* === GGX Microfacet distribution functions === */
+
+/* Isotropic GGX microfacet distribution */
+ccl_device_inline 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);
+}
+
+/* Anisotropic GGX microfacet distribution */
+ccl_device_inline 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;
+
+ 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_inline float2 mf_sampleP22_11(const float cosI, const float2 randU)
+{
+ if(cosI > 0.9999f || cosI < 1e-6f) {
+ const float r = sqrtf(randU.x / (1.0f - randU.x));
+ const float phi = M_2PI_F * randU.y;
+ return make_float2(r*cosf(phi), r*sinf(phi));
+ }
+
+ const float sinI = 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*randU.x*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(randU.y >= 0.5f)
+ U2 = 2.0f*(randU.y - 0.5f);
+ else
+ U2 = 2.0f*(0.5f - randU.y);
+ 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(randU.y >= 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_inline float3 mf_sample_vndf(const float3 wi, const float2 alpha, const float2 randU)
+{
+ 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, randU);
+
+ const float2 cossin_phi = normalize(make_float2(wi_11.x, wi_11.y));
+ 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));
+}
+
+/* === Phase functions: Glossy, Diffuse and Glass === */
+
+/* Phase function for reflective materials, either without a fresnel term (for compatibility) or with the conductive fresnel term. */
+ccl_device_inline float3 mf_sample_phase_glossy(const float3 wi, float3 *n, float3 *k, float3 *weight, const float3 wm)
+{
+ if(n && k)
+ *weight *= fresnel_conductor(dot(wi, wm), *n, *k);
+
+ return -wi + 2.0f * wm * dot(wi, wm);
+}
+
+ccl_device_inline float3 mf_eval_phase_glossy(const float3 w, const float lambda, const float3 wo, const float2 alpha, float3 *n, float3 *k)
+{
+ 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);
+
+ 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);
+
+ 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);
+
+ if(n && k) {
+ /* Apply conductive fresnel term. */
+ return phase * fresnel_conductor(dotW_WH, *n, *k);
+ }
+
+ return make_float3(phase, phase, phase);
+}
+
+/* Phase function for rough lambertian diffuse surfaces. */
+ccl_device_inline float3 mf_sample_phase_diffuse(const float3 wm, const float randu, const float randv)
+{
+ float3 tm, bm;
+ make_orthonormals(wm, &tm, &bm);
+
+ float2 disk = concentric_sample_disk(randu, randv);
+ return disk.x*tm + disk.y*bm + safe_sqrtf(1.0f - disk.x*disk.x - disk.y*disk.y)*wm;
+}
+
+ccl_device_inline float3 mf_eval_phase_diffuse(const float3 w, const float3 wm)
+{
+ const float v = max(0.0f, dot(w, wm)) * M_1_PI_F;
+ return make_float3(v, v, v);
+}
+
+/* Phase function for dielectric transmissive materials, including both reflection and refraction according to the dielectric fresnel term. */
+ccl_device_inline 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_inline 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 === */
+
+/* Smith Lambda function for GGX (based on page 12 of the supplemental implementation). */
+ccl_device_inline 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;
+
+ 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);
+}
+
+/* Height distribution CDF (based on page 4 of the supplemental implementation). */
+ccl_device_inline float mf_invC1(const float h)
+{
+ return 2.0f * saturate(h) - 1.0f;
+}
+
+ccl_device_inline float mf_C1(const float h)
+{
+ return saturate(0.5f * (h + 1.0f));
+}
+
+/* Masking function (based on page 16 of the supplemental implementation). */
+ccl_device_inline 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);
+}
+
+/* Sampling from the visible height distribution (based on page 17 of the supplemental implementation). */
+ccl_device_inline 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. ===
+ * As explained in bsdf_microfacet_multi_impl.h, using approximations with MIS still produces an unbiased result. */
+
+/* Approximation for the albedo of the single-scattering GGX distribution,
+ * the missing energy is then approximated as a diffuse reflection for the PDF. */
+ccl_device_inline 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);
+}
+
+ccl_device_inline 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 albedo = mf_ggx_albedo(alpha);
+ return 0.25f * D / max((1.0f + lambda) * wi.z, 1e-7f) + (1.0f - albedo) * wo.z;
+}
+
+ccl_device_inline float mf_ggx_aniso_pdf(const float3 wi, const float3 wo, const float2 alpha)
+{
+ return 0.25f * D_ggx_aniso(normalize(wi+wo), alpha) / ((1.0f + mf_lambda(wi, alpha)) * wi.z) + (1.0f - mf_ggx_albedo(sqrtf(alpha.x*alpha.y))) * wo.z;
+}
+
+ccl_device_inline float mf_diffuse_pdf(const float3 wo)
+{
+ return M_1_PI_F * wo.z;
+}
+
+ccl_device_inline float mf_glass_pdf(const float3 wi, const float3 wo, const float alpha, const float eta)
+{
+ float3 wh;
+ float fresnel;
+ if(wi.z*wo.z > 0.0f) {
+ wh = normalize(wi + wo);
+ fresnel = fresnel_dielectric_cos(dot(wi, wh), eta);
+ }
+ else {
+ wh = normalize(wi + wo*eta);
+ fresnel = 1.0f - fresnel_dielectric_cos(dot(wi, wh), eta);
+ }
+ if(wh.z < 0.0f)
+ wh = -wh;
+ float3 r_wi = (wi.z < 0.0f)? -wi: wi;
+ return fresnel * max(0.0f, dot(r_wi, wh)) * D_ggx(wh, alpha) / ((1.0f + mf_lambda(r_wi, make_float2(alpha, alpha))) * r_wi.z) + fabsf(wo.z);
+}
+
+/* === 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_FUNCTION_FULL_NAME(prefix) MF_NAME_EVAL(prefix, MF_PHASE_FUNCTION)
+
+#define MF_PHASE_FUNCTION glass
+#define MF_MULTI_GLASS
+#include "bsdf_microfacet_multi_impl.h"
+
+/* The diffuse phase function is not implemented as a node yet. */
+#if 0
+#define MF_PHASE_FUNCTION diffuse
+#define MF_MULTI_DIFFUSE
+#include "bsdf_microfacet_multi_impl.h"
+#endif
+
+#define MF_PHASE_FUNCTION glossy
+#define MF_MULTI_GLOSSY
+#include "bsdf_microfacet_multi_impl.h"
+
+ccl_device void bsdf_microfacet_multi_ggx_blur(ShaderClosure *sc, float roughness)
+{
+ MicrofacetBsdf *bsdf = (MicrofacetBsdf*)sc;
+
+ bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x);
+ bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y);
+}
+
+/* === Closure implementations === */
+
+/* Multiscattering GGX Glossy closure */
+
+ccl_device int bsdf_microfacet_multi_ggx_common_setup(MicrofacetBsdf *bsdf, bool use_fresnel = false)
+{
+ 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->use_fresnel = use_fresnel;
+ 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_ID;
+
+ return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG;
+}
+
+ccl_device int bsdf_microfacet_multi_ggx_aniso_setup(MicrofacetBsdf *bsdf, bool use_fresnel = false)
+{
+ if(is_zero(bsdf->T))
+ bsdf->T = make_float3(1.0f, 0.0f, 0.0f);
+
+ return bsdf_microfacet_multi_ggx_common_setup(bsdf, use_fresnel);
+}
+
+ccl_device int bsdf_microfacet_multi_ggx_setup(MicrofacetBsdf *bsdf, bool use_fresnel = false)
+{
+ bsdf->alpha_y = bsdf->alpha_x;
+
+ return bsdf_microfacet_multi_ggx_common_setup(bsdf, use_fresnel);
+}
+
+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 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;
+ 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, NULL, NULL);
+}
+
+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;
+ 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;
+
+ *eval = mf_sample_glossy(localI, &localO, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, NULL, NULL);
+ 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;
+#endif
+ return LABEL_REFLECT|LABEL_GLOSSY;
+}
+
+/* Multiscattering GGX Glass closure */
+
+ccl_device int bsdf_microfacet_multi_ggx_glass_setup(MicrofacetBsdf *bsdf, bool use_fresnel = false)
+{
+ 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->use_fresnel = use_fresnel;
+ 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_ID;
+
+ 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;
+ 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);
+}
+
+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;
+ 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);
+}
+
+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;
+ 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;
+
+ *eval = mf_sample_glass(localI, &localO, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior);
+ *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;
+#endif
+ 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;
+#endif
+
+ 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
new file mode 100644
index 00000000000..afd4a8da62a
--- /dev/null
+++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Evaluate the BSDF from wi to wo.
+ * Evaluation is split into the analytical single-scattering BSDF and the multi-scattering BSDF,
+ * which is evaluated stochastically through a random walk. At each bounce (except for the first one),
+ * the amount of reflection from here towards wo is evaluated before bouncing again.
+ *
+ * Because of the random walk, the evaluation is not deterministic, but its expected value is equal to
+ * the correct BSDF, which is enough for Monte-Carlo rendering. The PDF also can't be determined
+ * analytically, so the single-scattering PDF plus a diffuse term to account for the multi-scattered
+ * 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 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
+#ifdef MF_MULTI_GLASS
+ , const float eta
+#elif defined(MF_MULTI_GLOSSY)
+ , float3 *n, float3 *k
+#endif
+)
+{
+ /* 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
+#endif
+ 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);
+
+ 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);
+
+ /* Analytically compute single scattering for lower noise. */
+ float3 eval;
+#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);
+#elif defined(MF_MULTI_DIFFUSE)
+ /* Diffuse has no special closed form for the single scattering bounce */
+ eval = make_float3(0.0f, 0.0f, 0.0f);
+#else /* MF_MULTI_GLOSSY */
+ const float3 wh = normalize(wi+wo);
+ 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);
+ if(n && k) {
+ eval = fresnel_conductor(dot(wh, wi), *n, *k) * val;
+ }
+ else {
+ eval = make_float3(val, val, val);
+ }
+#endif
+
+ float3 wr = -wi;
+ 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);
+
+ for(int order = 0; order < 10; order++) {
+ /* Sample microfacet height and normal */
+ if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, lcg_step_float_addrspace(lcg_state)))
+ break;
+ float3 wm = mf_sample_vndf(-wr, alpha, make_float2(lcg_step_float_addrspace(lcg_state),
+ lcg_step_float_addrspace(lcg_state)));
+
+#ifdef MF_MULTI_DIFFUSE
+ if(order == 0) {
+ /* Compute single-scattering for diffuse. */
+ const float G2_G1 = -lambda_r / (shadowing_lambda - lambda_r);
+ eval += throughput * G2_G1 * mf_eval_phase_diffuse(wo, wm);
+ }
+#endif
+ 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);
+#elif defined(MF_MULTI_DIFFUSE)
+ phase = mf_eval_phase_diffuse(wo, wm);
+#else /* MF_MULTI_GLOSSY */
+ phase = mf_eval_phase_glossy(wr, lambda_r, wo, alpha, n, k) * 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. */
+#ifdef MF_MULTI_GLASS
+ bool next_outside;
+ wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float_addrspace(lcg_state), &next_outside);
+ if(!next_outside) {
+ outside = !outside;
+ wr = -wr;
+ hr = -hr;
+ }
+#elif defined(MF_MULTI_DIFFUSE)
+ wr = mf_sample_phase_diffuse(wm,
+ lcg_step_float_addrspace(lcg_state),
+ lcg_step_float_addrspace(lcg_state));
+#else /* MF_MULTI_GLOSSY */
+ wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm);
+#endif
+
+ lambda_r = mf_lambda(wr, alpha);
+
+ throughput *= color;
+
+ C1_r = mf_C1(hr);
+ G1_r = mf_G1(wr, C1_r, lambda_r);
+ }
+ }
+
+ 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 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
+#ifdef MF_MULTI_GLASS
+ , const float eta
+#elif defined(MF_MULTI_GLOSSY)
+ , float3 *n, float3 *k
+#endif
+)
+{
+ 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;
+
+ int order;
+ for(order = 0; order < 10; order++) {
+ /* Sample microfacet height. */
+ if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, lcg_step_float_addrspace(lcg_state))) {
+ /* The random walk has left the surface. */
+ *wo = outside? wr: -wr;
+ return throughput;
+ }
+ /* Sample microfacet normal. */
+ float3 wm = mf_sample_vndf(-wr, alpha, make_float2(lcg_step_float_addrspace(lcg_state),
+ lcg_step_float_addrspace(lcg_state)));
+
+ /* First-bounce color is already accounted for in mix weight. */
+ if(order > 0)
+ throughput *= color;
+
+ /* Bounce from the microfacet. */
+#ifdef MF_MULTI_GLASS
+ bool next_outside;
+ wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float_addrspace(lcg_state), &next_outside);
+ if(!next_outside) {
+ hr = -hr;
+ wr = -wr;
+ outside = !outside;
+ }
+#elif defined(MF_MULTI_DIFFUSE)
+ wr = mf_sample_phase_diffuse(wm,
+ lcg_step_float_addrspace(lcg_state),
+ lcg_step_float_addrspace(lcg_state));
+#else /* MF_MULTI_GLOSSY */
+ wr = mf_sample_phase_glossy(-wr, n, k, &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);
+}
+
+#undef MF_MULTI_GLASS
+#undef MF_MULTI_DIFFUSE
+#undef MF_MULTI_GLOSSY
+#undef MF_PHASE_FUNCTION
diff --git a/intern/cycles/kernel/closure/bsdf_oren_nayar.h b/intern/cycles/kernel/closure/bsdf_oren_nayar.h
index 61b7cb11b02..cb342a026ef 100644
--- a/intern/cycles/kernel/closure/bsdf_oren_nayar.h
+++ b/intern/cycles/kernel/closure/bsdf_oren_nayar.h
@@ -19,39 +19,59 @@
CCL_NAMESPACE_BEGIN
+typedef ccl_addr_space struct OrenNayarBsdf {
+ SHADER_CLOSURE_BASE;
+
+ float3 N;
+ float roughness;
+ float a;
+ float b;
+} OrenNayarBsdf;
+
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 * (sc->data0 + sc->data1 * t);
+ float is = nl * (bsdf->a + bsdf->b * t);
return make_float3(is, is, is);
}
-ccl_device int bsdf_oren_nayar_setup(ShaderClosure *sc)
+ccl_device int bsdf_oren_nayar_setup(OrenNayarBsdf *bsdf)
{
- float sigma = sc->data0;
+ float sigma = bsdf->roughness;
- sc->type = CLOSURE_BSDF_OREN_NAYAR_ID;
+ bsdf->type = CLOSURE_BSDF_OREN_NAYAR_ID;
sigma = saturate(sigma);
float div = 1.0f / (M_PI_F + ((3.0f * M_PI_F - 4.0f) / 6.0f) * sigma);
- sc->data0 = 1.0f * div;
- sc->data1 = sigma * div;
+ bsdf->a = 1.0f * div;
+ bsdf->b = sigma * div;
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;
+
+ 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)
{
- if(dot(sc->N, omega_in) > 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, sc->N, I, omega_in);
+ return bsdf_oren_nayar_get_intensity(sc, bsdf->N, I, omega_in);
}
else {
*pdf = 0.0f;
@@ -66,15 +86,16 @@ ccl_device float3 bsdf_oren_nayar_eval_transmit(const ShaderClosure *sc, const f
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)
{
- sample_uniform_hemisphere(sc->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, sc->N, I, *omega_in);
+ *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(sc->N, dIdx)) * sc->N - dIdx;
- *domega_in_dy = (2.0f * dot(sc->N, dIdy)) * sc->N - dIdy;
+ *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 {
diff --git a/intern/cycles/kernel/closure/bsdf_phong_ramp.h b/intern/cycles/kernel/closure/bsdf_phong_ramp.h
index 1ab15eee954..e152a8780db 100644
--- a/intern/cycles/kernel/closure/bsdf_phong_ramp.h
+++ b/intern/cycles/kernel/closure/bsdf_phong_ramp.h
@@ -35,7 +35,17 @@
CCL_NAMESPACE_BEGIN
-ccl_device float3 bsdf_phong_ramp_get_color(const ShaderClosure *sc, const float3 colors[8], float pos)
+#ifdef __OSL__
+
+typedef ccl_addr_space struct PhongRampBsdf {
+ SHADER_CLOSURE_BASE;
+
+ float3 N;
+ float exponent;
+ float3 *colors;
+} PhongRampBsdf;
+
+ccl_device float3 bsdf_phong_ramp_get_color(const float3 colors[8], float pos)
{
int MAXCOLORS = 8;
@@ -49,57 +59,54 @@ ccl_device float3 bsdf_phong_ramp_get_color(const ShaderClosure *sc, const float
return colors[ipos] * (1.0f - offset) + colors[ipos+1] * offset;
}
-ccl_device int bsdf_phong_ramp_setup(ShaderClosure *sc)
+ccl_device int bsdf_phong_ramp_setup(PhongRampBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_PHONG_RAMP_ID;
- sc->data0 = max(sc->data0, 0.0f);
- sc->data1 = 0.0f;
+ bsdf->type = CLOSURE_BSDF_PHONG_RAMP_ID;
+ bsdf->exponent = max(bsdf->exponent, 0.0f);
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
-ccl_device void bsdf_phong_ramp_blur(ShaderClosure *sc, float roughness)
-{
-}
-
-ccl_device float3 bsdf_phong_ramp_eval_reflect(const ShaderClosure *sc, const float3 colors[8], 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)
{
- float m_exponent = sc->data0;
- float cosNI = dot(sc->N, omega_in);
- float cosNO = dot(sc->N, I);
+ 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) * sc->N - I;
+ 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(sc, colors, cosp) * out;
+ 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 colors[8], 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);
}
-ccl_device int bsdf_phong_ramp_sample(const ShaderClosure *sc, const float3 colors[8], 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)
{
- float cosNO = dot(sc->N, I);
- float m_exponent = sc->data0;
+ 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) * sc->N - I;
+ float3 R = (2 * cosNO) * bsdf->N - I;
#ifdef __RAY_DIFFERENTIALS__
- *domega_in_dx = (2 * dot(sc->N, dIdx)) * sc->N - dIdx;
- *domega_in_dy = (2 * dot(sc->N, dIdy)) * sc->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
float3 T, B;
@@ -114,7 +121,7 @@ ccl_device int bsdf_phong_ramp_sample(const ShaderClosure *sc, const float3 colo
if(dot(Ng, *omega_in) > 0.0f)
{
// common terms for pdf and eval
- float cosNI = dot(sc->N, *omega_in);
+ float cosNI = dot(bsdf->N, *omega_in);
// make sure the direction we chose is still in the right hemisphere
if(cosNI > 0)
{
@@ -122,13 +129,14 @@ ccl_device int bsdf_phong_ramp_sample(const ShaderClosure *sc, const float3 colo
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(sc, colors, cosp) * out;
+ *eval = bsdf_phong_ramp_get_color(bsdf->colors, cosp) * out;
}
}
}
return LABEL_REFLECT|LABEL_GLOSSY;
}
+#endif /* __OSL__ */
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/closure/bsdf_reflection.h b/intern/cycles/kernel/closure/bsdf_reflection.h
index 303f4c9ce34..1d21614ecee 100644
--- a/intern/cycles/kernel/closure/bsdf_reflection.h
+++ b/intern/cycles/kernel/closure/bsdf_reflection.h
@@ -37,9 +37,9 @@ CCL_NAMESPACE_BEGIN
/* REFLECTION */
-ccl_device int bsdf_reflection_setup(ShaderClosure *sc)
+ccl_device int bsdf_reflection_setup(MicrofacetBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_REFLECTION_ID;
+ bsdf->type = CLOSURE_BSDF_REFLECTION_ID;
return SD_BSDF;
}
@@ -55,7 +55,8 @@ ccl_device float3 bsdf_reflection_eval_transmit(const ShaderClosure *sc, const f
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)
{
- float3 N = sc->N;
+ const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+ float3 N = bsdf->N;
// only one direction is possible
float cosNO = dot(N, I);
diff --git a/intern/cycles/kernel/closure/bsdf_refraction.h b/intern/cycles/kernel/closure/bsdf_refraction.h
index c78a4b67134..050a4e76fa9 100644
--- a/intern/cycles/kernel/closure/bsdf_refraction.h
+++ b/intern/cycles/kernel/closure/bsdf_refraction.h
@@ -37,9 +37,9 @@ CCL_NAMESPACE_BEGIN
/* REFRACTION */
-ccl_device int bsdf_refraction_setup(ShaderClosure *sc)
+ccl_device int bsdf_refraction_setup(MicrofacetBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_REFRACTION_ID;
+ bsdf->type = CLOSURE_BSDF_REFRACTION_ID;
return SD_BSDF;
}
@@ -55,8 +55,9 @@ ccl_device float3 bsdf_refraction_eval_transmit(const ShaderClosure *sc, const f
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)
{
- float m_eta = sc->data0;
- float3 N = sc->N;
+ const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+ float m_eta = bsdf->ior;
+ float3 N = bsdf->N;
float3 R, T;
#ifdef __RAY_DIFFERENTIALS__
diff --git a/intern/cycles/kernel/closure/bsdf_toon.h b/intern/cycles/kernel/closure/bsdf_toon.h
index e5b6ab93a64..28e775bcbc8 100644
--- a/intern/cycles/kernel/closure/bsdf_toon.h
+++ b/intern/cycles/kernel/closure/bsdf_toon.h
@@ -35,17 +35,35 @@
CCL_NAMESPACE_BEGIN
+typedef ccl_addr_space struct ToonBsdf {
+ SHADER_CLOSURE_BASE;
+
+ float3 N;
+ float size;
+ float smooth;
+} ToonBsdf;
+
/* DIFFUSE TOON */
-ccl_device int bsdf_diffuse_toon_setup(ShaderClosure *sc)
+ccl_device int bsdf_diffuse_toon_setup(ToonBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_DIFFUSE_TOON_ID;
- sc->data0 = saturate(sc->data0);
- sc->data1 = saturate(sc->data1);
+ bsdf->type = CLOSURE_BSDF_DIFFUSE_TOON_ID;
+ bsdf->size = saturate(bsdf->size);
+ bsdf->smooth = saturate(bsdf->smooth);
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;
+
+ 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;
@@ -67,9 +85,10 @@ ccl_device float bsdf_toon_get_sample_angle(float max_angle, float smooth)
ccl_device float3 bsdf_diffuse_toon_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
- float max_angle = sc->data0*M_PI_2_F;
- float smooth = sc->data1*M_PI_2_F;
- float angle = safe_acosf(fmaxf(dot(sc->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);
@@ -90,21 +109,22 @@ ccl_device float3 bsdf_diffuse_toon_eval_transmit(const ShaderClosure *sc, const
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)
{
- float max_angle = sc->data0*M_PI_2_F;
- float smooth = sc->data1*M_PI_2_F;
+ 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(sc->N, sample_angle, randu, randv, omega_in, pdf);
+ 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);
#ifdef __RAY_DIFFERENTIALS__
// TODO: find a better approximation for the bounce
- *domega_in_dx = (2.0f * dot(sc->N, dIdx)) * sc->N - dIdx;
- *domega_in_dy = (2.0f * dot(sc->N, dIdy)) * sc->N - dIdy;
+ *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
@@ -117,25 +137,26 @@ ccl_device int bsdf_diffuse_toon_sample(const ShaderClosure *sc, float3 Ng, floa
/* GLOSSY TOON */
-ccl_device int bsdf_glossy_toon_setup(ShaderClosure *sc)
+ccl_device int bsdf_glossy_toon_setup(ToonBsdf *bsdf)
{
- sc->type = CLOSURE_BSDF_GLOSSY_TOON_ID;
- sc->data0 = saturate(sc->data0);
- sc->data1 = saturate(sc->data1);
+ bsdf->type = CLOSURE_BSDF_GLOSSY_TOON_ID;
+ bsdf->size = saturate(bsdf->size);
+ bsdf->smooth = saturate(bsdf->smooth);
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)
{
- float max_angle = sc->data0*M_PI_2_F;
- float smooth = sc->data1*M_PI_2_F;
- float cosNI = dot(sc->N, omega_in);
- float cosNO = dot(sc->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) * sc->N - I;
+ float3 R = (2 * cosNO) * bsdf->N - I;
float cosRI = dot(R, omega_in);
float angle = safe_acosf(fmaxf(cosRI, 0.0f));
@@ -157,13 +178,14 @@ ccl_device float3 bsdf_glossy_toon_eval_transmit(const ShaderClosure *sc, const
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)
{
- float max_angle = sc->data0*M_PI_2_F;
- float smooth = sc->data1*M_PI_2_F;
- float cosNO = dot(sc->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) * sc->N - I;
+ float3 R = (2 * cosNO) * bsdf->N - I;
float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth);
float angle = sample_angle*randu;
@@ -171,15 +193,15 @@ ccl_device int bsdf_glossy_toon_sample(const ShaderClosure *sc, float3 Ng, float
sample_uniform_cone(R, sample_angle, randu, randv, omega_in, pdf);
if(dot(Ng, *omega_in) > 0.0f) {
- float cosNI = dot(sc->N, *omega_in);
+ 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);
#ifdef __RAY_DIFFERENTIALS__
- *domega_in_dx = (2 * dot(sc->N, dIdx)) * sc->N - dIdx;
- *domega_in_dy = (2 * dot(sc->N, dIdy)) * sc->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
diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h
index f99e0c3dca7..397d642c35a 100644
--- a/intern/cycles/kernel/closure/bsdf_util.h
+++ b/intern/cycles/kernel/closure/bsdf_util.h
@@ -80,7 +80,7 @@ ccl_device float fresnel_dielectric(
return 1; // total internal reflection
}
else {
- float dnp = sqrtf(arg);
+ float dnp = max(sqrtf(arg), 1e-7f);
float nK = (neta * cos)- dnp;
*T = -(neta * I)+(nK * Nn);
#ifdef __RAY_DIFFERENTIALS__
@@ -111,10 +111,9 @@ ccl_device float fresnel_dielectric_cos(float cosi, float eta)
return 1.0f; // TIR(no refracted component)
}
-#if 0
ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k)
{
- float3 cosi2 = make_float3(cosi*cosi);
+ 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;
@@ -124,7 +123,6 @@ ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k
(tmp_f + (2.0f * eta * cosi) + cosi2);
return(Rparl2 + Rperp2) * 0.5f;
}
-#endif
ccl_device float schlick_fresnel(float u)
{
diff --git a/intern/cycles/kernel/closure/bssrdf.h b/intern/cycles/kernel/closure/bssrdf.h
index a1920841e6e..e31d790dd84 100644
--- a/intern/cycles/kernel/closure/bssrdf.h
+++ b/intern/cycles/kernel/closure/bssrdf.h
@@ -19,6 +19,19 @@
CCL_NAMESPACE_BEGIN
+typedef ccl_addr_space struct Bssrdf {
+ SHADER_CLOSURE_BASE;
+
+ float radius;
+ float sharpness;
+ float d;
+ float texture_blur;
+ float albedo;
+ float roughness;
+ float3 N;
+ float3 baseColor;
+} Bssrdf;
+
/* Planar Truncated Gaussian
*
* Note how this is different from the typical gaussian, this one integrates
@@ -28,11 +41,12 @@ CCL_NAMESPACE_BEGIN
/* paper suggests 1/12.46 which is much too small, suspect it's *12.46 */
#define GAUSS_TRUNCATE 12.46f
-ccl_device float bssrdf_gaussian_eval(ShaderClosure *sc, float r)
+ccl_device float bssrdf_gaussian_eval(const ShaderClosure *sc, 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 = sc->data0*sc->data0*(0.25f*0.25f);
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
+ const float v = bssrdf->radius*bssrdf->radius*(0.25f*0.25f);
const float Rm = sqrtf(v*GAUSS_TRUNCATE);
if(r >= Rm)
@@ -41,7 +55,7 @@ ccl_device float bssrdf_gaussian_eval(ShaderClosure *sc, float r)
return expf(-r*r/(2.0f*v))/(2.0f*M_PI_F*v);
}
-ccl_device float bssrdf_gaussian_pdf(ShaderClosure *sc, float r)
+ccl_device float bssrdf_gaussian_pdf(const ShaderClosure *sc, float r)
{
/* 1.0 - expf(-Rm*Rm/(2*v)) simplified */
const float area_truncated = 1.0f - expf(-0.5f*GAUSS_TRUNCATE);
@@ -49,12 +63,12 @@ ccl_device float bssrdf_gaussian_pdf(ShaderClosure *sc, float r)
return bssrdf_gaussian_eval(sc, r) * (1.0f/(area_truncated));
}
-ccl_device void bssrdf_gaussian_sample(ShaderClosure *sc, float xi, float *r, float *h)
+ccl_device void bssrdf_gaussian_sample(const ShaderClosure *sc, 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 = sc->data0*sc->data0*(0.25f*0.25f);
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
+ const float v = bssrdf->radius*bssrdf->radius*(0.25f*0.25f);
const float Rm = sqrtf(v*GAUSS_TRUNCATE);
/* 1.0 - expf(-Rm*Rm/(2*v)) simplified */
@@ -75,12 +89,13 @@ ccl_device void bssrdf_gaussian_sample(ShaderClosure *sc, float xi, float *r, fl
* far as I can tell has no closed form solution. So we get an iterative solution
* instead with newton-raphson. */
-ccl_device float bssrdf_cubic_eval(ShaderClosure *sc, float r)
+ccl_device float bssrdf_cubic_eval(const ShaderClosure *sc, float r)
{
- const float sharpness = sc->T.x;
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
+ const float sharpness = bssrdf->sharpness;
if(sharpness == 0.0f) {
- const float Rm = sc->data0;
+ const float Rm = bssrdf->radius;
if(r >= Rm)
return 0.0f;
@@ -94,7 +109,7 @@ ccl_device float bssrdf_cubic_eval(ShaderClosure *sc, float r)
}
else {
- float Rm = sc->data0*(1.0f + sharpness);
+ float Rm = bssrdf->radius*(1.0f + sharpness);
if(r >= Rm)
return 0.0f;
@@ -122,7 +137,7 @@ ccl_device float bssrdf_cubic_eval(ShaderClosure *sc, float r)
}
}
-ccl_device float bssrdf_cubic_pdf(ShaderClosure *sc, float r)
+ccl_device float bssrdf_cubic_pdf(const ShaderClosure *sc, float r)
{
return bssrdf_cubic_eval(sc, r);
}
@@ -155,12 +170,13 @@ ccl_device float bssrdf_cubic_quintic_root_find(float xi)
return x;
}
-ccl_device void bssrdf_cubic_sample(ShaderClosure *sc, float xi, float *r, float *h)
+ccl_device void bssrdf_cubic_sample(const ShaderClosure *sc, float xi, float *r, float *h)
{
- float Rm = sc->data0;
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
+ const float sharpness = bssrdf->sharpness;
+ float Rm = bssrdf->radius;
float r_ = bssrdf_cubic_quintic_root_find(xi);
- const float sharpness = sc->T.x;
if(sharpness != 0.0f) {
r_ = powf(r_, 1.0f + sharpness);
Rm *= (1.0f + sharpness);
@@ -198,21 +214,22 @@ ccl_device_inline float bssrdf_burley_compatible_mfp(float r)
return 0.25f * M_1_PI_F * r;
}
-ccl_device void bssrdf_burley_setup(ShaderClosure *sc)
+ccl_device void bssrdf_burley_setup(Bssrdf *bssrdf)
{
/* Mean free path length. */
- const float l = bssrdf_burley_compatible_mfp(sc->data0);
+ const float l = bssrdf_burley_compatible_mfp(bssrdf->radius);
/* Surface albedo. */
- const float A = sc->data2;
+ const float A = bssrdf->albedo;
const float s = bssrdf_burley_fitting(A);
const float d = l / s;
- sc->custom1 = d;
+ bssrdf->d = d;
}
-ccl_device float bssrdf_burley_eval(ShaderClosure *sc, float r)
+ccl_device float bssrdf_burley_eval(const ShaderClosure *sc, float r)
{
- const float d = sc->custom1;
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
+ const float d = bssrdf->d;
const float Rm = BURLEY_TRUNCATE * d;
if(r >= Rm)
@@ -231,7 +248,7 @@ ccl_device float bssrdf_burley_eval(ShaderClosure *sc, float r)
return (exp_r_d + exp_r_3_d) / (4.0f*d);
}
-ccl_device float bssrdf_burley_pdf(ShaderClosure *sc, float r)
+ccl_device float bssrdf_burley_pdf(const ShaderClosure *sc, float r)
{
return bssrdf_burley_eval(sc, r) * (1.0f/BURLEY_TRUNCATE_CDF);
}
@@ -276,12 +293,13 @@ ccl_device float bssrdf_burley_root_find(float xi)
return r;
}
-ccl_device void bssrdf_burley_sample(ShaderClosure *sc,
+ccl_device void bssrdf_burley_sample(const ShaderClosure *sc,
float xi,
float *r,
float *h)
{
- const float d = sc->custom1;
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
+ const float d = bssrdf->d;
const float Rm = BURLEY_TRUNCATE * d;
const float r_ = bssrdf_burley_root_find(xi * BURLEY_TRUNCATE_CDF) * d;
@@ -295,26 +313,29 @@ ccl_device void bssrdf_burley_sample(ShaderClosure *sc,
*
* Samples distributed over disk with no falloff, for reference. */
-ccl_device float bssrdf_none_eval(ShaderClosure *sc, float r)
+ccl_device float bssrdf_none_eval(const ShaderClosure *sc, float r)
{
- const float Rm = sc->data0;
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
+ const float Rm = bssrdf->radius;
return (r < Rm)? 1.0f: 0.0f;
}
-ccl_device float bssrdf_none_pdf(ShaderClosure *sc, float r)
+ccl_device float bssrdf_none_pdf(const ShaderClosure *sc, float r)
{
/* integrate (2*pi*r)/(pi*Rm*Rm) from 0 to Rm = 1 */
- const float Rm = sc->data0;
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
+ const float Rm = bssrdf->radius;
const float area = (M_PI_F*Rm*Rm);
return bssrdf_none_eval(sc, r) / area;
}
-ccl_device void bssrdf_none_sample(ShaderClosure *sc, float xi, float *r, float *h)
+ccl_device void bssrdf_none_sample(const ShaderClosure *sc, 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 = sc->data0;
+ const Bssrdf *bssrdf = (const Bssrdf*)sc;
+ const float Rm = bssrdf->radius;
const float r_ = sqrtf(xi)*Rm;
*r = r_;
@@ -325,40 +346,54 @@ ccl_device void bssrdf_none_sample(ShaderClosure *sc, float xi, float *r, float
/* Generic */
-ccl_device int bssrdf_setup(ShaderClosure *sc, ClosureType type)
+ccl_device_inline Bssrdf *bssrdf_alloc(ShaderData *sd, float3 weight)
+{
+ Bssrdf *bssrdf = (Bssrdf*)closure_alloc(sd, sizeof(Bssrdf), CLOSURE_NONE_ID, weight);
+
+ if(!bssrdf)
+ return 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(Bssrdf *bssrdf, ClosureType type)
{
- if(sc->data0 < BSSRDF_MIN_RADIUS) {
+ if(bssrdf->radius < BSSRDF_MIN_RADIUS) {
/* revert to diffuse BSDF if radius too small */
int flag;
if (type == CLOSURE_BSSRDF_DISNEY_ID) {
- sc->data0 = sc->data3;
- sc->data1 = 0.0f;
- flag = bsdf_disney_diffuse_setup(sc);
- sc->type = CLOSURE_BSDF_BSSRDF_DISNEY_ID;
+ DisneyDiffuseBsdf *bsdf = (DisneyDiffuseBsdf*)bssrdf;
+ bsdf->N = bssrdf->N;
+ bsdf->roughness = bssrdf->roughness;
+ bsdf->baseColor = bssrdf->baseColor;
+ flag = bsdf_disney_diffuse_setup(bsdf);
+ bsdf->type = CLOSURE_BSDF_BSSRDF_DISNEY_ID;
}
else {
- sc->data0 = 0.0f;
- sc->data1 = 0.0f;
- flag = bsdf_diffuse_setup(sc);
- sc->type = CLOSURE_BSDF_BSSRDF_ID;
+ DiffuseBsdf *bsdf = (DiffuseBsdf*)bssrdf;
+ bsdf->N = bssrdf->N;
+ flag = bsdf_diffuse_setup(bsdf);
+ bsdf->type = CLOSURE_BSDF_BSSRDF_ID;
}
return flag;
}
else {
- sc->data1 = saturate(sc->data1); /* texture blur */
- sc->T.x = saturate(sc->T.x); /* sharpness */
- sc->type = type;
+ bssrdf->texture_blur = saturate(bssrdf->texture_blur);
+ bssrdf->sharpness = saturate(bssrdf->sharpness);
+ bssrdf->type = type;
if (type == CLOSURE_BSSRDF_BURLEY_ID || type == CLOSURE_BSSRDF_DISNEY_ID) {
- bssrdf_burley_setup(sc);
+ bssrdf_burley_setup(bssrdf);
}
return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSSRDF;
}
}
-ccl_device void bssrdf_sample(ShaderClosure *sc, float xi, float *r, float *h)
+ccl_device void bssrdf_sample(const ShaderClosure *sc, float xi, float *r, float *h)
{
if(sc->type == CLOSURE_BSSRDF_CUBIC_ID)
bssrdf_cubic_sample(sc, xi, r, h);
@@ -368,7 +403,7 @@ ccl_device void bssrdf_sample(ShaderClosure *sc, float xi, float *r, float *h)
bssrdf_burley_sample(sc, xi, r, h);
}
-ccl_device float bssrdf_pdf(ShaderClosure *sc, float r)
+ccl_device float bssrdf_pdf(const ShaderClosure *sc, float r)
{
if(sc->type == CLOSURE_BSSRDF_CUBIC_ID)
return bssrdf_cubic_pdf(sc, r);
diff --git a/intern/cycles/kernel/closure/volume.h b/intern/cycles/kernel/closure/volume.h
index 4d71ba50ec3..01e67c7c2fd 100644
--- a/intern/cycles/kernel/closure/volume.h
+++ b/intern/cycles/kernel/closure/volume.h
@@ -19,6 +19,12 @@
CCL_NAMESPACE_BEGIN
+typedef ccl_addr_space struct HenyeyGreensteinVolume {
+ SHADER_CLOSURE_BASE;
+
+ float g;
+} HenyeyGreensteinVolume;
+
/* HENYEY-GREENSTEIN CLOSURE */
/* Given cosine between rays, return probability density that a photon bounces
@@ -29,19 +35,28 @@ 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);
};
-ccl_device int volume_henyey_greenstein_setup(ShaderClosure *sc)
+ccl_device int volume_henyey_greenstein_setup(HenyeyGreensteinVolume *volume)
{
- sc->type = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
+ volume->type = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
/* clamp anisotropy to avoid delta function */
- sc->data0 = signf(sc->data0) * min(fabsf(sc->data0), 1.0f - 1e-3f);
+ volume->g = signf(volume->g) * min(fabsf(volume->g), 1.0f - 1e-3f);
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;
+
+ 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)
{
- float g = sc->data0;
+ const HenyeyGreensteinVolume *volume = (const HenyeyGreensteinVolume*)sc;
+ float g = volume->g;
/* note that I points towards the viewer */
if(fabsf(g) < 1e-3f) {
@@ -58,7 +73,8 @@ ccl_device float3 volume_henyey_greenstein_eval_phase(const ShaderClosure *sc, c
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)
{
- float g = sc->data0;
+ const HenyeyGreensteinVolume *volume = (const HenyeyGreensteinVolume*)sc;
+ float g = volume->g;
float cos_phi, sin_phi, cos_theta;
/* match pdf for small g */