Vector sampleVNormal(const Vector &wi, Sampler *sampler, Float Sxx, Float Syy, Float Szz, Float Sxy, Float Sxz, Float Syz) const { Float u1 = sampler->next1D(); Float u2 = sampler->next1D(); Float r = sqrtf(u1); Float phi = 2.f * M_PI * u2; Float u = r * cosf(phi); Float v = r * sinf(phi); Float w = sqrtf(1.f - u * u - v * v); Vector wk, wj; Frame frame(wi); wk = frame.s; wj = frame.t; // project S in this basis Float Skk = wk.x * wk.x * Sxx + wk.y * wk.y * Syy + wk.z * wk.z * Szz + 2.f * (wk.x * wk.y * Sxy + wk.x * wk.z * Sxz + wk.y * wk.z * Syz); Float Sjj = wj.x * wj.x * Sxx + wj.y * wj.y * Syy + wj.z * wj.z * Szz + 2.f * (wj.x * wj.y * Sxy + wj.x * wj.z * Sxz + wj.y * wj.z * Syz); Float Sii = wi.x * wi.x * Sxx + wi.y * wi.y * Syy + wi.z * wi.z * Szz + 2.f * (wi.x * wi.y * Sxy + wi.x * wi.z * Sxz + wi.y * wi.z * Syz); Float Skj = wk.x * wj.x * Sxx + wk.y * wj.y * Syy + wk.z * wj.z * Szz + (wk.x * wj.y + wk.y * wj.x) * Sxy + (wk.x * wj.z + wk.z * wj.x) * Sxz + (wk.y * wj.z + wk.z * wj.y) * Syz; Float Ski = wk.x * wi.x * Sxx + wk.y * wi.y * Syy + wk.z * wi.z * Szz + (wk.x * wi.y + wk.y * wi.x) * Sxy + (wk.x * wi.z + wk.z * wi.x) * Sxz + (wk.y * wi.z + wk.z * wi.y) * Syz; Float Sji = wj.x * wi.x * Sxx + wj.y * wi.y * Syy + wj.z * wi.z * Szz + (wj.x * wi.y + wj.y * wi.x) * Sxy + (wj.x * wi.z + wj.z * wi.x) * Sxz + (wj.y * wi.z + wj.z * wi.y) * Syz; Float sqrtDetSkji = sqrtf(fabs(Skk * Sjj * Sii - Skj * Skj * Sii - Ski * Ski * Sjj - Sji * Sji * Skk + 2.f * Skj * Ski * Sji)); Float invSqrtSii = 1.f / sqrt(Sii); Float tmp = sqrtf(Sjj * Sii - Sji * Sji); Vector Mk(sqrtDetSkji / tmp, 0.f, 0.f); Vector Mj(-invSqrtSii * (Ski * Sji - Skj * Sii) / tmp, invSqrtSii * tmp, 0); Vector Mi(invSqrtSii * Ski, invSqrtSii * Sji, invSqrtSii * Sii); Vector wm_kji = normalize(u * Mk + v * Mj + w * Mi); return normalize(wm_kji.x * wk + wm_kji.y * wj + wm_kji.z * wi); }
vec3 sample_VNDF(const vec3 wi, const float S_xx, const float S_yy, const float S_zz, const float S_xy, const float S_xz, const float S_yz, const float U1, const float U2) { // generate sample (u, v, w) const float r = sqrtf(U1); const float phi = 2.0f*M_PI*U2; const float u = r*cosf(phi); const float v = r*sinf(phi); const float w = sqrtf(1.0f - u*u - v*v); // build orthonormal basis vec3 wk, wj; buildOrthonormalBasis(wk, wj, wi); // project S in this basis const float S_kk = wk.x*wk.x*S_xx + wk.y*wk.y*S_yy + wk.z*wk.z*S_zz + 2.0f * (wk.x*wk.y*S_xy + wk.x*wk.z*S_xz + wk.y*wk.z*S_yz); const float S_jj = wj.x*wj.x*S_xx + wj.y*wj.y*S_yy + wj.z*wj.z*S_zz + 2.0f * (wj.x*wj.y*S_xy + wj.x*wj.z*S_xz + wj.y*wj.z*S_yz); const float S_ii = wi.x*wi.x*S_xx + wi.y*wi.y*S_yy + wi.z*wi.z*S_zz + 2.0f * (wi.x*wi.y*S_xy + wi.x*wi.z*S_xz + wi.y*wi.z*S_yz); const float S_kj = wk.x*wj.x*S_xx + wk.y*wj.y*S_yy + wk.z*wj.z*S_zz + (wk.x*wj.y + wk.y*wj.x)*S_xy + (wk.x*wj.z + wk.z*wj.x)*S_xz + (wk.y*wj.z + wk.z*wj.y)*S_yz; const float S_ki = wk.x*wi.x*S_xx + wk.y*wi.y*S_yy + wk.z*wi.z*S_zz + (wk.x*wi.y + wk.y*wi.x)*S_xy + (wk.x*wi.z + wk.z*wi.x)*S_xz + (wk.y*wi.z + wk.z*wi.y)*S_yz; const float S_ji = wj.x*wi.x*S_xx + wj.y*wi.y*S_yy + wj.z*wi.z*S_zz + (wj.x*wi.y + wj.y*wi.x)*S_xy + (wj.x*wi.z + wj.z*wi.x)*S_xz + (wj.y*wi.z + wj.z*wi.y)*S_yz; // compute normal float sqrtDetSkji = sqrtf(fabsf(S_kk*S_jj*S_ii - S_kj*S_kj*S_ii - S_ki*S_ki*S_jj - S_ji*S_ji*S_kk + 2.0f*S_kj*S_ki*S_ji)); float inv_sqrtS_ii = 1.0f / sqrtf(S_ii); float tmp = sqrtf(S_jj*S_ii - S_ji*S_ji); vec3 Mk(sqrtDetSkji / tmp, 0.0f, 0.0f); vec3 Mj(-inv_sqrtS_ii*(S_ki*S_ji - S_kj*S_ii) / tmp, inv_sqrtS_ii*tmp, 0); vec3 Mi(inv_sqrtS_ii*S_ki, inv_sqrtS_ii*S_ji, inv_sqrtS_ii*S_ii); vec3 wm_kji = normalize(u*Mk + v*Mj + w*Mi); // rotate back to world basis return wm_kji.x * wk + wm_kji.y * wj + wm_kji.z * wi; }