int Path::randomWalkFromPixel(const Scene *scene, Sampler *sampler, int nSteps, const Point2i &pixelPosition, int rrStart, MemoryPool &pool) { PathVertex *v1 = pool.allocVertex(), *v2 = pool.allocVertex(); PathEdge *e0 = pool.allocEdge(), *e1 = pool.allocEdge(); /* Use a special sampling routine for the first two sensor vertices so that the resulting subpath passes through the specified pixel position */ int t = vertex(0)->sampleSensor(scene, sampler, pixelPosition, e0, v1, e1, v2); if (t < 1) { pool.release(e0); pool.release(v1); return 0; } append(e0, v1); if (t < 2) { pool.release(e1); pool.release(v2); return 1; } append(e1, v2); PathVertex *predVertex = v1, *curVertex = v2; PathEdge *predEdge = e1; Spectrum throughput(1.0f); for (; t<nSteps || nSteps == -1; ++t) { PathVertex *succVertex = pool.allocVertex(); PathEdge *succEdge = pool.allocEdge(); if (!curVertex->sampleNext(scene, sampler, predVertex, predEdge, succEdge, succVertex, ERadiance, rrStart != -1 && t >= rrStart, &throughput)) { pool.release(succVertex); pool.release(succEdge); return t; } append(succEdge, succVertex); predVertex = curVertex; curVertex = succVertex; predEdge = succEdge; } return nSteps; }
int Path::randomWalk(const Scene *scene, Sampler *sampler, int nSteps, int rrStart, ETransportMode mode, MemoryPool &pool) { /* Determine the relevant edge and vertex to start the random walk */ PathVertex *curVertex = m_vertices[m_vertices.size()-1], *predVertex = m_vertices.size() < 2 ? NULL : m_vertices[m_vertices.size()-2]; PathEdge *predEdge = m_edges.empty() ? NULL : m_edges[m_edges.size()-1]; Spectrum throughput(1.0f); for (int i=0; i<nSteps || nSteps == -1; ++i) { PathVertex *succVertex = pool.allocVertex(); PathEdge *succEdge = pool.allocEdge(); if (!curVertex->sampleNext(scene, sampler, predVertex, predEdge, succEdge, succVertex, mode, rrStart != -1 && i >= rrStart, &throughput)) { pool.release(succVertex); pool.release(succEdge); return i; } append(succEdge, succVertex); predVertex = curVertex; curVertex = succVertex; predEdge = succEdge; } return nSteps; }
std::pair<int, int> Path::alternatingRandomWalkFromPixel(const Scene *scene, Sampler *sampler, Path &emitterPath, int nEmitterSteps, Path &sensorPath, int nSensorSteps, const Point2i &pixelPosition, int rrStart, MemoryPool &pool) { /* Determine the relevant edges and vertices to start the random walk */ PathVertex *curVertexS = emitterPath.vertex(0), *curVertexT = sensorPath.vertex(0), *predVertexS = NULL, *predVertexT = NULL; PathEdge *predEdgeS = NULL, *predEdgeT = NULL; PathVertex *v1 = pool.allocVertex(), *v2 = pool.allocVertex(); PathEdge *e0 = pool.allocEdge(), *e1 = pool.allocEdge(); /* Use a special sampling routine for the first two sensor vertices so that the resulting subpath passes through the specified pixel position */ int t = curVertexT->sampleSensor(scene, sampler, pixelPosition, e0, v1, e1, v2); if (t >= 1) { sensorPath.append(e0, v1); } else { pool.release(e0); pool.release(v1); } if (t == 2) { sensorPath.append(e1, v2); predVertexT = v1; curVertexT = v2; predEdgeT = e1; } else { pool.release(e1); pool.release(v2); curVertexT = NULL; } Spectrum throughputS(1.0f), throughputT(1.0f); int s = 0; do { if (curVertexT && (t < nSensorSteps || nSensorSteps == -1)) { PathVertex *succVertexT = pool.allocVertex(); PathEdge *succEdgeT = pool.allocEdge(); if (curVertexT->sampleNext(scene, sampler, predVertexT, predEdgeT, succEdgeT, succVertexT, ERadiance, rrStart != -1 && t >= rrStart, &throughputT)) { sensorPath.append(succEdgeT, succVertexT); predVertexT = curVertexT; curVertexT = succVertexT; predEdgeT = succEdgeT; t++; } else { pool.release(succVertexT); pool.release(succEdgeT); curVertexT = NULL; } } else { curVertexT = NULL; } if (curVertexS && (s < nEmitterSteps || nEmitterSteps == -1)) { PathVertex *succVertexS = pool.allocVertex(); PathEdge *succEdgeS = pool.allocEdge(); if (curVertexS->sampleNext(scene, sampler, predVertexS, predEdgeS, succEdgeS, succVertexS, EImportance, rrStart != -1 && s >= rrStart, &throughputS)) { emitterPath.append(succEdgeS, succVertexS); predVertexS = curVertexS; curVertexS = succVertexS; predEdgeS = succEdgeS; s++; } else { pool.release(succVertexS); pool.release(succEdgeS); curVertexS = NULL; } } else { curVertexS = NULL; } } while (curVertexS || curVertexT); return std::make_pair(s, t); }
void Path::initialize(const Scene *scene, Float time, ETransportMode mode, MemoryPool &pool) { release(pool); m_vertices.push_back(pool.allocVertex()); m_vertices[0]->makeEndpoint(scene, time, mode); }
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; }