diff --git a/include/mitsuba/core/util.h b/include/mitsuba/core/util.h index 0434d6b7..a05282ab 100644 --- a/include/mitsuba/core/util.h +++ b/include/mitsuba/core/util.h @@ -320,12 +320,14 @@ template inline T endianness_swap(T value) { } /// Return a string representation of a list of objects -template std::string listToString(const std::vector &vec) { +template std::string containerToString(const Iterator &start, const Iterator &end) { std::ostringstream oss; oss << "{" << endl; - for (size_t i=0; itoString()); - if (i != vec.size()-1) + Iterator it = start; + while (it != end) { + oss << " " << indent((*it)->toString()); + ++it; + if (it != end) oss << "," << endl; else oss << endl; diff --git a/include/mitsuba/render/integrator.h b/include/mitsuba/render/integrator.h index 450c3023..df1c9e4e 100644 --- a/include/mitsuba/render/integrator.h +++ b/include/mitsuba/render/integrator.h @@ -299,9 +299,8 @@ public: * Include indirect illumination in the estimate? */ virtual Spectrum E(const Scene *scene, const Point &p, const - Normal &n, Float time, const Medium *medium, - Sampler *sampler, int nSamples, - bool includeIndirect) const; + Normal &n, Float time, const Medium *medium, Sampler *sampler, + int nSamples, bool includeIndirect) const; /** * Perform the main rendering task. The work is automatically diff --git a/include/mitsuba/render/luminaire.h b/include/mitsuba/render/luminaire.h index ca8286aa..6fbaba6f 100644 --- a/include/mitsuba/render/luminaire.h +++ b/include/mitsuba/render/luminaire.h @@ -33,6 +33,9 @@ public: /// Create an invalid shadow ray sampling record inline LuminaireSamplingRecord() : luminaire(NULL) { } + /// Create a shadow ray sampling record based on a surface intersection + inline LuminaireSamplingRecord(const Intersection &its, const Vector &direction); + /// Return a string representation std::string toString() const; public: diff --git a/include/mitsuba/render/records.inl b/include/mitsuba/render/records.inl index 97b7bade..34caf460 100644 --- a/include/mitsuba/render/records.inl +++ b/include/mitsuba/render/records.inl @@ -81,7 +81,14 @@ inline const Medium *Intersection::getTargetMedium(const Ray &ray) const { else return shape->getInteriorMedium(); } - + +inline LuminaireSamplingRecord::LuminaireSamplingRecord(const Intersection &its, const Vector &dir) { + sRec.p = its.p; + sRec.n = its.geoFrame.n; + d = dir; + luminaire = its.shape->getLuminaire(); +} + inline bool RadianceQueryRecord::rayIntersect(const RayDifferential &ray) { /* Only search for an intersection if this was explicitly requested */ if (type & EIntersection) { diff --git a/include/mitsuba/render/scene.h b/include/mitsuba/render/scene.h index f4a64b75..1095cdbc 100644 --- a/include/mitsuba/render/scene.h +++ b/include/mitsuba/render/scene.h @@ -317,7 +317,10 @@ public: inline Spectrum LeAttenuatedBackground(const Ray &ray, const Medium *medium) const { if (!m_backgroundLuminaire) return Spectrum(0.0f); - return LeBackground(ray) * medium->tau(ray); + Spectrum result = LeBackground(ray); + if (medium) + result *= medium->tau(ray); + return result; } //! @} @@ -418,9 +421,9 @@ public: /// Return the scene's luminaires inline const std::vector &getLuminaires() const { return m_luminaires; } /// Return the scene's participating media - inline std::vector &getMedia() { return m_media; } + inline std::set &getMedia() { return m_media; } /// Return the scene's participating media - inline const std::vector &getMedia() const { return m_media; } + inline const std::set &getMedia() const { return m_media; } /// Return referenced objects (such as textures, BSDFs) inline std::vector &getReferencedObjects() { return m_objects; } /// Return referenced objects (such as textures, BSDFs) @@ -470,10 +473,10 @@ private: std::vector m_meshes; std::vector m_shapes; std::vector m_luminaires; - std::vector m_media; std::vector m_ssIntegrators; std::vector m_objects; std::vector m_netObjects; + std::set m_media; fs::path m_sourceFile; fs::path m_destinationFile; DiscretePDF m_luminairePDF; diff --git a/src/bsdfs/dielectric.cpp b/src/bsdfs/dielectric.cpp index cf345444..d0b6e289 100644 --- a/src/bsdfs/dielectric.cpp +++ b/src/bsdfs/dielectric.cpp @@ -95,7 +95,7 @@ public: wi = Vector(-wo.x, -wo.y, wo.z); } - Float refract(Float &intIOR, Float &extIOR, + Float refract(Float intIOR, Float extIOR, const Vector &wi, Vector &wo, ETransportQuantity quantity) const { Float cosTheta1 = Frame::cosTheta(wi); bool entering = cosTheta1 > 0.0f; diff --git a/src/integrators/direct/direct.cpp b/src/integrators/direct/direct.cpp index c8b65fae..7a60e1e9 100644 --- a/src/integrators/direct/direct.cpp +++ b/src/integrators/direct/direct.cpp @@ -127,7 +127,7 @@ public: for (int i=0; isampleLuminaire(its, lRec, sampleArray[i])) { + if (scene->sampleLuminaire(its.p, ray.time, lRec, sampleArray[i])) { /* Allocate a record for querying the BSDF */ const BSDFQueryRecord bRec(rRec, its, its.toLocal(-lRec.d)); @@ -181,7 +181,7 @@ public: } } else { /* No intersection found. Possibly, there is a background - luminaire such as an environment map? */ + luminaire such as an environment map? */ if (scene->hasBackgroundLuminaire()) { lRec.luminaire = scene->getBackgroundLuminaire(); lRec.d = -bsdfRay.d; diff --git a/src/librender/scene.cpp b/src/librender/scene.cpp index d3752df9..66ad8e66 100644 --- a/src/librender/scene.cpp +++ b/src/librender/scene.cpp @@ -112,8 +112,9 @@ Scene::Scene(Scene *scene) : NetworkedObject(Properties()) { for (size_t i=0; iincRef(); m_media = scene->m_media; - for (size_t i=0; iincRef(); + for (std::set::iterator it = m_media.begin(); + it != m_media.end(); ++it) + (*it)->incRef(); m_ssIntegrators = scene->m_ssIntegrators; for (size_t i=0; iincRef(); @@ -168,7 +169,7 @@ Scene::Scene(Stream *stream, InstanceManager *manager) for (int i=0; i(manager->getInstance(stream)); medium->incRef(); - m_media.push_back(medium); + m_media.insert(medium); } count = stream->readInt(); for (int i=0; idecRef(); for (size_t i=0; idecRef(); - for (size_t i=0; idecRef(); for (size_t i=0; idecRef(); for (size_t i=0; idecRef(); for (size_t i=0; idecRef(); + for (std::set::iterator it = m_media.begin(); + it != m_media.end(); ++it) + (*it)->decRef(); } void Scene::bindUsedResources(ParallelProcess *proc) const { @@ -390,42 +392,46 @@ bool Scene::sampleAttenuatedLuminaire(const Point &p, Float time, luminaire->sample(p, lRec, sample); if (lRec.pdf != 0) { - Vector d = lRec.sRec.p - p; - Float distance = d.length(), traveled = 0; - d /= distance; - distance *= 1-Epsilon; - - const Shape *shape; - Ray ray(p, d, time); - int iterations = 0; - - while (true) { - Normal n; - Float t; - - bool surface = rayIntersect(ray, t, shape, n); - - if (medium) - lRec.value *= medium->tau(Ray(ray.o, d, 0, t, time)); - - if (!surface) - break; - - ray.o = ray(t); - traveled += t; - - if (shape->isOccluder() && traveled < distance) + if (m_media.size() == 0) { + if (isOccluded(p, lRec.sRec.p, time)) return false; - else if (shape->isMediumTransition()) - medium = dot(n, d) > 0 ? shape->getExteriorMedium() - : shape->getInteriorMedium(); + } else { + Vector d = lRec.sRec.p - p; + Float distance = d.length(), traveled = 0; + d /= distance; + distance *= 1-Epsilon; - if (++iterations > 100) { /// Just a precaution.. - Log(EWarn, "sampleAttenuatedLuminaire(): round-off error issues?"); - break; + const Shape *shape; + Ray ray(p, d, time); + int iterations = 0; + + while (true) { + Normal n; + Float t; + + bool surface = rayIntersect(ray, t, shape, n); + + if (medium) + lRec.value *= medium->tau(Ray(ray.o, d, 0, t, time)); + + if (!surface) + break; + + ray.o = ray(t); + traveled += t; + + if (shape->isOccluder() && traveled < distance) + return false; + else if (shape->isMediumTransition()) + medium = dot(n, d) > 0 ? shape->getExteriorMedium() + : shape->getInteriorMedium(); + + if (++iterations > 100) { /// Just a precaution.. + Log(EWarn, "sampleAttenuatedLuminaire(): round-off error issues?"); + break; + } } } - lRec.pdf *= lumPdf; lRec.value /= lRec.pdf; lRec.luminaire = luminaire; @@ -497,8 +503,10 @@ void Scene::addChild(const std::string &name, ConfigurableObject *child) { m_objects.push_back(obj); } else if (cClass->derivesFrom(Medium::m_theClass)) { Medium *medium = static_cast(child); - medium->incRef(); - m_media.push_back(medium); + if (m_media.find(medium) == m_media.end()) { + medium->incRef(); + m_media.insert(medium); + } } else if (cClass->derivesFrom(Luminaire::m_theClass)) { Luminaire *luminaire = static_cast(child); luminaire->incRef(); @@ -531,8 +539,9 @@ void Scene::addChild(const std::string &name, ConfigurableObject *child) { obj->setParent(this); addChild("object", obj); } - for (size_t i=0; igetMedia().size(); ++i) { - Medium *medium = scene->getMedia()[i]; + for (std::set::iterator it = scene->getMedia().begin(); + it != scene->getMedia().end(); ++it) { + Medium *medium = *it; medium->setParent(this); addChild("medium", medium); } @@ -575,6 +584,20 @@ void Scene::addShape(Shape *shape) { shape->getSubsurface()->incRef(); } } + + Medium *iMedium = shape->getInteriorMedium(), + *eMedium = shape->getExteriorMedium(); + + if (eMedium != NULL && m_media.find(eMedium) == m_media.end()) { + m_media.insert(eMedium); + eMedium->incRef(); + } + + if (iMedium != NULL && m_media.find(iMedium) == m_media.end()) { + m_media.insert(iMedium); + iMedium->incRef(); + } + if (shape->getClass()->derivesFrom(TriMesh::m_theClass)) { if (std::find(m_meshes.begin(), m_meshes.end(), shape) == m_meshes.end()) { @@ -582,6 +605,7 @@ void Scene::addShape(Shape *shape) { shape->incRef(); } } + shape->incRef(); m_kdtree->addShape(shape); m_shapes.push_back(shape); @@ -618,8 +642,9 @@ void Scene::serialize(Stream *stream, InstanceManager *manager) const { for (size_t i=0; iserialize(stream, m_luminaires[i]); stream->writeUInt((uint32_t) m_media.size()); - for (size_t i=0; iserialize(stream, m_media[i]); + for (std::set::iterator it = m_media.begin(); + it != m_media.end(); ++it) + manager->serialize(stream, *it); stream->writeUInt((uint32_t) m_ssIntegrators.size()); for (size_t i=0; iserialize(stream, m_ssIntegrators[i]); @@ -643,12 +668,12 @@ std::string Scene::toString() const { << " integrator = " << indent(m_integrator.toString()) << "," << endl << " kdtree = " << indent(m_kdtree.toString()) << "," << endl << " backgroundLuminaire = " << indent(m_backgroundLuminaire.toString()) << "," << endl - << " meshes = " << indent(listToString(m_meshes)) << "," << endl - << " shapes = " << indent(listToString(m_shapes)) << "," << endl - << " luminaires = " << indent(listToString(m_luminaires)) << "," << endl - << " media = " << indent(listToString(m_media)) << "," << endl - << " ssIntegrators = " << indent(listToString(m_ssIntegrators)) << "," << endl - << " objects = " << indent(listToString(m_objects)) << endl; + << " meshes = " << indent(containerToString(m_meshes.begin(), m_meshes.end())) << "," << endl + << " shapes = " << indent(containerToString(m_shapes.begin(), m_shapes.end())) << "," << endl + << " luminaires = " << indent(containerToString(m_luminaires.begin(), m_luminaires.end())) << "," << endl + << " media = " << indent(containerToString(m_media.begin(), m_media.end())) << "," << endl + << " ssIntegrators = " << indent(containerToString(m_ssIntegrators.begin(), m_ssIntegrators.end())) << "," << endl + << " objects = " << indent(containerToString(m_objects.begin(), m_objects.end())) << endl; oss << "]"; return oss.str(); } diff --git a/src/shapes/obj.cpp b/src/shapes/obj.cpp index 30a0e472..be519f09 100644 --- a/src/shapes/obj.cpp +++ b/src/shapes/obj.cpp @@ -458,6 +458,12 @@ public: child->setParent(m_meshes[i]); m_meshes[i]->addChild(name, child); } + } else if (cClass->derivesFrom(Medium::m_theClass)) { + Assert(m_subsurface == NULL); + for (size_t i=0; isetParent(m_meshes[i]); + m_meshes[i]->addChild(name, child); + } } else { Shape::addChild(name, child); } diff --git a/src/subsurface/irrproc.cpp b/src/subsurface/irrproc.cpp index 869126aa..0d2576ae 100644 --- a/src/subsurface/irrproc.cpp +++ b/src/subsurface/irrproc.cpp @@ -27,7 +27,8 @@ MTS_NAMESPACE_BEGIN class IrradianceSamplingWorker : public WorkProcessor { public: IrradianceSamplingWorker(size_t sampleCount, int ssIndex, int irrSamples, bool irrIndirect) - : m_sampleCount(sampleCount), m_ssIndex(ssIndex), m_irrSamples(irrSamples), m_irrIndirect(irrIndirect) { + : m_sampleCount(sampleCount), m_ssIndex(ssIndex), + m_irrSamples(irrSamples), m_irrIndirect(irrIndirect) { } IrradianceSamplingWorker(Stream *stream, InstanceManager *manager) { @@ -93,8 +94,8 @@ public: result->put(IrradianceSample( sRec.p, integrator->E(m_scene.get(), sRec.p, sRec.n, time, - m_independentSampler, m_irrSamples, m_irrIndirect), - 1/pdf + camera->getMedium(), m_independentSampler, + m_irrSamples, m_irrIndirect), 1/pdf )); } }