void handleMiss(RayDifferential ray, const RadianceQueryRecord &rRec, Spectrum &E) const { /* Handle an irradiance cache miss */ HemisphereSampler *hs = m_hemisphereSampler.get(); Sampler *sampler = m_sampleGenerator.get(); RadianceQueryRecord rRec2; if (hs == NULL) { Properties props("independent"); sampler = static_cast<Sampler *> (PluginManager::getInstance()-> createObject(MTS_CLASS(Sampler), props)); hs = new HemisphereSampler(m_resolution, 2 * m_resolution); m_hemisphereSampler.set(hs); m_sampleGenerator.set(sampler); } /* Generate stratified cosine-weighted samples and compute rotational + translational gradients */ hs->generateDirections(rRec.its); sampler->generate(Point2i(0)); for (unsigned int j=0; j<hs->getM(); j++) { for (unsigned int k=0; k<hs->getN(); k++) { HemisphereSampler::SampleEntry &entry = (*hs)(j, k); entry.dist = std::numeric_limits<Float>::infinity(); rRec2.recursiveQuery(rRec, RadianceQueryRecord::ERadianceNoEmission | RadianceQueryRecord::EDistance); rRec2.extra = 1; rRec2.sampler = sampler; entry.L = m_subIntegrator->Li(RayDifferential(rRec.its.p, entry.d, ray.time), rRec2); entry.dist = rRec2.dist; sampler->advance(); } } hs->process(rRec.its); /* Undo ray differential scaling done by the integrator */ if (ray.hasDifferentials) ray.scaleDifferential(m_diffScaleFactor); m_irrCache->put(ray, rRec.its, *hs); E = hs->getIrradiance(); }
void distributedRTPass(Scene *scene, std::vector<SerializableObject *> &samplers) { ref<Camera> camera = scene->getCamera(); bool needsLensSample = camera->needsLensSample(); bool needsTimeSample = camera->needsTimeSample(); ref<Film> film = camera->getFilm(); Vector2i cropSize = film->getCropSize(); Point2i cropOffset = film->getCropOffset(); /* Process the image in parallel using blocks for better memory locality */ Log(EInfo, "Creating %i gather points", cropSize.x*cropSize.y); #pragma omp parallel for schedule(dynamic) for (int i=-1; i<(int) m_gatherBlocks.size(); ++i) { std::vector<GatherPoint> &gatherPoints = m_gatherBlocks[i]; #if !defined(__OSX__) && defined(_OPENMP) Sampler *sampler = static_cast<Sampler *>(samplers[omp_get_thread_num()]); #else Sampler *sampler = static_cast<Sampler *>(samplers[0]); #endif int xofs = m_offset[i].x, yofs = m_offset[i].y; int index = 0; for (int yofsInt = 0; yofsInt < m_blockSize; ++yofsInt) { if (yofsInt + yofs - cropOffset.y >= cropSize.y) continue; for (int xofsInt = 0; xofsInt < m_blockSize; ++xofsInt) { if (xofsInt + xofs - cropOffset.x >= cropSize.x) continue; Point2 lensSample, sample; Float timeSample = 0.0f; GatherPoint &gatherPoint = gatherPoints[index++]; sampler->generate(); if (needsLensSample) lensSample = sampler->next2D(); if (needsTimeSample) timeSample = sampler->next1D(); gatherPoint.pos = Point2i(xofs + xofsInt, yofs + yofsInt); sample = sampler->next2D(); sample += Vector2((Float) gatherPoint.pos.x, (Float) gatherPoint.pos.y); RayDifferential ray; camera->generateRayDifferential(sample, lensSample, timeSample, ray); Spectrum weight(1.0f); int depth = 1; while (true) { if (depth > m_maxDepth) { gatherPoint.depth = -1; break; } if (scene->rayIntersect(ray, gatherPoint.its)) { const BSDF *bsdf = gatherPoint.its.shape->getBSDF(); /* Create hit point if this is a diffuse material or a glossy one, and there has been a previous interaction with a glossy material */ if (bsdf->getType() == BSDF::EDiffuseReflection || bsdf->getType() == BSDF::EDiffuseTransmission) { gatherPoint.weight = weight; gatherPoint.depth = depth; if (gatherPoint.its.isLuminaire()) gatherPoint.emission = gatherPoint.its.Le(-ray.d); else gatherPoint.emission = Spectrum(0.0f); break; } else { /* Recurse for dielectric materials and (specific to SPPM): recursive "final gathering" for glossy materials */ BSDFQueryRecord bRec(gatherPoint.its); weight *= bsdf->sampleCos(bRec, sampler->next2D()); if (weight.isZero()) { gatherPoint.depth = -1; break; } ray = RayDifferential(gatherPoint.its.p, gatherPoint.its.toWorld(bRec.wo), ray.time); ++depth; } } else { /* Generate an invalid sample */ gatherPoint.depth = -1; break; } } sampler->advance(); } } } }
bool render(Scene *scene, RenderQueue *queue, const RenderJob *job, int sceneResID, int cameraResID, int samplerResID) { ref<Scheduler> sched = Scheduler::getInstance(); ref<Camera> camera = scene->getCamera(); ref<Film> film = camera->getFilm(); size_t nCores = sched->getCoreCount(); Sampler *cameraSampler = (Sampler *) sched->getResource(samplerResID, 0); size_t sampleCount = cameraSampler->getSampleCount(); Log(EInfo, "Starting render job (%ix%i, " SIZE_T_FMT " %s, " SIZE_T_FMT " %s, " SSE_STR ") ..", film->getCropSize().x, film->getCropSize().y, sampleCount, sampleCount == 1 ? "sample" : "samples", nCores, nCores == 1 ? "core" : "cores"); Vector2i cropSize = film->getCropSize(); Point2i cropOffset = film->getCropOffset(); m_gatherPoints.clear(); m_running = true; for (size_t i=0; i<m_blocks.size(); ++i) m_blocks[i]->decRef(); m_blocks.clear(); m_totalEmitted = 0; bool needsLensSample = camera->needsLensSample(); bool needsTimeSample = camera->needsTimeSample(); Log(EInfo, "Creating approximately %i gather points", cropSize.x*cropSize.y*sampleCount); Point2 lensSample, sample; RayDifferential eyeRay; Float timeSample = 0; m_filter = camera->getFilm()->getTabulatedFilter(); Vector2 filterSize = m_filter->getFilterSize(); int borderSize = (int) std::ceil(std::max(filterSize.x, filterSize.y)); ref<Sampler> independentSampler = static_cast<Sampler *> (PluginManager::getInstance()-> createObject(MTS_CLASS(Sampler), Properties("independent"))); /* Create a sampler instance for every core */ std::vector<SerializableObject *> samplers(sched->getCoreCount()); for (size_t i=0; i<sched->getCoreCount(); ++i) { ref<Sampler> clonedSampler = independentSampler->clone(); clonedSampler->incRef(); samplers[i] = clonedSampler.get(); } int independentSamplerResID = sched->registerManifoldResource(samplers); for (size_t i=0; i<sched->getCoreCount(); ++i) samplers[i]->decRef(); #ifdef MTS_DEBUG_FP enableFPExceptions(); #endif /* Create gather points in blocks so that gathering can be parallelized later on */ for (int yofs=0; yofs<cropSize.y; yofs += m_blockSize) { for (int xofs=0; xofs<cropSize.x; xofs += m_blockSize) { ImageBlock *block = new ImageBlock(Vector2i(m_blockSize, m_blockSize), borderSize, true, true, false, false); block->setSize(Vector2i(m_blockSize, m_blockSize)); block->setOffset(Point2i(cropOffset.x + xofs, cropOffset.y + yofs)); block->incRef(); std::vector<GatherPoint> gatherPoints; gatherPoints.reserve(m_blockSize*m_blockSize*sampleCount); for (int yofsInt = 0; yofsInt < m_blockSize; ++yofsInt) { if (yofsInt + yofs >= cropSize.y) continue; for (int xofsInt = 0; xofsInt < m_blockSize; ++xofsInt) { if (xofsInt + xofs >= cropSize.x) continue; int y = cropOffset.y + yofs + yofsInt; int x = cropOffset.x + xofs + xofsInt; cameraSampler->generate(); for (size_t j = 0; j<sampleCount; j++) { if (needsLensSample) lensSample = cameraSampler->next2D(); if (needsTimeSample) timeSample = cameraSampler->next1D(); sample = cameraSampler->next2D(); sample.x += x; sample.y += y; camera->generateRayDifferential(sample, lensSample, timeSample, eyeRay); size_t offset = gatherPoints.size(); Float count = (Float) createGatherPoints(scene, eyeRay, sample, cameraSampler, Spectrum(1.0f), gatherPoints, 1); if (count > 1) { // necessary because of filter weight computation for (int i = 0; i<count; ++i) gatherPoints[offset+i].weight *= count; } cameraSampler->advance(); } } } m_blocks.push_back(block); m_gatherPoints.push_back(gatherPoints); } } int it=0; while (m_running) photonMapPass(++it, queue, job, film, sceneResID, cameraResID, independentSamplerResID); #ifdef MTS_DEBUG_FP disableFPExceptions(); #endif sched->unregisterResource(independentSamplerResID); return true; }