#include #include #include #include MTS_NAMESPACE_BEGIN Scene::Scene(const Properties &props) : NetworkedObject(props), m_blockSize(32) { m_kdtree = new KDTree(); /* When test case mode is active (Mitsuba is started with the -t parameter), this specifies the type of test performed. Mitsuba will expect a reference solution file of the name <sceneName>.ref. When set to t-test, a two-sided t-test on equality to the reference will be performed at the (1 - testThresh) level (99% by default). When set to relerr, the test will fail if the relative error exceeds testThresh (default: 0.01%). */ std::string testType = props.getString("testType", "none"); if (testType == "none") m_testType = ENone; else if (testType == "t-test") m_testType = ETTest; else if (testType == "relerr") m_testType = ERelativeError; else Log(EError, "Unknown test mode \"%s\" specified (must be \"t-test\" or \"relerr\")", testType.c_str()); /* Error threshold for use with testType */ m_testThresh = props.getFloat("testThresh", 0.01); /* By default, luminaire sampling chooses a luminaire with a probability dependent on the emitted power. Setting this parameter to false switches to uniform sampling. */ m_importanceSampleLuminaires = props.getBoolean("importanceSampleLuminaires", true); /* kd-tree construction: Enable primitive clipping? Generally leads to a significant improvement of the resulting tree. */ if (props.hasProperty("kdClip")) m_kdtree->setClip(props.getBoolean("kdClip")); /* kd-tree construction: Relative cost of a triangle intersection operation in the surface area heuristic. */ if (props.hasProperty("kdIntersectionCost")) m_kdtree->setIntersectionCost(props.getFloat("kdIntersectionCost")); /* kd-tree construction: Relative cost of a kd-tree traversal operation in the surface area heuristic. */ if (props.hasProperty("kdTraversalCost")) m_kdtree->setTraversalCost(props.getFloat("kdTraversalCost")); /* kd-tree construction: Bonus factor for cutting away regions of empty space */ if (props.hasProperty("kdEmptyBonus")) m_kdtree->setEmptyBonus(props.getFloat("kdEmptyBonus")); /* kd-tree construction: A kd-tree node containing this many or fewer primitives will not be split */ if (props.hasProperty("kdStopPrims")) m_kdtree->setStopPrims(props.getInteger("kdStopPrims")); } Scene::Scene(Scene *scene) : NetworkedObject(Properties()) { m_kdtree = scene->m_kdtree; m_testType = scene->m_testType; m_testThresh = scene->m_testThresh; m_blockSize = scene->m_blockSize; m_aabb = scene->m_aabb; m_bsphere = scene->m_bsphere; m_backgroundLuminaire = scene->m_backgroundLuminaire; m_camera = scene->m_camera; m_integrator = scene->m_integrator; m_sourceFile = scene->m_sourceFile; m_destinationFile = scene->m_destinationFile; m_luminairePDF = scene->m_luminairePDF; m_importanceSampleLuminaires = scene->m_importanceSampleLuminaires; m_shapes = scene->m_shapes; for (size_t i=0; iincRef(); m_meshes = scene->m_meshes; for (size_t i=0; iincRef(); m_luminaires = scene->m_luminaires; for (size_t i=0; iincRef(); m_media = scene->m_media; for (size_t i=0; iincRef(); m_ssIntegrators = scene->m_ssIntegrators; for (size_t i=0; iincRef(); m_objects = scene->m_objects; for (size_t i=0; iincRef(); m_netObjects = scene->m_netObjects; for (size_t i=0; iincRef(); } Scene::Scene(Stream *stream, InstanceManager *manager) : NetworkedObject(stream, manager) { m_kdtree = new KDTree(); m_kdtree->setIntersectionCost(stream->readFloat()); m_kdtree->setTraversalCost(stream->readFloat()); m_kdtree->setEmptyBonus(stream->readFloat()); m_kdtree->setStopPrims(stream->readInt()); m_kdtree->setClip(stream->readBool()); m_importanceSampleLuminaires = stream->readBool(); m_testType = (ETestType) stream->readInt(); m_testThresh = stream->readFloat(); m_blockSize = stream->readInt(); m_aabb = AABB(stream); m_bsphere = BSphere(stream); m_backgroundLuminaire = static_cast(manager->getInstance(stream)); int count = stream->readInt(); for (int i=0; i(manager->getInstance(stream)); shape->incRef(); m_shapes.push_back(shape); } count = stream->readInt(); for (int i=0; i(manager->getInstance(stream)); trimesh->incRef(); m_meshes.push_back(trimesh); } count = stream->readInt(); for (int i=0; i(manager->getInstance(stream)); luminaire->incRef(); m_luminaires.push_back(luminaire); } count = stream->readInt(); for (int i=0; i(manager->getInstance(stream)); medium->incRef(); m_media.push_back(medium); } count = stream->readInt(); for (int i=0; i(manager->getInstance(stream)); ssIntegrator->incRef(); m_ssIntegrators.push_back(ssIntegrator); } count = stream->readInt(); for (int i=0; i(manager->getInstance(stream)); obj->incRef(); m_objects.push_back(obj); } count = stream->readInt(); for (int i=0; i(manager->getInstance(stream)); m_netObjects.push_back(obj); // Do not increase the ref. count } initialize(); } Scene::~Scene() { for (unsigned int i=0; idecRef(); for (unsigned int i=0; idecRef(); for (unsigned int i=0; idecRef(); for (unsigned int i=0; idecRef(); for (unsigned int i=0; idecRef(); for (unsigned int i=0; idecRef(); } void Scene::bindUsedResources(ParallelProcess *proc) const { for (size_t i=0; ibindUsedResources(proc); } void Scene::wakeup(std::map ¶ms) { for (size_t i=0; iwakeup(params); } void Scene::configure() { if (m_integrator == NULL) { /* Create a direct integrator by default */ m_integrator = static_cast (PluginManager::getInstance()-> createObject(Integrator::m_theClass, Properties("direct"))); m_integrator->configure(); } if (m_camera == NULL) { Properties props("perspective"); /* Create a perspective camera with 45deg. FOV, which can see the whole scene */ AABB aabb; for (size_t i=0; igetAABB()); Point center = aabb.getCenter(); Vector extents = aabb.getExtents(); Float maxExtents = std::max(extents.x, extents.y); Float distance = maxExtents/(2.0f * std::tan(45 * .5f * M_PI/180)); props.setTransform("toWorld", Transform::translate(Vector(center.x, center.y, aabb.getMinimum().x - distance))); props.setFloat("fov", 45.0f); m_camera = static_cast (PluginManager::getInstance()->createObject(Camera::m_theClass, props)); m_camera->configure(); m_sampler = m_camera->getSamplerX(); } if (m_media.size() > 1) Log(EError, "Scenes are currently restricted to at most one participating medium."); m_integrator->configureSampler(m_sampler); /** * make it possible to serialize the integrator by * itself without all the extra baggage */ m_integrator->setParent(NULL); } void Scene::initialize() { if (!m_kdtree->isBuilt()) { /* Expand all geometry */ std::vector tempShapes; tempShapes.reserve(m_shapes.size()); m_shapes.swap(tempShapes); for (size_t i=0; idecRef(); } /* Build the kd-tree */ m_kdtree->build(); m_aabb = m_kdtree->getAABB(); m_bsphere = m_kdtree->getBSphere(); for (unsigned int i=0; igetAABB(); m_aabb.expandBy(aabb); for (int j=0; j<8; ++j) m_bsphere.expandBy(aabb.getCorner(j)); } } if (!m_luminairePDF.isReady()) { if (m_luminaires.size() == 0) Log(EError, "The scene contains no light sources! Aborting.."); /* Calculate a discrete PDF to importance sample luminaires */ for (std::vector::iterator it = m_luminaires.begin(); it != m_luminaires.end(); ++it) { (*it)->preprocess(this); /* Add with a probability proportional to the luminaire's power */ if (m_importanceSampleLuminaires) m_luminairePDF.put((*it)->getPower().getLuminance()); else m_luminairePDF.put(1.0f); } m_luminairePDF.build(); } } void Scene::preprocess(RenderQueue *queue, const RenderJob *job, int sceneResID, int cameraResID, int samplerResID) { /* Pre-process step for the main scene integrator */ m_integrator->preprocess(this, queue, job, sceneResID, cameraResID, samplerResID); /* Pre-process step for all sub-surface integrators */ for (std::vector::iterator it = m_ssIntegrators.begin(); it != m_ssIntegrators.end(); ++it) (*it)->preprocess(this, queue, job, sceneResID, cameraResID, samplerResID); /* Pre-process step for all participating media */ for (std::vector::iterator it = m_media.begin(); it != m_media.end(); ++it) (*it)->preprocess(this, queue, job, sceneResID, cameraResID, samplerResID); } bool Scene::render(RenderQueue *queue, const RenderJob *job, int sceneResID, int cameraResID, int samplerResID) { m_camera->getFilm()->clear(); return m_integrator->render(this, queue, job, sceneResID, cameraResID, samplerResID); } void Scene::cancel() { m_integrator->cancel(); } void Scene::flush() { m_camera->getFilm()->develop(m_destinationFile); } void Scene::postprocess(RenderQueue *queue, const RenderJob *job, int sceneResID, int cameraResID, int samplerResID) { m_integrator->postprocess(this, queue, job, sceneResID, cameraResID, samplerResID); m_camera->getFilm()->develop(m_destinationFile); } Float Scene::pdfLuminaire(const Point &p, const LuminaireSamplingRecord &lRec) const { const Luminaire *luminaire = lRec.luminaire; Float luminance; if (m_importanceSampleLuminaires) luminance = luminaire->getPower().getLuminance(); else luminance = 1.0f; /* Calculate the probability of importance sampling this luminaire */ const Float fraction = luminance / m_luminairePDF.getOriginalSum(); return luminaire->pdf(p, lRec) * fraction; } Float Scene::pdfLuminaire(const Intersection &its, const LuminaireSamplingRecord &lRec) const { const Luminaire *luminaire = lRec.luminaire; Float luminance; if (m_importanceSampleLuminaires) luminance = luminaire->getPower().getLuminance(); else luminance = 1.0f; /* Calculate the probability of importance sampling this luminaire */ const Float fraction = luminance / m_luminairePDF.getOriginalSum(); return luminaire->pdf(its, lRec) * fraction; } bool Scene::sampleLuminaire(const Point &p, LuminaireSamplingRecord &lRec, const Point2 &s, bool testVisibility) const { Point2 sample(s); Float lumPdf; unsigned int index = m_luminairePDF.sampleReuse(sample.x, lumPdf); const Luminaire *luminaire = m_luminaires[index]; luminaire->sample(p, lRec, sample); if (lRec.pdf != 0) { if (testVisibility && isOccluded(p, lRec.sRec.p)) return false; lRec.pdf *= lumPdf; lRec.Le /= lRec.pdf; lRec.luminaire = luminaire; return true; } else { return false; } } bool Scene::sampleLuminaire(const Intersection &its, LuminaireSamplingRecord &lRec, const Point2 &s, bool testVisibility) const { Point2 sample(s); Float lumPdf; unsigned int index = m_luminairePDF.sampleReuse(sample.x, lumPdf); const Luminaire *luminaire = m_luminaires[index]; luminaire->sample(its, lRec, sample); if (lRec.pdf != 0) { if (testVisibility && isOccluded(its.p, lRec.sRec.p)) return false; lRec.pdf *= lumPdf; lRec.Le /= lRec.pdf; lRec.luminaire = luminaire; return true; } else { return false; } } void Scene::sampleEmission(EmissionRecord &eRec, Point2 &sample1, Point2 &sample2) const { Float lumPdf; unsigned int index = m_luminairePDF.sampleReuse(sample1.x, lumPdf); const Luminaire *luminaire = m_luminaires[index]; luminaire->sampleEmission(eRec, sample1, sample2); eRec.pdfArea *= lumPdf; eRec.luminaire = luminaire; Float cosTheta = eRec.sRec.n.isZero() ? (Float) 1 : absDot(eRec.sRec.n, eRec.d); eRec.P *= cosTheta / (eRec.pdfArea * eRec.pdfDir); } void Scene::sampleEmissionArea(EmissionRecord &eRec, Point2 &sample) const { Float lumPdf; unsigned int index = m_luminairePDF.sampleReuse(sample.x, lumPdf); const Luminaire *luminaire = m_luminaires[index]; luminaire->sampleEmissionArea(eRec, sample); eRec.pdfArea *= lumPdf; eRec.luminaire = luminaire; } Spectrum Scene::sampleEmissionDirection(EmissionRecord &eRec, Point2 &sample) const { return eRec.luminaire->sampleEmissionDirection(eRec, sample); } void Scene::pdfEmission(EmissionRecord &eRec) const { const Luminaire *luminaire = eRec.luminaire; Float luminance; if (m_importanceSampleLuminaires) luminance = luminaire->getPower().getLuminance(); else luminance = 1.0f; /* Calculate the probability of importance sampling this luminaire */ const Float fraction = luminance / m_luminairePDF.getOriginalSum(); luminaire->pdfEmission(eRec); eRec.pdfArea *= fraction; } Spectrum Scene::LeBackground(const Ray &ray) const { Spectrum Le(0.0f); for (std::vector::const_iterator it = m_luminaires.begin(); it != m_luminaires.end(); ++it) Le += (*it)->Le(ray); return Le; } Spectrum Scene::getAttenuation(const Ray &ray) const { Spectrum extinction(0.0f); for (std::vector::const_iterator it = m_media.begin(); it != m_media.end(); ++it) { extinction += (*it)->tau(ray); } if (extinction.isBlack()) return Spectrum(1.0f); else return (-extinction).exp(); } bool Scene::sampleDistance(const Ray &ray, Float maxDist, MediumSamplingRecord &mRec, Sampler *sampler) const { if (m_media.size() > 0) { return m_media[0]->sampleDistance(ray, maxDist, mRec, sampler); } else { mRec.pdf = 1.0f; mRec.miWeight = 1.0f; mRec.attenuation = 1.0f; return false; } } void Scene::addChild(const std::string &name, ConfigurableObject *child) { const Class *cClass = child->getClass(); if (cClass->derivesFrom(NetworkedObject::m_theClass) && !cClass->derivesFrom(Integrator::m_theClass)) m_netObjects.push_back(static_cast(child)); if (cClass->derivesFrom(Camera::m_theClass)) { AssertEx(m_camera == NULL, "There can only be one camera per scene"); m_camera = static_cast(child); m_sampler = m_camera->getSamplerX(); } else if (cClass->derivesFrom(Integrator::m_theClass)) { AssertEx(m_integrator == NULL, "There can only be one integrator per scene"); m_integrator = static_cast(child); } else if (cClass->derivesFrom(Texture::m_theClass) || cClass->derivesFrom(BSDF::m_theClass)) { ConfigurableObject *obj= static_cast(child); obj->incRef(); m_objects.push_back(obj); } else if (cClass->derivesFrom(Medium::m_theClass)) { Medium *medium = static_cast(child); medium->incRef(); m_media.push_back(medium); } else if (cClass->derivesFrom(Luminaire::m_theClass)) { Luminaire *luminaire = static_cast(child); luminaire->incRef(); m_luminaires.push_back(luminaire); if (luminaire->isBackgroundLuminaire()) { AssertEx(m_backgroundLuminaire.get() == NULL, "The scene may only contain one background luminaire"); m_backgroundLuminaire = luminaire; } } else if (cClass->derivesFrom(Shape::m_theClass)) { ref shape = static_cast(child); shape->incRef(); m_shapes.push_back(shape); } else if (cClass->derivesFrom(Scene::m_theClass)) { ref scene = static_cast(child); /* A scene from somewhere else has been included. Add all of its contents */ for (unsigned int i=0; igetLuminaires().size(); ++i) { Luminaire *lum = scene->getLuminaires()[i]; lum->setParent(this); addChild("luminaire", lum); } for (unsigned int i=0; igetShapes().size(); ++i) { Shape *shape = scene->getShapes()[i]; shape->setParent(this); addChild("shape", shape); } for (unsigned int i=0; igetReferencedObjects().size(); ++i) { ConfigurableObject *obj = scene->getReferencedObjects()[i]; obj->setParent(this); addChild("object", obj); } for (unsigned int i=0; igetMedia().size(); ++i) { Medium *medium = scene->getMedia()[i]; medium->setParent(this); addChild("medium", medium); } if (scene->getIntegrator() != NULL) { scene->getIntegrator()->setParent(this); addChild("integrator", scene->getIntegrator()); } if (scene->getCamera() != NULL) { scene->getCamera()->setParent(this); addChild("integrator", scene->getCamera()); } } else { Log(EError, "Scene: Invalid child node! (\"%s\")", cClass->getName().c_str()); } } void Scene::addShape(Shape *shape) { if (shape->isCompound()) { int index = 0; do { ref element = shape->getElement(index++); if (element == NULL) break; addShape(element); } while (true); } else { if (shape->isLuminaire()) { if (std::find(m_luminaires.begin(), m_luminaires.end(), shape->getLuminaire()) == m_luminaires.end()) { m_luminaires.push_back(shape->getLuminaire()); shape->getLuminaire()->incRef(); } } if (shape->hasSubsurface()) { m_netObjects.push_back(static_cast(shape->getSubsurface())); if (std::find(m_ssIntegrators.begin(), m_ssIntegrators.end(), shape->getSubsurface()) == m_ssIntegrators.end()) { m_ssIntegrators.push_back(shape->getSubsurface()); shape->getSubsurface()->incRef(); } } if (shape->getClass()->derivesFrom(TriMesh::m_theClass)) { if (std::find(m_meshes.begin(), m_meshes.end(), shape) == m_meshes.end()) { m_meshes.push_back(static_cast(shape)); shape->incRef(); } } shape->incRef(); m_kdtree->addShape(shape); m_shapes.push_back(shape); } } void Scene::serialize(Stream *stream, InstanceManager *manager) const { ConfigurableObject::serialize(stream, manager); stream->writeFloat(m_kdtree->getIntersectionCost()); stream->writeFloat(m_kdtree->getTraversalCost()); stream->writeFloat(m_kdtree->getEmptyBonus()); stream->writeInt(m_kdtree->getStopPrims()); stream->writeBool(m_kdtree->getClip()); stream->writeBool(m_importanceSampleLuminaires); stream->writeInt(m_testType); stream->writeFloat(m_testThresh); stream->writeInt(m_blockSize); m_aabb.serialize(stream); m_bsphere.serialize(stream); manager->serialize(stream, m_backgroundLuminaire.get()); stream->writeUInt((unsigned int) m_shapes.size()); for (size_t i=0; iserialize(stream, m_shapes[i]); stream->writeUInt((unsigned int) m_meshes.size()); for (size_t i=0; iserialize(stream, m_meshes[i]); stream->writeUInt((unsigned int) m_luminaires.size()); for (size_t i=0; iserialize(stream, m_luminaires[i]); stream->writeUInt((unsigned int) m_media.size()); for (size_t i=0; iserialize(stream, m_media[i]); stream->writeUInt((unsigned int) m_ssIntegrators.size()); for (size_t i=0; iserialize(stream, m_ssIntegrators[i]); stream->writeUInt((unsigned int) m_objects.size()); for (size_t i=0; iserialize(stream, m_objects[i]); stream->writeUInt((unsigned int) m_netObjects.size()); for (size_t i=0; iserialize(stream, m_netObjects[i]); } template std::string listToString(const std::vector &vec) { std::ostringstream oss; oss << "{" << endl; for (size_t i=0; itoString()); if (i != vec.size()-1) oss << "," << endl; else oss << endl; } oss << "}"; return oss.str(); } std::string Scene::toString() const { std::ostringstream oss; oss << "Scene[" << endl << " testType = " << ((m_testType == ETTest) ? "t-test" : "relerr") << ", " << endl << " testThresh = " << m_testThresh << ", " << endl << " importanceSampleLuminaires = " << (int) m_importanceSampleLuminaires << ", " << endl << " camera = " << indent(m_camera.toString()) << "," << endl << " sampler = " << indent(m_sampler.toString()) << "," << endl << " 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; oss << "]"; return oss.str(); } MTS_IMPLEMENT_CLASS_S(Scene, false, ConfigurableObject) MTS_NAMESPACE_END