diff options
Diffstat (limited to 'intern/cycles/kernel/closure/bsdf_microfacet_multi.h')
-rw-r--r-- | intern/cycles/kernel/closure/bsdf_microfacet_multi.h | 972 |
1 files changed, 553 insertions, 419 deletions
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h index 2f2c35d5d1f..2cc1a9c5299 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h @@ -23,149 +23,168 @@ CCL_NAMESPACE_BEGIN /* 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); + 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; + 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); + 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 = safe_sqrtf(1.0f - cosI*cosI); - const float tanI = sinI/cosI; - const float projA = 0.5f * (cosI + 1.0f); - if(projA < 0.0001f) - return make_float2(0.0f, 0.0f); - const float A = 2.0f*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); +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 = safe_sqrtf(1.0f - cosI * cosI); + const float tanI = sinI / cosI; + const float projA = 0.5f * (cosI + 1.0f); + if (projA < 0.0001f) + return make_float2(0.0f, 0.0f); + const float A = 2.0f * 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) +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 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); + 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)); + 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, float3 *weight, const float3 wm) +ccl_device_forceinline float3 mf_sample_phase_glossy(const float3 wi, + float3 *weight, + const float3 wm) { - return -wi + 2.0f * wm * dot(wi, wm); + 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) +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); + if (w.z > 0.9999f) + return make_float3(0.0f, 0.0f, 0.0f); - const float3 wh = normalize(wo - w); - if(wh.z < 0.0f) - return make_float3(0.0f, 0.0f, 0.0f); + const float3 wh = normalize(wo - w); + if (wh.z < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); - float pArea = (w.z < -0.9999f)? 1.0f: lambda*w.z; + float pArea = (w.z < -0.9999f) ? 1.0f : lambda * w.z; - const float dotW_WH = dot(-w, wh); - if(dotW_WH < 0.0f) - return make_float3(0.0f, 0.0f, 0.0f); + const float dotW_WH = dot(-w, wh); + if (dotW_WH < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); - float phase = max(0.0f, dotW_WH) * 0.25f / max(pArea * dotW_WH, 1e-7f); - if(alpha.x == alpha.y) - phase *= D_ggx(wh, alpha.x); - else - phase *= D_ggx_aniso(wh, alpha); + 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_float3(phase, phase, phase); + return make_float3(phase, phase, 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, 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 float3 mf_eval_phase_glass(const float3 w, const float lambda, const float3 wo, const bool wo_outside, const float2 alpha, const float eta) -{ - if(w.z > 0.9999f) - return make_float3(0.0f, 0.0f, 0.0f); - - float pArea = (w.z < -0.9999f)? 1.0f: lambda*w.z; - float v; - if(wo_outside) { - const float3 wh = normalize(wo - w); - if(wh.z < 0.0f) - return make_float3(0.0f, 0.0f, 0.0f); - - const float dotW_WH = dot(-w, wh); - v = fresnel_dielectric_cos(dotW_WH, eta) * max(0.0f, dotW_WH) * D_ggx(wh, alpha.x) * 0.25f / (pArea * dotW_WH); - } - else { - float3 wh = normalize(wo*eta - w); - if(wh.z < 0.0f) - wh = -wh; - const float dotW_WH = dot(-w, wh), dotWO_WH = dot(wo, wh); - if(dotW_WH < 0.0f) - return make_float3(0.0f, 0.0f, 0.0f); - - float temp = dotW_WH + eta*dotWO_WH; - v = (1.0f - fresnel_dielectric_cos(dotW_WH, eta)) * max(0.0f, dotW_WH) * max(0.0f, -dotWO_WH) * D_ggx(wh, alpha.x) / (pArea * temp * temp); - } - - return make_float3(v, v, v); +ccl_device_forceinline float3 mf_sample_phase_glass( + const float3 wi, const float eta, const float3 wm, const float randV, bool *outside) +{ + float cosI = dot(wi, wm); + float f = fresnel_dielectric_cos(cosI, eta); + if (randV < f) { + *outside = true; + return -wi + 2.0f * wm * cosI; + } + *outside = false; + float inv_eta = 1.0f / eta; + float cosT = -safe_sqrtf(1.0f - (1.0f - cosI * cosI) * inv_eta * inv_eta); + return normalize(wm * (cosI * inv_eta + cosT) - wi * inv_eta); +} + +ccl_device_forceinline float3 mf_eval_phase_glass(const float3 w, + const float lambda, + const float3 wo, + const bool wo_outside, + const float2 alpha, + const float eta) +{ + if (w.z > 0.9999f) + return make_float3(0.0f, 0.0f, 0.0f); + + float pArea = (w.z < -0.9999f) ? 1.0f : lambda * w.z; + float v; + if (wo_outside) { + const float3 wh = normalize(wo - w); + if (wh.z < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + const float dotW_WH = dot(-w, wh); + v = fresnel_dielectric_cos(dotW_WH, eta) * max(0.0f, dotW_WH) * D_ggx(wh, alpha.x) * 0.25f / + (pArea * dotW_WH); + } + else { + float3 wh = normalize(wo * eta - w); + if (wh.z < 0.0f) + wh = -wh; + const float dotW_WH = dot(-w, wh), dotWO_WH = dot(wo, wh); + if (dotW_WH < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + float temp = dotW_WH + eta * dotWO_WH; + v = (1.0f - fresnel_dielectric_cos(dotW_WH, eta)) * max(0.0f, dotW_WH) * max(0.0f, -dotWO_WH) * + D_ggx(wh, alpha.x) / (pArea * temp * temp); + } + + return make_float3(v, v, v); } /* === Utility functions for the random walks === */ @@ -173,64 +192,65 @@ ccl_device_forceinline float3 mf_eval_phase_glass(const float3 w, const float la /* 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; + 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; + 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); + 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 * saturate(h) - 1.0f; + return 2.0f * saturate(h) - 1.0f; } ccl_device_forceinline float mf_C1(const float h) { - return saturate(0.5f * (h + 1.0f)); + return saturate(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); + 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, float *h, float *C1, float *G1, float *lambda, const float U) -{ - if(w.z > 0.9999f) - return false; - if(w.z < -0.9999f) { - *C1 *= U; - *h = mf_invC1(*C1); - *G1 = mf_G1(w, *C1, *lambda); - } - else if(fabsf(w.z) >= 0.0001f) { - if(U > 1.0f - *G1) - return false; - if(*lambda >= 0.0f) { - *C1 = 1.0f; - } - else { - *C1 *= powf(1.0f-U, -1.0f / *lambda); - } - *h = mf_invC1(*C1); - *G1 = mf_G1(w, *C1, *lambda); - } - return true; +ccl_device_forceinline bool mf_sample_height( + const float3 w, float *h, float *C1, float *G1, float *lambda, const float U) +{ + if (w.z > 0.9999f) + return false; + if (w.z < -0.9999f) { + *C1 *= U; + *h = mf_invC1(*C1); + *G1 = mf_G1(w, *C1, *lambda); + } + else if (fabsf(w.z) >= 0.0001f) { + if (U > 1.0f - *G1) + return false; + if (*lambda >= 0.0f) { + *C1 = 1.0f; + } + else { + *C1 *= powf(1.0f - U, -1.0f / *lambda); + } + *h = mf_invC1(*C1); + *G1 = mf_G1(w, *C1, *lambda); + } + return true; } /* === PDF approximations for the different phase functions. === @@ -240,80 +260,92 @@ ccl_device_forceinline bool mf_sample_height(const float3 w, float *h, float *C1 * 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 saturate(albedo); + float albedo = 0.806495f * expf(-1.98712f * r * r) + 0.199531f; + albedo -= ((((((1.76741f * r - 8.43891f) * r + 15.784f) * r - 14.398f) * r + 6.45221f) * r - + 1.19722f) * + r + + 0.027803f) * + r + + 0.00568739f; + return saturate(albedo); } ccl_device_inline float mf_ggx_transmission_albedo(float a, float ior) { - if(ior < 1.0f) { - ior = 1.0f/ior; - } - a = saturate(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 saturate(1.0f + I_2*R_2*0.0019127f - (1.0f - I_1)*(1.0f - R_1)*9.3205f); + if (ior < 1.0f) { + ior = 1.0f / ior; + } + a = saturate(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 saturate(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 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 multiscatter = wo.z * M_1_PI_F; - float albedo = mf_ggx_albedo(alpha); - return albedo*singlescatter + (1.0f - albedo)*multiscatter; + 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 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 multiscatter = wo.z * M_1_PI_F; - float albedo = mf_ggx_albedo(sqrtf(alpha.x*alpha.y)); - return albedo*singlescatter + (1.0f - albedo)*multiscatter; + 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) +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); - } + 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_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 @@ -326,10 +358,10 @@ ccl_device_forceinline float mf_glass_pdf(const float3 wi, const float3 wo, cons ccl_device void bsdf_microfacet_multi_ggx_blur(ShaderClosure *sc, float roughness) { - MicrofacetBsdf *bsdf = (MicrofacetBsdf*)sc; + MicrofacetBsdf *bsdf = (MicrofacetBsdf *)sc; - bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x); - bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); + bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x); + bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); } /* === Closure implementations === */ @@ -338,293 +370,395 @@ ccl_device void bsdf_microfacet_multi_ggx_blur(ShaderClosure *sc, float roughnes ccl_device int bsdf_microfacet_multi_ggx_common_setup(MicrofacetBsdf *bsdf) { - bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); - bsdf->alpha_y = clamp(bsdf->alpha_y, 1e-4f, 1.0f); - bsdf->extra->color.x = saturate(bsdf->extra->color.x); - bsdf->extra->color.y = saturate(bsdf->extra->color.y); - bsdf->extra->color.z = saturate(bsdf->extra->color.z); - bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); - bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); - bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); + bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); + bsdf->alpha_y = clamp(bsdf->alpha_y, 1e-4f, 1.0f); + bsdf->extra->color.x = saturate(bsdf->extra->color.x); + bsdf->extra->color.y = saturate(bsdf->extra->color.y); + bsdf->extra->color.z = saturate(bsdf->extra->color.z); + bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); + bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); + bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); - return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG; + return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG; } ccl_device int bsdf_microfacet_multi_ggx_aniso_setup(MicrofacetBsdf *bsdf) { - if(is_zero(bsdf->T)) - bsdf->T = make_float3(1.0f, 0.0f, 0.0f); + if (is_zero(bsdf->T)) + bsdf->T = make_float3(1.0f, 0.0f, 0.0f); - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; - return bsdf_microfacet_multi_ggx_common_setup(bsdf); + return bsdf_microfacet_multi_ggx_common_setup(bsdf); } -ccl_device int bsdf_microfacet_multi_ggx_aniso_fresnel_setup(MicrofacetBsdf *bsdf, const ShaderData *sd) +ccl_device int bsdf_microfacet_multi_ggx_aniso_fresnel_setup(MicrofacetBsdf *bsdf, + const ShaderData *sd) { - if(is_zero(bsdf->T)) - bsdf->T = make_float3(1.0f, 0.0f, 0.0f); + if (is_zero(bsdf->T)) + bsdf->T = make_float3(1.0f, 0.0f, 0.0f); - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID; - float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); - float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0)); - bsdf->sample_weight *= F; + float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); + float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0)); + bsdf->sample_weight *= F; - return bsdf_microfacet_multi_ggx_common_setup(bsdf); + return bsdf_microfacet_multi_ggx_common_setup(bsdf); } ccl_device int bsdf_microfacet_multi_ggx_setup(MicrofacetBsdf *bsdf) { - bsdf->alpha_y = bsdf->alpha_x; + bsdf->alpha_y = bsdf->alpha_x; - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; - return bsdf_microfacet_multi_ggx_common_setup(bsdf); + return bsdf_microfacet_multi_ggx_common_setup(bsdf); } ccl_device int bsdf_microfacet_multi_ggx_fresnel_setup(MicrofacetBsdf *bsdf, const ShaderData *sd) { - bsdf->alpha_y = bsdf->alpha_x; + bsdf->alpha_y = bsdf->alpha_x; - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID; - float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); - float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0)); - bsdf->sample_weight *= F; + float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); + float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0)); + bsdf->sample_weight *= F; - return bsdf_microfacet_multi_ggx_common_setup(bsdf); + return bsdf_microfacet_multi_ggx_common_setup(bsdf); } ccl_device int bsdf_microfacet_multi_ggx_refraction_setup(MicrofacetBsdf *bsdf) { - bsdf->alpha_y = bsdf->alpha_x; - - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; + bsdf->alpha_y = bsdf->alpha_x; - return bsdf_microfacet_multi_ggx_common_setup(bsdf); -} + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; -ccl_device float3 bsdf_microfacet_multi_ggx_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { - *pdf = 0.0f; - return make_float3(0.0f, 0.0f, 0.0f); + return bsdf_microfacet_multi_ggx_common_setup(bsdf); } -ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; - - if(bsdf->alpha_x*bsdf->alpha_y < 1e-7f) { - return make_float3(0.0f, 0.0f, 0.0f); - } - - bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID); - - bool is_aniso = (bsdf->alpha_x != bsdf->alpha_y); - float3 X, Y, Z; - Z = bsdf->N; - if(is_aniso) - make_orthonormals_tangent(Z, bsdf->T, &X, &Y); - else - make_orthonormals(Z, &X, &Y); - - float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); - float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); - - if(is_aniso) - *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(bsdf->alpha_x, bsdf->alpha_y)); - else - *pdf = mf_ggx_pdf(localI, localO, bsdf->alpha_x); - return mf_eval_glossy(localI, localO, true, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior, use_fresnel, bsdf->extra->cspec0); +ccl_device float3 bsdf_microfacet_multi_ggx_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf, + ccl_addr_space uint *lcg_state) +{ + *pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device 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) +ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf, + ccl_addr_space uint *lcg_state) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; + + if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) { + return make_float3(0.0f, 0.0f, 0.0f); + } + + bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID); + + bool is_aniso = (bsdf->alpha_x != bsdf->alpha_y); + float3 X, Y, Z; + Z = bsdf->N; + if (is_aniso) + make_orthonormals_tangent(Z, bsdf->T, &X, &Y); + else + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + if (is_aniso) + *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(bsdf->alpha_x, bsdf->alpha_y)); + else + *pdf = mf_ggx_pdf(localI, localO, bsdf->alpha_x); + return mf_eval_glossy(localI, + localO, + true, + bsdf->extra->color, + bsdf->alpha_x, + bsdf->alpha_y, + lcg_state, + 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) +{ + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; - float3 X, Y, Z; - Z = bsdf->N; + float3 X, Y, Z; + Z = bsdf->N; - if(bsdf->alpha_x*bsdf->alpha_y < 1e-7f) { - *omega_in = 2*dot(Z, I)*Z - I; - *pdf = 1e6f; - *eval = make_float3(1e6f, 1e6f, 1e6f); + if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) { + *omega_in = 2 * dot(Z, I) * Z - I; + *pdf = 1e6f; + *eval = make_float3(1e6f, 1e6f, 1e6f); #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx; - *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy; + *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx; + *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy; #endif - return LABEL_REFLECT|LABEL_SINGULAR; - } - - bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID); - - 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 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, 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 - *pdf = mf_ggx_pdf(localI, localO, bsdf->alpha_x); - *eval *= *pdf; - - *omega_in = X*localO.x + Y*localO.y + Z*localO.z; + return LABEL_REFLECT | LABEL_SINGULAR; + } + + bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID); + + 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 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, + 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 + *pdf = mf_ggx_pdf(localI, localO, bsdf->alpha_x); + *eval *= *pdf; + + *omega_in = X * localO.x + Y * localO.y + Z * localO.z; #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx; - *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy; + *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx; + *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy; #endif - return LABEL_REFLECT|LABEL_GLOSSY; + return LABEL_REFLECT | LABEL_GLOSSY; } /* Multiscattering GGX Glass closure */ ccl_device int bsdf_microfacet_multi_ggx_glass_setup(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); - bsdf->extra->color.x = saturate(bsdf->extra->color.x); - bsdf->extra->color.y = saturate(bsdf->extra->color.y); - bsdf->extra->color.z = saturate(bsdf->extra->color.z); + bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); + bsdf->alpha_y = bsdf->alpha_x; + bsdf->ior = max(0.0f, bsdf->ior); + bsdf->extra->color.x = saturate(bsdf->extra->color.x); + bsdf->extra->color.y = saturate(bsdf->extra->color.y); + bsdf->extra->color.z = saturate(bsdf->extra->color.z); - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; - return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG; + return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG; } -ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(MicrofacetBsdf *bsdf, const ShaderData *sd) +ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(MicrofacetBsdf *bsdf, + 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); - bsdf->extra->color.x = saturate(bsdf->extra->color.x); - bsdf->extra->color.y = saturate(bsdf->extra->color.y); - bsdf->extra->color.z = saturate(bsdf->extra->color.z); - bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); - bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); - bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); - - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID; - - float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); - float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0)); - bsdf->sample_weight *= F; - - return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG; -} - -ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; - - if(bsdf->alpha_x*bsdf->alpha_y < 1e-7f) { - return make_float3(0.0f, 0.0f, 0.0f); - } - - float3 X, Y, Z; - Z = bsdf->N; - make_orthonormals(Z, &X, &Y); - - float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); - float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); - - *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); - return mf_eval_glass(localI, localO, false, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior, false, bsdf->extra->color); -} - -ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; - - if(bsdf->alpha_x*bsdf->alpha_y < 1e-7f) { - return make_float3(0.0f, 0.0f, 0.0f); - } - - bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID); - - float3 X, Y, Z; - Z = bsdf->N; - make_orthonormals(Z, &X, &Y); - - float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); - float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); - - *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); - return mf_eval_glass(localI, localO, true, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior, use_fresnel, bsdf->extra->cspec0); -} - -ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf, ccl_addr_space uint *lcg_state) + bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); + bsdf->alpha_y = bsdf->alpha_x; + bsdf->ior = max(0.0f, bsdf->ior); + bsdf->extra->color.x = saturate(bsdf->extra->color.x); + bsdf->extra->color.y = saturate(bsdf->extra->color.y); + bsdf->extra->color.z = saturate(bsdf->extra->color.z); + bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); + bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); + bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); + + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID; + + float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); + float F = average(interpolate_fresnel_color(sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0)); + bsdf->sample_weight *= F; + + return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG; +} + +ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_transmit(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf, + ccl_addr_space uint *lcg_state) +{ + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; + + if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) { + return make_float3(0.0f, 0.0f, 0.0f); + } + + float3 X, Y, Z; + Z = bsdf->N; + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); + return mf_eval_glass(localI, + localO, + false, + bsdf->extra->color, + bsdf->alpha_x, + bsdf->alpha_y, + lcg_state, + bsdf->ior, + false, + bsdf->extra->color); +} + +ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + float *pdf, + ccl_addr_space uint *lcg_state) +{ + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; + + if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) { + return make_float3(0.0f, 0.0f, 0.0f); + } + + bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID); + + float3 X, Y, Z; + Z = bsdf->N; + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); + return mf_eval_glass(localI, + localO, + true, + bsdf->extra->color, + bsdf->alpha_x, + bsdf->alpha_y, + lcg_state, + bsdf->ior, + use_fresnel, + bsdf->extra->cspec0); +} + +ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg, + const ShaderClosure *sc, + float3 Ng, + float3 I, + float3 dIdx, + float3 dIdy, + float randu, + float randv, + float3 *eval, + float3 *omega_in, + float3 *domega_in_dx, + float3 *domega_in_dy, + float *pdf, + ccl_addr_space uint *lcg_state) { - const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc; - float3 X, Y, Z; - Z = bsdf->N; + float3 X, Y, Z; + Z = bsdf->N; - if(bsdf->alpha_x*bsdf->alpha_y < 1e-7f) { - float3 R, T; + if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) { + float3 R, T; #ifdef __RAY_DIFFERENTIALS__ - float3 dRdx, dRdy, dTdx, dTdy; + float3 dRdx, dRdy, dTdx, dTdy; #endif - bool inside; - float fresnel = fresnel_dielectric(bsdf->ior, Z, I, &R, &T, + bool inside; + float fresnel = fresnel_dielectric(bsdf->ior, + Z, + I, + &R, + &T, #ifdef __RAY_DIFFERENTIALS__ - dIdx, dIdy, &dRdx, &dRdy, &dTdx, &dTdy, + dIdx, + dIdy, + &dRdx, + &dRdy, + &dTdx, + &dTdy, #endif - &inside); + &inside); - *pdf = 1e6f; - *eval = make_float3(1e6f, 1e6f, 1e6f); - if(randu < fresnel) { - *omega_in = R; + *pdf = 1e6f; + *eval = make_float3(1e6f, 1e6f, 1e6f); + if (randu < fresnel) { + *omega_in = R; #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = dRdx; - *domega_in_dy = dRdy; + *domega_in_dx = dRdx; + *domega_in_dy = dRdy; #endif - return LABEL_REFLECT|LABEL_SINGULAR; - } - else { - *omega_in = T; + return LABEL_REFLECT | LABEL_SINGULAR; + } + else { + *omega_in = T; #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = dTdx; - *domega_in_dy = dTdy; + *domega_in_dx = dTdx; + *domega_in_dy = dTdy; #endif - return LABEL_TRANSMIT|LABEL_SINGULAR; - } - } - - bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID); - - make_orthonormals(Z, &X, &Y); - - float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); - float3 localO; - - *eval = mf_sample_glass(localI, &localO, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior, use_fresnel, bsdf->extra->cspec0); - *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); - *eval *= *pdf; - - *omega_in = X*localO.x + Y*localO.y + Z*localO.z; - if(localO.z*localI.z > 0.0f) { + return LABEL_TRANSMIT | LABEL_SINGULAR; + } + } + + bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID); + + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO; + + *eval = mf_sample_glass(localI, + &localO, + bsdf->extra->color, + bsdf->alpha_x, + bsdf->alpha_y, + lcg_state, + bsdf->ior, + use_fresnel, + bsdf->extra->cspec0); + *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); + *eval *= *pdf; + + *omega_in = X * localO.x + Y * localO.y + Z * localO.z; + if (localO.z * localI.z > 0.0f) { #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx; - *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy; + *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx; + *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy; #endif - return LABEL_REFLECT|LABEL_GLOSSY; - } - else { + return LABEL_REFLECT | LABEL_GLOSSY; + } + else { #ifdef __RAY_DIFFERENTIALS__ - float cosI = dot(Z, I); - float dnp = max(sqrtf(1.0f - (bsdf->ior * bsdf->ior * (1.0f - cosI*cosI))), 1e-7f); - *domega_in_dx = -(bsdf->ior * dIdx) + ((bsdf->ior - bsdf->ior * bsdf->ior * cosI / dnp) * dot(dIdx, Z)) * Z; - *domega_in_dy = -(bsdf->ior * dIdy) + ((bsdf->ior - bsdf->ior * bsdf->ior * cosI / dnp) * dot(dIdy, Z)) * Z; + float cosI = dot(Z, I); + float dnp = max(sqrtf(1.0f - (bsdf->ior * bsdf->ior * (1.0f - cosI * cosI))), 1e-7f); + *domega_in_dx = -(bsdf->ior * dIdx) + + ((bsdf->ior - bsdf->ior * bsdf->ior * cosI / dnp) * dot(dIdx, Z)) * Z; + *domega_in_dy = -(bsdf->ior * dIdy) + + ((bsdf->ior - bsdf->ior * bsdf->ior * cosI / dnp) * dot(dIdy, Z)) * Z; #endif - return LABEL_TRANSMIT|LABEL_GLOSSY; - } + return LABEL_TRANSMIT | LABEL_GLOSSY; + } } CCL_NAMESPACE_END |