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:
Lukas Stockner
2023-02-06 04:23:20 +01:00
parent 014f6e4309
commit 9139983f94
4 changed files with 307 additions and 7 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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,

View File

@@ -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)