Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/closure/bsdf_microfacet.h
| Show First 20 Lines • Show All 249 Lines • ▼ Show 20 Lines | if(use_fresnel) { | ||||
| float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); | float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); | ||||
| F = interpolate_fresnel_color(L, H, bsdf->ior, F0, bsdf->extra->cspec0); | F = interpolate_fresnel_color(L, H, bsdf->ior, F0, bsdf->extra->cspec0); | ||||
| } | } | ||||
| return F; | return F; | ||||
| } | } | ||||
| ccl_device_forceinline float D_GTR1(float NdotH, float alpha) | |||||
| /* GGX microfacet distribution functions: | |||||
| * Here, GTR refers to the Generalized Trowbridge-Reitz model from "Physically Based Shading at Disney". | |||||
| * GTR with falloff parameter 2 corresponds to GGX, while GTR1 is used for the clearcoat component of the Principled BSDF. | |||||
| */ | |||||
| ccl_device_forceinline float D_GTR1(float NdotH, float alpha2) | |||||
| { | { | ||||
| if(alpha >= 1.0f) return M_1_PI_F; | if(alpha2 >= 1.0f) return M_1_PI_F; | ||||
| float alpha2 = alpha*alpha; | float t = 1.0f + (alpha2 - 1.0f) * sqr(NdotH); | ||||
| float t = 1.0f + (alpha2 - 1.0f) * NdotH*NdotH; | |||||
| return (alpha2 - 1.0f) / (M_PI_F * logf(alpha2) * t); | return (alpha2 - 1.0f) / (M_PI_F * logf(alpha2) * t); | ||||
| } | } | ||||
| ccl_device_forceinline float D_GTR2(float NdotM, float alpha2) | |||||
| { | |||||
| return alpha2 / (M_PI_F * sqr(1.0f + (alpha2 - 1.0f)*sqr(NdotM))); | |||||
| } | |||||
| ccl_device_forceinline float D_GTR2_aniso(float MdotX, float MdotY, float MdotZ, float alpha_x, float alpha_y, float alpha2) | |||||
| { | |||||
| float slope_x = MdotX/(MdotZ*alpha_x); | |||||
| float slope_y = MdotY/(MdotZ*alpha_y); | |||||
| float slope_len = 1 + sqr(slope_x) + sqr(slope_y); | |||||
| return 1.0f / (sqr(slope_len * sqr(MdotZ)) * M_PI_F * alpha2); | |||||
| } | |||||
| /* GGX geometric shadowing terms. | |||||
| * | |||||
| * Note on the implementation: | |||||
| * In the final BSDF equation, NdotO and NdotI appear in the denominator. | |||||
| * Since Cycles returns the product of BSDF and NdotI by convention, NdotI cancels out. | |||||
| * In the formulation of G1 that is used here, the NdotD factor appears in the numerator, | |||||
| * so we can avoid dividing by NdotO in the BSDF by letting it cancel out with NdotO in the G1o term. | |||||
| * | |||||
| * Therefore, G1o actually returns G1/NdotO while G1i returns G1. | |||||
| */ | |||||
| ccl_device_forceinline float GGX_G1o(float NdotO, float alpha2) | |||||
| { | |||||
| return 2.0f / (NdotO + safe_sqrtf(sqr(NdotO) * (1.0f - alpha2) + alpha2)); | |||||
| } | |||||
| ccl_device_forceinline float GGX_G1i(float NdotI, float alpha2) | |||||
| { | |||||
| return 2.0f * NdotI / (NdotI + safe_sqrtf(sqr(NdotI) * (1.0f - alpha2) + alpha2)); | |||||
| } | |||||
| ccl_device_forceinline float GGX_G1o_aniso(float XdotD, float YdotD, float NdotD, float alpha_x, float alpha_y) | |||||
| { | |||||
| float alphaI2 = sqr(XdotD*alpha_x) + sqr(YdotD*alpha_y); | |||||
| return 2.0f / (NdotD + safe_sqrtf(sqr(NdotD) + alphaI2)); | |||||
| } | |||||
| ccl_device_forceinline float GGX_G1i_aniso(float XdotD, float YdotD, float NdotD, float alpha_x, float alpha_y) | |||||
| { | |||||
| float alphaI2 = sqr(XdotD*alpha_x) + sqr(YdotD*alpha_y); | |||||
| return 2.0f * NdotD / (NdotD + safe_sqrtf(sqr(NdotD) + alphaI2)); | |||||
| } | |||||
| /* GGX microfacet with Smith shadow-masking from: | /* GGX microfacet with Smith shadow-masking from: | ||||
| * | * | ||||
| * Microfacet Models for Refraction through Rough Surfaces | * Microfacet Models for Refraction through Rough Surfaces | ||||
| * B. Walter, S. R. Marschner, H. Li, K. E. Torrance, EGSR 2007 | * B. Walter, S. R. Marschner, H. Li, K. E. Torrance, EGSR 2007 | ||||
| * | * | ||||
| * Anisotropic from: | * Anisotropic from: | ||||
| * | * | ||||
| * Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs | * Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs | ||||
| ▲ Show 20 Lines • Show All 117 Lines • ▼ Show 20 Lines | ccl_device void bsdf_microfacet_ggx_blur(ShaderClosure *sc, float roughness) | ||||
| bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); | bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); | ||||
| } | } | ||||
| ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) | ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) | ||||
| { | { | ||||
| const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; | const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; | ||||
| float alpha_x = bsdf->alpha_x; | float alpha_x = bsdf->alpha_x; | ||||
| float alpha_y = bsdf->alpha_y; | float alpha_y = bsdf->alpha_y; | ||||
| float alpha2 = alpha_x * alpha_y; | |||||
| bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; | bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; | ||||
| float3 N = bsdf->N; | float3 N = bsdf->N; | ||||
| if(m_refractive || alpha_x*alpha_y <= 1e-7f) | if(m_refractive || alpha_x*alpha_y <= 1e-7f) { | ||||
| return make_float3(0.0f, 0.0f, 0.0f); | return make_float3(0.0f, 0.0f, 0.0f); | ||||
| } | |||||
| float cosNO = dot(N, I); | float cosNO = dot(N, I); | ||||
| float cosNI = dot(N, omega_in); | float cosNI = dot(N, omega_in); | ||||
| if(cosNI > 0 && cosNO > 0) { | if(cosNI <= 0 && cosNO <= 0) { | ||||
| /* get half vector */ | /* This might happen due to e.g. normal mapping - not supported here, so just give up and return black. */ | ||||
| return make_float3(0.0f, 0.0f, 0.0f); | |||||
| } | |||||
| /* Calculate the half vector as the average of the incoming and outgoing direction. */ | |||||
| float3 m = normalize(omega_in + I); | float3 m = normalize(omega_in + I); | ||||
| float alpha2 = alpha_x * alpha_y; | |||||
| float D, G1o, G1i; | float D, G1o, G1i; | ||||
| /* Calculation of D and G1 can be simplified for the common isotropic case. */ | |||||
| if(alpha_x == alpha_y) { | if(alpha_x == alpha_y) { | ||||
| /* isotropic | |||||
| * eq. 20: (F*G*D)/(4*in*on) | |||||
| * eq. 33: first we calculate D(m) */ | |||||
| float cosThetaM = dot(N, m); | float cosThetaM = dot(N, m); | ||||
| float cosThetaM2 = cosThetaM * cosThetaM; | |||||
| float cosThetaM4 = cosThetaM2 * cosThetaM2; | |||||
| float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; | |||||
| if(bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { | if(bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { | ||||
| /* use GTR1 for clearcoat */ | /* Use the GTR1 model for clearcoat reflection. */ | ||||
| D = D_GTR1(cosThetaM, bsdf->alpha_x); | D = D_GTR1(cosThetaM, alpha2); | ||||
| /* the alpha value for clearcoat is a fixed 0.25 => alpha2 = 0.25 * 0.25 */ | /* The alpha value for clearcoat is a fixed 0.25. */ | ||||
| alpha2 = 0.0625f; | alpha2 = 0.0625f; | ||||
| } | } | ||||
| else { | else { | ||||
| /* use GTR2 otherwise */ | /* Use GTR2 (aka GGX) otherwise. */ | ||||
| D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); | D = D_GTR2(cosThetaM, alpha2); | ||||
| } | } | ||||
| /* eq. 34: now calculate G1(i,m) and G1(o,m) */ | /* Calculate the geometric terms (note the comment about the functions above). */ | ||||
| G1o = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); | G1o = GGX_G1o(cosNO, alpha2); | ||||
| G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); | G1i = GGX_G1i(cosNI, alpha2); | ||||
| } | } | ||||
| else { | else { | ||||
| /* anisotropic */ | /* Construct orthonormal system from the given tangent. | ||||
| * | |||||
| * TODO(lukas): Check whether making bsdf->T orthonormal to bsdf->N in the setup code and just getting | |||||
| * the bitangent with a single cross() here is faster since it can be reused. */ | |||||
| float3 X, Y, Z = N; | float3 X, Y, Z = N; | ||||
| make_orthonormals_tangent(Z, bsdf->T, &X, &Y); | make_orthonormals_tangent(Z, bsdf->T, &X, &Y); | ||||
| /* distribution */ | /* Evaluate distribution and geometric terms. */ | ||||
| float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); | D = D_GTR2_aniso(dot(X, m), dot(Y, m), dot(Z, m), alpha_x, alpha_y, alpha2); | ||||
| float slope_x = -local_m.x/(local_m.z*alpha_x); | G1o = GGX_G1o_aniso(dot(I, X), dot(I, Y), cosNO, alpha_x, alpha_y); | ||||
| float slope_y = -local_m.y/(local_m.z*alpha_y); | G1i = GGX_G1i_aniso(dot(omega_in, X), dot(omega_in, Y), cosNI, alpha_x, alpha_y); | ||||
| float slope_len = 1 + slope_x*slope_x + slope_y*slope_y; | |||||
| float cosThetaM = local_m.z; | |||||
| float cosThetaM2 = cosThetaM * cosThetaM; | |||||
| float cosThetaM4 = cosThetaM2 * cosThetaM2; | |||||
| D = 1 / ((slope_len * slope_len) * M_PI_F * alpha2 * cosThetaM4); | |||||
| /* G1(i,m) and G1(o,m) */ | |||||
| float tanThetaO2 = (1 - cosNO * cosNO) / (cosNO * cosNO); | |||||
| float cosPhiO = dot(I, X); | |||||
| float sinPhiO = dot(I, Y); | |||||
| float alphaO2 = (cosPhiO*cosPhiO)*(alpha_x*alpha_x) + (sinPhiO*sinPhiO)*(alpha_y*alpha_y); | |||||
| alphaO2 /= cosPhiO*cosPhiO + sinPhiO*sinPhiO; | |||||
| G1o = 2 / (1 + safe_sqrtf(1 + alphaO2 * tanThetaO2)); | |||||
| float tanThetaI2 = (1 - cosNI * cosNI) / (cosNI * cosNI); | |||||
| float cosPhiI = dot(omega_in, X); | |||||
| float sinPhiI = dot(omega_in, Y); | |||||
| float alphaI2 = (cosPhiI*cosPhiI)*(alpha_x*alpha_x) + (sinPhiI*sinPhiI)*(alpha_y*alpha_y); | |||||
| alphaI2 /= cosPhiI*cosPhiI + sinPhiI*sinPhiI; | |||||
| G1i = 2 / (1 + safe_sqrtf(1 + alphaI2 * tanThetaI2)); | |||||
| } | } | ||||
| float G = G1o * G1i; | /* The full BSDF is f = F*D*G1o*G1i / (4*cosNO*cosNI). | ||||
| * In Cycles we return f*cosNI and 1/cosNO is included in G1o, so the result here is F*D*G1i*G1i / 4. | |||||
| /* eq. 20 */ | * F and G1i are not included in the importance sampling, so the PDF is D*G1o / 4. | ||||
| float common = D * 0.25f / cosNO; | * | ||||
| * Note that since the PDF is normalized and F*G1i is never >1, this formulation doesn't conserve energy. */ | |||||
| float common = 0.25f * G1o * D; | |||||
| float3 F = reflection_color(bsdf, omega_in, m); | float3 F = reflection_color(bsdf, omega_in, m); | ||||
| if(bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { | if(bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { | ||||
| F *= 0.25f * bsdf->extra->clearcoat; | F *= 0.25f * bsdf->extra->clearcoat; | ||||
| } | } | ||||
| float3 out = F * G * common; | *pdf = common; | ||||
| return G1i * common * F; | |||||
| /* eq. 2 in distribution of visible normals sampling | |||||
| * pm = Dw = G1o * dot(m, I) * D / dot(N, I); */ | |||||
| /* eq. 38 - but see also: | |||||
| * eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf | |||||
| * pdf = pm * 0.25 / dot(m, I); */ | |||||
| *pdf = G1o * common; | |||||
| return out; | |||||
| } | |||||
| return make_float3(0.0f, 0.0f, 0.0f); | |||||
| } | } | ||||
| ccl_device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) | ccl_device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) | ||||
| { | { | ||||
| const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; | const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; | ||||
| float alpha_x = bsdf->alpha_x; | float alpha_x = bsdf->alpha_x; | ||||
| float alpha_y = bsdf->alpha_y; | float alpha_y = bsdf->alpha_y; | ||||
| float m_eta = bsdf->ior; | float m_eta = bsdf->ior; | ||||
| bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; | bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; | ||||
| float3 N = bsdf->N; | float3 N = bsdf->N; | ||||
| if(!m_refractive || alpha_x*alpha_y <= 1e-7f) | float alpha2 = alpha_x * alpha_y; | ||||
| if(!m_refractive || alpha2 <= 1e-7f) { | |||||
| return make_float3(0.0f, 0.0f, 0.0f); | return make_float3(0.0f, 0.0f, 0.0f); | ||||
| } | |||||
| float cosNO = dot(N, I); | float cosNO = dot(N, I); | ||||
| float cosNI = dot(N, omega_in); | float cosNI = dot(N, omega_in); | ||||
| if(cosNO <= 0 || cosNI >= 0) | if(cosNO <= 0 || cosNI >= 0) { | ||||
| return make_float3(0.0f, 0.0f, 0.0f); /* vectors on same side -- not possible */ | /* This might happen due to e.g. normal mapping - not supported here, so just give up and return black. */ | ||||
| return make_float3(0.0f, 0.0f, 0.0f); | |||||
| } | |||||
| /* compute half-vector of the refraction (eq. 16) */ | /* Compute half-vector of the refraction (eq. 16). */ | ||||
| float3 ht = -(m_eta * omega_in + I); | float3 ht = -(m_eta * omega_in + I); | ||||
| float3 Ht = normalize(ht); | float ht_inv_len = 1.0f / sqrtf(dot(ht, ht)); | ||||
| float3 Ht = ht * ht_inv_len; | |||||
| float cosHO = dot(Ht, I); | float cosHO = dot(Ht, I); | ||||
| float cosHI = dot(Ht, omega_in); | float cosHI = dot(Ht, omega_in); | ||||
| float D, G1o, G1i; | /* Evaluate distribution and geometric terms. */ | ||||
| float D = D_GTR2(dot(Ht, N), alpha2); | |||||
| /* eq. 33: first we calculate D(m) with m=Ht: */ | float G1o = GGX_G1o(cosNO, alpha2); | ||||
| float alpha2 = alpha_x * alpha_y; | float G1i = GGX_G1i(-cosNI, alpha2); | ||||
| float cosThetaM = dot(N, Ht); | |||||
| float cosThetaM2 = cosThetaM * cosThetaM; | /* For the refraction case, the BSDF is abs(cosHI * cosHO) * eta^2 * G1o * G1i * D / (cosNO * cosNI * Ht2). | ||||
| float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; | * Again, G1i includes cosNO and cosNI cancels out in Cycles, so by grouping some terms we get: | ||||
| float cosThetaM4 = cosThetaM2 * cosThetaM2; | * abs(cosHI * cosHO) * G1o * G1i * (eta * (1 / Ht))^2 | ||||
| D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); | * | ||||
| * The PDF here is abs(cosHI * cosHO) * G1o * (eta * (1 / Ht))^2. */ | |||||
| /* eq. 34: now calculate G1(i,m) and G1(o,m) */ | float common = G1o * D * fabsf(cosHI * cosHO) * sqr(m_eta * ht_inv_len); | ||||
| G1o = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); | float out = G1i * common; | ||||
| G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); | *pdf = common; | ||||
| float G = G1o * G1i; | |||||
| /* probability */ | |||||
| float Ht2 = dot(ht, ht); | |||||
| /* eq. 2 in distribution of visible normals sampling | |||||
| * pm = Dw = G1o * dot(m, I) * D / dot(N, I); */ | |||||
| /* out = fabsf(cosHI * cosHO) * (m_eta * m_eta) * G * D / (cosNO * Ht2) | |||||
| * pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2 */ | |||||
| float common = D * (m_eta * m_eta) / (cosNO * Ht2); | |||||
| float out = G * fabsf(cosHI * cosHO) * common; | |||||
| *pdf = G1o * fabsf(cosHO * cosHI) * common; | |||||
| return make_float3(out, out, out); | return make_float3(out, out, out); | ||||
| } | } | ||||
| ccl_device int bsdf_microfacet_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_device int bsdf_microfacet_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) | ||||
| { | { | ||||
| const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; | const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; | ||||
| float alpha_x = bsdf->alpha_x; | float alpha_x = bsdf->alpha_x; | ||||
| float alpha_y = bsdf->alpha_y; | float alpha_y = bsdf->alpha_y; | ||||
| bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; | bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; | ||||
| float3 N = bsdf->N; | float3 N = bsdf->N; | ||||
| int label; | int label; | ||||
| float alpha2 = alpha_x * alpha_y; | |||||
| float cosNO = dot(N, I); | float cosNO = dot(N, I); | ||||
| if(cosNO > 0) { | if(cosNO > 0) { | ||||
| float3 X, Y, Z = N; | float3 X, Y, Z = N; | ||||
| if(alpha_x == alpha_y) | if(alpha_x == alpha_y) | ||||
| make_orthonormals(Z, &X, &Y); | make_orthonormals(Z, &X, &Y); | ||||
| else | else | ||||
| make_orthonormals_tangent(Z, bsdf->T, &X, &Y); | make_orthonormals_tangent(Z, bsdf->T, &X, &Y); | ||||
| /* importance sampling with distribution of visible normals. vectors are | /* Sample half-vector from the distribution of visible normals. | ||||
| * transformed to local space before and after */ | * | ||||
| * Sampling happens in local coordinates, so transform I before calling | |||||
| * and then transform the result back. */ | |||||
| float3 local_I = make_float3(dot(X, I), dot(Y, I), cosNO); | float3 local_I = make_float3(dot(X, I), dot(Y, I), cosNO); | ||||
| float3 local_m; | |||||
| float G1o; | |||||
| local_m = microfacet_sample_stretched(kg, local_I, alpha_x, alpha_y, | float G1o; | ||||
| float3 local_m = microfacet_sample_stretched(kg, local_I, alpha_x, alpha_y, | |||||
| randu, randv, false, &G1o); | randu, randv, false, &G1o); | ||||
| float3 m = X*local_m.x + Y*local_m.y + Z*local_m.z; | float3 m = X*local_m.x + Y*local_m.y + Z*local_m.z; | ||||
| float cosThetaM = local_m.z; | float cosThetaM = local_m.z; | ||||
| /* reflection or refraction? */ | /* Reflection or refraction? */ | ||||
| if(!m_refractive) { | if(!m_refractive) { | ||||
| float cosMO = dot(m, I); | float cosMO = dot(m, I); | ||||
| label = LABEL_REFLECT | LABEL_GLOSSY; | label = LABEL_REFLECT | LABEL_GLOSSY; | ||||
| if(cosMO > 0) { | if(cosMO > 0) { | ||||
| /* eq. 39 - compute actual reflected direction */ | /* Compute reflected direction. */ | ||||
| *omega_in = 2 * cosMO * m - I; | *omega_in = 2 * cosMO * m - I; | ||||
| if(dot(Ng, *omega_in) > 0) { | if(dot(Ng, *omega_in) > 0) { | ||||
| if(alpha_x*alpha_y <= 1e-7f) { | if(alpha_x*alpha_y <= 1e-7f) { | ||||
| /* some high number for MIS */ | /* some high number for MIS */ | ||||
| *pdf = 1e6f; | *pdf = 1e6f; | ||||
| *eval = make_float3(1e6f, 1e6f, 1e6f); | *eval = make_float3(1e6f, 1e6f, 1e6f); | ||||
| bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID | bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID | ||||
| || bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID | || bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID | ||||
| || bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID); | || bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID); | ||||
| /* if fresnel is used, calculate the color with reflection_color(...) */ | /* if fresnel is used, calculate the color with reflection_color(...) */ | ||||
| if(use_fresnel) { | if(use_fresnel) { | ||||
| *eval *= reflection_color(bsdf, *omega_in, m); | *eval *= reflection_color(bsdf, *omega_in, m); | ||||
| } | } | ||||
| label = LABEL_REFLECT | LABEL_SINGULAR; | label = LABEL_REFLECT | LABEL_SINGULAR; | ||||
| } | } | ||||
| else { | else { | ||||
| /* microfacet normal is visible to this ray */ | |||||
| /* eq. 33 */ | |||||
| float alpha2 = alpha_x * alpha_y; | |||||
| float D, G1i; | float D, G1i; | ||||
| if(alpha_x == alpha_y) { | if(alpha_x == alpha_y) { | ||||
| /* isotropic */ | |||||
| float cosThetaM2 = cosThetaM * cosThetaM; | |||||
| float cosThetaM4 = cosThetaM2 * cosThetaM2; | |||||
| float tanThetaM2 = 1/(cosThetaM2) - 1; | |||||
| /* eval BRDF*cosNI */ | |||||
| float cosNI = dot(N, *omega_in); | |||||
| if(bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { | if(bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { | ||||
| /* use GTR1 for clearcoat */ | /* Use the GTR1 model for clearcoat reflection. */ | ||||
| D = D_GTR1(cosThetaM, bsdf->alpha_x); | D = D_GTR1(cosThetaM, alpha2); | ||||
| /* the alpha value for clearcoat is a fixed 0.25 => alpha2 = 0.25 * 0.25 */ | /* The alpha value for clearcoat is a fixed 0.25. */ | ||||
| alpha2 = 0.0625f; | alpha2 = 0.0625f; | ||||
| /* recalculate G1o */ | /* Recalculate G1o since the previous value is based on a different alpha. */ | ||||
| G1o = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); | G1o = GGX_G1o(cosNO, alpha2); | ||||
| } | } | ||||
| else { | else { | ||||
| /* use GTR2 otherwise */ | /* Use GTR2 (aka GGX) otherwise. */ | ||||
| D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); | D = D_GTR2(cosThetaM, alpha2); | ||||
| } | } | ||||
| /* eq. 34: now calculate G1(i,m) */ | /* G1o is already known, so we only need to evaluate G1i here. */ | ||||
| G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); | G1i = GGX_G1i(dot(Z, *omega_in), alpha2); | ||||
| } | } | ||||
| else { | else { | ||||
| /* anisotropic distribution */ | /* Use the anisotropic distribution. */ | ||||
| float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); | D = D_GTR2_aniso(dot(X, m), dot(Y, m), dot(Z, m), alpha_x, alpha_y, alpha2); | ||||
| float slope_x = -local_m.x/(local_m.z*alpha_x); | G1i = GGX_G1i_aniso(dot(X, *omega_in), dot(Y, *omega_in), dot(Z, *omega_in), alpha_x, alpha_y); | ||||
| float slope_y = -local_m.y/(local_m.z*alpha_y); | |||||
| float slope_len = 1 + slope_x*slope_x + slope_y*slope_y; | |||||
| float cosThetaM = local_m.z; | |||||
| float cosThetaM2 = cosThetaM * cosThetaM; | |||||
| float cosThetaM4 = cosThetaM2 * cosThetaM2; | |||||
| D = 1 / ((slope_len * slope_len) * M_PI_F * alpha2 * cosThetaM4); | |||||
| /* calculate G1(i,m) */ | |||||
| float cosNI = dot(N, *omega_in); | |||||
| float tanThetaI2 = (1 - cosNI * cosNI) / (cosNI * cosNI); | |||||
| float cosPhiI = dot(*omega_in, X); | |||||
| float sinPhiI = dot(*omega_in, Y); | |||||
| float alphaI2 = (cosPhiI*cosPhiI)*(alpha_x*alpha_x) + (sinPhiI*sinPhiI)*(alpha_y*alpha_y); | |||||
| alphaI2 /= cosPhiI*cosPhiI + sinPhiI*sinPhiI; | |||||
| G1i = 2 / (1 + safe_sqrtf(1 + alphaI2 * tanThetaI2)); | |||||
| } | } | ||||
| /* see eval function for derivation */ | /* The BSDF calculation here follows the evaluation code, with the exception that here G1o doesn't | ||||
| float common = (G1o * D) * 0.25f / cosNO; | * contain the 1/cosNO factor already. */ | ||||
| float common = 0.25f * D * G1o / cosNO; | |||||
| *pdf = common; | *pdf = common; | ||||
| float3 F = reflection_color(bsdf, *omega_in, m); | float3 F = reflection_color(bsdf, *omega_in, m); | ||||
| *eval = G1i * common * F; | *eval = G1i * common * F; | ||||
| } | } | ||||
| if(bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { | if(bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { | ||||
| *eval *= 0.25f * bsdf->extra->clearcoat; | *eval *= 0.25f * bsdf->extra->clearcoat; | ||||
| } | } | ||||
| #ifdef __RAY_DIFFERENTIALS__ | #ifdef __RAY_DIFFERENTIALS__ | ||||
| *domega_in_dx = (2 * dot(m, dIdx)) * m - dIdx; | *domega_in_dx = (2 * dot(m, dIdx)) * m - dIdx; | ||||
| *domega_in_dy = (2 * dot(m, dIdy)) * m - dIdy; | *domega_in_dy = (2 * dot(m, dIdy)) * m - dIdy; | ||||
| #endif | #endif | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| label = LABEL_TRANSMIT | LABEL_GLOSSY; | label = LABEL_TRANSMIT | LABEL_GLOSSY; | ||||
| /* CAUTION: the i and o variables are inverted relative to the paper | /* Compute the refracted direction and make sure that no TIR occurs. */ | ||||
| * eq. 39 - compute actual refractive direction */ | float3 T; | ||||
| float3 R, T; | |||||
| #ifdef __RAY_DIFFERENTIALS__ | #ifdef __RAY_DIFFERENTIALS__ | ||||
| float3 dRdx, dRdy, dTdx, dTdy; | float3 dTdx, dTdy; | ||||
| #endif | #endif | ||||
| float m_eta = bsdf->ior, fresnel; | float m_eta = bsdf->ior; | ||||
| bool inside; | if(refract_dielectric(m_eta, m, I, | ||||
| fresnel = fresnel_dielectric(m_eta, m, I, &R, &T, | |||||
| #ifdef __RAY_DIFFERENTIALS__ | #ifdef __RAY_DIFFERENTIALS__ | ||||
| dIdx, dIdy, &dRdx, &dRdy, &dTdx, &dTdy, | dIdx, dIdy, &dTdx, &dTdy, | ||||
| #endif | #endif | ||||
| &inside); | &T)) | ||||
| { | |||||
| if(!inside && fresnel != 1.0f) { | |||||
| *omega_in = T; | *omega_in = T; | ||||
| #ifdef __RAY_DIFFERENTIALS__ | #ifdef __RAY_DIFFERENTIALS__ | ||||
| *domega_in_dx = dTdx; | *domega_in_dx = dTdx; | ||||
| *domega_in_dy = dTdy; | *domega_in_dy = dTdy; | ||||
| #endif | #endif | ||||
| if(alpha_x*alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) { | if(alpha2 <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) { | ||||
| /* some high number for MIS */ | /* some high number for MIS */ | ||||
| *pdf = 1e6f; | *pdf = 1e6f; | ||||
| *eval = make_float3(1e6f, 1e6f, 1e6f); | *eval = make_float3(1e6f, 1e6f, 1e6f); | ||||
| label = LABEL_TRANSMIT | LABEL_SINGULAR; | label = LABEL_TRANSMIT | LABEL_SINGULAR; | ||||
| } | } | ||||
| else { | else { | ||||
| /* eq. 33 */ | /* Evaluate distribution and geometric term - G1o is already known from the half-vector sampling. */ | ||||
| float alpha2 = alpha_x * alpha_y; | float D = D_GTR2(cosThetaM, alpha2); | ||||
| float cosThetaM2 = cosThetaM * cosThetaM; | float G1i = GGX_G1i(-dot(N, *omega_in), alpha2); | ||||
| float cosThetaM4 = cosThetaM2 * cosThetaM2; | |||||
| float tanThetaM2 = 1/(cosThetaM2) - 1; | |||||
| float D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); | |||||
| /* eval BRDF*cosNI */ | |||||
| float cosNI = dot(N, *omega_in); | |||||
| /* eq. 34: now calculate G1(i,m) */ | |||||
| float G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); | |||||
| /* eq. 21 */ | /* eq. 21 */ | ||||
| float cosHI = dot(m, *omega_in); | float cosHI = dot(m, *omega_in); | ||||
| float cosHO = dot(m, I); | float cosHO = dot(m, I); | ||||
| float Ht2 = m_eta * cosHI + cosHO; | float Ht2 = m_eta * cosHI + cosHO; | ||||
| Ht2 *= Ht2; | |||||
| /* see eval function for derivation */ | /* The BSDF calculation here follows the evaluation code, with the exception that here G1o doesn't | ||||
| float common = (G1o * D) * (m_eta * m_eta) / (cosNO * Ht2); | * contain the 1/cosNO factor already. */ | ||||
| float out = G1i * fabsf(cosHI * cosHO) * common; | float common = D * G1o * fabsf(cosHI * cosHO) * sqr(m_eta) / (cosNO * sqr(Ht2)); | ||||
| *pdf = cosHO * fabsf(cosHI) * common; | float out = G1i * common; | ||||
| *pdf = common; | |||||
| *eval = make_float3(out, out, out); | *eval = make_float3(out, out, out); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| label = (m_refractive) ? LABEL_TRANSMIT|LABEL_GLOSSY : LABEL_REFLECT|LABEL_GLOSSY; | label = (m_refractive) ? LABEL_TRANSMIT|LABEL_GLOSSY : LABEL_REFLECT|LABEL_GLOSSY; | ||||
| ▲ Show 20 Lines • Show All 297 Lines • ▼ Show 20 Lines | #endif | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| label = LABEL_TRANSMIT | LABEL_GLOSSY; | label = LABEL_TRANSMIT | LABEL_GLOSSY; | ||||
| /* CAUTION: the i and o variables are inverted relative to the paper | /* CAUTION: the i and o variables are inverted relative to the paper | ||||
| * eq. 39 - compute actual refractive direction */ | * eq. 39 - compute actual refractive direction */ | ||||
| float3 R, T; | float3 T; | ||||
| #ifdef __RAY_DIFFERENTIALS__ | #ifdef __RAY_DIFFERENTIALS__ | ||||
| float3 dRdx, dRdy, dTdx, dTdy; | float3 dTdx, dTdy; | ||||
| #endif | #endif | ||||
| float m_eta = bsdf->ior, fresnel; | float m_eta = bsdf->ior; | ||||
| bool inside; | |||||
| fresnel = fresnel_dielectric(m_eta, m, I, &R, &T, | if(refract_dielectric(m_eta, m, I, | ||||
| #ifdef __RAY_DIFFERENTIALS__ | #ifdef __RAY_DIFFERENTIALS__ | ||||
| dIdx, dIdy, &dRdx, &dRdy, &dTdx, &dTdy, | dIdx, dIdy, &dTdx, &dTdy, | ||||
| #endif | #endif | ||||
| &inside); | &T)) | ||||
| { | |||||
| if(!inside && fresnel != 1.0f) { | |||||
| *omega_in = T; | *omega_in = T; | ||||
| #ifdef __RAY_DIFFERENTIALS__ | #ifdef __RAY_DIFFERENTIALS__ | ||||
| *domega_in_dx = dTdx; | *domega_in_dx = dTdx; | ||||
| *domega_in_dy = dTdy; | *domega_in_dy = dTdy; | ||||
| #endif | #endif | ||||
| if(alpha_x*alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) { | if(alpha_x*alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) { | ||||
| ▲ Show 20 Lines • Show All 45 Lines • Show Last 20 Lines | |||||