/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2012 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
#include
MTS_NAMESPACE_BEGIN
PhotonMap::PhotonMap(size_t photonCount)
: m_kdtree(0, PhotonTree::ESlidingMidpoint), m_scale(1.0f) {
m_kdtree.reserve(photonCount);
Assert(Photon::m_precompTableReady);
}
PhotonMap::PhotonMap(Stream *stream, InstanceManager *manager)
: SerializableObject(stream, manager),
m_kdtree(0, PhotonTree::ESlidingMidpoint) {
Assert(Photon::m_precompTableReady);
m_scale = (Float) stream->readFloat();
m_kdtree.resize(stream->readSize());
m_kdtree.setDepth(stream->readSize());
m_kdtree.setAABB(AABB(stream));
for (size_t i=0; iwriteFloat(m_scale);
stream->writeSize(m_kdtree.size());
stream->writeSize(m_kdtree.getDepth());
m_kdtree.getAABB().serialize(stream);
for (size_t i=0; i(
alloca((maxPhotons+1) * sizeof(SearchResult)));
Float squaredRadius = searchRadius*searchRadius;
size_t resultCount = nnSearch(p, squaredRadius, maxPhotons, results);
Float invSquaredRadius = 1.0f / squaredRadius;
/* Sum over all contributions */
Spectrum result(0.0f);
for (size_t i=0; i maxDepth)
continue;
Vector wi = -photon.getDirection();
Vector photonNormal = photon.getNormal();
Float wiDotGeoN = dot(photonNormal, wi),
wiDotShN = dot(n, wi);
/* Only use photons from the top side of the surface */
if (dot(wi, n) > 0 && dot(photonNormal, n) > 1e-1f && wiDotGeoN > 1e-2f) {
/* Account for non-symmetry due to shading normals */
Spectrum power = photon.getPower() * std::abs(wiDotShN / wiDotGeoN);
/* Weight the samples using Simpson's kernel */
Float sqrTerm = 1.0f - searchResult.distSquared*invSquaredRadius;
result += power * (sqrTerm*sqrTerm);
}
}
/* Based on the assumption that the surface is locally flat,
the estimate is divided by the area of a disc corresponding to
the projected spherical search region */
return result * (m_scale * 3 * INV_PI * invSquaredRadius);
}
Spectrum PhotonMap::estimateRadiance(const Intersection &its,
Float searchRadius, size_t maxPhotons) const {
SearchResult *results = static_cast(
alloca((maxPhotons+1) * sizeof(SearchResult)));
Float squaredRadius = searchRadius*searchRadius;
size_t resultCount = nnSearch(its.p, squaredRadius, maxPhotons, results);
Float invSquaredRadius = 1.0f / squaredRadius;
/* Sum over all contributions */
Spectrum result(0.0f);
const BSDF *bsdf = its.getBSDF();
for (size_t i=0; ieval(bRec) * (sqrTerm*sqrTerm);
}
/* Based on the assumption that the surface is locally flat,
the estimate is divided by the area of a disc corresponding to
the projected spherical search region */
return result * (m_scale * 3 * INV_PI * invSquaredRadius);
}
struct RawRadianceQuery {
RawRadianceQuery(const Intersection &its, int maxDepth)
: its(its), maxDepth(maxDepth), result(0.0f) {
bsdf = its.getBSDF();
}
inline void operator()(const Photon &photon) {
Normal photonNormal(photon.getNormal());
Vector wi = -photon.getDirection();
Float wiDotGeoN = absDot(photonNormal, wi);
if (photon.getDepth() > maxDepth
|| dot(photonNormal, its.shFrame.n) < 1e-1f
|| wiDotGeoN < 1e-2f)
return;
BSDFSamplingRecord bRec(its, its.toLocal(wi), its.wi, EImportance);
Spectrum value = photon.getPower() * bsdf->eval(bRec);
if (value.isZero())
return;
/* Account for non-symmetry due to shading normals */
value *= std::abs(Frame::cosTheta(bRec.wi) /
(wiDotGeoN * Frame::cosTheta(bRec.wo)));
result += value;
}
const Intersection &its;
const BSDF *bsdf;
int maxDepth;
Spectrum result;
};
size_t PhotonMap::estimateRadianceRaw(const Intersection &its,
Float searchRadius, Spectrum &result, int maxDepth) const {
RawRadianceQuery query(its, maxDepth);
size_t count = m_kdtree.executeQuery(its.p, searchRadius, query);
result = query.result;
return count;
}
MTS_IMPLEMENT_CLASS_S(PhotonMap, false, SerializableObject)
MTS_NAMESPACE_END