bool PathEdge::pathConnect(const Scene *scene, const PathEdge *predEdge, const PathVertex *vs, Path &result, const PathVertex *vt, const PathEdge *succEdge, int maxInteractions, MemoryPool &pool) { BDAssert(result.edgeCount() == 0 && result.vertexCount() == 0); if (vs->isEmitterSupernode() || vt->isSensorSupernode()) { Float radianceTransport = vt->isSensorSupernode() ? 1.0f : 0.0f, importanceTransport = 1-radianceTransport; PathEdge *edge = pool.allocEdge(); edge->medium = NULL; edge->length = 0.0f; edge->d = Vector(0.0f); edge->pdf[ERadiance] = radianceTransport; edge->pdf[EImportance] = importanceTransport; edge->weight[ERadiance] = Spectrum(radianceTransport); edge->weight[EImportance] = Spectrum(importanceTransport); result.append(edge); } else { Point vsp = vs->getPosition(), vtp = vt->getPosition(); Vector d(vsp-vtp); Float remaining = d.length(); d /= remaining; if (remaining == 0) { #if defined(MTS_BD_DEBUG) SLog(EWarn, "Tried to connect %s and %s, which are located at exactly the same position!", vs->toString().c_str(), vt->toString().c_str()); #endif return false; } Float lengthFactor = vs->isOnSurface() ? (1-ShadowEpsilon) : 1; Ray ray(vtp, d, vt->isOnSurface() ? Epsilon : 0, remaining * lengthFactor, vs->getTime()); const Medium *medium = vt->getTargetMedium(succEdge, d); int interactions = 0; Intersection its; while (true) { bool surface = scene->rayIntersectAll(ray, its); if (surface && (interactions == maxInteractions || !(its.getBSDF()->getType() & BSDF::ENull))) { /* Encountered an occluder -- zero transmittance. */ result.release(pool); return false; } /* Construct an edge */ PathEdge *edge = pool.allocEdge(); result.append(edge); edge->length = std::min(its.t, remaining); edge->medium = medium; edge->d = d; if (medium) { MediumSamplingRecord mRec; medium->eval(Ray(ray, 0, edge->length), mRec); edge->pdf[ERadiance] = (surface || !vs->isMediumInteraction()) ? mRec.pdfFailure : mRec.pdfSuccess; edge->pdf[EImportance] = (interactions > 0 || !vt->isMediumInteraction()) ? mRec.pdfFailure : mRec.pdfSuccessRev; if (edge->pdf[ERadiance] == 0 || edge->pdf[EImportance] == 0 || mRec.transmittance.isZero()) { /* Zero transmittance */ result.release(pool); return false; } edge->weight[EImportance] = mRec.transmittance / edge->pdf[EImportance]; edge->weight[ERadiance] = mRec.transmittance / edge->pdf[ERadiance]; } else { edge->weight[ERadiance] = edge->weight[EImportance] = Spectrum(1.0f); edge->pdf[ERadiance] = edge->pdf[EImportance] = 1.0f; } if (!surface || remaining - its.t < 0) break; /* Advance the ray */ ray.o = ray(its.t); remaining -= its.t; ray.mint = Epsilon; ray.maxt = remaining * lengthFactor; const BSDF *bsdf = its.getBSDF(); /* Account for the ENull interaction */ Vector wo = its.toLocal(ray.d); BSDFSamplingRecord bRec(its, -wo, wo, ERadiance); bRec.component = BSDF::ENull; Float nullPdf = bsdf->pdf(bRec, EDiscrete); if (nullPdf == 0) { result.release(pool); return false; } PathVertex *vertex = pool.allocVertex(); vertex->type = PathVertex::ESurfaceInteraction; vertex->degenerate = !(bsdf->hasComponent(BSDF::ESmooth) || its.shape->isEmitter() || its.shape->isSensor()); vertex->measure = EDiscrete; vertex->componentType = BSDF::ENull; vertex->pdf[EImportance] = vertex->pdf[ERadiance] = nullPdf; vertex->weight[EImportance] = vertex->weight[ERadiance] = bsdf->eval(bRec, EDiscrete) / nullPdf; vertex->rrWeight = 1.0f; vertex->getIntersection() = its; result.append(vertex); if (its.isMediumTransition()) { const Medium *expected = its.getTargetMedium(-ray.d); if (medium != expected) { #if defined(MTS_BD_TRACE) SLog(EWarn, "PathEdge::pathConnect(): attempted two connect " "two vertices that disagree about the medium in between! " "Please check your scene for leaks."); #endif ++mediumInconsistencies; result.release(pool); return false; } medium = its.getTargetMedium(ray.d); } if (++interactions > 100) { /// Just a precaution.. SLog(EWarn, "pathConnect(): round-off error issues?"); result.release(pool); return false; } } if (medium != vs->getTargetMedium(predEdge, -d)) { #if defined(MTS_BD_TRACE) SLog(EWarn, "PathEdge::pathConnect(): attempted two connect " "two vertices that disagree about the medium in between! " "Please check your scene for leaks."); #endif ++mediumInconsistencies; result.release(pool); return false; } } result.reverse(); BDAssert(result.edgeCount() == result.vertexCount() + 1); BDAssert((int) result.vertexCount() <= maxInteractions || maxInteractions < 0); return true; }
bool PathEdge::pathConnectAndCollapse(const Scene *scene, const PathEdge *predEdge, const PathVertex *vs, const PathVertex *vt, const PathEdge *succEdge, int &interactions) { if (vs->isEmitterSupernode() || vt->isSensorSupernode()) { Float radianceTransport = vt->isSensorSupernode() ? 1.0f : 0.0f, importanceTransport = 1-radianceTransport; medium = NULL; length = 0.0f; d = Vector(0.0f); pdf[ERadiance] = radianceTransport; pdf[EImportance] = importanceTransport; weight[ERadiance] = Spectrum(radianceTransport); weight[EImportance] = Spectrum(importanceTransport); interactions = 0; } else { Point vsp = vs->getPosition(), vtp = vt->getPosition(); d = vsp-vtp; length = d.length(); int maxInteractions = interactions; interactions = 0; if (length == 0) { #if defined(MTS_BD_DEBUG) SLog(EWarn, "Tried to connect %s and %s, which are located at exactly the same position!", vs->toString().c_str(), vt->toString().c_str()); #endif return false; } d /= length; Float lengthFactor = vs->isOnSurface() ? (1-ShadowEpsilon) : 1; Ray ray(vtp, d, vt->isOnSurface() ? Epsilon : 0, length * lengthFactor, vs->getTime()); weight[ERadiance] = Spectrum(1.0f); weight[EImportance] = Spectrum(1.0f); pdf[ERadiance] = 1.0f; pdf[EImportance] = 1.0f; Intersection its; Float remaining = length; medium = vt->getTargetMedium(succEdge, d); while (true) { bool surface = scene->rayIntersectAll(ray, its); if (surface && (interactions == maxInteractions || !(its.getBSDF()->getType() & BSDF::ENull))) { /* Encountered an occluder -- zero transmittance. */ return false; } if (medium) { Float segmentLength = std::min(its.t, remaining); MediumSamplingRecord mRec; medium->eval(Ray(ray, 0, segmentLength), mRec); Float pdfRadiance = (surface || !vs->isMediumInteraction()) ? mRec.pdfFailure : mRec.pdfSuccess; Float pdfImportance = (interactions > 0 || !vt->isMediumInteraction()) ? mRec.pdfFailure : mRec.pdfSuccessRev; if (pdfRadiance == 0 || pdfImportance == 0 || mRec.transmittance.isZero()) { /* Zero transmittance */ return false; } weight[EImportance] *= mRec.transmittance / pdfImportance; weight[ERadiance] *= mRec.transmittance / pdfRadiance; pdf[EImportance] *= pdfImportance; pdf[ERadiance] *= pdfRadiance; } if (!surface || remaining - its.t < 0) break; /* Advance the ray */ ray.o = ray(its.t); remaining -= its.t; ray.mint = Epsilon; ray.maxt = remaining * lengthFactor; /* Account for the ENull interaction */ const BSDF *bsdf = its.getBSDF(); Vector wo = its.toLocal(ray.d); BSDFSamplingRecord bRec(its, -wo, wo, ERadiance); bRec.component = BSDF::ENull; Float nullPdf = bsdf->pdf(bRec, EDiscrete); if (nullPdf == 0) return false; Spectrum nullWeight = bsdf->eval(bRec, EDiscrete) / nullPdf; weight[EImportance] *= nullWeight; weight[ERadiance] *= nullWeight; pdf[EImportance] *= nullPdf; pdf[ERadiance] *= nullPdf; if (its.isMediumTransition()) { const Medium *expected = its.getTargetMedium(-ray.d); if (medium != expected) { #if defined(MTS_BD_TRACE) SLog(EWarn, "PathEdge::pathConnectAndCollapse(): attempted two connect " "two vertices that disagree about the medium in between! " "Please check your scene for leaks."); #endif ++mediumInconsistencies; return false; } medium = its.getTargetMedium(ray.d); } if (++interactions > 100) { /// Just a precaution.. SLog(EWarn, "pathConnectAndCollapse(): round-off error issues?"); return false; } } if (medium != vs->getTargetMedium(predEdge, -d)) { #if defined(MTS_BD_TRACE) SLog(EWarn, "PathEdge::pathConnectAndCollapse(): attempted two connect " "two vertices that disagree about the medium in between! " "Please check your scene for leaks."); #endif ++mediumInconsistencies; return false; } } return true; }
bool PathEdge::connect(const Scene *scene, const PathEdge *predEdge, const PathVertex *vs, const PathVertex *vt, const PathEdge *succEdge) { if (vs->isEmitterSupernode() || vt->isSensorSupernode()) { Float radianceTransport = vt->isSensorSupernode() ? 1.0f : 0.0f, importanceTransport = 1-radianceTransport; medium = NULL; d = Vector(0.0f); length = 0.0f; pdf[ERadiance] = radianceTransport; pdf[EImportance] = importanceTransport; weight[ERadiance] = Spectrum(radianceTransport); weight[EImportance] = Spectrum(importanceTransport); } else { Point vsp = vs->getPosition(), vtp = vt->getPosition(); d = vsp-vtp; length = d.length(); d /= length; Ray ray(vtp, d, vt->isOnSurface() ? Epsilon : 0, length * (vs->isOnSurface() ? (1-ShadowEpsilon) : 1), vs->getTime()); /* Check for occlusion */ if (scene->rayIntersectAll(ray)) return false; const Medium *vtMedium = vt->getTargetMedium(succEdge, d); const Medium *vsMedium = vs->getTargetMedium(predEdge, -d); if (vsMedium != vtMedium) { #if defined(MTS_BD_TRACE) SLog(EWarn, "PathEdge::connect(): attempted two connect " "two vertices that disagree about the medium in between! " "Please check your scene for leaks."); #endif ++mediumInconsistencies; return false; } medium = vtMedium; if (medium) { MediumSamplingRecord mRec; medium->eval(ray, mRec); pdf[EImportance] = vt->isMediumInteraction() ? mRec.pdfSuccessRev : mRec.pdfFailure; pdf[ERadiance] = vs->isMediumInteraction() ? mRec.pdfSuccess : mRec.pdfFailure; /* Fail if there is no throughput */ if (mRec.transmittance.isZero() || pdf[EImportance] == 0 || pdf[ERadiance] == 0) return false; weight[EImportance] = mRec.transmittance / pdf[EImportance]; weight[ERadiance] = mRec.transmittance / pdf[ERadiance]; } else { weight[ERadiance] = weight[EImportance] = Spectrum(1.0f); pdf[ERadiance] = pdf[EImportance] = 1.0f; } } return true; }
int importMain(int argc, char **argv) { bool srgb = false, mapSmallerSide = true; int optchar; char *end_ptr = NULL; int xres = -1, yres = -1; std::string filmType = "hdrfilm"; FileResolver *fileResolver = Thread::getThread()->getFileResolver(); ELogLevel logLevel = EInfo; bool packGeometry = true, importMaterials = true, importAnimations = false; optind = 1; while ((optchar = getopt(argc, argv, "snzvyhmr:a:l:")) != -1) { switch (optchar) { case 'a': { std::vector<std::string> paths = tokenize(optarg, ";"); for (int i=(int) paths.size()-1; i>=0; --i) fileResolver->prependPath(paths[i]); } break; case 's': srgb = true; break; case 'm': mapSmallerSide = false; break; case 'n': importMaterials = false; break; case 'z': importAnimations = true; break; case 'v': logLevel = EDebug; break; case 'l': filmType = optarg; break; case 'y': packGeometry = false; break; case 'r': { std::vector<std::string> tokens = tokenize(optarg, "x"); if (tokens.size() != 2) SLog(EError, "Invalid resolution argument supplied!"); xres = strtol(tokens[0].c_str(), &end_ptr, 10); if (*end_ptr != '\0') SLog(EError, "Invalid resolution argument supplied!"); yres = strtol(tokens[1].c_str(), &end_ptr, 10); if (*end_ptr != '\0') SLog(EError, "Invalid resolution argument supplied!"); } break; case 'h': default: help(); return -1; } }; if (argc-optind < 2) { help(); return -1; } ref<Logger> log = Thread::getThread()->getLogger(); log->setLogLevel(logLevel); ConsoleGeometryConverter converter; converter.setSRGB(srgb); converter.setResolution(xres, yres); converter.setImportMaterials(importMaterials); converter.setImportAnimations(importAnimations); converter.setMapSmallerSide(mapSmallerSide); converter.setPackGeometry(packGeometry); converter.setFilmType(filmType); const Logger *logger = Thread::getThread()->getLogger(); size_t initialWarningCount = logger->getWarningCount(); converter.convert(argv[optind], "", argv[optind+1], argc > optind+2 ? argv[optind+2] : ""); size_t warningCount = logger->getWarningCount() - initialWarningCount; if (warningCount > 0) SLog(EInfo, "Encountered " SIZE_T_FMT " warnings -- please check the " "messages above for details.", warningCount); return 0; }
static void setProperties(QDomDocument &doc, QDomElement &element, const Properties &props) { element.setAttribute("type", props.getPluginName().c_str()); std::vector<std::string> propertyNames; props.putPropertyNames(propertyNames); for (std::vector<std::string>::const_iterator it = propertyNames.begin(); it != propertyNames.end(); ++it) { QDomElement property; switch (props.getType(*it)) { case Properties::EBoolean: property = doc.createElement("boolean"); property.setAttribute("value", props.getBoolean(*it) ? "true" : "false"); break; case Properties::EInteger: property = doc.createElement("integer"); property.setAttribute("value", QString::number(props.getInteger(*it))); break; case Properties::EFloat: property = doc.createElement("float"); property.setAttribute("value", QString::number(props.getFloat(*it))); break; case Properties::EString: property = doc.createElement("string"); property.setAttribute("value", props.getString(*it).c_str()); break; case Properties::EAnimatedTransform: { const AnimatedTransform *trafo = props.getAnimatedTransform(*it); std::set<Float> times; trafo->collectKeyframes(times); property = doc.createElement("animation"); for (std::set<Float>::iterator it2 = times.begin(); it2 != times.end(); ++it2) { const Matrix4x4 &matrix = trafo->eval(*it2).getMatrix(); QDomElement trafoTag = doc.createElement("transform"); QDomElement matrixTag = doc.createElement("matrix"); QString value; for (int i=0; i<4; ++i) for (int j=0; j<4; ++j) value += QString("%1 ").arg(matrix(i, j)); matrixTag.setAttribute("value", value); trafoTag.setAttribute("time", *it2); trafoTag.appendChild(matrixTag); property.appendChild(trafoTag); } } break; case Properties::ETransform: { /* Captures the subset of transformations that are used by Mitsuba's perspective and orthographic camera classes */ property = doc.createElement("transform"); Transform trafo = props.getTransform(*it); if (trafo.hasScale()) { QDomElement scale = doc.createElement("scale"); Float valueX = trafo(Vector(1, 0, 0)).length(); Float valueY = trafo(Vector(0, 1, 0)).length(); Float valueZ = trafo(Vector(0, 0, 1)).length(); if (std::abs(1-valueX) < 1e-3f) valueX = 1.0f; if (std::abs(1-valueY) < 1e-3f) valueY = 1.0f; if (std::abs(1-valueZ) < 1e-3f) valueZ = 1.0f; scale.setAttribute("x", QString("%1").arg(valueX)); scale.setAttribute("y", QString("%1").arg(valueY)); scale.setAttribute("z", QString("%1").arg(valueZ)); property.appendChild(scale); trafo = trafo * Transform::scale(Vector(1.0f/valueX, 1.0f/valueY, 1.0f/valueZ)); } QDomElement lookAt = doc.createElement("lookat"); property.appendChild(lookAt); if (trafo.det3x3() < 0) { QDomElement scale = doc.createElement("scale"); scale.setAttribute("x", "-1"); property.insertBefore(scale, lookAt); } Point p = trafo(Point(0,0,0)); Point t = p + trafo(Vector(0,0,1)); Vector u = trafo(Vector(0,1,0)); lookAt.setAttribute("origin", QString("%1, %2, %3").arg(p.x).arg(p.y).arg(p.z)); lookAt.setAttribute("up", QString("%1, %2, %3").arg(u.x).arg(u.y).arg(u.z)); lookAt.setAttribute("target", QString("%1, %2, %3").arg(t.x).arg(t.y).arg(t.z)); } break; default: SLog(EError, "setProperties(): \"%s\": Unable to handle elements of type %i", (*it).c_str(), props.getType(*it)); } property.setAttribute("name", (*it).c_str()); element.appendChild(property); } }
void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) { QDomElement root = ctx->doc.documentElement(); // ==================================================================== // Serialize the sensor configuration // ==================================================================== QList<QDomElement> oldSensors = findAllChildren(root, "sensor"); const ref_vector<Sensor> sensors = ctx->scene->getSensors(); ref_vector<Sensor>::const_iterator it = std::find(sensors.begin(), sensors.end(), ctx->scene->getSensor()); if (it == sensors.end()) SLog(EError, "Number of sensors did not match between loaded scene and XML file!"); QDomElement sensor, oldSensor; if (oldSensors.size() == 0) ; // ok -- scene did not contain a sensor before else if ((size_t) oldSensors.size() != ctx->scene->getSensors().size()) SLog(EError, "Number of sensors did not match between loaded scene and XML file!"); else oldSensor = oldSensors[it-sensors.begin()]; if (oldSensor.isNull()) { sensor = ctx->doc.createElement("sensor"); root.insertAfter(sensor, QDomNode()); } else { sensor = ctx->doc.createElement("sensor"); root.insertAfter(sensor, oldSensor); root.removeChild(oldSensor); } setProperties(ctx->doc, sensor, ctx->scene->getSensor()->getProperties()); // ==================================================================== // Serialize the sampler configuration // ==================================================================== QDomElement sampler = ctx->doc.createElement("sampler"); sensor.appendChild(sampler); setProperties(ctx->doc, sampler, ctx->scene->getSampler()->getProperties()); // ==================================================================== // Serialize the film configuration // ==================================================================== QDomElement film = ctx->doc.createElement("film"); sensor.appendChild(film); Properties filmProps(ctx->scene->getFilm()->getProperties()); if (filmProps.getPluginName() == "ldrfilm") { /* Also export the tonemapper settings */ if (ctx->toneMappingMethod == EGamma) { filmProps.setString("tonemapMethod", "gamma", false); filmProps.setFloat("exposure", ctx->exposure, false); filmProps.removeProperty("key"); filmProps.removeProperty("burn"); } else { filmProps.setString("tonemapMethod", "reinhard", false); filmProps.setFloat("key", ctx->reinhardKey, false); filmProps.setFloat("burn", (ctx->reinhardBurn + 10) / 20.0f, false); filmProps.removeProperty("exposure"); } filmProps.setFloat("gamma", ctx->srgb ? -1 : ctx->gamma, false); } setProperties(ctx->doc, film, filmProps); // ==================================================================== // Serialize the reconstruction filter configuration // ==================================================================== QDomElement rfilter = ctx->doc.createElement("rfilter"); film.appendChild(rfilter); setProperties(ctx->doc, rfilter, ctx->scene->getFilm()->getReconstructionFilter()->getProperties()); // ==================================================================== // Serialize medium references of the sensor // ==================================================================== QList<QDomElement> oldSensorReferences = findAllChildren(oldSensor, "ref"); oldSensorReferences.append(findAllChildren(oldSensor, "medium")); for (int i=0; i<oldSensorReferences.size(); ++i) sensor.appendChild(ctx->doc.importNode(oldSensorReferences[i], true)); // ==================================================================== // Serialize the integrator configuration // ==================================================================== QDomElement oldIntegratorNode = findUniqueChild(root, "integrator"); QDomElement newIntegratorNode = ctx->doc.createElement("integrator"); const Integrator *integrator = ctx->scene->getIntegrator(); setProperties(ctx->doc, newIntegratorNode, integrator->getProperties()); processSubIntegrators(ctx->doc, integrator, newIntegratorNode); root.insertBefore(newIntegratorNode, oldIntegratorNode); root.removeChild(oldIntegratorNode); QFile file; file.setFileName(targetFile); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { QMessageBox::critical(parent, parent->tr("Unable to save"), parent->tr("Unable to save changes: could not open the destination file <b>%1</b>.").arg(targetFile), QMessageBox::Ok); return; } /* Clean up the XML output generated by Qt so that it is more suitable for human consumption .. Beware: the code below is tailored to Qt's output and won't work on arbitrary XML files */ QString textContent = ctx->doc.toString(); QTextStream input(&textContent); QTextStream output(&file); cleanupXML(input, output); file.close(); }
BrentSolver::Result BrentSolver::solve(const boost::function<Float (Float)> &f, Float x0, Float y0, Float x1, Float y1, Float x2, Float y2) const { Float delta = x1 - x0; Float oldDelta = delta; size_t i = 0; while (i < m_maxIterations) { if (std::abs(y2) < std::abs(y1)) { // use the bracket point if is better than last approximation x0 = x1; x1 = x2; x2 = x0; y0 = y1; y1 = y2; y2 = y0; } if (std::abs(y1) <= m_absAccuracy) { // Avoid division by very small values. Assume // the iteration has converged (the problem may // still be ill conditioned) return Result(true, i, x1, y1); } Float dx = x2 - x1; Float tolerance = std::max(m_relAccuracyPos * std::abs(x1), m_absAccuracyPos); if (std::abs(dx) <= tolerance) return Result(true, i, x1, y1); if ((std::abs(oldDelta) < tolerance) || (std::abs(y0) <= std::abs(y1))) { // Force bisection. delta = (Float) 0.5f * dx; oldDelta = delta; } else { Float r3 = y1 / y0; Float p; Float p1; // the equality test (x0 == x2) is intentional, // it is part of the original Brent's method, // it should NOT be replaced by proximity test if (x0 == x2) { // Linear interpolation. p = dx * r3; p1 = 1 - r3; } else { // Inverse quadratic interpolation. Float r1 = y0 / y2; Float r2 = y1 / y2; p = r3 * (dx * r1 * (r1 - r2) - (x1 - x0) * (r2 - 1)); p1 = (r1 - 1) * (r2 - 1) * (r3 - 1); } if (p > 0) { p1 = -p1; } else { p = -p; } if (2 * p >= (Float) 1.5f * dx * p1 - std::abs(tolerance * p1) || p >= std::abs((Float) 0.5f * oldDelta * p1)) { // Inverse quadratic interpolation gives a value // in the wrong direction, or progress is slow. // Fall back to bisection. delta = (Float) 0.5f * dx; oldDelta = delta; } else { oldDelta = delta; delta = p / p1; } } // Save old X1, Y1 x0 = x1; y0 = y1; // Compute new X1, Y1 if (std::abs(delta) > tolerance) { x1 = x1 + delta; } else if (dx > 0) { x1 = x1 + (Float) 0.5f * tolerance; } else if (dx <= 0) { x1 = x1 - (Float) 0.5f * tolerance; } y1 = f(x1); if ((y1 > 0) == (y2 > 0)) { x2 = x0; y2 = y0; delta = x1 - x0; oldDelta = delta; } i++; } SLog(EWarn, "BrentSolver: Maximum number of iterations (" SIZE_T_FMT ") exceeded!", m_maxIterations); return Result(false, i, x1, y1); }