Cycles: Implement MaterialX OSL microfacet closures
This commit implements three OSL microfacet closures that are needed to support MaterialX: dielectric_bsdf, conductor_bsdf and generalized_schlick_bsdf. Internally these map to existing microfacet closures, only the Fresnel term is different.
This commit is contained in:
@@ -25,6 +25,9 @@ enum MicrofacetType {
|
||||
enum MicrofacetFresnel {
|
||||
NONE = 0,
|
||||
DIELECTRIC,
|
||||
DIELECTRIC_TINT, /* used by the OSL MaterialX closures */
|
||||
CONDUCTOR,
|
||||
GENERALIZED_SCHLICK,
|
||||
CONSTANT, /* only needed by MultiGGX */
|
||||
PRINCIPLED_V1,
|
||||
};
|
||||
@@ -38,6 +41,22 @@ typedef struct FresnelConstant {
|
||||
Spectrum color;
|
||||
} FresnelConstant;
|
||||
|
||||
typedef struct FresnelDielectricTint {
|
||||
Spectrum reflection_tint;
|
||||
Spectrum transmission_tint;
|
||||
} FresnelDielectricTint;
|
||||
|
||||
typedef struct FresnelConductor {
|
||||
Spectrum n, k;
|
||||
} FresnelConductor;
|
||||
|
||||
typedef struct FresnelGeneralizedSchlick {
|
||||
Spectrum reflection_tint;
|
||||
Spectrum transmission_tint;
|
||||
Spectrum f0, f90;
|
||||
float exponent;
|
||||
} FresnelGeneralizedSchlick;
|
||||
|
||||
typedef struct MicrofacetBsdf {
|
||||
SHADER_CLOSURE_BASE;
|
||||
|
||||
@@ -210,6 +229,40 @@ ccl_device_forceinline Spectrum microfacet_fresnel(ccl_private const MicrofacetB
|
||||
const float F = fresnel_dielectric_cos(dot(wi, H), bsdf->ior);
|
||||
return make_spectrum(refraction ? 1.0f - F : F);
|
||||
}
|
||||
else if (bsdf->fresnel_type == MicrofacetFresnel::DIELECTRIC_TINT) {
|
||||
ccl_private FresnelDielectricTint *fresnel = (ccl_private FresnelDielectricTint *)
|
||||
bsdf->fresnel;
|
||||
const float F = fresnel_dielectric_cos(dot(wi, H), bsdf->ior);
|
||||
return refraction ? (1.0f - F) * fresnel->transmission_tint : F * fresnel->reflection_tint;
|
||||
}
|
||||
else if (bsdf->fresnel_type == MicrofacetFresnel::CONDUCTOR) {
|
||||
kernel_assert(!refraction);
|
||||
ccl_private FresnelConductor *fresnel = (ccl_private FresnelConductor *)bsdf->fresnel;
|
||||
return fresnel_conductor(dot(wi, H), fresnel->n, fresnel->k);
|
||||
}
|
||||
else if (bsdf->fresnel_type == MicrofacetFresnel::GENERALIZED_SCHLICK) {
|
||||
ccl_private FresnelGeneralizedSchlick *fresnel = (ccl_private FresnelGeneralizedSchlick *)
|
||||
bsdf->fresnel;
|
||||
float cosI = dot(wi, H);
|
||||
if (bsdf->ior < 1.0f) {
|
||||
/* When going from a higher to a lower IOR, we must use the transmitted angle. */
|
||||
float sinT2 = (1.0f - sqr(cosI)) / sqr(bsdf->ior);
|
||||
if (sinT2 >= 1.0f) {
|
||||
/* Total internal reflection */
|
||||
return refraction ? zero_spectrum() : fresnel->reflection_tint;
|
||||
}
|
||||
cosI = safe_sqrtf(1.0f - sinT2);
|
||||
}
|
||||
/* TODO(lukas): Is a special case for exponent==5 worth it? */
|
||||
const float s = powf(1.0f - cosI, fresnel->exponent);
|
||||
const Spectrum F = mix(fresnel->f0, fresnel->f90, s);
|
||||
if (refraction) {
|
||||
return (one_spectrum() - F) * fresnel->transmission_tint;
|
||||
}
|
||||
else {
|
||||
return F * fresnel->reflection_tint;
|
||||
}
|
||||
}
|
||||
else if (bsdf->fresnel_type == MicrofacetFresnel::CONSTANT) {
|
||||
kernel_assert(!refraction);
|
||||
ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)bsdf->fresnel;
|
||||
@@ -600,6 +653,35 @@ ccl_device void bsdf_microfacet_setup_fresnel_principledv1(
|
||||
bsdf_microfacet_adjust_weight(sd, bsdf);
|
||||
}
|
||||
|
||||
ccl_device void bsdf_microfacet_setup_fresnel_conductor(ccl_private MicrofacetBsdf *bsdf,
|
||||
ccl_private const ShaderData *sd,
|
||||
ccl_private FresnelConductor *fresnel)
|
||||
{
|
||||
bsdf->fresnel_type = MicrofacetFresnel::CONDUCTOR;
|
||||
bsdf->fresnel = fresnel;
|
||||
bsdf_microfacet_adjust_weight(sd, bsdf);
|
||||
}
|
||||
|
||||
ccl_device void bsdf_microfacet_setup_fresnel_dielectric_tint(
|
||||
ccl_private MicrofacetBsdf *bsdf,
|
||||
ccl_private const ShaderData *sd,
|
||||
ccl_private FresnelDielectricTint *fresnel)
|
||||
{
|
||||
bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC_TINT;
|
||||
bsdf->fresnel = fresnel;
|
||||
bsdf_microfacet_adjust_weight(sd, bsdf);
|
||||
}
|
||||
|
||||
ccl_device void bsdf_microfacet_setup_fresnel_generalized_schlick(
|
||||
ccl_private MicrofacetBsdf *bsdf,
|
||||
ccl_private const ShaderData *sd,
|
||||
ccl_private FresnelGeneralizedSchlick *fresnel)
|
||||
{
|
||||
bsdf->fresnel_type = MicrofacetFresnel::GENERALIZED_SCHLICK;
|
||||
bsdf->fresnel = fresnel;
|
||||
bsdf_microfacet_adjust_weight(sd, bsdf);
|
||||
}
|
||||
|
||||
/* GGX microfacet with Smith shadow-masking from:
|
||||
*
|
||||
* Microfacet Models for Refraction through Rough Surfaces
|
||||
|
||||
@@ -64,17 +64,23 @@ ccl_device float fresnel_dielectric_cos(float cosi, float eta)
|
||||
return 1.0f; // TIR(no refracted component)
|
||||
}
|
||||
|
||||
ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k)
|
||||
ccl_device Spectrum fresnel_conductor(float cosi, const Spectrum eta, const Spectrum k)
|
||||
{
|
||||
float3 cosi2 = make_float3(cosi * cosi, cosi * cosi, cosi * cosi);
|
||||
float3 one = make_float3(1.0f, 1.0f, 1.0f);
|
||||
float3 tmp_f = eta * eta + k * k;
|
||||
float3 tmp = tmp_f * cosi2;
|
||||
float3 Rparl2 = (tmp - (2.0f * eta * cosi) + one) / (tmp + (2.0f * eta * cosi) + one);
|
||||
float3 Rperp2 = (tmp_f - (2.0f * eta * cosi) + cosi2) / (tmp_f + (2.0f * eta * cosi) + cosi2);
|
||||
Spectrum cosi2 = make_spectrum(cosi * cosi);
|
||||
Spectrum one = make_spectrum(1.0f);
|
||||
Spectrum tmp_f = eta * eta + k * k;
|
||||
Spectrum tmp = tmp_f * cosi2;
|
||||
Spectrum Rparl2 = (tmp - (2.0f * eta * cosi) + one) / (tmp + (2.0f * eta * cosi) + one);
|
||||
Spectrum Rperp2 = (tmp_f - (2.0f * eta * cosi) + cosi2) / (tmp_f + (2.0f * eta * cosi) + cosi2);
|
||||
return (Rparl2 + Rperp2) * 0.5f;
|
||||
}
|
||||
|
||||
ccl_device float ior_from_F0(Spectrum f0)
|
||||
{
|
||||
const float sqrt_f0 = sqrtf(clamp(average(f0), 0.0f, 0.99f));
|
||||
return (1.0f + sqrt_f0) / (1.0f - sqrt_f0);
|
||||
}
|
||||
|
||||
ccl_device float schlick_fresnel(float u)
|
||||
{
|
||||
float m = clamp(1.0f - u, 0.0f, 1.0f);
|
||||
|
||||
@@ -178,6 +178,184 @@ ccl_device void osl_closure_transparent_setup(KernelGlobals kg,
|
||||
bsdf_transparent_setup(sd, rgb_to_spectrum(weight), path_flag);
|
||||
}
|
||||
|
||||
/* MaterialX closures */
|
||||
ccl_device void osl_closure_dielectric_bsdf_setup(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
uint32_t path_flag,
|
||||
float3 weight,
|
||||
ccl_private const DielectricBSDFClosure *closure)
|
||||
{
|
||||
const bool has_reflection = !is_zero(closure->reflection_tint);
|
||||
const bool has_transmission = !is_zero(closure->transmission_tint);
|
||||
|
||||
if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
|
||||
sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(weight));
|
||||
if (!bsdf) {
|
||||
return;
|
||||
}
|
||||
|
||||
ccl_private FresnelDielectricTint *fresnel = (ccl_private FresnelDielectricTint *)
|
||||
closure_alloc_extra(sd, sizeof(FresnelDielectricTint));
|
||||
if (!fresnel) {
|
||||
return;
|
||||
}
|
||||
|
||||
bsdf->N = ensure_valid_reflection(sd->Ng, sd->wi, closure->N);
|
||||
bsdf->alpha_x = closure->alpha_x;
|
||||
bsdf->alpha_y = closure->alpha_y;
|
||||
bsdf->ior = closure->ior;
|
||||
if (sd->flag & SD_BACKFACING) {
|
||||
bsdf->ior = 1.0f / bsdf->ior;
|
||||
}
|
||||
bsdf->T = closure->T;
|
||||
|
||||
/* GGX */
|
||||
if (closure->distribution == make_string("ggx", 11253504724482777663ull) ||
|
||||
closure->distribution == make_string("default", 4430693559278735917ull)) {
|
||||
if (has_reflection && has_transmission) {
|
||||
sd->flag |= bsdf_microfacet_ggx_glass_setup(bsdf);
|
||||
}
|
||||
else if (has_transmission) {
|
||||
sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf);
|
||||
}
|
||||
else {
|
||||
sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
|
||||
}
|
||||
}
|
||||
/* Beckmann */
|
||||
else {
|
||||
if (has_reflection && has_transmission) {
|
||||
sd->flag |= bsdf_microfacet_beckmann_glass_setup(bsdf);
|
||||
}
|
||||
else if (has_transmission) {
|
||||
sd->flag |= bsdf_microfacet_beckmann_refraction_setup(bsdf);
|
||||
}
|
||||
else {
|
||||
sd->flag |= bsdf_microfacet_beckmann_setup(bsdf);
|
||||
}
|
||||
}
|
||||
|
||||
fresnel->reflection_tint = rgb_to_spectrum(closure->reflection_tint);
|
||||
fresnel->transmission_tint = rgb_to_spectrum(closure->transmission_tint);
|
||||
bsdf_microfacet_setup_fresnel_dielectric_tint(bsdf, sd, fresnel);
|
||||
}
|
||||
|
||||
ccl_device void osl_closure_conductor_bsdf_setup(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
uint32_t path_flag,
|
||||
float3 weight,
|
||||
ccl_private const ConductorBSDFClosure *closure)
|
||||
{
|
||||
if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
|
||||
sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(weight));
|
||||
if (!bsdf) {
|
||||
return;
|
||||
}
|
||||
|
||||
ccl_private FresnelConductor *fresnel = (ccl_private FresnelConductor *)closure_alloc_extra(
|
||||
sd, sizeof(FresnelConductor));
|
||||
if (!fresnel) {
|
||||
return;
|
||||
}
|
||||
|
||||
bsdf->N = ensure_valid_reflection(sd->Ng, sd->wi, closure->N);
|
||||
bsdf->alpha_x = closure->alpha_x;
|
||||
bsdf->alpha_y = closure->alpha_y;
|
||||
bsdf->ior = 0.0f;
|
||||
bsdf->T = closure->T;
|
||||
|
||||
/* GGX */
|
||||
if (closure->distribution == make_string("ggx", 11253504724482777663ull) ||
|
||||
closure->distribution == make_string("default", 4430693559278735917ull)) {
|
||||
sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
|
||||
}
|
||||
/* Beckmann */
|
||||
else {
|
||||
sd->flag |= bsdf_microfacet_beckmann_setup(bsdf);
|
||||
}
|
||||
|
||||
fresnel->n = rgb_to_spectrum(closure->ior);
|
||||
fresnel->k = rgb_to_spectrum(closure->extinction);
|
||||
bsdf_microfacet_setup_fresnel_conductor(bsdf, sd, fresnel);
|
||||
}
|
||||
|
||||
ccl_device void osl_closure_generalized_schlick_bsdf_setup(
|
||||
KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
uint32_t path_flag,
|
||||
float3 weight,
|
||||
ccl_private const GeneralizedSchlickBSDFClosure *closure)
|
||||
{
|
||||
const bool has_reflection = !is_zero(closure->reflection_tint);
|
||||
const bool has_transmission = !is_zero(closure->transmission_tint);
|
||||
|
||||
if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
|
||||
sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(weight));
|
||||
if (!bsdf) {
|
||||
return;
|
||||
}
|
||||
|
||||
ccl_private FresnelGeneralizedSchlick *fresnel = (ccl_private FresnelGeneralizedSchlick *)
|
||||
closure_alloc_extra(sd, sizeof(FresnelGeneralizedSchlick));
|
||||
if (!fresnel) {
|
||||
return;
|
||||
}
|
||||
|
||||
bsdf->N = ensure_valid_reflection(sd->Ng, sd->wi, closure->N);
|
||||
bsdf->alpha_x = closure->alpha_x;
|
||||
bsdf->alpha_y = closure->alpha_y;
|
||||
bsdf->ior = ior_from_F0(closure->f0);
|
||||
if (sd->flag & SD_BACKFACING) {
|
||||
bsdf->ior = 1.0f / bsdf->ior;
|
||||
}
|
||||
bsdf->T = closure->T;
|
||||
|
||||
/* GGX */
|
||||
if (closure->distribution == make_string("ggx", 11253504724482777663ull) ||
|
||||
closure->distribution == make_string("default", 4430693559278735917ull)) {
|
||||
if (has_reflection && has_transmission) {
|
||||
sd->flag |= bsdf_microfacet_ggx_glass_setup(bsdf);
|
||||
}
|
||||
else if (has_transmission) {
|
||||
sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf);
|
||||
}
|
||||
else {
|
||||
sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
|
||||
}
|
||||
}
|
||||
/* Beckmann */
|
||||
else {
|
||||
if (has_reflection && has_transmission) {
|
||||
sd->flag |= bsdf_microfacet_beckmann_glass_setup(bsdf);
|
||||
}
|
||||
else if (has_transmission) {
|
||||
sd->flag |= bsdf_microfacet_beckmann_refraction_setup(bsdf);
|
||||
}
|
||||
else {
|
||||
sd->flag |= bsdf_microfacet_beckmann_setup(bsdf);
|
||||
}
|
||||
}
|
||||
|
||||
fresnel->reflection_tint = rgb_to_spectrum(closure->reflection_tint);
|
||||
fresnel->transmission_tint = rgb_to_spectrum(closure->transmission_tint);
|
||||
fresnel->f0 = rgb_to_spectrum(closure->f0);
|
||||
fresnel->f90 = rgb_to_spectrum(closure->f90);
|
||||
fresnel->exponent = closure->exponent;
|
||||
bsdf_microfacet_setup_fresnel_generalized_schlick(bsdf, sd, fresnel);
|
||||
}
|
||||
|
||||
/* Standard microfacet closures */
|
||||
|
||||
ccl_device void osl_closure_microfacet_setup(KernelGlobals kg,
|
||||
|
||||
@@ -39,6 +39,40 @@ OSL_CLOSURE_STRUCT_END(Refraction, refraction)
|
||||
OSL_CLOSURE_STRUCT_BEGIN(Transparent, transparent)
|
||||
OSL_CLOSURE_STRUCT_END(Transparent, transparent)
|
||||
|
||||
OSL_CLOSURE_STRUCT_BEGIN(DielectricBSDF, dielectric_bsdf)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(DielectricBSDF, VECTOR, packed_float3, N, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(DielectricBSDF, VECTOR, packed_float3, T, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(DielectricBSDF, VECTOR, packed_float3, reflection_tint, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(DielectricBSDF, VECTOR, packed_float3, transmission_tint, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(DielectricBSDF, FLOAT, float, alpha_x, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(DielectricBSDF, FLOAT, float, alpha_y, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(DielectricBSDF, FLOAT, float, ior, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(DielectricBSDF, STRING, DeviceString, distribution, NULL)
|
||||
OSL_CLOSURE_STRUCT_END(DielectricBSDF, dielectric_bsdf)
|
||||
|
||||
OSL_CLOSURE_STRUCT_BEGIN(ConductorBSDF, conductor_bsdf)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(ConductorBSDF, VECTOR, packed_float3, N, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(ConductorBSDF, VECTOR, packed_float3, T, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(ConductorBSDF, FLOAT, float, alpha_x, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(ConductorBSDF, FLOAT, float, alpha_y, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(ConductorBSDF, VECTOR, packed_float3, ior, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(ConductorBSDF, VECTOR, packed_float3, extinction, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(ConductorBSDF, STRING, DeviceString, distribution, NULL)
|
||||
OSL_CLOSURE_STRUCT_END(ConductorBSDF, conductor_bsdf)
|
||||
|
||||
OSL_CLOSURE_STRUCT_BEGIN(GeneralizedSchlickBSDF, generalized_schlick_bsdf)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(GeneralizedSchlickBSDF, VECTOR, packed_float3, N, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(GeneralizedSchlickBSDF, VECTOR, packed_float3, T, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(GeneralizedSchlickBSDF, VECTOR, packed_float3, reflection_tint, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(GeneralizedSchlickBSDF, VECTOR, packed_float3, transmission_tint, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(GeneralizedSchlickBSDF, FLOAT, float, alpha_x, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(GeneralizedSchlickBSDF, FLOAT, float, alpha_y, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(GeneralizedSchlickBSDF, VECTOR, packed_float3, f0, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(GeneralizedSchlickBSDF, VECTOR, packed_float3, f90, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(GeneralizedSchlickBSDF, FLOAT, float, exponent, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(GeneralizedSchlickBSDF, STRING, DeviceString, distribution, NULL)
|
||||
OSL_CLOSURE_STRUCT_END(GeneralizedSchlickBSDF, generalized_schlick_bsdf)
|
||||
|
||||
OSL_CLOSURE_STRUCT_BEGIN(Microfacet, microfacet)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(Microfacet, STRING, DeviceString, distribution, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(Microfacet, VECTOR, packed_float3, N, NULL)
|
||||
|
||||
Reference in New Issue
Block a user