/* This file is part of Mitsuba, a physically based rendering system. Copyright (c) 2007-2010 by Wenzel Jakob and others. Mitsuba is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License Version 3 as published by the Free Software Foundation. Mitsuba is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include MTS_NAMESPACE_BEGIN Float *SHVector::m_normalization = NULL; SHVector::SHVector(Stream *stream) { m_bands = stream->readInt(); unsigned int size = m_bands*m_bands; m_coeffs.resize(size); for (size_t i=0; ireadFloat(); } void SHVector::serialize(Stream *stream) const { stream->writeInt(m_bands); for (size_t i=0; iwriteFloat(m_coeffs[i]); } bool SHVector::isAzimuthallyInvariant() const { for (int l=0; l Epsilon || std::abs(operator()(l, m)) > Epsilon) return false; } } return true; } Float SHVector::eval(Float theta, Float phi) const { Float result = 0; Float cosTheta = std::cos(theta); Float *sinPhi = (Float *) alloca(sizeof(Float)*m_bands), *cosPhi = (Float *) alloca(sizeof(Float)*m_bands); for (int m=0; m::infinity(); for (int i=0; i<=res; ++i) { Float theta = hExt*i; for (int j=0; j<=res*2; ++j) { Float phi = hInt*j; minimum = std::min(minimum, eval(theta, phi)); } } return minimum; } void SHVector::offset(Float value) { operator()(0, 0) += 2 * value * (Float) std::sqrt(M_PI); } Float SHVector::eval(const Vector &v) const { Float result = 0; Float cosTheta = v.z, phi = std::atan2(v.y, v.x); if (phi < 0) phi += 2*M_PI; Float *sinPhi = (Float *) alloca(sizeof(Float)*m_bands), *cosPhi = (Float *) alloca(sizeof(Float)*m_bands); for (int m=0; m0) { Float somx2 = std::sqrt(((Float) 1 - x) * ((Float) 1 + x)); Float fact = 1.0; for (int i=1; i<=m; i++) { pmm *= (-fact) * somx2; fact += (Float) 2; } } if (l==m) return pmm; Float pmmp1 = x * ((Float) 2 * m + (Float) 1) * pmm; if (l==m+1) return pmmp1; Float pll = (Float) 0; for (int ll=m+2; ll<=l; ++ll) { pll = (((Float) 2 * ll - (Float) 1)*x*pmmp1 - (ll + m - (Float) 1) * pmm ) / (ll-m); pmm = pmmp1; pmmp1 = pll; } return pll; } void SHVector::normalize() { Float correction = 1/(2 * (Float) std::sqrt(M_PI)*operator()(0,0)); for (size_t i=0; i SHVector::mu2() const { const Float sqrt5o3 = std::sqrt((Float) 5/ (Float) 3); const Float sqrto3 = std::sqrt((Float) 1/ (Float) 3); ublas::matrix result(3, 3); SAssert(m_bands > 0); result.clear(); result(0, 0) = result(1, 1) = result(2, 2) = sqrt5o3*operator()(0,0); if (m_bands >= 3) { result(0, 0) += -operator()(2,0)*sqrto3 + operator()(2,2); result(0, 1) = operator()(2,-2); result(0, 2) = -operator()(2, 1); result(1, 0) = operator()(2,-2); result(1, 1) += -operator()(2,0)*sqrto3 - operator()(2,2); result(1, 2) = -operator()(2,-1); result(2, 0) = -operator()(2, 1); result(2, 1) = -operator()(2,-1); result(2, 2) += 2*sqrto3*operator()(2,0); } return result * (2*std::sqrt((Float) M_PI / 15)); } std::string SHVector::toString() const { std::ostringstream oss; oss << "SHVector[bands=" << m_bands << ", {"; int pos = 0; for (int i=0; i=0); return std::sqrt( ((2*l+1) * boost::math::factorial(l-m)) / (4 * (Float) M_PI * boost::math::factorial(l+m))); } void SHVector::staticInitialization() { m_normalization = new Float[SH_NORMTBL_SIZE*(SH_NORMTBL_SIZE+1)/2]; for (int l=0; l &M1, &Mp; ublas::matrix &Mn; int prevLevel, level; inline RotationBlockHelper( const ublas::matrix &M1, const ublas::matrix &Mp, ublas::matrix &Mn) : M1(M1), Mp(Mp), Mn(Mn), prevLevel((int) Mp.size1()/2), level((int) Mp.size1()/2+1) { } inline Float delta(int i, int j) const { return (i == j) ? (Float) 1 : (Float) 0; } inline Float U(int l, int m, int n) const { return P(l, m, n, 0); } inline Float V(int l, int m, int n) const { if (m == 0) { return P(l, 1, n, 1) + P(l, -1, n, -1); } else if (m > 0) { if (m == 1) return SQRT_TWO * P(l, 0, n, 1); else return P(l, m-1, n, 1) - P(l, -m+1, n, -1); } else { if (m == -1) return SQRT_TWO * P(l, 0, n, -1); else return P(l, -m-1, n, -1) + P(l, m+1, n, 1); } } inline Float W(int l, int m, int n) const { if (m > 0) { return P(l, m+1, n, 1) + P(l, -m-1, n, -1); } else { return P(l, m-1, n, 1) - P(l, -m+1, n, -1); } } inline Float u(int l, int m, int n) const { int denom = (std::abs(n) == l) ? (2*l*(2*l-1)) : ((l+n)*(l-n)); return std::sqrt((Float) ((l+m)*(l-m)) / (Float) denom); } inline Float v(int l, int m, int n) const { int denom = (std::abs(n) == l) ? (2*l*(2*l-1)) : ((l+n)*(l-n)), absM = std::abs(m); return .5f * (1-2*delta(m, 0)) * std::sqrt( (Float) ((1+delta(m, 0)) * (l+absM-1)*(l+absM)) / (Float) denom ); } inline Float w(int l, int m, int n) const { if (m == 0) return 0.0f; int absM = std::abs(m); int denom = (std::abs(n) < l) ? ((l+n)*(l-n)) : (2*l*(2*l-1)); return -.5f * std::sqrt((Float) ((l-absM-1)*(l-absM)) / (Float) denom); } inline Float P(int l, int m, int n, int i) const { if (std::abs(n) < l) return R(i, 0) * M(m, n); else if (n == l) return R(i, 1) * M(m, l-1) - R(i, -1) * M(m, -l+1); else if (n == -l) return R(i, 1) * M(m, -l+1) + R(i, -1) * M(m, l-1); else { SLog(EError, "Internal error!"); return 0.0f; } } inline Float R(int m, int n) const { return M1(m+1, n+1); } inline Float M(int m, int n) const { return Mp(m+prevLevel, n+prevLevel); } void compute() { for (int m=-level; m<=level; ++m) { for (int n=-level; n<=level; ++n) { Float uVal = u(level, m, n), vVal = v(level, m, n), wVal = w(level, m, n); Mn(m+level, n+level) = (uVal != 0 ? (uVal * U(level, m, n)) : (Float) 0) + (vVal != 0 ? (vVal * V(level, m, n)) : (Float) 0) + (wVal != 0 ? (wVal * W(level, m, n)) : (Float) 0); } } } }; void SHVector::rotationBlock( const ublas::matrix &M1, const ublas::matrix &Mp, ublas::matrix &Mn) { RotationBlockHelper rbh(M1, Mp, Mn); rbh.compute(); } void SHVector::rotation(const Transform &t, SHRotation &rot) { rot.blocks[0](0, 0) = 1; if (rot.blocks.size() <= 1) return; const Matrix4x4 *trafo = t.getMatrix(); rot.blocks[1](0, 0) = trafo->m[1][1]; rot.blocks[1](0, 1) = -trafo->m[2][1]; rot.blocks[1](0, 2) = trafo->m[0][1]; rot.blocks[1](1, 0) = -trafo->m[1][2]; rot.blocks[1](1, 1) = trafo->m[2][2]; rot.blocks[1](1, 2) = -trafo->m[0][2]; rot.blocks[1](2, 0) = trafo->m[1][0]; rot.blocks[1](2, 1) = -trafo->m[2][0]; rot.blocks[1](2, 2) = trafo->m[0][0]; if (rot.blocks.size() <= 2) return; for (size_t i=2; i &M = blocks[l]; for (int m1=-l; m1<=l; ++m1) { Float result = 0; for (int m2=-l; m2<=l; ++m2) result += M(m1+l, m2+l)*source(l, m2); target(l, m1) = result; } } } SHSampler::SHSampler(int bands, int depth) : m_bands(bands), m_depth(depth) { m_phiMap = new Float**[depth+1]; m_legendreMap = new Float**[depth+1]; m_normalization = new Float[m_bands*(m_bands+1)/2]; m_dataSize = m_bands*(m_bands+1)/2; Assert(depth >= 1); for (int i=0; i<=depth; ++i) { int res = 1 << i; Float zStep = -2 / (Float) res; Float phiStep = 2 * (Float) M_PI / (Float) res; m_phiMap[i] = new Float*[res]; m_legendreMap[i] = new Float*[res]; for (int j=0; j()); normFactor = std::sqrt(normFactor * (2 * l + 1) / (4 * (Float) M_PI)); if (m != 0) normFactor *= SQRT_TWO; m_normalization[I(l, m)] = normFactor; } } } std::string SHSampler::toString() const { std::ostringstream oss; oss << "SHSampler[bands=" << m_bands << ", depth=" << m_depth << ", size=" << (m_dataSize*sizeof(double))/1024 << " KiB]"; return oss.str(); } Float SHSampler::warp(const SHVector &f, Point2 &sample) const { int i = 0, j = 0; Float integral = 0, integralRoot = integrate(0, 0, 0, f); for (int depth = 1; depth <= m_depth; ++depth) { /* Do not sample negative areas */ Float q00 = std::max(integrate(depth, i, j, f), (Float) 0); Float q10 = std::max(integrate(depth, i, j+1, f), (Float) 0); Float q01 = std::max(integrate(depth, i+1, j, f), (Float) 0); Float q11 = std::max(integrate(depth, i+1, j+1, f), (Float) 0); Float z1 = q00 + q10, z2 = q01 + q11, phi1, phi2; Float zNorm = (Float) 1 / (z1+z2); z1 *= zNorm; z2 *= zNorm; if (sample.x <= z1) { sample.x /= z1; phi1 = q00; phi2 = q10; i <<= 1; } else { sample.x = (sample.x - z1) / z2; phi1 = q01; phi2 = q11; i = (i+1) << 1; } Float phiNorm = (Float) 1 / (phi1+phi2); Float phi1Norm = phi1*phiNorm, phi2Norm = phi2*phiNorm; if (sample.y <= phi1Norm) { sample.y /= phi1Norm; j <<= 1; integral = phi1; } else { sample.y = (sample.y - phi1Norm) / phi2Norm; j = (j+1) << 1; integral = phi2; } } Float zStep = -2 / (Float) (1 << m_depth); Float phiStep = 2 * (Float) M_PI / (Float) (1 << m_depth); i >>= 1; j >>= 1; Float z = 1 + zStep * i + zStep * sample.x; sample.x = std::acos(z); sample.y = phiStep * j + phiStep * sample.y; /* PDF of sampling the mip-map bin */ Float pdfBin = integral/integralRoot; /* Density within the bin */ Float density = -1/(zStep*phiStep); return density*pdfBin; } SHSampler::~SHSampler() { for (int i=0; i<=m_depth; ++i) { int res = 1 << i; for (int j=0; j 0) result[P(m)] = (sinPhiB[m]-sinPhiA[m])/m; else result[P(m)] = (cosPhiB[-m]-cosPhiA[-m])/m; } delete[] sinPhiA; delete[] sinPhiB; delete[] cosPhiA; delete[] cosPhiB; return result; } Float *SHSampler::legendreIntegrals(Float a, Float b) { Float *P = new Float[m_bands*(m_bands+1)/2]; m_dataSize += m_bands*(m_bands+1)/2; P[I(0, 0)] = b-a; if (m_bands == 1) return P; Float *Pa = new Float[m_bands*(m_bands+1)/2]; Float *Pb = new Float[m_bands*(m_bands+1)/2]; for (int l=0; l