Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/closure/bsdf_microfacet.h
| Show First 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | ccl_device_inline void microfacet_beckmann_sample_slopes(KernelGlobals kg, | ||||
| 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); | const float Lambda = 0.5f * (erf_a - 1.0f) + (0.5f * SQRT_PI_INV) * (exp_a2 * inv_a); | ||||
| const float G1 = 1.0f / (1.0f + Lambda); /* masking */ | const float G1 = 1.0f / (1.0f + Lambda); /* masking */ | ||||
| *G1i = G1; | *G1i = G1; | ||||
| #if defined(__KERNEL_GPU__) | |||||
| /* 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) | ||||
| */ | */ | ||||
| float K = tan_theta_i * SQRT_PI_INV; | const float K = tan_theta_i * SQRT_PI_INV; | ||||
| 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)); | ||||
| 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; | ||||
| /* Perform newton step to refine toward the true root. */ | |||||
| float inv_erf = fast_ierff(b); | float inv_erf = fast_ierff(b); | ||||
| float value = 1.0f + b + K * expf(-inv_erf * inv_erf) - y_exact; | float2 begin = make_float2(-1.0f, -y_exact); | ||||
| /* Check if we are close enough already, | float2 end = make_float2(erf_a, 1.0f + erf_a + K * exp_a2 - y_exact); | ||||
| * this also avoids NaNs as we get close to the root. | float2 current = make_float2(b, 1.0f + b + K * expf(-sqr(inv_erf)) - y_exact); | ||||
| */ | |||||
| if (fabsf(value) > 1e-6f) { | /* Find root in a monotonic interval using newton method, under given precision and maximal | ||||
| b -= value / (1.0f - inv_erf * tan_theta_i); /* newton step 1. */ | * iterations. Falls back to bisection if newton step produces results outside of the valid | ||||
| inv_erf = fast_ierff(b); | * interval.*/ | ||||
| value = 1.0f + b + K * expf(-inv_erf * inv_erf) - y_exact; | const float precision = 1e-6f; | ||||
| b -= value / (1.0f - inv_erf * tan_theta_i); /* newton step 2. */ | const int max_iter = 3; | ||||
| /* Compute the slope from the refined value. */ | int iter = 0; | ||||
| *slope_x = fast_ierff(b); | while (fabsf(current.y) > precision && iter++ < max_iter) { | ||||
| if (signf(begin.y) == signf(current.y)) { | |||||
| begin.x = current.x; | |||||
| begin.y = current.y; | |||||
| } | } | ||||
| else { | else { | ||||
| /* We are close enough already. */ | end.x = current.x; | ||||
| *slope_x = inv_erf; | } | ||||
| 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); | |||||
| inv_erf = fast_ierff(current.x); | |||||
| current.y = 1.0f + current.x + K * expf(-sqr(inv_erf)) - y_exact; | |||||
| } | } | ||||
| *slope_y = fast_ierff(2.0f * randv - 1.0f); | |||||
| #else | |||||
| /* Use precomputed table on CPU, it gives better performance. */ | |||||
| int beckmann_table_offset = kernel_data.tables.beckmann_offset; | |||||
| *slope_x = lookup_table_read_2D( | *slope_x = inv_erf; | ||||
| kg, randu, cos_theta_i, beckmann_table_offset, BECKMANN_TABLE_SIZE, BECKMANN_TABLE_SIZE); | |||||
| *slope_y = fast_ierff(2.0f * randv - 1.0f); | *slope_y = fast_ierff(2.0f * randv - 1.0f); | ||||
| #endif | |||||
| } | } | ||||
| /* GGX microfacet importance sampling from: | /* GGX microfacet importance sampling from: | ||||
| * | * | ||||
| * Importance Sampling Microfacet-Based BSDFs using the Distribution of Visible Normals. | * Importance Sampling Microfacet-Based BSDFs using the Distribution of Visible Normals. | ||||
| * E. Heitz and E. d'Eon, EGSR 2014 | * E. Heitz and E. d'Eon, EGSR 2014 | ||||
| */ | */ | ||||
| ▲ Show 20 Lines • Show All 606 Lines • Show Last 20 Lines | |||||