diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h index 6d42a8152b6..deb7de7df73 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet.h @@ -590,6 +590,7 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc, } const float m_eta = bsdf->ior; + const float m_inv_eta = 1.0f / bsdf->ior; const bool m_refraction = CLOSURE_IS_REFRACTION(bsdf->type); const bool m_glass = CLOSURE_IS_GLASS(bsdf->type); const float alpha_x = bsdf->alpha_x; @@ -624,14 +625,14 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc, H = X * local_H.x + Y * local_H.y + N * local_H.z; } + const float cos_HI = dot(H, wi); - bool valid; + /* The angle between the half vector and the refracted ray. Not used when sampling reflection. */ + float cos_HO; bool do_refract; float lobe_pdf; if (m_refraction || m_glass) { - bool inside; - float fresnel = fresnel_dielectric(m_eta, H, wi, wo, &inside); - valid = !inside; + float fresnel = fresnel_dielectric(cos_HI, m_eta, &cos_HO); /* For glass closures, we decide between reflection and refraction here. */ if (m_glass) { @@ -640,32 +641,30 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc, } else { /* For pure refractive closures, refraction is the only option. */ + if (fresnel == 1.0f) { + return LABEL_NONE; + } do_refract = true; lobe_pdf = 1.0f; - valid = valid && (fresnel != 1.0f); } } else { /* Pure reflective closure, reflection is the only option. */ - valid = true; lobe_pdf = 1.0f; do_refract = false; } - const float cos_HI = dot(H, wi); if (do_refract) { - /* wo was already set to the refracted direction by fresnel_dielectric. */ - // valid = valid && (dot(Ng, *wo) < 0); + *wo = refract_angle(wi, H, cos_HO, m_inv_eta); /* If the IOR is close enough to 1.0, just treat the interaction as specular. */ m_singular = m_singular || (fabsf(m_eta - 1.0f) < 1e-4f); } else { /* Eq. 39 - compute actual reflected direction */ *wo = 2 * cos_HI * H - wi; - valid = valid && (dot(Ng, *wo) > 0); } - if (!valid) { + if ((dot(Ng, *wo) < 0) != do_refract) { return LABEL_NONE; } @@ -706,9 +705,8 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc, lambdaI = bsdf_aniso_lambda(alpha_x, alpha_y, local_I); } - const float cos_HO = dot(H, *wo); const float common = D / cos_NI * - (do_refract ? fabsf(cos_HI * cos_HO) / sqr(cos_HO + cos_HI / m_eta) : + (do_refract ? fabsf(cos_HI * cos_HO) / sqr(cos_HO + cos_HI * m_inv_eta) : 0.25f); *pdf = common * lobe_pdf / (1.0f + lambdaI); @@ -718,7 +716,7 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc, } *sampled_roughness = make_float2(alpha_x, alpha_y); - *eta = do_refract ? 1.0f / m_eta : m_eta; + *eta = do_refract ? m_inv_eta : m_eta; return (do_refract ? LABEL_TRANSMIT : LABEL_REFLECT) | (m_singular ? LABEL_SINGULAR : LABEL_GLOSSY); diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h index d26c1f0d6a1..30d9ae39fa7 100644 --- a/intern/cycles/kernel/closure/bsdf_util.h +++ b/intern/cycles/kernel/closure/bsdf_util.h @@ -17,15 +17,15 @@ ccl_device float fresnel_dielectric(float cos_theta_i, float eta, ccl_private fl /* Using Snell's law, calculate the squared cosine of the angle between the surface normal and * the transmitted ray. */ - const float cos_theta_t_sq = 1.0f - (1.0f - sqr(cos_theta_i)) / sqr(eta); - if (cos_theta_t_sq <= 0) { + const float eta_cos_theta_t_sq = sqr(eta) - (1.0f - sqr(cos_theta_i)); + if (eta_cos_theta_t_sq <= 0) { /* Total internal reflection. */ return 1.0f; } cos_theta_i = fabsf(cos_theta_i); /* Relative to the surface normal. */ - const float cos_theta_t = -safe_sqrtf(cos_theta_t_sq); + const float cos_theta_t = -safe_sqrtf(eta_cos_theta_t_sq) / eta; if (r_cos_theta_t) { *r_cos_theta_t = cos_theta_t; @@ -48,45 +48,6 @@ ccl_device_inline float3 refract_angle(const float3 incident, return (inv_eta * dot(normal, incident) + cos_theta_t) * normal - inv_eta * incident; } -ccl_device float fresnel_dielectric( - float eta, const float3 N, const float3 I, ccl_private float3 *T, ccl_private bool *is_inside) -{ - float cos = dot(N, I), neta; - float3 Nn; - - // check which side of the surface we are on - if (cos > 0) { - // we are on the outside of the surface, going in - neta = 1 / eta; - Nn = N; - *is_inside = false; - } - else { - // we are inside the surface - cos = -cos; - neta = eta; - Nn = -N; - *is_inside = true; - } - - float arg = 1 - (neta * neta * (1 - (cos * cos))); - if (arg < 0) { - *T = make_float3(0.0f, 0.0f, 0.0f); - return 1; // total internal reflection - } - else { - float dnp = max(sqrtf(arg), 1e-7f); - float nK = (neta * cos) - dnp; - *T = -(neta * I) + (nK * Nn); - // compute Fresnel terms - float cosTheta1 = cos; // N.R - float cosTheta2 = -dot(Nn, *T); - float pPara = (cosTheta1 - eta * cosTheta2) / (cosTheta1 + eta * cosTheta2); - float pPerp = (eta * cosTheta1 - cosTheta2) / (eta * cosTheta1 + cosTheta2); - return 0.5f * (pPara * pPara + pPerp * pPerp); - } -} - ccl_device float fresnel_dielectric_cos(float cosi, float eta) { // compute fresnel reflectance without explicitly computing