Cycles: Remove MultiGGX code, replace with albedo scaling #107958
|
@ -123,8 +123,6 @@ set(SRC_KERNEL_CLOSURE_HEADERS
|
|||
closure/bsdf_diffuse.h
|
||||
closure/bsdf_diffuse_ramp.h
|
||||
closure/bsdf_microfacet.h
|
||||
closure/bsdf_microfacet_multi.h
|
||||
closure/bsdf_microfacet_multi_impl.h
|
||||
closure/bsdf_oren_nayar.h
|
||||
closure/bsdf_phong_ramp.h
|
||||
closure/bsdf_toon.h
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "kernel/closure/bsdf_phong_ramp.h"
|
||||
#include "kernel/closure/bsdf_diffuse_ramp.h"
|
||||
#include "kernel/closure/bsdf_microfacet.h"
|
||||
#include "kernel/closure/bsdf_microfacet_multi.h"
|
||||
#include "kernel/closure/bsdf_transparent.h"
|
||||
#include "kernel/closure/bsdf_ashikhmin_shirley.h"
|
||||
#include "kernel/closure/bsdf_toon.h"
|
||||
|
@ -170,34 +169,6 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg,
|
|||
label = bsdf_microfacet_ggx_sample(
|
||||
sc, path_flag, Ng, sd->wi, rand, eval, wo, pdf, sampled_roughness, eta);
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
|
||||
label = bsdf_microfacet_multi_ggx_sample(kg,
|
||||
sc,
|
||||
Ng,
|
||||
sd->wi,
|
||||
rand.x,
|
||||
rand.y,
|
||||
eval,
|
||||
wo,
|
||||
pdf,
|
||||
&sd->lcg_state,
|
||||
sampled_roughness,
|
||||
eta);
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
|
||||
label = bsdf_microfacet_multi_ggx_glass_sample(kg,
|
||||
sc,
|
||||
Ng,
|
||||
sd->wi,
|
||||
rand.x,
|
||||
rand.y,
|
||||
eval,
|
||||
wo,
|
||||
pdf,
|
||||
&sd->lcg_state,
|
||||
sampled_roughness,
|
||||
eta);
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID:
|
||||
|
@ -339,13 +310,6 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg,
|
|||
*eta = CLOSURE_IS_REFRACTIVE(bsdf->type) ? 1.0f / bsdf->ior : bsdf->ior;
|
||||
break;
|
||||
}
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: {
|
||||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
*roughness = make_float2(bsdf->alpha_x, bsdf->alpha_y);
|
||||
*eta = bsdf->ior;
|
||||
break;
|
||||
}
|
||||
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: {
|
||||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
*roughness = make_float2(bsdf->alpha_x, bsdf->alpha_y);
|
||||
|
@ -433,13 +397,11 @@ ccl_device_inline int bsdf_label(const KernelGlobals kg,
|
|||
case CLOSURE_BSDF_SHARP_GLASS_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: {
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID: {
|
||||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
label = ((bsdf_is_transmission(sc, wo)) ? LABEL_TRANSMIT : LABEL_REFLECT) |
|
||||
((bsdf->alpha_x * bsdf->alpha_y <= 1e-7f) ? LABEL_SINGULAR : LABEL_GLOSSY);
|
||||
|
@ -542,12 +504,6 @@ ccl_device_inline
|
|||
case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID:
|
||||
eval = bsdf_microfacet_ggx_eval(sc, sd->N, sd->wi, wo, pdf);
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
|
||||
eval = bsdf_microfacet_multi_ggx_eval(sc, sd->N, sd->wi, wo, pdf, &sd->lcg_state);
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
|
||||
eval = bsdf_microfacet_multi_ggx_glass_eval(sc, sd->wi, wo, pdf, &sd->lcg_state);
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID:
|
||||
|
@ -613,14 +569,11 @@ ccl_device void bsdf_blur(KernelGlobals kg, ccl_private ShaderClosure *sc, float
|
|||
/* TODO: do we want to blur volume closures? */
|
||||
#if defined(__SVM__) || defined(__OSL__)
|
||||
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_CLEARCOAT_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID:
|
||||
/* TODO: Recompute energy preservation after blur? */
|
||||
bsdf_microfacet_ggx_blur(sc, roughness);
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
|
||||
|
|
|
@ -28,19 +28,8 @@ enum MicrofacetFresnel {
|
|||
DIELECTRIC_TINT, /* used by the OSL MaterialX closures */
|
||||
CONDUCTOR,
|
||||
GENERALIZED_SCHLICK,
|
||||
CONSTANT, /* only needed by MultiGGX */
|
||||
PRINCIPLED_V1,
|
||||
};
|
||||
|
||||
typedef struct FresnelPrincipledV1 {
|
||||
Spectrum color; /* only needed by MultiGGX */
|
||||
Spectrum cspec0;
|
||||
} FresnelPrincipledV1;
|
||||
|
||||
typedef struct FresnelConstant {
|
||||
Spectrum color;
|
||||
} FresnelConstant;
|
||||
|
||||
typedef struct FresnelDielectricTint {
|
||||
Spectrum reflection_tint;
|
||||
Spectrum transmission_tint;
|
||||
|
@ -53,7 +42,9 @@ typedef struct FresnelConductor {
|
|||
typedef struct FresnelGeneralizedSchlick {
|
||||
Spectrum reflection_tint;
|
||||
Spectrum transmission_tint;
|
||||
/* Reflectivity at perpendicular (F0) and glancing (F90) angles. */
|
||||
Spectrum f0, f90;
|
||||
/* Negative exponent signals a special case where the real Fresnel is remapped to F0...F90. */
|
||||
float exponent;
|
||||
} FresnelGeneralizedSchlick;
|
||||
|
||||
|
@ -218,12 +209,7 @@ ccl_device_forceinline Spectrum microfacet_fresnel(ccl_private const MicrofacetB
|
|||
const float3 H,
|
||||
const bool refraction)
|
||||
{
|
||||
if (bsdf->fresnel_type == MicrofacetFresnel::PRINCIPLED_V1) {
|
||||
kernel_assert(!refraction);
|
||||
ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *)bsdf->fresnel;
|
||||
return interpolate_fresnel_color(wi, H, bsdf->ior, fresnel->cspec0);
|
||||
}
|
||||
else if (bsdf->fresnel_type == MicrofacetFresnel::DIELECTRIC) {
|
||||
if (bsdf->fresnel_type == MicrofacetFresnel::DIELECTRIC) {
|
||||
const float F = fresnel_dielectric_cos(dot(wi, H), bsdf->ior);
|
||||
return make_spectrum(refraction ? 1.0f - F : F);
|
||||
}
|
||||
|
@ -241,6 +227,16 @@ ccl_device_forceinline Spectrum microfacet_fresnel(ccl_private const MicrofacetB
|
|||
else if (bsdf->fresnel_type == MicrofacetFresnel::GENERALIZED_SCHLICK) {
|
||||
ccl_private FresnelGeneralizedSchlick *fresnel = (ccl_private FresnelGeneralizedSchlick *)
|
||||
bsdf->fresnel;
|
||||
float s;
|
||||
if (fresnel->exponent < 0.0f) {
|
||||
/* Special case: Use real Fresnel curve to determine the interpolation between F0 and F90.
|
||||
* Used by Principled v1. */
|
||||
const float F_real = fresnel_dielectric_cos(dot(wi, H), bsdf->ior);
|
||||
const float F0_real = F0_from_ior(bsdf->ior);
|
||||
s = inverse_lerp(F0_real, 1.0f, F_real);
|
||||
}
|
||||
else {
|
||||
/* Regular case: Generalized Schlick term. */
|
||||
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. */
|
||||
|
@ -252,7 +248,8 @@ ccl_device_forceinline Spectrum microfacet_fresnel(ccl_private const MicrofacetB
|
|||
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);
|
||||
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;
|
||||
|
@ -261,12 +258,6 @@ ccl_device_forceinline Spectrum microfacet_fresnel(ccl_private const MicrofacetB
|
|||
return F * fresnel->reflection_tint;
|
||||
}
|
||||
}
|
||||
else if (bsdf->fresnel_type == MicrofacetFresnel::CONSTANT) {
|
||||
/* CONSTANT is only used my MultiGGX, which doesn't call this function.
|
||||
* Therefore, this case only happens when determining the albedo of a MultiGGX closure.
|
||||
* In that case, return 1.0 since the constant color is already baked into the weight. */
|
||||
return one_spectrum();
|
||||
}
|
||||
else {
|
||||
return one_spectrum();
|
||||
}
|
||||
|
@ -658,18 +649,6 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc,
|
|||
/* Fresnel term setup functions. These get called after the distribution-specific setup functions
|
||||
* like bsdf_microfacet_ggx_setup. */
|
||||
|
||||
ccl_device void bsdf_microfacet_setup_fresnel_principledv1(
|
||||
ccl_private MicrofacetBsdf *bsdf,
|
||||
ccl_private const ShaderData *sd,
|
||||
ccl_private FresnelPrincipledV1 *fresnel)
|
||||
{
|
||||
fresnel->cspec0 = saturate(fresnel->cspec0);
|
||||
|
||||
bsdf->fresnel_type = MicrofacetFresnel::PRINCIPLED_V1;
|
||||
bsdf->fresnel = fresnel;
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
}
|
||||
|
||||
ccl_device void bsdf_microfacet_setup_fresnel_conductor(ccl_private MicrofacetBsdf *bsdf,
|
||||
ccl_private const ShaderData *sd,
|
||||
ccl_private FresnelConductor *fresnel)
|
||||
|
|
|
@ -1,759 +0,0 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright 2011-2022 Blender Foundation */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/sample/lcg.h"
|
||||
#include "kernel/sample/mapping.h"
|
||||
|
||||
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_forceinline float D_ggx(float3 wm, float alpha)
|
||||
{
|
||||
wm.z *= wm.z;
|
||||
alpha *= alpha;
|
||||
float tmp = (1.0f - wm.z) + alpha * wm.z;
|
||||
return alpha / max(M_PI_F * tmp * tmp, 1e-7f);
|
||||
}
|
||||
|
||||
/* Anisotropic GGX microfacet distribution */
|
||||
ccl_device_forceinline float D_ggx_aniso(const float3 wm, const float2 alpha)
|
||||
{
|
||||
float slope_x = -wm.x / alpha.x;
|
||||
float slope_y = -wm.y / alpha.y;
|
||||
float tmp = wm.z * wm.z + slope_x * slope_x + slope_y * slope_y;
|
||||
|
||||
return 1.0f / max(M_PI_F * tmp * tmp * alpha.x * alpha.y, 1e-7f);
|
||||
}
|
||||
|
||||
/* Sample slope distribution (based on page 14 of the supplemental implementation). */
|
||||
ccl_device_forceinline float2 mf_sampleP22_11(const float cosI,
|
||||
const float randx,
|
||||
const float randy)
|
||||
{
|
||||
if (cosI > 0.9999f || fabsf(cosI) < 1e-6f) {
|
||||
const float r = sqrtf(randx / max(1.0f - randx, 1e-7f));
|
||||
const float phi = M_2PI_F * randy;
|
||||
return make_float2(r * cosf(phi), r * sinf(phi));
|
||||
}
|
||||
|
||||
const float sinI = sin_from_cos(cosI);
|
||||
const float tanI = sinI / cosI;
|
||||
const float projA = 0.5f * (cosI + 1.0f);
|
||||
if (projA < 0.0001f)
|
||||
return make_float2(0.0f, 0.0f);
|
||||
const float A = 2.0f * randx * projA / cosI - 1.0f;
|
||||
float tmp = A * A - 1.0f;
|
||||
if (fabsf(tmp) < 1e-7f)
|
||||
return make_float2(0.0f, 0.0f);
|
||||
tmp = 1.0f / tmp;
|
||||
const float D = safe_sqrtf(tanI * tanI * tmp * tmp - (A * A - tanI * tanI) * tmp);
|
||||
|
||||
const float slopeX2 = tanI * tmp + D;
|
||||
const float slopeX = (A < 0.0f || slopeX2 > 1.0f / tanI) ? (tanI * tmp - D) : slopeX2;
|
||||
|
||||
float U2;
|
||||
if (randy >= 0.5f)
|
||||
U2 = 2.0f * (randy - 0.5f);
|
||||
else
|
||||
U2 = 2.0f * (0.5f - randy);
|
||||
const float z = (U2 * (U2 * (U2 * 0.27385f - 0.73369f) + 0.46341f)) /
|
||||
(U2 * (U2 * (U2 * 0.093073f + 0.309420f) - 1.0f) + 0.597999f);
|
||||
const float slopeY = z * sqrtf(1.0f + slopeX * slopeX);
|
||||
|
||||
if (randy >= 0.5f)
|
||||
return make_float2(slopeX, slopeY);
|
||||
else
|
||||
return make_float2(slopeX, -slopeY);
|
||||
}
|
||||
|
||||
/* Visible normal sampling for the GGX distribution
|
||||
* (based on page 7 of the supplemental implementation). */
|
||||
ccl_device_forceinline float3 mf_sample_vndf(const float3 wi,
|
||||
const float2 alpha,
|
||||
const float randx,
|
||||
const float randy)
|
||||
{
|
||||
const float3 wi_11 = normalize(make_float3(alpha.x * wi.x, alpha.y * wi.y, wi.z));
|
||||
const float2 slope_11 = mf_sampleP22_11(wi_11.z, randx, randy);
|
||||
|
||||
const float3 cossin_phi = safe_normalize(make_float3(wi_11.x, wi_11.y, 0.0f));
|
||||
const float slope_x = alpha.x * (cossin_phi.x * slope_11.x - cossin_phi.y * slope_11.y);
|
||||
const float slope_y = alpha.y * (cossin_phi.y * slope_11.x + cossin_phi.x * slope_11.y);
|
||||
|
||||
kernel_assert(isfinite(slope_x));
|
||||
return normalize(make_float3(-slope_x, -slope_y, 1.0f));
|
||||
}
|
||||
|
||||
/* === Phase functions: Glossy and Glass === */
|
||||
|
||||
/* Phase function for reflective materials. */
|
||||
ccl_device_forceinline float3 mf_sample_phase_glossy(const float3 wi,
|
||||
ccl_private Spectrum *weight,
|
||||
const float3 wm)
|
||||
{
|
||||
return -wi + 2.0f * wm * dot(wi, wm);
|
||||
}
|
||||
|
||||
ccl_device_forceinline Spectrum mf_eval_phase_glossy(const float3 w,
|
||||
const float lambda,
|
||||
const float3 wo,
|
||||
const float2 alpha)
|
||||
{
|
||||
if (w.z > 0.9999f)
|
||||
return zero_spectrum();
|
||||
|
||||
const float3 wh = normalize(wo - w);
|
||||
if (wh.z < 0.0f)
|
||||
return zero_spectrum();
|
||||
|
||||
float pArea = (w.z < -0.9999f) ? 1.0f : lambda * w.z;
|
||||
|
||||
const float dotW_WH = dot(-w, wh);
|
||||
if (dotW_WH < 0.0f)
|
||||
return zero_spectrum();
|
||||
|
||||
float phase = max(0.0f, dotW_WH) * 0.25f / max(pArea * dotW_WH, 1e-7f);
|
||||
if (alpha.x == alpha.y)
|
||||
phase *= D_ggx(wh, alpha.x);
|
||||
else
|
||||
phase *= D_ggx_aniso(wh, alpha);
|
||||
|
||||
return make_spectrum(phase);
|
||||
}
|
||||
|
||||
/* Phase function for dielectric transmissive materials, including both reflection and refraction
|
||||
* according to the dielectric fresnel term. */
|
||||
ccl_device_forceinline float3 mf_sample_phase_glass(const float3 wi,
|
||||
const float eta,
|
||||
const float3 wm,
|
||||
const float randV,
|
||||
ccl_private bool *outside)
|
||||
{
|
||||
float cosI = dot(wi, wm);
|
||||
float f = fresnel_dielectric_cos(cosI, eta);
|
||||
if (randV < f) {
|
||||
*outside = true;
|
||||
return -wi + 2.0f * wm * cosI;
|
||||
}
|
||||
*outside = false;
|
||||
float inv_eta = 1.0f / eta;
|
||||
float cosT = -safe_sqrtf(1.0f - (1.0f - cosI * cosI) * inv_eta * inv_eta);
|
||||
return normalize(wm * (cosI * inv_eta + cosT) - wi * inv_eta);
|
||||
}
|
||||
|
||||
ccl_device_forceinline Spectrum 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 zero_spectrum();
|
||||
|
||||
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 zero_spectrum();
|
||||
|
||||
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 zero_spectrum();
|
||||
|
||||
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_spectrum(v);
|
||||
}
|
||||
|
||||
/* === Utility functions for the random walks === */
|
||||
|
||||
/* Smith Lambda function for GGX (based on page 12 of the supplemental implementation). */
|
||||
ccl_device_forceinline float mf_lambda(const float3 w, const float2 alpha)
|
||||
{
|
||||
if (w.z > 0.9999f)
|
||||
return 0.0f;
|
||||
else if (w.z < -0.9999f)
|
||||
return -0.9999f;
|
||||
|
||||
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_forceinline float mf_invC1(const float h)
|
||||
{
|
||||
return 2.0f * saturatef(h) - 1.0f;
|
||||
}
|
||||
|
||||
ccl_device_forceinline float mf_C1(const float h)
|
||||
{
|
||||
return saturatef(0.5f * (h + 1.0f));
|
||||
}
|
||||
|
||||
/* Masking function (based on page 16 of the supplemental implementation). */
|
||||
ccl_device_forceinline float mf_G1(const float3 w, const float C1, const float lambda)
|
||||
{
|
||||
if (w.z > 0.9999f)
|
||||
return 1.0f;
|
||||
if (w.z < 1e-5f)
|
||||
return 0.0f;
|
||||
return powf(C1, lambda);
|
||||
}
|
||||
|
||||
/* Sampling from the visible height distribution (based on page 17 of the supplemental
|
||||
* implementation). */
|
||||
ccl_device_forceinline bool mf_sample_height(const float3 w,
|
||||
ccl_private float *h,
|
||||
ccl_private float *C1,
|
||||
ccl_private float *G1,
|
||||
ccl_private 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_forceinline float mf_ggx_albedo(float r)
|
||||
{
|
||||
float albedo = 0.806495f * expf(-1.98712f * r * r) + 0.199531f;
|
||||
albedo -= ((((((1.76741f * r - 8.43891f) * r + 15.784f) * r - 14.398f) * r + 6.45221f) * r -
|
||||
1.19722f) *
|
||||
r +
|
||||
0.027803f) *
|
||||
r +
|
||||
0.00568739f;
|
||||
return saturatef(albedo);
|
||||
}
|
||||
|
||||
ccl_device_inline float mf_ggx_transmission_albedo(float a, float ior)
|
||||
{
|
||||
if (ior < 1.0f) {
|
||||
ior = 1.0f / ior;
|
||||
}
|
||||
a = saturatef(a);
|
||||
ior = clamp(ior, 1.0f, 3.0f);
|
||||
float I_1 = 0.0476898f * expf(-0.978352f * (ior - 0.65657f) * (ior - 0.65657f)) -
|
||||
0.033756f * ior + 0.993261f;
|
||||
float R_1 = (((0.116991f * a - 0.270369f) * a + 0.0501366f) * a - 0.00411511f) * a + 1.00008f;
|
||||
float I_2 = (((-2.08704f * ior + 26.3298f) * ior - 127.906f) * ior + 292.958f) * ior - 287.946f +
|
||||
199.803f / (ior * ior) - 101.668f / (ior * ior * ior);
|
||||
float R_2 = ((((5.3725f * a - 24.9307f) * a + 22.7437f) * a - 3.40751f) * a + 0.0986325f) * a +
|
||||
0.00493504f;
|
||||
|
||||
return saturatef(1.0f + I_2 * R_2 * 0.0019127f - (1.0f - I_1) * (1.0f - R_1) * 9.3205f);
|
||||
}
|
||||
|
||||
ccl_device_forceinline float mf_ggx_pdf(const float3 wi, const float3 wo, const float alpha)
|
||||
{
|
||||
float D = D_ggx(normalize(wi + wo), alpha);
|
||||
float lambda = mf_lambda(wi, make_float2(alpha, alpha));
|
||||
float singlescatter = 0.25f * D / max((1.0f + lambda) * wi.z, 1e-7f);
|
||||
|
||||
float multiscatter = wo.z * M_1_PI_F;
|
||||
|
||||
float albedo = mf_ggx_albedo(alpha);
|
||||
return albedo * singlescatter + (1.0f - albedo) * multiscatter;
|
||||
}
|
||||
|
||||
ccl_device_forceinline float mf_ggx_aniso_pdf(const float3 wi, const float3 wo, const float2 alpha)
|
||||
{
|
||||
float D = D_ggx_aniso(normalize(wi + wo), alpha);
|
||||
float lambda = mf_lambda(wi, alpha);
|
||||
float singlescatter = 0.25f * D / max((1.0f + lambda) * wi.z, 1e-7f);
|
||||
|
||||
float multiscatter = wo.z * M_1_PI_F;
|
||||
|
||||
float albedo = mf_ggx_albedo(sqrtf(alpha.x * alpha.y));
|
||||
return albedo * singlescatter + (1.0f - albedo) * multiscatter;
|
||||
}
|
||||
|
||||
ccl_device_forceinline float mf_glass_pdf(const float3 wi,
|
||||
const float3 wo,
|
||||
const float alpha,
|
||||
const float eta)
|
||||
{
|
||||
bool reflective = (wi.z * wo.z > 0.0f);
|
||||
|
||||
float wh_len;
|
||||
float3 wh = normalize_len(wi + (reflective ? wo : (wo * eta)), &wh_len);
|
||||
if (wh.z < 0.0f)
|
||||
wh = -wh;
|
||||
float3 r_wi = (wi.z < 0.0f) ? -wi : wi;
|
||||
float lambda = mf_lambda(r_wi, make_float2(alpha, alpha));
|
||||
float D = D_ggx(wh, alpha);
|
||||
float fresnel = fresnel_dielectric_cos(dot(r_wi, wh), eta);
|
||||
|
||||
float multiscatter = fabsf(wo.z * M_1_PI_F);
|
||||
if (reflective) {
|
||||
float singlescatter = 0.25f * D / max((1.0f + lambda) * r_wi.z, 1e-7f);
|
||||
float albedo = mf_ggx_albedo(alpha);
|
||||
return fresnel * (albedo * singlescatter + (1.0f - albedo) * multiscatter);
|
||||
}
|
||||
else {
|
||||
float singlescatter = fabsf(dot(r_wi, wh) * dot(wo, wh) * D * eta * eta /
|
||||
max((1.0f + lambda) * r_wi.z * wh_len * wh_len, 1e-7f));
|
||||
float albedo = mf_ggx_transmission_albedo(alpha, eta);
|
||||
return (1.0f - fresnel) * (albedo * singlescatter + (1.0f - albedo) * multiscatter);
|
||||
}
|
||||
}
|
||||
|
||||
/* === Actual random walk implementations === */
|
||||
/* One version of mf_eval and mf_sample per phase function. */
|
||||
|
||||
#define MF_NAME_JOIN(x, y) x##_##y
|
||||
#define MF_NAME_EVAL(x, y) MF_NAME_JOIN(x, y)
|
||||
#define MF_FUNCTION_FULL_NAME(prefix) MF_NAME_EVAL(prefix, MF_PHASE_FUNCTION)
|
||||
|
||||
#define MF_PHASE_FUNCTION glass
|
||||
#define MF_MULTI_GLASS
|
||||
#include "kernel/closure/bsdf_microfacet_multi_impl.h"
|
||||
|
||||
#define MF_PHASE_FUNCTION glossy
|
||||
#define MF_MULTI_GLOSSY
|
||||
#include "kernel/closure/bsdf_microfacet_multi_impl.h"
|
||||
|
||||
ccl_device void bsdf_microfacet_multi_ggx_blur(ccl_private ShaderClosure *sc, float roughness)
|
||||
{
|
||||
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc;
|
||||
|
||||
bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x);
|
||||
bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y);
|
||||
}
|
||||
|
||||
/* === Closure implementations === */
|
||||
|
||||
/* Multi-scattering GGX Glossy closure */
|
||||
|
||||
ccl_device int bsdf_microfacet_multi_ggx_common_setup(ccl_private MicrofacetBsdf *bsdf)
|
||||
{
|
||||
bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
|
||||
bsdf->alpha_y = clamp(bsdf->alpha_y, 1e-4f, 1.0f);
|
||||
|
||||
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG;
|
||||
}
|
||||
|
||||
ccl_device int bsdf_microfacet_multi_ggx_setup(ccl_private MicrofacetBsdf *bsdf)
|
||||
{
|
||||
if (is_zero(bsdf->T))
|
||||
bsdf->T = make_float3(1.0f, 0.0f, 0.0f);
|
||||
|
||||
ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)bsdf->fresnel;
|
||||
fresnel->color = saturate(fresnel->color);
|
||||
|
||||
bsdf->fresnel_type = MicrofacetFresnel::CONSTANT;
|
||||
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
|
||||
|
||||
return bsdf_microfacet_multi_ggx_common_setup(bsdf);
|
||||
}
|
||||
|
||||
ccl_device int bsdf_microfacet_multi_ggx_fresnel_setup(ccl_private MicrofacetBsdf *bsdf,
|
||||
ccl_private const ShaderData *sd)
|
||||
{
|
||||
if (is_zero(bsdf->T))
|
||||
bsdf->T = make_float3(1.0f, 0.0f, 0.0f);
|
||||
|
||||
ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *)bsdf->fresnel;
|
||||
fresnel->color = saturate(fresnel->color);
|
||||
fresnel->cspec0 = saturate(fresnel->cspec0);
|
||||
|
||||
bsdf->fresnel_type = MicrofacetFresnel::PRINCIPLED_V1;
|
||||
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
|
||||
return bsdf_microfacet_multi_ggx_common_setup(bsdf);
|
||||
}
|
||||
|
||||
ccl_device int bsdf_microfacet_multi_ggx_refraction_setup(ccl_private MicrofacetBsdf *bsdf)
|
||||
{
|
||||
bsdf->alpha_y = bsdf->alpha_x;
|
||||
|
||||
ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)bsdf->fresnel;
|
||||
fresnel->color = saturate(fresnel->color);
|
||||
|
||||
bsdf->fresnel_type = MicrofacetFresnel::CONSTANT;
|
||||
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
|
||||
|
||||
return bsdf_microfacet_multi_ggx_common_setup(bsdf);
|
||||
}
|
||||
|
||||
ccl_device Spectrum bsdf_microfacet_multi_ggx_eval(ccl_private const ShaderClosure *sc,
|
||||
const float3 Ng,
|
||||
const float3 wi,
|
||||
const float3 wo,
|
||||
ccl_private float *pdf,
|
||||
ccl_private uint *lcg_state)
|
||||
{
|
||||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
const float cosNgO = dot(Ng, wo);
|
||||
|
||||
if ((cosNgO < 0.0f) || bsdf->alpha_x * bsdf->alpha_y < 1e-7f) {
|
||||
*pdf = 0.0f;
|
||||
return zero_spectrum();
|
||||
}
|
||||
|
||||
float3 X, Y, Z;
|
||||
Z = bsdf->N;
|
||||
|
||||
/* Ensure that the both directions are on the outside w.r.t. the shading normal. */
|
||||
if (dot(Z, wi) <= 0.0f || dot(Z, wo) <= 0.0f) {
|
||||
*pdf = 0.0f;
|
||||
return zero_spectrum();
|
||||
}
|
||||
|
||||
Spectrum color, cspec0;
|
||||
bool use_fresnel;
|
||||
if (bsdf->fresnel_type == MicrofacetFresnel::PRINCIPLED_V1) {
|
||||
ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *)bsdf->fresnel;
|
||||
use_fresnel = true;
|
||||
color = fresnel->color;
|
||||
cspec0 = fresnel->cspec0;
|
||||
}
|
||||
else {
|
||||
kernel_assert(bsdf->fresnel_type == MicrofacetFresnel::CONSTANT);
|
||||
ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)bsdf->fresnel;
|
||||
use_fresnel = false;
|
||||
color = fresnel->color;
|
||||
cspec0 = zero_spectrum();
|
||||
}
|
||||
|
||||
bool is_aniso = (bsdf->alpha_x != bsdf->alpha_y);
|
||||
if (is_aniso)
|
||||
make_orthonormals_tangent(Z, bsdf->T, &X, &Y);
|
||||
else
|
||||
make_orthonormals(Z, &X, &Y);
|
||||
|
||||
float3 local_I = make_float3(dot(wi, X), dot(wi, Y), dot(wi, Z));
|
||||
float3 local_O = make_float3(dot(wo, X), dot(wo, Y), dot(wo, Z));
|
||||
|
||||
if (is_aniso)
|
||||
*pdf = mf_ggx_aniso_pdf(local_I, local_O, make_float2(bsdf->alpha_x, bsdf->alpha_y));
|
||||
else
|
||||
*pdf = mf_ggx_pdf(local_I, local_O, bsdf->alpha_x);
|
||||
|
||||
if (*pdf <= 0.f) {
|
||||
*pdf = 0.f;
|
||||
return make_float3(0.f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
return mf_eval_glossy(local_I,
|
||||
local_O,
|
||||
true,
|
||||
color,
|
||||
bsdf->alpha_x,
|
||||
bsdf->alpha_y,
|
||||
lcg_state,
|
||||
bsdf->ior,
|
||||
use_fresnel,
|
||||
cspec0);
|
||||
}
|
||||
|
||||
ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals kg,
|
||||
ccl_private const ShaderClosure *sc,
|
||||
float3 Ng,
|
||||
float3 wi,
|
||||
float randu,
|
||||
float randv,
|
||||
ccl_private Spectrum *eval,
|
||||
ccl_private float3 *wo,
|
||||
ccl_private float *pdf,
|
||||
ccl_private uint *lcg_state,
|
||||
ccl_private float2 *sampled_roughness,
|
||||
ccl_private float *eta)
|
||||
{
|
||||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
|
||||
float3 X, Y, Z;
|
||||
Z = bsdf->N;
|
||||
|
||||
/* Ensure that the view direction is on the outside w.r.t. the shading normal. */
|
||||
if (dot(Z, wi) <= 0.0f) {
|
||||
*pdf = 0.0f;
|
||||
return LABEL_NONE;
|
||||
}
|
||||
|
||||
/* Special case: Extremely low roughness.
|
||||
* Don't bother with microfacets, just do specular reflection. */
|
||||
if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) {
|
||||
*wo = 2 * dot(Z, wi) * Z - wi;
|
||||
if (dot(Ng, *wo) <= 0.0f) {
|
||||
*pdf = 0.0f;
|
||||
return LABEL_NONE;
|
||||
}
|
||||
*pdf = 1e6f;
|
||||
*eval = make_spectrum(1e6f);
|
||||
return LABEL_REFLECT | LABEL_SINGULAR;
|
||||
}
|
||||
|
||||
Spectrum color, cspec0;
|
||||
bool use_fresnel;
|
||||
if (bsdf->fresnel_type == MicrofacetFresnel::PRINCIPLED_V1) {
|
||||
ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *)bsdf->fresnel;
|
||||
use_fresnel = true;
|
||||
color = fresnel->color;
|
||||
cspec0 = fresnel->cspec0;
|
||||
}
|
||||
else {
|
||||
kernel_assert(bsdf->fresnel_type == MicrofacetFresnel::CONSTANT);
|
||||
ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)bsdf->fresnel;
|
||||
use_fresnel = false;
|
||||
color = fresnel->color;
|
||||
cspec0 = zero_spectrum();
|
||||
}
|
||||
|
||||
*eta = bsdf->ior;
|
||||
*sampled_roughness = make_float2(bsdf->alpha_x, bsdf->alpha_y);
|
||||
|
||||
bool is_aniso = (bsdf->alpha_x != bsdf->alpha_y);
|
||||
if (is_aniso)
|
||||
make_orthonormals_tangent(Z, bsdf->T, &X, &Y);
|
||||
else
|
||||
make_orthonormals(Z, &X, &Y);
|
||||
|
||||
float3 local_I = make_float3(dot(wi, X), dot(wi, Y), dot(wi, Z));
|
||||
float3 local_O;
|
||||
|
||||
*eval = mf_sample_glossy(local_I,
|
||||
&local_O,
|
||||
color,
|
||||
bsdf->alpha_x,
|
||||
bsdf->alpha_y,
|
||||
lcg_state,
|
||||
bsdf->ior,
|
||||
use_fresnel,
|
||||
cspec0);
|
||||
*wo = X * local_O.x + Y * local_O.y + Z * local_O.z;
|
||||
|
||||
/* Ensure that the light direction is on the outside w.r.t. the geometry normal. */
|
||||
if (dot(Ng, *wo) <= 0.0f) {
|
||||
*pdf = 0.0f;
|
||||
return LABEL_NONE;
|
||||
}
|
||||
|
||||
if (is_aniso)
|
||||
*pdf = mf_ggx_aniso_pdf(local_I, local_O, make_float2(bsdf->alpha_x, bsdf->alpha_y));
|
||||
else
|
||||
*pdf = mf_ggx_pdf(local_I, local_O, bsdf->alpha_x);
|
||||
*pdf = fmaxf(0.f, *pdf);
|
||||
*eval *= *pdf;
|
||||
|
||||
return LABEL_REFLECT | LABEL_GLOSSY;
|
||||
}
|
||||
|
||||
/* Multi-scattering GGX Glass closure */
|
||||
|
||||
ccl_device int bsdf_microfacet_multi_ggx_glass_setup(ccl_private MicrofacetBsdf *bsdf)
|
||||
{
|
||||
bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
|
||||
bsdf->alpha_y = bsdf->alpha_x;
|
||||
bsdf->ior = max(0.0f, bsdf->ior);
|
||||
|
||||
ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)bsdf->fresnel;
|
||||
fresnel->color = saturate(fresnel->color);
|
||||
|
||||
bsdf->fresnel_type = MicrofacetFresnel::CONSTANT;
|
||||
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
|
||||
|
||||
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG | SD_BSDF_HAS_TRANSMISSION;
|
||||
}
|
||||
|
||||
ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(ccl_private MicrofacetBsdf *bsdf,
|
||||
ccl_private const ShaderData *sd)
|
||||
{
|
||||
bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
|
||||
bsdf->alpha_y = bsdf->alpha_x;
|
||||
bsdf->ior = max(0.0f, bsdf->ior);
|
||||
|
||||
ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *)bsdf->fresnel;
|
||||
fresnel->color = saturate(fresnel->color);
|
||||
fresnel->cspec0 = saturate(fresnel->cspec0);
|
||||
|
||||
bsdf->fresnel_type = MicrofacetFresnel::PRINCIPLED_V1;
|
||||
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
|
||||
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG;
|
||||
}
|
||||
|
||||
ccl_device Spectrum bsdf_microfacet_multi_ggx_glass_eval(ccl_private const ShaderClosure *sc,
|
||||
const float3 wi,
|
||||
const float3 wo,
|
||||
ccl_private float *pdf,
|
||||
ccl_private uint *lcg_state)
|
||||
{
|
||||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
|
||||
if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) {
|
||||
*pdf = 0.0f;
|
||||
return zero_spectrum();
|
||||
}
|
||||
|
||||
float3 X, Y, Z;
|
||||
Z = bsdf->N;
|
||||
make_orthonormals(Z, &X, &Y);
|
||||
|
||||
float3 local_I = make_float3(dot(wi, X), dot(wi, Y), dot(wi, Z));
|
||||
float3 local_O = make_float3(dot(wo, X), dot(wo, Y), dot(wo, Z));
|
||||
|
||||
const bool is_transmission = local_O.z < 0.0f;
|
||||
|
||||
Spectrum color, cspec0;
|
||||
bool use_fresnel;
|
||||
if (bsdf->fresnel_type == MicrofacetFresnel::PRINCIPLED_V1) {
|
||||
ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *)bsdf->fresnel;
|
||||
use_fresnel = true;
|
||||
color = fresnel->color;
|
||||
cspec0 = is_transmission ? fresnel->color : fresnel->cspec0;
|
||||
}
|
||||
else {
|
||||
kernel_assert(bsdf->fresnel_type == MicrofacetFresnel::CONSTANT);
|
||||
ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)bsdf->fresnel;
|
||||
use_fresnel = false;
|
||||
color = fresnel->color;
|
||||
cspec0 = zero_spectrum();
|
||||
}
|
||||
|
||||
*pdf = mf_glass_pdf(local_I, local_O, bsdf->alpha_x, bsdf->ior);
|
||||
kernel_assert(*pdf >= 0.f);
|
||||
return mf_eval_glass(local_I,
|
||||
local_O,
|
||||
!is_transmission,
|
||||
color,
|
||||
bsdf->alpha_x,
|
||||
bsdf->alpha_y,
|
||||
lcg_state,
|
||||
bsdf->ior,
|
||||
!is_transmission && use_fresnel,
|
||||
cspec0);
|
||||
}
|
||||
|
||||
ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals kg,
|
||||
ccl_private const ShaderClosure *sc,
|
||||
float3 Ng,
|
||||
float3 wi,
|
||||
float randu,
|
||||
float randv,
|
||||
ccl_private Spectrum *eval,
|
||||
ccl_private float3 *wo,
|
||||
ccl_private float *pdf,
|
||||
ccl_private uint *lcg_state,
|
||||
ccl_private float2 *sampled_roughness,
|
||||
ccl_private float *eta)
|
||||
{
|
||||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
|
||||
float3 X, Y, Z;
|
||||
Z = bsdf->N;
|
||||
|
||||
*eta = bsdf->ior;
|
||||
*sampled_roughness = make_float2(bsdf->alpha_x, bsdf->alpha_y);
|
||||
|
||||
if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) {
|
||||
float3 T;
|
||||
bool inside;
|
||||
float fresnel = fresnel_dielectric(bsdf->ior, Z, wi, &T, &inside);
|
||||
|
||||
*pdf = 1e6f;
|
||||
*eval = make_spectrum(1e6f);
|
||||
if (randu < fresnel) {
|
||||
*wo = 2 * dot(Z, wi) * Z - wi;
|
||||
return LABEL_REFLECT | LABEL_SINGULAR;
|
||||
}
|
||||
else {
|
||||
*wo = T;
|
||||
return LABEL_TRANSMIT | LABEL_SINGULAR;
|
||||
}
|
||||
}
|
||||
|
||||
Spectrum color, cspec0;
|
||||
bool use_fresnel;
|
||||
if (bsdf->fresnel_type == MicrofacetFresnel::PRINCIPLED_V1) {
|
||||
ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *)bsdf->fresnel;
|
||||
use_fresnel = true;
|
||||
color = fresnel->color;
|
||||
cspec0 = fresnel->cspec0;
|
||||
}
|
||||
else {
|
||||
kernel_assert(bsdf->fresnel_type == MicrofacetFresnel::CONSTANT);
|
||||
ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)bsdf->fresnel;
|
||||
use_fresnel = false;
|
||||
color = fresnel->color;
|
||||
cspec0 = zero_spectrum();
|
||||
}
|
||||
|
||||
make_orthonormals(Z, &X, &Y);
|
||||
|
||||
float3 local_I = make_float3(dot(wi, X), dot(wi, Y), dot(wi, Z));
|
||||
float3 local_O;
|
||||
|
||||
*eval = mf_sample_glass(local_I,
|
||||
&local_O,
|
||||
color,
|
||||
bsdf->alpha_x,
|
||||
bsdf->alpha_y,
|
||||
lcg_state,
|
||||
bsdf->ior,
|
||||
use_fresnel,
|
||||
cspec0);
|
||||
*pdf = mf_glass_pdf(local_I, local_O, bsdf->alpha_x, bsdf->ior);
|
||||
kernel_assert(*pdf >= 0.f);
|
||||
*eval *= *pdf;
|
||||
|
||||
*wo = X * local_O.x + Y * local_O.y + Z * local_O.z;
|
||||
if (local_O.z * local_I.z > 0.0f) {
|
||||
return LABEL_REFLECT | LABEL_GLOSSY;
|
||||
}
|
||||
else {
|
||||
return LABEL_TRANSMIT | LABEL_GLOSSY;
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
|
@ -1,250 +0,0 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright 2011-2022 Blender Foundation */
|
||||
|
||||
/* 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_forceinline Spectrum MF_FUNCTION_FULL_NAME(mf_eval)(float3 wi,
|
||||
float3 wo,
|
||||
const bool wo_outside,
|
||||
const Spectrum color,
|
||||
const float alpha_x,
|
||||
const float alpha_y,
|
||||
ccl_private uint *lcg_state,
|
||||
const float eta,
|
||||
bool use_fresnel,
|
||||
const Spectrum cspec0)
|
||||
{
|
||||
/* 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 zero_spectrum();
|
||||
|
||||
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. */
|
||||
Spectrum eval;
|
||||
Spectrum throughput = one_spectrum();
|
||||
const float3 wh = normalize(wi + wo);
|
||||
#ifdef MF_MULTI_GLASS
|
||||
eval = mf_eval_phase_glass(-wi, lambda_r, wo, wo_outside, alpha, eta);
|
||||
if (wo_outside)
|
||||
eval *= -lambda_r / (shadowing_lambda - lambda_r);
|
||||
else
|
||||
eval *= -lambda_r * beta(-lambda_r, shadowing_lambda + 1.0f);
|
||||
#else /* MF_MULTI_GLOSSY */
|
||||
const float G2 = 1.0f / (1.0f - (lambda_r + 1.0f) + shadowing_lambda);
|
||||
float val = G2 * 0.25f / wi.z;
|
||||
if (alpha.x == alpha.y)
|
||||
val *= D_ggx(wh, alpha.x);
|
||||
else
|
||||
val *= D_ggx_aniso(wh, alpha);
|
||||
eval = make_spectrum(val);
|
||||
#endif
|
||||
|
||||
if (use_fresnel) {
|
||||
throughput = interpolate_fresnel_color(wi, wh, eta, cspec0);
|
||||
|
||||
eval *= throughput;
|
||||
}
|
||||
|
||||
float3 wr = -wi;
|
||||
float hr = 1.0f;
|
||||
float C1_r = 1.0f;
|
||||
float G1_r = 0.0f;
|
||||
bool outside = true;
|
||||
|
||||
for (int order = 0; order < 10; order++) {
|
||||
/* Sample microfacet height. */
|
||||
float height_rand = lcg_step_float(lcg_state);
|
||||
if (!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, height_rand))
|
||||
break;
|
||||
/* Sample microfacet normal. */
|
||||
float vndf_rand_y = lcg_step_float(lcg_state);
|
||||
float vndf_rand_x = lcg_step_float(lcg_state);
|
||||
float3 wm = mf_sample_vndf(-wr, alpha, vndf_rand_x, vndf_rand_y);
|
||||
|
||||
#ifdef MF_MULTI_GLASS
|
||||
if (order == 0 && use_fresnel) {
|
||||
/* Evaluate amount of scattering towards wo on this microfacet. */
|
||||
Spectrum phase;
|
||||
if (outside)
|
||||
phase = mf_eval_phase_glass(wr, lambda_r, wo, wo_outside, alpha, eta);
|
||||
else
|
||||
phase = mf_eval_phase_glass(wr, lambda_r, -wo, !wo_outside, alpha, 1.0f / eta);
|
||||
|
||||
eval = throughput * phase *
|
||||
mf_G1(wo_outside ? wo : -wo,
|
||||
mf_C1((outside == wo_outside) ? hr : -hr),
|
||||
shadowing_lambda);
|
||||
}
|
||||
#endif
|
||||
if (order > 0) {
|
||||
/* Evaluate amount of scattering towards wo on this microfacet. */
|
||||
Spectrum phase;
|
||||
#ifdef MF_MULTI_GLASS
|
||||
if (outside)
|
||||
phase = mf_eval_phase_glass(wr, lambda_r, wo, wo_outside, alpha, eta);
|
||||
else
|
||||
phase = mf_eval_phase_glass(wr, lambda_r, -wo, !wo_outside, alpha, 1.0f / eta);
|
||||
#else /* MF_MULTI_GLOSSY */
|
||||
phase = mf_eval_phase_glossy(wr, lambda_r, wo, alpha) * throughput;
|
||||
#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;
|
||||
float3 wi_prev = -wr;
|
||||
float phase_rand = lcg_step_float(lcg_state);
|
||||
wr = mf_sample_phase_glass(-wr, outside ? eta : 1.0f / eta, wm, phase_rand, &next_outside);
|
||||
if (!next_outside) {
|
||||
outside = !outside;
|
||||
wr = -wr;
|
||||
hr = -hr;
|
||||
}
|
||||
|
||||
if (use_fresnel && !next_outside) {
|
||||
throughput *= color;
|
||||
}
|
||||
else if (use_fresnel && order > 0) {
|
||||
throughput *= interpolate_fresnel_color(wi_prev, wm, eta, cspec0);
|
||||
}
|
||||
#else /* MF_MULTI_GLOSSY */
|
||||
if (use_fresnel && order > 0) {
|
||||
throughput *= interpolate_fresnel_color(-wr, wm, eta, cspec0);
|
||||
}
|
||||
wr = mf_sample_phase_glossy(-wr, &throughput, wm);
|
||||
#endif
|
||||
|
||||
lambda_r = mf_lambda(wr, alpha);
|
||||
|
||||
if (!use_fresnel)
|
||||
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_forceinline Spectrum MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi,
|
||||
ccl_private float3 *wo,
|
||||
const Spectrum color,
|
||||
const float alpha_x,
|
||||
const float alpha_y,
|
||||
ccl_private uint *lcg_state,
|
||||
const float eta,
|
||||
bool use_fresnel,
|
||||
const Spectrum cspec0)
|
||||
{
|
||||
const float2 alpha = make_float2(alpha_x, alpha_y);
|
||||
|
||||
Spectrum throughput = one_spectrum();
|
||||
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. */
|
||||
float height_rand = lcg_step_float(lcg_state);
|
||||
if (!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, height_rand)) {
|
||||
/* The random walk has left the surface. */
|
||||
*wo = outside ? wr : -wr;
|
||||
return throughput;
|
||||
}
|
||||
/* Sample microfacet normal. */
|
||||
float vndf_rand_y = lcg_step_float(lcg_state);
|
||||
float vndf_rand_x = lcg_step_float(lcg_state);
|
||||
float3 wm = mf_sample_vndf(-wr, alpha, vndf_rand_x, vndf_rand_y);
|
||||
|
||||
/* First-bounce color is already accounted for in mix weight. */
|
||||
if (!use_fresnel && order > 0)
|
||||
throughput *= color;
|
||||
|
||||
/* Bounce from the microfacet. */
|
||||
#ifdef MF_MULTI_GLASS
|
||||
bool next_outside;
|
||||
float3 wi_prev = -wr;
|
||||
float phase_rand = lcg_step_float(lcg_state);
|
||||
wr = mf_sample_phase_glass(-wr, outside ? eta : 1.0f / eta, wm, phase_rand, &next_outside);
|
||||
if (!next_outside) {
|
||||
hr = -hr;
|
||||
wr = -wr;
|
||||
outside = !outside;
|
||||
}
|
||||
|
||||
if (use_fresnel) {
|
||||
if (!next_outside) {
|
||||
throughput *= color;
|
||||
}
|
||||
else {
|
||||
throughput *= interpolate_fresnel_color(wi_prev, wm, eta, cspec0);
|
||||
}
|
||||
}
|
||||
#else /* MF_MULTI_GLOSSY */
|
||||
if (use_fresnel) {
|
||||
throughput *= interpolate_fresnel_color(-wr, wm, eta, cspec0);
|
||||
}
|
||||
wr = mf_sample_phase_glossy(-wr, &throughput, wm);
|
||||
#endif
|
||||
|
||||
/* Update random walk parameters. */
|
||||
lambda_r = mf_lambda(wr, alpha);
|
||||
G1_r = mf_G1(wr, C1_r, lambda_r);
|
||||
}
|
||||
*wo = make_float3(0.0f, 0.0f, 1.0f);
|
||||
return zero_spectrum();
|
||||
}
|
||||
|
||||
#undef MF_MULTI_GLASS
|
||||
#undef MF_MULTI_GLOSSY
|
||||
#undef MF_PHASE_FUNCTION
|
|
@ -81,6 +81,11 @@ ccl_device float ior_from_F0(Spectrum f0)
|
|||
return (1.0f + sqrt_f0) / (1.0f - sqrt_f0);
|
||||
}
|
||||
|
||||
ccl_device float F0_from_ior(float ior)
|
||||
{
|
||||
return sqr((ior - 1.0f) / (ior + 1.0f));
|
||||
}
|
||||
|
||||
ccl_device float schlick_fresnel(float u)
|
||||
{
|
||||
float m = clamp(1.0f - u, 0.0f, 1.0f);
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "kernel/closure/bsdf_ashikhmin_velvet.h"
|
||||
#include "kernel/closure/bsdf_diffuse.h"
|
||||
#include "kernel/closure/bsdf_microfacet.h"
|
||||
#include "kernel/closure/bsdf_microfacet_multi.h"
|
||||
#include "kernel/closure/bsdf_oren_nayar.h"
|
||||
#include "kernel/closure/bsdf_transparent.h"
|
||||
#include "kernel/closure/bsdf_ashikhmin_shirley.h"
|
||||
|
|
|
@ -261,9 +261,9 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
|
|||
|
||||
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
|
||||
sd, sizeof(MicrofacetBsdf), spec_weight);
|
||||
ccl_private FresnelPrincipledV1 *fresnel =
|
||||
(bsdf != NULL) ? (ccl_private FresnelPrincipledV1 *)closure_alloc_extra(
|
||||
sd, sizeof(FresnelPrincipledV1)) :
|
||||
ccl_private FresnelGeneralizedSchlick *fresnel =
|
||||
(bsdf != NULL) ? (ccl_private FresnelGeneralizedSchlick *)closure_alloc_extra(
|
||||
sd, sizeof(FresnelGeneralizedSchlick)) :
|
||||
NULL;
|
||||
|
||||
if (bsdf && fresnel) {
|
||||
|
@ -283,21 +283,18 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
|
|||
one_float3(); // normalize lum. to isolate hue+sat
|
||||
float3 tmp_col = make_float3(1.0f - specular_tint) + m_ctint * specular_tint;
|
||||
|
||||
fresnel->cspec0 = rgb_to_spectrum((specular * 0.08f * tmp_col) * (1.0f - metallic) +
|
||||
fresnel->f0 = rgb_to_spectrum((specular * 0.08f * tmp_col) * (1.0f - metallic) +
|
||||
base_color * metallic);
|
||||
fresnel->color = rgb_to_spectrum(base_color);
|
||||
fresnel->f90 = one_spectrum();
|
||||
fresnel->exponent = -1.0f;
|
||||
fresnel->reflection_tint = one_spectrum();
|
||||
fresnel->transmission_tint = zero_spectrum();
|
||||
|
||||
/* setup bsdf */
|
||||
|
||||
/* Use single-scatter GGX. */
|
||||
if (distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID || roughness <= 0.075f) {
|
||||
sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
|
||||
bsdf_microfacet_setup_fresnel_principledv1(bsdf, sd, fresnel);
|
||||
} /* Use multi-scatter GGX. */
|
||||
else {
|
||||
|
||||
bsdf->fresnel = fresnel;
|
||||
sd->flag |= bsdf_microfacet_multi_ggx_fresnel_setup(bsdf, sd);
|
||||
bsdf_microfacet_setup_fresnel_generalized_schlick(bsdf, sd, fresnel);
|
||||
if (distribution == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) {
|
||||
/* TODO: Energy preservation */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -327,9 +324,9 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
|
|||
{
|
||||
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
|
||||
sd, sizeof(MicrofacetBsdf), glass_weight * fresnel);
|
||||
ccl_private FresnelPrincipledV1 *fresnel =
|
||||
(bsdf != NULL) ? (ccl_private FresnelPrincipledV1 *)closure_alloc_extra(
|
||||
sd, sizeof(FresnelPrincipledV1)) :
|
||||
ccl_private FresnelGeneralizedSchlick *fresnel =
|
||||
(bsdf != NULL) ? (ccl_private FresnelGeneralizedSchlick *)closure_alloc_extra(
|
||||
sd, sizeof(FresnelGeneralizedSchlick)) :
|
||||
NULL;
|
||||
|
||||
if (bsdf && fresnel) {
|
||||
|
@ -344,9 +341,13 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
|
|||
/* setup bsdf */
|
||||
sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
|
||||
|
||||
fresnel->color = rgb_to_spectrum(base_color);
|
||||
fresnel->cspec0 = rgb_to_spectrum(cspec0);
|
||||
bsdf_microfacet_setup_fresnel_principledv1(bsdf, sd, fresnel);
|
||||
fresnel->f0 = cspec0;
|
||||
fresnel->f90 = one_spectrum();
|
||||
fresnel->exponent = -1.0f;
|
||||
fresnel->reflection_tint = one_spectrum();
|
||||
fresnel->transmission_tint = zero_spectrum();
|
||||
|
||||
bsdf_microfacet_setup_fresnel_generalized_schlick(bsdf, sd, fresnel);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -384,9 +385,9 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
|
|||
else {
|
||||
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
|
||||
sd, sizeof(MicrofacetBsdf), glass_weight);
|
||||
ccl_private FresnelPrincipledV1 *fresnel =
|
||||
(bsdf != NULL) ? (ccl_private FresnelPrincipledV1 *)closure_alloc_extra(
|
||||
sd, sizeof(FresnelPrincipledV1)) :
|
||||
ccl_private FresnelGeneralizedSchlick *fresnel =
|
||||
(bsdf != NULL) ? (ccl_private FresnelGeneralizedSchlick *)closure_alloc_extra(
|
||||
sd, sizeof(FresnelGeneralizedSchlick)) :
|
||||
NULL;
|
||||
|
||||
if (bsdf && fresnel) {
|
||||
|
@ -398,11 +399,16 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
|
|||
bsdf->alpha_y = roughness * roughness;
|
||||
bsdf->ior = ior;
|
||||
|
||||
fresnel->color = rgb_to_spectrum(base_color);
|
||||
fresnel->cspec0 = rgb_to_spectrum(cspec0);
|
||||
fresnel->f0 = make_spectrum(F0_from_ior(ior));
|
||||
fresnel->f90 = one_spectrum();
|
||||
fresnel->exponent = -1.0f;
|
||||
fresnel->reflection_tint = cspec0;
|
||||
fresnel->transmission_tint = base_color;
|
||||
|
||||
/* setup bsdf */
|
||||
sd->flag |= bsdf_microfacet_multi_ggx_glass_fresnel_setup(bsdf, sd);
|
||||
sd->flag |= bsdf_microfacet_ggx_glass_setup(bsdf);
|
||||
bsdf_microfacet_setup_fresnel_generalized_schlick(bsdf, sd, fresnel);
|
||||
/* TODO: Energy preservation */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -525,20 +531,15 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
|
|||
sd->flag |= bsdf_reflection_setup(bsdf);
|
||||
else if (type == CLOSURE_BSDF_MICROFACET_BECKMANN_ID)
|
||||
sd->flag |= bsdf_microfacet_beckmann_setup(bsdf);
|
||||
else if (type == CLOSURE_BSDF_MICROFACET_GGX_ID)
|
||||
sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
|
||||
else if (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) {
|
||||
kernel_assert(stack_valid(data_node.w));
|
||||
ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)closure_alloc_extra(
|
||||
sd, sizeof(FresnelConstant));
|
||||
if (fresnel) {
|
||||
bsdf->fresnel = fresnel;
|
||||
fresnel->color = rgb_to_spectrum(stack_load_float3(stack, data_node.w));
|
||||
sd->flag |= bsdf_microfacet_multi_ggx_setup(bsdf);
|
||||
}
|
||||
else if (type == CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID) {
|
||||
sd->flag |= bsdf_ashikhmin_shirley_setup(bsdf);
|
||||
}
|
||||
else {
|
||||
sd->flag |= bsdf_ashikhmin_shirley_setup(bsdf);
|
||||
sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
|
||||
if (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) {
|
||||
kernel_assert(stack_valid(data_node.w));
|
||||
/* TODO: Color multiplier and energy preservation */
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -587,7 +588,8 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
|
|||
}
|
||||
case CLOSURE_BSDF_SHARP_GLASS_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID: {
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: {
|
||||
#ifdef __CAUSTICS_TRICKS__
|
||||
if (!kernel_data.integrator.caustics_reflective &&
|
||||
!kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE))
|
||||
|
@ -621,47 +623,16 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
|
|||
|
||||
if (type == CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID)
|
||||
sd->flag |= bsdf_microfacet_beckmann_glass_setup(bsdf);
|
||||
else
|
||||
else {
|
||||
sd->flag |= bsdf_microfacet_ggx_glass_setup(bsdf);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: {
|
||||
#ifdef __CAUSTICS_TRICKS__
|
||||
if (!kernel_data.integrator.caustics_reflective &&
|
||||
!kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE))
|
||||
break;
|
||||
#endif
|
||||
Spectrum weight = sd->svm_closure_weight * mix_weight;
|
||||
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
|
||||
sd, sizeof(MicrofacetBsdf), weight);
|
||||
if (!bsdf) {
|
||||
break;
|
||||
}
|
||||
|
||||
ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)closure_alloc_extra(
|
||||
sd, sizeof(FresnelConstant));
|
||||
if (!fresnel) {
|
||||
break;
|
||||
}
|
||||
|
||||
bsdf->N = maybe_ensure_valid_specular_reflection(sd, N);
|
||||
bsdf->fresnel = fresnel;
|
||||
bsdf->T = zero_float3();
|
||||
|
||||
float roughness = sqr(param1);
|
||||
bsdf->alpha_x = roughness;
|
||||
bsdf->alpha_y = roughness;
|
||||
float eta = fmaxf(param2, 1e-5f);
|
||||
bsdf->ior = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta;
|
||||
|
||||
if (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) {
|
||||
kernel_assert(stack_valid(data_node.z));
|
||||
fresnel->color = rgb_to_spectrum(stack_load_float3(stack, data_node.z));
|
||||
/* TODO: Color multiplier and energy preservation */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* setup bsdf */
|
||||
sd->flag |= bsdf_microfacet_multi_ggx_glass_setup(bsdf);
|
||||
break;
|
||||
}
|
||||
case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: {
|
||||
|
|
|
@ -423,7 +423,7 @@ typedef enum ClosureType {
|
|||
CLOSURE_BSDF_MICROFACET_GGX_ID,
|
||||
CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID,
|
||||
CLOSURE_BSDF_MICROFACET_BECKMANN_ID,
|
||||
CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID,
|
||||
CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID, /* virtual closure */
|
||||
CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID,
|
||||
CLOSURE_BSDF_ASHIKHMIN_VELVET_ID,
|
||||
CLOSURE_BSDF_PHONG_RAMP_ID,
|
||||
|
@ -437,7 +437,7 @@ typedef enum ClosureType {
|
|||
CLOSURE_BSDF_SHARP_GLASS_ID,
|
||||
CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID,
|
||||
CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID,
|
||||
CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID,
|
||||
CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID, /* virtual closure */
|
||||
CLOSURE_BSDF_HAIR_PRINCIPLED_ID,
|
||||
CLOSURE_BSDF_HAIR_TRANSMISSION_ID,
|
||||
|
||||
|
|
|
@ -2350,7 +2350,7 @@ NODE_DEFINE(GlossyBsdfNode)
|
|||
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
|
||||
distribution_enum.insert("ggx", CLOSURE_BSDF_MICROFACET_GGX_ID);
|
||||
distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
|
||||
distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
|
||||
distribution_enum.insert("multi_ggx", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
|
||||
SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID);
|
||||
|
||||
SOCKET_IN_VECTOR(tangent, "Tangent", zero_float3(), SocketType::LINK_TANGENT);
|
||||
|
@ -2444,6 +2444,7 @@ void GlossyBsdfNode::compile(SVMCompiler &compiler)
|
|||
|
||||
if (closure == CLOSURE_BSDF_REFLECTION_ID)
|
||||
BsdfNode::compile(compiler, NULL, NULL);
|
||||
/* TODO: Just use weight for legacy MultiGGX? Would also simplify OSL. */
|
||||
else if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID)
|
||||
BsdfNode::compile(
|
||||
compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color"));
|
||||
|
@ -2471,7 +2472,7 @@ NODE_DEFINE(GlassBsdfNode)
|
|||
distribution_enum.insert("sharp", CLOSURE_BSDF_SHARP_GLASS_ID);
|
||||
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
|
||||
distribution_enum.insert("ggx", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
|
||||
distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
|
||||
distribution_enum.insert("multi_ggx", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
|
||||
SOCKET_ENUM(
|
||||
distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
|
||||
SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
|
||||
|
@ -2750,7 +2751,7 @@ NODE_DEFINE(PrincipledBsdfNode)
|
|||
|
||||
static NodeEnum distribution_enum;
|
||||
distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
|
||||
distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
|
||||
distribution_enum.insert("multi_ggx", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
|
||||
SOCKET_ENUM(
|
||||
distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
|
||||
|
||||
|
|
Loading…
Reference in New Issue