| 328 | }; |
| 329 | |
| 330 | struct BeckmannDist { |
| 331 | static float F(const float tan_m2) { |
| 332 | return float(1 / M_PI) * OIIO::fast_exp(-tan_m2); |
| 333 | } |
| 334 | |
| 335 | static float Lambda(const float a2) { |
| 336 | const float a = sqrtf(a2); |
| 337 | return a < 1.6f ? (1.0f - 1.259f * a + 0.396f * a2) / (3.535f * a + 2.181f * a2) : 0.0f; |
| 338 | } |
| 339 | |
| 340 | static Vec2 sampleSlope(float cos_theta, float randu, float randv) { |
| 341 | const float SQRT_PI_INV = 1 / sqrtf(float(M_PI)); |
| 342 | float ct = cos_theta < 1e-6f ? 1e-6f : cos_theta; |
| 343 | float tanThetaI = sqrtf(1 - ct * ct) / ct; |
| 344 | float cotThetaI = 1 / tanThetaI; |
| 345 | |
| 346 | /* sample slope X */ |
| 347 | // compute a coarse approximation using the approximation: |
| 348 | // exp(-ierf(x)^2) ~= 1 - x * x |
| 349 | // solve y = 1 + b + K * (1 - b * b) |
| 350 | float c = OIIO::fast_erf(cotThetaI); |
| 351 | float K = tanThetaI * SQRT_PI_INV; |
| 352 | float yApprox = randu * (1.0f + c + K * (1 - c * c)); |
| 353 | float yExact = randu * (1.0f + c + K * OIIO::fast_exp(-cotThetaI * cotThetaI)); |
| 354 | float b = K > 0 ? (0.5f - sqrtf(K * (K - yApprox + 1.0f) + 0.25f)) / K : yApprox - 1.0f; |
| 355 | |
| 356 | // perform newton step to refine toward the true root |
| 357 | float invErf = OIIO::fast_ierf(b); |
| 358 | float value = 1.0f + b + K * OIIO::fast_exp(-invErf * invErf) - yExact; |
| 359 | |
| 360 | // check if we are close enough already |
| 361 | // this also avoids NaNs as we get close to the root |
| 362 | Vec2 slope; |
| 363 | if (fabsf(value) > 1e-6f) { |
| 364 | b -= value / (1 - invErf * tanThetaI); // newton step 1 |
| 365 | invErf = OIIO::fast_ierf(b); |
| 366 | value = 1.0f + b + K * OIIO::fast_exp(-invErf * invErf) - yExact; |
| 367 | b -= value / (1 - invErf * tanThetaI); // newton step 2 |
| 368 | // compute the slope from the refined value |
| 369 | slope.x = OIIO::fast_ierf(b); |
| 370 | } else { |
| 371 | // we are close enough already |
| 372 | slope.x = invErf; |
| 373 | } |
| 374 | |
| 375 | /* sample slope Y */ |
| 376 | slope.y = OIIO::fast_ierf(2.0f * randv - 1.0f); |
| 377 | |
| 378 | return slope; |
| 379 | } |
| 380 | }; |
| 381 | |
| 382 | |
| 383 | template <typename Distribution, int Refract> |
nothing calls this directly
no outgoing calls
no test coverage detected