Eigen::MatrixBase<Eigen::Matrix<typename matrix::Scalar, matrix::Rows + 1, matrix::Rows + 1>> get_rigid_transform( const Eigen::MatrixBase<matrix>& a, const Eigen::MatrixBase<matrix>& b) { Eigen::Matrix<typename matrix::Scalar, matrix::Rows + 1, matrix::Rows + 1> transform = Eigen::Matrix<typename matrix::Scalar, matrix::Rows + 1, matrix::Rows + 1>::Identity(); auto centroid_a = a.colwise() - a.rowwise().mean(); auto centroid_b = b.colwise() - b.rowwise().mean(); auto svd = (centered_a * centered_b.transpose()).eval().jacobiSVD(Eigen::ComputeFullU | Eigen::ComputeFullV); auto U = svd.matrixU(); auto V = svd.matrixV(); auto R = (V * U.transpose()).eval(); auto C = Eigen::Matrix<typename matrix::Scalar, matrix::Rows, matrix::Rows>::Identity().eval(); C(matrix::Rows - 1, matrix::Rows - 1) = R.determinant(); R = V * C * U.transpose(); auto T = -R * centroid_a + centroid_b; transform.block<matrix::Rows, matrix::Rows>(0, 0) = R; transform.block<matrix::Rows, 1>(0, matrix::Rows) = T; return transform; }
void microfacetNoExpFourierSeries(Float mu_o, Float mu_i, std::complex<Float> eta_, Float alpha, size_t n, Float phiMax, std::vector<Float> &result) { bool reflect = -mu_i * mu_o > 0; Float sinMu2 = math::safe_sqrt((1 - mu_i * mu_i) * (1 - mu_o * mu_o)), phiCritical = 0.0f; bool conductor = (eta_.imag() != 0.0f); std::complex<Float> eta = (-mu_i > 0 || conductor) ? eta_ : std::complex<Float>(1) / eta_; if (reflect) { if (!conductor) phiCritical = math::safe_acos((2*eta.real()*eta.real()-mu_i*mu_o-1)/sinMu2); } else if (!reflect) { if (conductor) throw std::runtime_error("lowfreqFourierSeries(): encountered refraction case for a conductor"); Float etaDenser = (eta.real() > 1 ? eta.real() : 1 / eta.real()); phiCritical = math::safe_acos((1 - etaDenser * mu_i * mu_o) / (etaDenser * sinMu2)); } if (!conductor && phiCritical > math::Epsilon && phiCritical < math::Pi - math::Epsilon && phiCritical < phiMax - math::Epsilon) { /* Uh oh, some high frequency content leaked in the generally low frequency part. Increase the number of coefficients so that we can capture it. Fortunately, this happens very rarely. */ n = std::max(n, (size_t) 100); } VectorX coeffs(n); coeffs.setZero(); std::function<Float(Float)> integrand = std::bind( µfacetNoExp, mu_o, mu_i, eta_, alpha, std::placeholders::_1); const int nEvals = 200; if (reflect) { if (phiCritical > math::Epsilon && phiCritical < phiMax-math::Epsilon) { filonIntegrate(integrand, coeffs.data(), n, nEvals, 0, phiCritical); filonIntegrate(integrand, coeffs.data(), n, nEvals, phiCritical, phiMax); } else { filonIntegrate(integrand, coeffs.data(), n, nEvals, 0, phiMax); } } else { filonIntegrate(integrand, coeffs.data(), n, nEvals, 0, std::min(phiCritical, phiMax)); } if (phiMax < math::Pi - math::Epsilon) { /* Precompute some sines and cosines */ VectorX cosPhi(n), sinPhi(n); for (int i=0; i<n; ++i) { sinPhi[i] = std::sin(i*phiMax); cosPhi[i] = std::cos(i*phiMax); } /* The fit only occurs on a subset [0, phiMax], where the Fourier Fourier basis functions are not orthogonal anymore! The following then does a change of basis to proper Fourier coefficients. */ MatrixX A(n, n); for (int i=0; i<n; ++i) { for (int j=0; j<=i; ++j) { if (i != j) { A(i, j) = A(j, i) = (i * cosPhi[j] * sinPhi[i] - j * cosPhi[i] * sinPhi[j]) / (i * i - j * j); } else if (i != 0) { A(i, i) = (std::sin(2 * i * phiMax) + 2 * i * phiMax) / (4 * i); } else { A(i, i) = phiMax; } } } auto svd = A.bdcSvd(Eigen::ComputeFullU | Eigen::ComputeFullV); const MatrixX &U = svd.matrixU(); const MatrixX &V = svd.matrixV(); const VectorX &sigma = svd.singularValues(); if (sigma[0] == 0) { result.clear(); result.push_back(0); return; } VectorX temp = VectorX::Zero(n); coeffs[0] *= math::Pi; coeffs.tail(n-1) *= 0.5 * math::Pi; for (int i=0; i<n; ++i) { if (sigma[i] < 1e-9f * sigma[0]) break; temp += V.col(i) * U.col(i).dot(coeffs) / sigma[i]; } coeffs = temp; } result.resize(coeffs.size()); memcpy(result.data(), coeffs.data(), sizeof(Float) * coeffs.size()); }