Changeset View
Standalone View
intern/cycles/kernel/closure/bsdf_microfacet.h
| Show All 31 Lines | typedef struct MicrofacetBsdf { | ||||
| float alpha_x, alpha_y, ior; | float alpha_x, alpha_y, ior; | ||||
| ccl_private MicrofacetExtra *extra; | ccl_private MicrofacetExtra *extra; | ||||
| float3 T; | float3 T; | ||||
| } MicrofacetBsdf; | } MicrofacetBsdf; | ||||
| static_assert(sizeof(ShaderClosure) >= sizeof(MicrofacetBsdf), "MicrofacetBsdf is too large!"); | static_assert(sizeof(ShaderClosure) >= sizeof(MicrofacetBsdf), "MicrofacetBsdf is too large!"); | ||||
| /* Beckmann and GGX microfacet importance sampling. */ | /* Beckmann VNDF importance sampling algorithm from: | ||||
| * Importance Sampling Microfacet-Based BSDFs using the Distribution of Visible Normals. | |||||
| * Eric Heitz and Eugene d'Eon, EGSR 2014. | |||||
| * https://hal.inria.fr/hal-00996995v2/document */ | |||||
| ccl_device_inline void microfacet_beckmann_sample_slopes(KernelGlobals kg, | ccl_device_forceinline float3 microfacet_beckmann_sample_vndf(KernelGlobals kg, | ||||
| const float cos_theta_i, | const float3 wi, | ||||
| const float sin_theta_i, | const float alpha_x, | ||||
| float randu, | const float alpha_y, | ||||
| float randv, | const float randu, | ||||
| ccl_private float *slope_x, | const float randv) | ||||
| ccl_private float *slope_y, | |||||
| ccl_private float *lambda_i) | |||||
| { | { | ||||
| /* 1. stretch wi */ | |||||
| float3 wi_ = make_float3(alpha_x * wi.x, alpha_y * wi.y, wi.z); | |||||
| wi_ = normalize(wi_); | |||||
| /* 2. sample P22_{wi}(x_slope, y_slope, 1, 1) */ | |||||
| float slope_x, slope_y; | |||||
| float cos_phi_i = 1.0f; | |||||
| float sin_phi_i = 0.0f; | |||||
| if (wi_.z >= 0.99999f) { | |||||
| /* Special case (normal incidence). */ | /* Special case (normal incidence). */ | ||||
| if (cos_theta_i >= 0.99999f) { | |||||
| const float r = sqrtf(-logf(randu)); | const float r = sqrtf(-logf(randu)); | ||||
| const float phi = M_2PI_F * randv; | const float phi = M_2PI_F * randv; | ||||
| *slope_x = r * cosf(phi); | slope_x = r * cosf(phi); | ||||
| *slope_y = r * sinf(phi); | slope_y = r * sinf(phi); | ||||
| *lambda_i = 0.0f; | |||||
| return; | |||||
| } | } | ||||
| else { | |||||
| /* Precomputations. */ | /* Precomputations. */ | ||||
| const float cos_theta_i = wi_.z; | |||||
| const float sin_theta_i = sin_from_cos(cos_theta_i); | |||||
weizhen: Could we make utility functions out of this? Seem to be used often, see `sin_from_cos` in [tree. | |||||
Done Inline ActionsGood point, I moved them to math.h and replaced the obvious uses I could find. lukasstockner97: Good point, I moved them to `math.h` and replaced the obvious uses I could find.
I kept both… | |||||
Not Done Inline ActionsI think keeping both sin_from_cos and cos_from_sin is fine, it's more readable and makes it more clear what we are computing there. weizhen: I think keeping both `sin_from_cos` and `cos_from_sin` is fine, it's more readable and makes it… | |||||
| const float tan_theta_i = sin_theta_i / cos_theta_i; | const float tan_theta_i = sin_theta_i / cos_theta_i; | ||||
| const float inv_a = tan_theta_i; | |||||
| const float cot_theta_i = 1.0f / tan_theta_i; | const float cot_theta_i = 1.0f / tan_theta_i; | ||||
| const float erf_a = fast_erff(cot_theta_i); | const float erf_a = fast_erff(cot_theta_i); | ||||
| const float exp_a2 = expf(-cot_theta_i * cot_theta_i); | const float exp_a2 = expf(-cot_theta_i * cot_theta_i); | ||||
| const float SQRT_PI_INV = 0.56418958354f; | const float SQRT_PI_INV = 0.56418958354f; | ||||
| const float Lambda = 0.5f * (erf_a - 1.0f) + (0.5f * SQRT_PI_INV) * (exp_a2 * inv_a); | |||||
| *lambda_i = Lambda; | float invlen = 1.0f / sin_theta_i; | ||||
| cos_phi_i = wi_.x * invlen; | |||||
| sin_phi_i = wi_.y * invlen; | |||||
| /* Based on paper from Wenzel Jakob | /* Based on paper from Wenzel Jakob | ||||
| * An Improved Visible Normal Sampling Routine for the Beckmann Distribution | * An Improved Visible Normal Sampling Routine for the Beckmann Distribution | ||||
| * | * | ||||
| * http://www.mitsuba-renderer.org/~wenzel/files/visnormal.pdf | * http://www.mitsuba-renderer.org/~wenzel/files/visnormal.pdf | ||||
| * | * | ||||
| * Reformulation from OpenShadingLanguage which avoids using inverse | * Reformulation from OpenShadingLanguage which avoids using inverse | ||||
| * trigonometric functions. | * trigonometric functions. | ||||
| */ | */ | ||||
| /* Sample slope X. | /* Sample slope X. | ||||
| * | * | ||||
| * Compute a coarse approximation using the approximation: | * Compute a coarse approximation using the approximation: | ||||
| * exp(-ierf(x)^2) ~= 1 - x * x | * exp(-ierf(x)^2) ~= 1 - x * x | ||||
| * solve y = 1 + b + K * (1 - b * b) | * solve y = 1 + b + K * (1 - b * b) | ||||
| */ | */ | ||||
| const float K = tan_theta_i * SQRT_PI_INV; | const float K = tan_theta_i * SQRT_PI_INV; | ||||
| const float y_approx = randu * (1.0f + erf_a + K * (1 - erf_a * erf_a)); | const float y_approx = randu * (1.0f + erf_a + K * (1 - erf_a * erf_a)); | ||||
| const float y_exact = randu * (1.0f + erf_a + K * exp_a2); | const float y_exact = randu * (1.0f + erf_a + K * exp_a2); | ||||
| float b = K > 0 ? (0.5f - sqrtf(K * (K - y_approx + 1.0f) + 0.25f)) / K : y_approx - 1.0f; | float b = K > 0 ? (0.5f - sqrtf(K * (K - y_approx + 1.0f) + 0.25f)) / K : y_approx - 1.0f; | ||||
| float inv_erf = fast_ierff(b); | float inv_erf = fast_ierff(b); | ||||
| float2 begin = make_float2(-1.0f, -y_exact); | float2 begin = make_float2(-1.0f, -y_exact); | ||||
| float2 end = make_float2(erf_a, 1.0f + erf_a + K * exp_a2 - y_exact); | float2 end = make_float2(erf_a, 1.0f + erf_a + K * exp_a2 - y_exact); | ||||
| float2 current = make_float2(b, 1.0f + b + K * expf(-sqr(inv_erf)) - y_exact); | float2 current = make_float2(b, 1.0f + b + K * expf(-sqr(inv_erf)) - y_exact); | ||||
| /* Find root in a monotonic interval using newton method, under given precision and maximal | /* Find root in a monotonic interval using newton method, under given precision and maximal | ||||
| * iterations. Falls back to bisection if newton step produces results outside of the valid | * iterations. Falls back to bisection if newton step produces results outside of the valid | ||||
| * interval.*/ | * interval.*/ | ||||
| const float precision = 1e-6f; | const float precision = 1e-6f; | ||||
| const int max_iter = 3; | const int max_iter = 3; | ||||
| int iter = 0; | int iter = 0; | ||||
| while (fabsf(current.y) > precision && iter++ < max_iter) { | while (fabsf(current.y) > precision && iter++ < max_iter) { | ||||
| if (signf(begin.y) == signf(current.y)) { | if (signf(begin.y) == signf(current.y)) { | ||||
| begin.x = current.x; | begin.x = current.x; | ||||
| begin.y = current.y; | begin.y = current.y; | ||||
| } | } | ||||
| else { | else { | ||||
| end.x = current.x; | end.x = current.x; | ||||
| } | } | ||||
| const float newton_x = current.x - current.y / (1.0f - inv_erf * tan_theta_i); | const float newton_x = current.x - current.y / (1.0f - inv_erf * tan_theta_i); | ||||
| current.x = (newton_x >= begin.x && newton_x <= end.x) ? newton_x : 0.5f * (begin.x + end.x); | current.x = (newton_x >= begin.x && newton_x <= end.x) ? newton_x : 0.5f * (begin.x + end.x); | ||||
| inv_erf = fast_ierff(current.x); | inv_erf = fast_ierff(current.x); | ||||
| current.y = 1.0f + current.x + K * expf(-sqr(inv_erf)) - y_exact; | current.y = 1.0f + current.x + K * expf(-sqr(inv_erf)) - y_exact; | ||||
| } | } | ||||
| *slope_x = inv_erf; | slope_x = inv_erf; | ||||
| *slope_y = fast_ierff(2.0f * randv - 1.0f); | slope_y = fast_ierff(2.0f * randv - 1.0f); | ||||
| } | |||||
| /* GGX microfacet importance sampling from: | |||||
| * | |||||
| * Importance Sampling Microfacet-Based BSDFs using the Distribution of Visible Normals. | |||||
| * E. Heitz and E. d'Eon, EGSR 2014 | |||||
| */ | |||||
| ccl_device_inline void microfacet_ggx_sample_slopes(const float cos_theta_i, | |||||
| const float sin_theta_i, | |||||
| float randu, | |||||
| float randv, | |||||
| ccl_private float *slope_x, | |||||
| ccl_private float *slope_y, | |||||
| ccl_private float *lambda_i) | |||||
| { | |||||
| /* Special case (normal incidence). */ | |||||
| if (cos_theta_i >= 0.99999f) { | |||||
| const float r = sqrtf(randu / (1.0f - randu)); | |||||
| const float phi = M_2PI_F * randv; | |||||
| *slope_x = r * cosf(phi); | |||||
| *slope_y = r * sinf(phi); | |||||
| *lambda_i = 0.0f; | |||||
| return; | |||||
| } | } | ||||
| /* Precomputations. */ | /* 3. rotate */ | ||||
| const float tan_theta_i = sin_theta_i / cos_theta_i; | float tmp = cos_phi_i * slope_x - sin_phi_i * slope_y; | ||||
| const float G1_inv = 0.5f * (1.0f + safe_sqrtf(1.0f + tan_theta_i * tan_theta_i)); | slope_y = sin_phi_i * slope_x + cos_phi_i * slope_y; | ||||
| slope_x = tmp; | |||||
| *lambda_i = G1_inv - 1.0f; | |||||
| /* Sample slope_x. */ | |||||
| const float A = 2.0f * randu * G1_inv - 1.0f; | |||||
| const float AA = A * A; | |||||
| const float tmp = 1.0f / (AA - 1.0f); | |||||
| const float B = tan_theta_i; | |||||
| const float BB = B * B; | |||||
| const float D = safe_sqrtf(BB * (tmp * tmp) - (AA - BB) * tmp); | |||||
| const float slope_x_1 = B * tmp - D; | |||||
| const float slope_x_2 = B * tmp + D; | |||||
| *slope_x = (A < 0.0f || slope_x_2 * tan_theta_i > 1.0f) ? slope_x_1 : slope_x_2; | |||||
| /* Sample slope_y. */ | |||||
| float S; | |||||
| if (randv > 0.5f) { | /* 4. unstretch */ | ||||
| S = 1.0f; | slope_x = alpha_x * slope_x; | ||||
| randv = 2.0f * (randv - 0.5f); | slope_y = alpha_y * slope_y; | ||||
| } | |||||
| else { | |||||
| S = -1.0f; | |||||
| randv = 2.0f * (0.5f - randv); | |||||
| } | |||||
| const float z = (randv * (randv * (randv * 0.27385f - 0.73369f) + 0.46341f)) / | /* 5. compute normal */ | ||||
| (randv * (randv * (randv * 0.093073f + 0.309420f) - 1.000000f) + 0.597999f); | return normalize(make_float3(-slope_x, -slope_y, 1.0f)); | ||||
| *slope_y = S * z * safe_sqrtf(1.0f + (*slope_x) * (*slope_x)); | |||||
| } | } | ||||
| template<MicrofacetType m_type> | /* GGX VNDF importance sampling algorithm from: | ||||
| ccl_device_forceinline float3 microfacet_sample_stretched(KernelGlobals kg, | * Sampling the GGX Distribution of Visible Normals. | ||||
| const float3 wi, | * Eric Heitz, JCGT Vol. 7, No. 4, 2018. | ||||
| * https://jcgt.org/published/0007/04/01/ */ | |||||
| ccl_device_forceinline float3 microfacet_ggx_sample_vndf(const float3 wi, | |||||
| const float alpha_x, | const float alpha_x, | ||||
| const float alpha_y, | const float alpha_y, | ||||
| const float randu, | const float randu, | ||||
| const float randv, | const float randv) | ||||
| ccl_private float *lambda_i) | |||||
| { | { | ||||
| /* 1. stretch wi */ | /* Section 3.2: Transforming the view direction to the hemisphere configuration. */ | ||||
| float3 wi_ = make_float3(alpha_x * wi.x, alpha_y * wi.y, wi.z); | float3 wi_ = normalize(make_float3(alpha_x * wi.x, alpha_y * wi.y, wi.z)); | ||||
| wi_ = normalize(wi_); | |||||
| /* Compute polar coordinates of wi_. */ | /* Section 4.1: Orthonormal basis. */ | ||||
| float costheta_ = 1.0f; | float lensq = sqr(wi_.x) + sqr(wi_.y); | ||||
| float sintheta_ = 0.0f; | float3 T1, T2; | ||||
Done Inline ActionsWe have inversesqrtf() weizhen: We have `inversesqrtf()` | |||||
| float cosphi_ = 1.0f; | if (lensq > 1e-7f) { | ||||
| float sinphi_ = 0.0f; | T1 = make_float3(-wi_.y, wi_.x, 0.0f) * inversesqrtf(lensq); | ||||
| T2 = cross(wi_, T1); | |||||
| if (wi_.z < 0.99999f) { | |||||
| costheta_ = wi_.z; | |||||
| sintheta_ = sin_from_cos(costheta_); | |||||
| float invlen = 1.0f / sintheta_; | |||||
| cosphi_ = wi_.x * invlen; | |||||
| sinphi_ = wi_.y * invlen; | |||||
| } | |||||
| /* 2. sample P22_{wi}(x_slope, y_slope, 1, 1) */ | |||||
| float slope_x, slope_y; | |||||
| if (m_type == MicrofacetType::BECKMANN) { | |||||
| microfacet_beckmann_sample_slopes( | |||||
| kg, costheta_, sintheta_, randu, randv, &slope_x, &slope_y, lambda_i); | |||||
| } | } | ||||
| else { | else { | ||||
| microfacet_ggx_sample_slopes(costheta_, sintheta_, randu, randv, &slope_x, &slope_y, lambda_i); | /* Normal incidence, any basis is fine. */ | ||||
| T1 = make_float3(1.0f, 0.0f, 0.0f); | |||||
| T2 = make_float3(0.0f, 1.0f, 0.0f); | |||||
| } | } | ||||
| /* 3. rotate */ | /* Section 4.2: Parameterization of the projected area. */ | ||||
| float tmp = cosphi_ * slope_x - sinphi_ * slope_y; | float2 t = concentric_sample_disk(randu, randv); | ||||
| slope_y = sinphi_ * slope_x + cosphi_ * slope_y; | t.y = mix(safe_sqrtf(1.0f - sqr(t.x)), t.y, 0.5f * (1.0f + wi_.z)); | ||||
| slope_x = tmp; | |||||
| /* 4. unstretch */ | /* Section 4.3: Reprojection onto hemisphere. */ | ||||
| slope_x = alpha_x * slope_x; | float3 H_ = t.x * T1 + t.y * T2 + safe_sqrtf(1.0f - len_squared(t)) * wi_; | ||||
| slope_y = alpha_y * slope_y; | |||||
| /* 5. compute normal */ | /* Section 3.4: Transforming the normal back to the ellipsoid configuration. */ | ||||
| return normalize(make_float3(-slope_x, -slope_y, 1.0f)); | return normalize(make_float3(alpha_x * H_.x, alpha_y * H_.y, max(0.0f, H_.z))); | ||||
| } | } | ||||
| /* Calculate the reflection color | /* Calculate the reflection color | ||||
| * | * | ||||
| * If fresnel is used, the color is an interpolation of the F0 color and white | * If fresnel is used, the color is an interpolation of the F0 color and white | ||||
| * with respect to the fresnel | * with respect to the fresnel | ||||
| * | * | ||||
| * Else it is simply white | * Else it is simply white | ||||
| Show All 29 Lines | ccl_device_forceinline float bsdf_clearcoat_D(float alpha2, float cos_NH) | ||||
| const float t = 1.0f + (alpha2 - 1.0f) * cos_NH * cos_NH; | const float t = 1.0f + (alpha2 - 1.0f) * cos_NH * cos_NH; | ||||
| return (alpha2 - 1.0f) / (M_PI_F * logf(alpha2) * t); | return (alpha2 - 1.0f) / (M_PI_F * logf(alpha2) * t); | ||||
| } | } | ||||
| /* Smith shadowing-masking term, here in the non-separable form. | /* Smith shadowing-masking term, here in the non-separable form. | ||||
| * For details, see: | * For details, see: | ||||
| * Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs. | * Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs. | ||||
| * Eric Heitz, JCGT Vol. 3, No. 2, 2014. | * Eric Heitz, JCGT Vol. 3, No. 2, 2014. | ||||
Done Inline ActionsYou mean the paper Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs, Eric Heitz, Journal of Computer Graphics Techniques 3.2 (2014)? weizhen: You mean the paper Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs, Eric… | |||||
Done Inline ActionsAh, yeah, I had moved the comment from below but I mixed the papers up. This reference is supposed to go with the Beckmann sampling. lukasstockner97: Ah, yeah, I had moved the comment from below but I mixed the papers up. This reference is… | |||||
| * https://jcgt.org/published/0003/02/03/ */ | * https://jcgt.org/published/0003/02/03/ */ | ||||
| template<MicrofacetType m_type> | template<MicrofacetType m_type> | ||||
Done Inline ActionsIn the paper just below Eq 69 (and Eq 72) there is a = 1/(alpha tan), so I think it's fine not to comment on this? Just a minor remark from me, doesn't matter much. weizhen: In the paper just below Eq 69 (and Eq 72) there is a = 1/(alpha tan), so I think it's fine not… | |||||
Done Inline ActionsYeah, this is quite obvious I guess. I'll remove it. lukasstockner97: Yeah, this is quite obvious I guess. I'll remove it. | |||||
| ccl_device_inline float bsdf_lambda_from_sqr_alpha_tan_n(float sqr_alpha_tan_n) | ccl_device_inline float bsdf_lambda_from_sqr_alpha_tan_n(float sqr_alpha_tan_n) | ||||
| { | { | ||||
| if (m_type == MicrofacetType::GGX) { | if (m_type == MicrofacetType::GGX) { | ||||
| /* Equation 72. */ | /* Equation 72. */ | ||||
| return 0.5f * (sqrtf(1.0f + sqr_alpha_tan_n) - 1.0f); | return 0.5f * (sqrtf(1.0f + sqr_alpha_tan_n) - 1.0f); | ||||
| } | } | ||||
| else { | else { | ||||
| /* m_type == MicrofacetType::BECKMANN | /* m_type == MicrofacetType::BECKMANN | ||||
| ▲ Show 20 Lines • Show All 184 Lines • ▼ Show 20 Lines | if (alpha_x == alpha_y) { | ||||
| make_orthonormals(N, &X, &Y); | make_orthonormals(N, &X, &Y); | ||||
| } | } | ||||
| else { | else { | ||||
| make_orthonormals_tangent(N, bsdf->T, &X, &Y); | make_orthonormals_tangent(N, bsdf->T, &X, &Y); | ||||
| } | } | ||||
| /* Importance sampling with distribution of visible normals. Vectors are transformed to local | /* Importance sampling with distribution of visible normals. Vectors are transformed to local | ||||
| * space before and after sampling. */ | * space before and after sampling. */ | ||||
| float lambdaI; | |||||
| const float3 local_I = make_float3(dot(X, wi), dot(Y, wi), cos_NI); | const float3 local_I = make_float3(dot(X, wi), dot(Y, wi), cos_NI); | ||||
| const float3 local_H = microfacet_sample_stretched<m_type>( | float3 local_H; | ||||
| kg, local_I, alpha_x, alpha_y, randu, randv, &lambdaI); | if (m_type == MicrofacetType::GGX) { | ||||
| local_H = microfacet_ggx_sample_vndf(local_I, alpha_x, alpha_y, randu, randv); | |||||
| } | |||||
| else { | |||||
| /* m_type == MicrofacetType::BECKMANN */ | |||||
| local_H = microfacet_beckmann_sample_vndf(kg, local_I, alpha_x, alpha_y, randu, randv); | |||||
| } | |||||
| const float3 H = X * local_H.x + Y * local_H.y + N * local_H.z; | const float3 H = X * local_H.x + Y * local_H.y + N * local_H.z; | ||||
| const float cos_NH = local_H.z; | const float cos_NH = local_H.z; | ||||
| const float cos_HI = dot(H, wi); | const float cos_HI = dot(H, wi); | ||||
| bool valid = false; | bool valid = false; | ||||
| if (m_refractive) { | if (m_refractive) { | ||||
| float3 R, T; | float3 R, T; | ||||
| Show All 28 Lines | if (alpha_x * alpha_y <= 1e-7f || (m_refractive && fabsf(m_eta - 1.0f) < 1e-4f)) { | ||||
| if (use_fresnel && !m_refractive) { | if (use_fresnel && !m_refractive) { | ||||
| *eval *= reflection_color(bsdf, *wo, H); | *eval *= reflection_color(bsdf, *wo, H); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| label |= LABEL_GLOSSY; | label |= LABEL_GLOSSY; | ||||
| float cos_NO = dot(N, *wo); | float cos_NO = dot(N, *wo); | ||||
| float D, lambdaO; | float D, lambdaI, lambdaO; | ||||
| /* TODO: add support for anisotropic transmission. */ | /* TODO: add support for anisotropic transmission. */ | ||||
| if (alpha_x == alpha_y || m_refractive) { /* Isotropic. */ | if (alpha_x == alpha_y || m_refractive) { /* Isotropic. */ | ||||
| float alpha2 = alpha_x * alpha_y; | float alpha2 = alpha_x * alpha_y; | ||||
| if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { | if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { | ||||
| D = bsdf_clearcoat_D(alpha2, cos_NH); | D = bsdf_clearcoat_D(alpha2, cos_NH); | ||||
| /* The masking-shadowing term for clearcoat has a fixed alpha of 0.25 | /* The masking-shadowing term for clearcoat has a fixed alpha of 0.25 | ||||
| * => alpha2 = 0.25 * 0.25 */ | * => alpha2 = 0.25 * 0.25 */ | ||||
| alpha2 = 0.0625f; | alpha2 = 0.0625f; | ||||
| /* Recalculate lambdaI. */ | |||||
| lambdaI = bsdf_lambda<m_type>(alpha2, cos_NI); | |||||
| } | } | ||||
| else { | else { | ||||
| D = bsdf_D<m_type>(alpha2, cos_NH); | D = bsdf_D<m_type>(alpha2, cos_NH); | ||||
| } | } | ||||
| lambdaO = bsdf_lambda<m_type>(alpha2, cos_NO); | lambdaO = bsdf_lambda<m_type>(alpha2, cos_NO); | ||||
| lambdaI = bsdf_lambda<m_type>(alpha2, cos_NI); | |||||
| } | } | ||||
| else { /* Anisotropic. */ | else { /* Anisotropic. */ | ||||
| const float3 local_O = make_float3(dot(X, *wo), dot(Y, *wo), cos_NO); | const float3 local_O = make_float3(dot(X, *wo), dot(Y, *wo), cos_NO); | ||||
| D = bsdf_aniso_D<m_type>(alpha_x, alpha_y, local_H); | D = bsdf_aniso_D<m_type>(alpha_x, alpha_y, local_H); | ||||
| lambdaO = bsdf_aniso_lambda<m_type>(alpha_x, alpha_y, local_O); | lambdaO = bsdf_aniso_lambda<m_type>(alpha_x, alpha_y, local_O); | ||||
| lambdaI = bsdf_aniso_lambda<m_type>(alpha_x, alpha_y, local_I); | |||||
| } | } | ||||
| const float cos_HO = dot(H, *wo); | const float cos_HO = dot(H, *wo); | ||||
| const float common = D / cos_NI * | const float common = D / cos_NI * | ||||
| (m_refractive ? fabsf(cos_HI * cos_HO) / sqr(cos_HO + cos_HI / m_eta) : | (m_refractive ? fabsf(cos_HI * cos_HO) / sqr(cos_HO + cos_HI / m_eta) : | ||||
| 0.25f); | 0.25f); | ||||
| *pdf = common / (1.0f + lambdaI); | *pdf = common / (1.0f + lambdaI); | ||||
| ▲ Show 20 Lines • Show All 185 Lines • Show Last 20 Lines | |||||
Could we make utility functions out of this? Seem to be used often, see sin_from_cos in tree.h and cos_from_sin in bsdf_hair_principled.h