The anisotropic variant of GGX and Beckmann comes from * "Understanding the Masking-Shadowing Function in * Microfacet-Based BRDFs" by Eric Heitz, JCGT 2014 (section 5.4) * * We use the height correlated masking and shadowing function * instead of the separable form as it is more realistic and * reduces energy loss at grazing angles. * * The sampling method is derived from "Importance Samp
| 295 | * is sufficient). |
| 296 | */ |
| 297 | struct GGXDist { |
| 298 | static float F(const float tan_m2) { |
| 299 | return 1 / (float(M_PI) * (1 + tan_m2) * (1 + tan_m2)); |
| 300 | } |
| 301 | |
| 302 | static float Lambda(const float a2) { |
| 303 | return 0.5f * (-1.0f + sqrtf(1.0f + 1.0f / a2)); |
| 304 | } |
| 305 | |
| 306 | static Vec2 sampleSlope(float cos_theta, float randu, float randv) { |
| 307 | // GGX |
| 308 | Vec2 slope; |
| 309 | /* sample slope_x */ |
| 310 | |
| 311 | float c = cos_theta < 1e-6f ? 1e-6f : cos_theta; |
| 312 | float Q = (1 + c) * randu - c; |
| 313 | float num = c * sqrtf((1 - c) * (1 + c)) - Q * sqrtf((1 - Q) * (1 + Q)); |
| 314 | float den = (Q - c) * (Q + c); |
| 315 | float eps = 1.0f / 4294967296.0f; |
| 316 | den = fabsf(den) < eps ? copysignf(eps, den) : den; |
| 317 | slope.x = num / den; |
| 318 | |
| 319 | /* sample slope_y */ |
| 320 | float Ru = 1 - 2 * randv; |
| 321 | float u2 = fabsf(Ru); |
| 322 | float z = (u2 * (u2 * (u2 * 0.27385f - 0.73369f) + 0.46341f)) / |
| 323 | (u2 * (u2 * (u2 * 0.093073f + 0.309420f) - 1.0f) + 0.597999f); |
| 324 | slope.y = copysignf(1.0f, Ru) * z * sqrtf(1.0f + slope.x * slope.x); |
| 325 | |
| 326 | return slope; |
| 327 | } |
| 328 | }; |
| 329 | |
| 330 | struct BeckmannDist { |
| 331 | static float F(const float tan_m2) { |
nothing calls this directly
no outgoing calls
no test coverage detected