Cycles: Cleanup MultiGGX closure implementation

The implementation originally handled four different cases:
Regular glossy, glass, metallic fresnel glossy and diffuse.

However, only the first two are actually used currently. Therefore, this commit
removes the other two, which allows to simplify the code.

Additionally, due to the Principled BSDF, the function arguments are now
identical for glossy and glass, which allows to get rid of some ugly #ifdefs.
This commit is contained in:
Lukas Stockner 2017-05-14 21:17:32 +02:00
parent 6bf05ab2ca
commit 9586cc4708
2 changed files with 34 additions and 128 deletions

View File

@ -91,18 +91,15 @@ ccl_device_forceinline float3 mf_sample_vndf(const float3 wi, const float2 alpha
return normalize(make_float3(-slope_x, -slope_y, 1.0f));
}
/* === Phase functions: Glossy, Diffuse and Glass === */
/* === Phase functions: Glossy and Glass === */
/* Phase function for reflective materials, either without a fresnel term (for compatibility) or with the conductive fresnel term. */
ccl_device_forceinline float3 mf_sample_phase_glossy(const float3 wi, float3 *n, float3 *k, float3 *weight, const float3 wm)
/* Phase function for reflective materials. */
ccl_device_forceinline float3 mf_sample_phase_glossy(const float3 wi, 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_forceinline float3 mf_eval_phase_glossy(const float3 w, const float lambda, const float3 wo, const float2 alpha, float3 *n, float3 *k)
ccl_device_forceinline float3 mf_eval_phase_glossy(const float3 w, const float lambda, const float3 wo, const float2 alpha)
{
if(w.z > 0.9999f)
return make_float3(0.0f, 0.0f, 0.0f);
@ -123,30 +120,9 @@ ccl_device_forceinline float3 mf_eval_phase_glossy(const float3 w, const float l
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_forceinline 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_forceinline 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_forceinline float3 mf_sample_phase_glass(const float3 wi, const float eta, const float3 wm, const float randV, bool *outside)
{
@ -282,11 +258,6 @@ ccl_device_forceinline float mf_ggx_aniso_pdf(const float3 wi, const float3 wo,
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_forceinline float mf_diffuse_pdf(const float3 wo)
{
return M_1_PI_F * wo.z;
}
ccl_device_forceinline float mf_glass_pdf(const float3 wi, const float3 wo, const float alpha, const float eta)
{
float3 wh;
@ -315,13 +286,6 @@ ccl_device_forceinline float mf_glass_pdf(const float3 wi, const float3 wo, cons
#define MF_MULTI_GLASS
#include "kernel/closure/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 "kernel/closure/bsdf_microfacet_multi_impl.h"
#endif
#define MF_PHASE_FUNCTION glossy
#define MF_MULTI_GLOSSY
#include "kernel/closure/bsdf_microfacet_multi_impl.h"
@ -428,7 +392,7 @@ ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(const ShaderClosure *sc
*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, bsdf->ior, use_fresnel, bsdf->extra->cspec0);
return mf_eval_glossy(localI, localO, true, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior, use_fresnel, bsdf->extra->cspec0);
}
ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf, ccl_addr_space uint *lcg_state)
@ -456,7 +420,7 @@ ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, const ShaderC
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, bsdf->ior, use_fresnel, bsdf->extra->cspec0);
*eval = mf_sample_glossy(localI, &localO, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior, use_fresnel, bsdf->extra->cspec0);
if(is_aniso)
*pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(bsdf->alpha_x, bsdf->alpha_y));
else

View File

@ -26,24 +26,16 @@
* the balance heuristic isn't necessarily optimal anymore.
*/
ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(
float3 wi,
float3 wo,
const bool wo_outside,
const float3 color,
const float alpha_x,
const float alpha_y,
ccl_addr_space uint *lcg_state
#ifdef MF_MULTI_GLASS
, const float eta
, bool use_fresnel
, const float3 cspec0
#elif defined(MF_MULTI_GLOSSY)
, float3 *n, float3 *k
, const float eta
, bool use_fresnel
, const float3 cspec0
#endif
)
float3 wi,
float3 wo,
const bool wo_outside,
const float3 color,
const float alpha_x,
const float alpha_y,
ccl_addr_space uint *lcg_state,
const float eta,
bool use_fresnel,
const float3 cspec0)
{
/* Evaluating for a shallower incoming direction produces less noise, and the properties of the BSDF guarantee reciprocity. */
bool swapped = false;
@ -77,44 +69,29 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(
/* Analytically compute single scattering for lower noise. */
float3 eval;
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
const float3 wh = normalize(wi+wo);
#ifdef MF_MULTI_GLASS
eval = mf_eval_phase_glass(-wi, lambda_r, wo, wo_outside, alpha, eta);
if(wo_outside)
eval *= -lambda_r / (shadowing_lambda - lambda_r);
else
eval *= -lambda_r * beta(-lambda_r, shadowing_lambda+1.0f);
float F0 = fresnel_dielectric_cos(1.0f, eta);
if(use_fresnel) {
throughput = interpolate_fresnel_color(wi, normalize(wi + wo), eta, F0, cspec0);
eval *= throughput;
}
#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);
}
eval = make_float3(val, val, val);
#endif
float F0 = fresnel_dielectric_cos(1.0f, eta);
if(use_fresnel) {
throughput = interpolate_fresnel_color(wi, wh, eta, F0, cspec0);
eval = throughput * val;
eval *= throughput;
}
#endif
float3 wr = -wi;
float hr = 1.0f;
@ -129,13 +106,6 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(
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
#ifdef MF_MULTI_GLASS
if(order == 0 && use_fresnel) {
/* Evaluate amount of scattering towards wo on this microfacet. */
@ -156,10 +126,8 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(
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;
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);
}
@ -181,25 +149,17 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(
else if(use_fresnel && order > 0) {
throughput *= interpolate_fresnel_color(wi_prev, wm, eta, F0, cspec0);
}
#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 */
if(use_fresnel && order > 0) {
throughput *= interpolate_fresnel_color(-wr, wm, eta, F0, cspec0);
}
wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm);
wr = mf_sample_phase_glossy(-wr, &throughput, wm);
#endif
lambda_r = mf_lambda(wr, alpha);
#if defined(MF_MULTI_GLOSSY) || defined(MF_MULTI_GLASS)
if(!use_fresnel)
throughput *= color;
#else
throughput *= color;
#endif
C1_r = mf_C1(hr);
G1_r = mf_G1(wr, C1_r, lambda_r);
@ -215,18 +175,16 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(
* escaped the surface in wo. The function returns the throughput between wi and wo.
* Without reflection losses due to coloring or fresnel absorption in conductors, the sampling is optimal.
*/
ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3 *wo, const float3 color, const float alpha_x, const float alpha_y, ccl_addr_space uint *lcg_state
#ifdef MF_MULTI_GLASS
, const float eta
, bool use_fresnel
, const float3 cspec0
#elif defined(MF_MULTI_GLOSSY)
, float3 *n, float3 *k
, const float eta
, bool use_fresnel
, const float3 cspec0
#endif
)
ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)(
float3 wi,
float3 *wo,
const float3 color,
const float alpha_x,
const float alpha_y,
ccl_addr_space uint *lcg_state,
const float eta,
bool use_fresnel,
const float3 cspec0)
{
const float2 alpha = make_float2(alpha_x, alpha_y);
@ -237,17 +195,11 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3
float C1_r = 1.0f;
float G1_r = 0.0f;
bool outside = true;
#ifdef MF_MULTI_GLASS
float F0 = fresnel_dielectric_cos(1.0f, eta);
if(use_fresnel) {
throughput = interpolate_fresnel_color(wi, normalize(wi + wr), eta, F0, cspec0);
}
#elif defined(MF_MULTI_GLOSSY)
float F0 = fresnel_dielectric_cos(1.0f, eta);
if(use_fresnel) {
throughput = interpolate_fresnel_color(wi, normalize(wi + wr), eta, F0, cspec0);
}
#endif
int order;
for(order = 0; order < 10; order++) {
@ -262,13 +214,8 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3
lcg_step_float_addrspace(lcg_state)));
/* First-bounce color is already accounted for in mix weight. */
#if defined(MF_MULTI_GLASS) || defined(MF_MULTI_GLOSSY)
if(!use_fresnel && order > 0)
throughput *= color;
#else
if(order > 0)
throughput *= color;
#endif
/* Bounce from the microfacet. */
#ifdef MF_MULTI_GLASS
@ -294,10 +241,6 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3
throughput *= t_color;
}
}
#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 */
if(use_fresnel) {
float3 t_color = interpolate_fresnel_color(-wr, wm, eta, F0, cspec0);
@ -307,7 +250,7 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3
else
throughput *= t_color;
}
wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm);
wr = mf_sample_phase_glossy(-wr, &throughput, wm);
#endif
/* Update random walk parameters. */
@ -319,6 +262,5 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3
}
#undef MF_MULTI_GLASS
#undef MF_MULTI_DIFFUSE
#undef MF_MULTI_GLOSSY
#undef MF_PHASE_FUNCTION