void CaptureParticleWorker::handleSurfaceInteraction(int depth, int nullInteractions, bool caustic, const Intersection &its, const Medium *medium, const Spectrum &weight) { if (its.isSensor()) { if (!m_bruteForce && !caustic) return; const Sensor *sensor = its.shape->getSensor(); if (sensor != m_sensor) return; Vector wi = its.toWorld(its.wi); Point2 uv; Spectrum value = sensor->eval(its, wi, uv) * weight; if (value.isZero()) return; m_workResult->put(uv, (Float *) &value[0]); return; } if (m_bruteForce || (depth >= m_maxPathDepth && m_maxPathDepth > 0)) return; int maxInteractions = m_maxPathDepth - depth - 1; DirectSamplingRecord dRec(its); Spectrum value = weight * m_scene->sampleAttenuatedSensorDirect( dRec, its, medium, maxInteractions, m_sampler->next2D(), m_sampler); if (value.isZero()) return; const BSDF *bsdf = its.getBSDF(); Vector wo = dRec.d; BSDFSamplingRecord bRec(its, its.toLocal(wo), EImportance); /* Prevent light leaks due to the use of shading normals -- [Veach, p. 158] */ Vector wi = its.toWorld(its.wi); Float wiDotGeoN = dot(its.geoFrame.n, wi), woDotGeoN = dot(its.geoFrame.n, wo); if (wiDotGeoN * Frame::cosTheta(bRec.wi) <= 0 || woDotGeoN * Frame::cosTheta(bRec.wo) <= 0) return; /* Adjoint BSDF for shading normals -- [Veach, p. 155] */ Float correction = std::abs( (Frame::cosTheta(bRec.wi) * woDotGeoN)/ (Frame::cosTheta(bRec.wo) * wiDotGeoN)); value *= bsdf->eval(bRec) * correction; /* Splat onto the accumulation buffer */ m_workResult->put(dRec.uv, (Float *) &value[0]); }
Color3f Li(const Scene *scene, Sampler *sampler, const Ray3f &ray) const { /* Find the surface that is visible in the requested direction */ Intersection its; //check if the ray intersects the scene if (!scene->rayIntersect(ray, its)) { //check if a distant disk light is set const Emitter* distantsDisk = scene->getDistantEmitter(); if(distantsDisk == nullptr ) return Color3f(0.0f); //sample the distant disk light return distantsDisk->sampleL(ray.d); } //get the radiance of hitten object Color3f Le(0.0f, 0.0f, 0.0f); if (its.mesh->isEmitter() ) { const Emitter* areaLightEM = its.mesh->getEmitter(); const areaLight* aEM = static_cast<const areaLight *> (areaLightEM); Le = aEM->sampleL(-ray.d, its.shFrame.n, its); } //get the asigned BSDF const BSDF* curBSDF = its.mesh->getBSDF(); Color3f Ld(0.0f, 0.0f, 0.0f); Color3f f(0.0f, 0.0f, 0.0f); Color3f totalLight(0.0f, 0.0f, 0.0f); //transform to the local frame //create a BRDF Query BSDFQueryRecord query = BSDFQueryRecord(its.toLocal(-ray.d), Vector3f(0.0f), EMeasure::ESolidAngle); //sample the BRDF Color3f mats = curBSDF->sample(query, sampler->next2D()); if(mats.maxCoeff() > 0.0f) { //Check for the light source Vector3f wo = its.toWorld(query.wo); Ray3f shadowRay(its.p, wo); Intersection itsShadow; if (scene->rayIntersect(shadowRay, itsShadow)) { //intersection check if mesh is emitter if(itsShadow.mesh->isEmitter()){ Ld = itsShadow.mesh->getEmitter()->radiance(); } } else { //check for distant disk light const Emitter* distantsDisk = scene->getDistantEmitter(); if(distantsDisk != nullptr ) Ld = distantsDisk->sampleL(wo); } totalLight += Ld * mats; } return Le + totalLight; }
void CaptureParticleWorker::handleSurfaceInteraction(int depth, bool caustic, const Intersection &its, const Medium *medium, const Spectrum &weight) { const ProjectiveCamera *camera = static_cast<const ProjectiveCamera *>(m_camera.get()); Point2 screenSample; if (camera->positionToSample(its.p, screenSample)) { Point cameraPosition = camera->getPosition(screenSample); Float t = dot(camera->getImagePlaneNormal(), its.p-cameraPosition); if (t < camera->getNearClip() || t > camera->getFarClip()) return; if (its.isMediumTransition()) medium = its.getTargetMedium(cameraPosition - its.p); Spectrum transmittance = m_scene->getTransmittance(its.p, cameraPosition, its.time, medium); if (transmittance.isZero()) return; const BSDF *bsdf = its.shape->getBSDF(); Vector wo = cameraPosition - its.p; Float dist = wo.length(); wo /= dist; BSDFQueryRecord bRec(its, its.toLocal(wo)); bRec.quantity = EImportance; Float importance; if (m_isPerspectiveCamera) importance = ((const PerspectiveCamera *) camera)->importance(screenSample) / (dist * dist); else importance = 1/camera->areaDensity(screenSample); Vector wi = its.toWorld(its.wi); /* Prevent light leaks due to the use of shading normals -- [Veach, p. 158] */ Float wiDotGeoN = dot(its.geoFrame.n, wi), woDotGeoN = dot(its.geoFrame.n, wo); if (wiDotGeoN * Frame::cosTheta(bRec.wi) <= 0 || woDotGeoN * Frame::cosTheta(bRec.wo) <= 0) return; /* Adjoint BSDF for shading normals -- [Veach, p. 155] */ Float correction = std::abs( (Frame::cosTheta(bRec.wi) * woDotGeoN)/ (Frame::cosTheta(bRec.wo) * wiDotGeoN)); /* Splat onto the accumulation buffer */ Ray ray(its.p, wo, 0, dist, its.time); Spectrum sampleVal = weight * bsdf->fCos(bRec) * transmittance * (importance * correction); m_workResult->splat(screenSample, sampleVal, m_filter); } }
void fillIntersectionRecord(const Ray &ray, const void *temp, Intersection &its) const { const Float *data = static_cast<const Float *>(temp); its.shFrame = its.geoFrame = m_frame; its.shape = this; its.dpdu = m_dpdu; its.dpdv = m_dpdv; its.uv = Point2(0.5f * (data[0]+1), 0.5f * (data[1]+1)); its.p = ray(its.t); its.wi = its.toLocal(-ray.d); its.hasUVPartials = false; its.instance = NULL; its.time = ray.time; }
virtual Vec sample( Intersection const &isect, float u1, float u2, Vec& WiW, float& pdfResult, int &bxdfType) const { pdfResult = 1.f; // should be a dirac? Vec Wi = perfectSpecularReflection(isect.toLocal(isect.WoW)); WiW = isect.toWorld(Wi); bxdfType = BxDF_SPECULAR; return isect.texSample * fresnelCoef(Wi, m_R0); }
virtual Vec sample( Intersection const &isect, float u1, float u2, Vec& WiW, float& pdfResult, int &bxdfType) const { Vec WoL = isect.toLocal(isect.WoW); Vec result; if (WoL.z() < 0.f) { Vec Wi = perfectSpecularRefraction(-WoL, 1.f / m_ior); result = Vec(1.f, 1.f, 1.f) * fresnelCoef(Wi * Vec(1.f, 1.f, -1.f), m_r0); WiW = isect.toWorld(-Wi); } else { Vec Wi = perfectSpecularRefraction(WoL, m_ior); result = Vec(1.f, 1.f, 1.f) * fresnelCoef(Wi * Vec(1.f, 1.f, -1.f), m_r0); WiW = isect.toWorld(Wi); } bxdfType = BxDF_SPECULAR; pdfResult = 1.f; return result; }
Color3f Li(const Scene *scene, Sampler *sampler, const Ray3f &ray) const { /* Find the surface that is visible in the requested direction */ Intersection its; //check if the ray intersects the scene if (!scene->rayIntersect(ray, its)) { //check if a distant disk light is set const Emitter* distantsDisk = scene->getDistantEmitter(); if(distantsDisk == nullptr ) return Color3f(0.0f); //sample the distant disk light Vector3f d = ray.d; return distantsDisk->sampleL(d); } //get the Number of lights from the scene const std::vector<Emitter *> lights = scene->getEmitters(); uint32_t nLights = lights.size(); Color3f tp(1.0f, 1.0f, 1.0f); Color3f L(0.0f, 0.0f, 0.0f); Ray3f pathRay(ray.o, ray.d); bool deltaFlag = true; while(true) { if (its.mesh->isEmitter() && deltaFlag) { const Emitter* areaLightEM = its.mesh->getEmitter(); const areaLight* aEM = static_cast<const areaLight *> (areaLightEM); L += tp * aEM->sampleL(-pathRay.d, its.shFrame.n, its); } //Light sampling //randomly select a lightsource uint32_t var = uint32_t(std::min(sampler->next1D()*nLights, float(nLights) - 1.0f)); //init the light color Color3f Li(0.0f, 0.0f, 0.0f); Color3f Ld(1.0f, 1.0f, 1.0f); //create a sample for the light const BSDF* curBSDF = its.mesh->getBSDF(); const Point2f lightSample = sampler->next2D(); VisibilityTester vis; Vector3f wo; float lightpdf; float bsdfpdf; Normal3f n = its.shFrame.n; deltaFlag = curBSDF->isDeltaBSDF(); //sample the light { Li = lights[var]->sampleL(its.p, Epsilon, lightSample , &wo, &lightpdf, &vis); lightpdf /= float(nLights); //check if the pdf of the sample is greater than 0 and if the color is not black if(lightpdf > 0 && Li.maxCoeff() != 0.0f) { //calculate the cosine term wi in my case the vector to the light float cosTerm = std::abs(n.dot(wo)); const BSDFQueryRecord queryEM = BSDFQueryRecord(its.toLocal(- pathRay.d), its.toLocal(wo), EMeasure::ESolidAngle, sampler); Color3f f = curBSDF->eval(queryEM); if(f.maxCoeff() > 0.0f && f.minCoeff() >= 0.0f && vis.Unoccluded(scene)) { bsdfpdf = curBSDF->pdf(queryEM); float weight = BalanceHeuristic(float(1), lightpdf, float(1), bsdfpdf); if(curBSDF->isDeltaBSDF()) weight = 1.0f; if(bsdfpdf > 0.0f) { Ld = (weight * f * Li * cosTerm) / lightpdf; L += tp * Ld; } else { //cout << "bsdfpdf = " << bsdfpdf << endl; //cout << "f = " << f << endl; } } } } //Material part BSDFQueryRecord queryMats = BSDFQueryRecord(its.toLocal(-pathRay.d), Vector3f(0.0f), EMeasure::ESolidAngle, sampler); Color3f fi = curBSDF->sample(queryMats, sampler->next2D()); bsdfpdf = curBSDF->pdf(queryMats); lightpdf = 0.0f; if(fi.maxCoeff() > 0.0f && fi.minCoeff() >= 0.0f) { if(bsdfpdf > 0.0f) { Ray3f shadowRay(its.p, its.toWorld(queryMats.wo)); Intersection lightIsect; if (scene->rayIntersect(shadowRay, lightIsect)) { if(lightIsect.mesh->isEmitter()){ const Emitter* areaLightEMcur = lightIsect.mesh->getEmitter(); const areaLight* aEMcur = static_cast<const areaLight *> (areaLightEMcur); Li = aEMcur->sampleL(-shadowRay.d, lightIsect.shFrame.n, lightIsect); lightpdf = aEMcur->pdf(its.p, (lightIsect.p - its.p).normalized(), lightIsect.p, Normal3f(lightIsect.shFrame.n)); } } else { const Emitter* distantsDisk = scene->getDistantEmitter(); if(distantsDisk != nullptr ) { //check if THIS is right! Li = distantsDisk->sampleL(lightIsect.toWorld(queryMats.wo)); lightpdf = distantsDisk->pdf(Point3f(0.0f), wo, Point3f(0.0f), Normal3f(0.0f)); } } lightpdf /= float(nLights); //calculate the weights float weight = BalanceHeuristic(float(1), bsdfpdf, float(1), lightpdf); //check if the lightcolor is not black if(Li.maxCoeff() > 0.0f && lightpdf > 0.0f ) { //wo in my case the vector to the light Ld = weight * Li * fi; L += tp * Ld; } } tp *= fi; } else { break; } wo = its.toWorld(queryMats.wo); pathRay = Ray3f(its.p, wo); if (!scene->rayIntersect(pathRay, its)) { const Emitter* distantsDisk = scene->getDistantEmitter(); if(distantsDisk != nullptr ) { //sample the distant disk light Vector3f d = pathRay.d; L += tp * distantsDisk->sampleL(d); } break; } float maxCoeff = tp.maxCoeff(); float q = std::min(0.99f, maxCoeff); if(q < sampler->next1D()){ break; } tp /= q; } return L; }
Spectrum MisPathTracer::Li(const Scene* scene, Sampler& sampler, Ray3f& ray) const { Spectrum L(0.f); Intersection its; Spectrum throughput(1.f); bool isSpecular = true; while (true) { if (!scene->rayIntersect(ray, its)) break; if (isSpecular && its.shape->getEmitter()) { EmitterSample emittanceSample(ray.o, its.p, its.shFrame.n); L += throughput * its.shape->getEmitter()->eval(emittanceSample); } if (its.shape->getBSDF()->getType() != BSDFType::Delta) { EmitterSample emSam(its.p); auto lightSpec = scene->sampleEmitter(its, sampler, emSam); float cosFactor = its.shFrame.n.dot(emSam.wi); if (!(cosFactor <= 0.f || lightSpec.isZero() || scene->rayIntersect(emSam.shadowRay))) { BSDFSample bsdfSam(its.p, its.toLocal(-ray.d), its.toLocal(emSam.wi)); bsdfSam.measure = Measure::SolidAngle; auto bsdfSpec = its.shape->getBSDF()->eval(bsdfSam); float pdfEm = emSam.pdf; float pdfBsdf = its.shape->getBSDF()->pdf(bsdfSam); L += throughput * bsdfSpec * lightSpec * cosFactor * miWeight(pdfEm, pdfBsdf); } } BSDFSample bsdfSample(its.p, its.toLocal(-ray.d)); auto bsdf = its.shape->getBSDF()->sample(bsdfSample, sampler); Intersection bsdfIts; Ray3f bsdfRay(its.p, its.toWorld(bsdfSample.wo)); if (scene->rayIntersect(bsdfRay, bsdfIts) && bsdfIts.shape->getEmitter()) { const auto* em = bsdfIts.shape->getEmitter(); EmitterSample emSam(its.p, bsdfIts.p, bsdfIts.shFrame.n); emSam.wi = bsdfRay.d; auto lightSpec = em->eval(emSam); float pdfBsdf = its.shape->getBSDF()->pdf(bsdfSample); float pdfEm = em->pdf(emSam) * scene->getEmitterPdf(); if (pdfBsdf + pdfEm > 0.f) L += throughput * bsdf * lightSpec * miWeight(pdfBsdf, pdfEm); } isSpecular = its.shape->getBSDF()->getType() == BSDFType::Delta; throughput *= bsdf; ray = bsdfRay; float q = 1.f - std::min(throughput.maxCoeff(), 0.99f); if (sampler.next1D() > q) throughput /= (1.f - q); else break; } return L; }
void PreviewWorker::processIncoherent(const WorkUnit *workUnit, WorkResult *workResult, const bool &stop) { const RectangularWorkUnit *rect = static_cast<const RectangularWorkUnit *>(workUnit); ImageBlock *block = static_cast<ImageBlock *>(workResult); block->setOffset(rect->getOffset()); block->setSize(rect->getSize()); const int sx = rect->getOffset().x, sy = block->getOffset().y; const int ex = sx + rect->getSize().x, ey = sy + rect->getSize().y; /* Some local variables */ int pos = 0; Intersection its; Spectrum value, bsdfVal; Vector toVPL; Ray primary, secondary; int numRays = 0; float shutterOpen = m_scene->getCamera()->getShutterOpen(); for (int y=sy; y<ey; ++y) { for (int x=sx; x<ex; ++x) { /* Generate a camera ray without normalization */ primary = Ray(m_cameraO, m_cameraTL + m_cameraDx * (Float) x + m_cameraDy * (Float) y, shutterOpen); ++numRays; if (!m_kdtree->rayIntersect(primary, its)) { block->setPixel(pos++, m_scene->LeBackground(primary)*m_backgroundScale); continue; } if (its.shape->isLuminaire()) value = its.Le(-primary.d); else value = Spectrum(0.0f); toVPL = m_vpl.its.p - its.p; secondary = Ray(its.p, toVPL, ShadowEpsilon, 1-ShadowEpsilon, shutterOpen); ++numRays; if (m_kdtree->rayIntersect(secondary)) { block->setPixel(pos++, value); continue; } Float length = toVPL.length(); toVPL/=length; BSDFQueryRecord rr(its, its.toLocal(toVPL)); rr.wi = normalize(rr.wi); bsdfVal = its.shape->getBSDF()->eval(rr); length = std::max(length, m_minDist); if (m_vpl.type == ESurfaceVPL) { BSDFQueryRecord bRec(m_vpl.its, -m_vpl.its.toLocal(toVPL)); bRec.quantity = EImportance; value += m_vpl.P * bsdfVal * m_vpl.its.shape->getBSDF()->eval(bRec) / (length*length); } else { EmissionRecord eRec(m_vpl.luminaire, ShapeSamplingRecord(m_vpl.its.p, m_vpl.its.shFrame.n), -toVPL); eRec.type = EmissionRecord::EPreview; value += m_vpl.P * bsdfVal * m_vpl.luminaire->evalDirection(eRec) * ((m_vpl.luminaire->getType() & Luminaire::EOnSurface ? dot(m_vpl.its.shFrame.n, -toVPL) : (Float) 1) / (length*length)); } block->setPixel(pos++, value); } } block->setExtra(numRays); }
void PreviewWorker::processCoherent(const WorkUnit *workUnit, WorkResult *workResult, const bool &stop) { #if defined(MTS_HAS_COHERENT_RT) const RectangularWorkUnit *rect = static_cast<const RectangularWorkUnit *>(workUnit); ImageBlock *block = static_cast<ImageBlock *>(workResult); block->setOffset(rect->getOffset()); block->setSize(rect->getSize()); /* Some constants */ const int sx = rect->getOffset().x, sy = block->getOffset().y; const int ex = sx + rect->getSize().x, ey = sy + rect->getSize().y; const int width = rect->getSize().x; const SSEVector MM_ALIGN16 xOffset(0.0f, 1.0f, 0.0f, 1.0f); const SSEVector MM_ALIGN16 yOffset(0.0f, 0.0f, 1.0f, 1.0f); const int pixelOffset[] = {0, 1, width, width+1}; const __m128 clamping = _mm_set1_ps(1/(m_minDist*m_minDist)); uint8_t temp[MTS_KD_INTERSECTION_TEMP*4]; const __m128 camTL[3] = { _mm_set1_ps(m_cameraTL.x), _mm_set1_ps(m_cameraTL.y), _mm_set1_ps(m_cameraTL.z) }; const __m128 camDx[3] = { _mm_set1_ps(m_cameraDx.x), _mm_set1_ps(m_cameraDx.y), _mm_set1_ps(m_cameraDx.z) }; const __m128 camDy[3] = { _mm_set1_ps(m_cameraDy.x), _mm_set1_ps(m_cameraDy.y), _mm_set1_ps(m_cameraDy.z) }; const __m128 lumPos[3] = { _mm_set1_ps(m_vpl.its.p.x), _mm_set1_ps(m_vpl.its.p.y), _mm_set1_ps(m_vpl.its.p.z) }; const __m128 lumDir[3] = { _mm_set1_ps(m_vpl.its.shFrame.n.x), _mm_set1_ps(m_vpl.its.shFrame.n.y), _mm_set1_ps(m_vpl.its.shFrame.n.z) }; /* Some local variables */ int pos = 0; int numRays = 0; RayPacket4 MM_ALIGN16 primRay4, secRay4; Intersection4 MM_ALIGN16 its4, secIts4; RayInterval4 MM_ALIGN16 itv4, secItv4; SSEVector MM_ALIGN16 nSecD[3], cosThetaLight, invLengthSquared; Spectrum emitted[4], direct[4]; Intersection its; Vector wo, wi; its.hasUVPartials = false; bool diffuseVPL = false, vplOnSurface = false; Spectrum vplWeight; if (m_vpl.type == ESurfaceVPL && (m_diffuseSources || m_vpl.its.shape->getBSDF()->getType() == BSDF::EDiffuseReflection)) { diffuseVPL = true; vplOnSurface = true; vplWeight = m_vpl.its.shape->getBSDF()->getDiffuseReflectance(m_vpl.its) * m_vpl.P / M_PI; } else if (m_vpl.type == ELuminaireVPL) { vplOnSurface = m_vpl.luminaire->getType() & Luminaire::EOnSurface; diffuseVPL = m_vpl.luminaire->getType() & Luminaire::EDiffuseDirection; EmissionRecord eRec(m_vpl.luminaire, ShapeSamplingRecord(m_vpl.its.p, m_vpl.its.shFrame.n), m_vpl.its.shFrame.n); vplWeight = m_vpl.P * m_vpl.luminaire->evalDirection(eRec); } primRay4.o[0].ps = _mm_set1_ps(m_cameraO.x); primRay4.o[1].ps = _mm_set1_ps(m_cameraO.y); primRay4.o[2].ps = _mm_set1_ps(m_cameraO.z); secItv4.mint.ps = _mm_set1_ps(ShadowEpsilon); /* Work on 2x2 sub-blocks */ for (int y=sy; y<ey; y += 2, pos += width) { for (int x=sx; x<ex; x += 2, pos += 2) { /* Generate camera rays without normalization */ const __m128 xPixel = _mm_add_ps(xOffset.ps, _mm_set1_ps((float) x)), yPixel = _mm_add_ps(yOffset.ps, _mm_set1_ps((float) y)); primRay4.d[0].ps = _mm_add_ps(camTL[0], _mm_add_ps( _mm_mul_ps(xPixel, camDx[0]), _mm_mul_ps(yPixel, camDy[0]))); primRay4.d[1].ps = _mm_add_ps(camTL[1], _mm_add_ps( _mm_mul_ps(xPixel, camDx[1]), _mm_mul_ps(yPixel, camDy[1]))); primRay4.d[2].ps = _mm_add_ps(camTL[2], _mm_add_ps( _mm_mul_ps(xPixel, camDx[2]), _mm_mul_ps(yPixel, camDy[2]))); primRay4.dRcp[0].ps = _mm_div_ps(SSEConstants::one.ps, primRay4.d[0].ps); primRay4.dRcp[1].ps = _mm_div_ps(SSEConstants::one.ps, primRay4.d[1].ps); primRay4.dRcp[2].ps = _mm_div_ps(SSEConstants::one.ps, primRay4.d[2].ps); /* Ray coherence test */ const int primSignsX = _mm_movemask_ps(primRay4.d[0].ps); const int primSignsY = _mm_movemask_ps(primRay4.d[1].ps); const int primSignsZ = _mm_movemask_ps(primRay4.d[2].ps); const bool primCoherent = (primSignsX == 0 || primSignsX == 0xF) && (primSignsY == 0 || primSignsY == 0xF) && (primSignsZ == 0 || primSignsZ == 0xF); /* Trace the primary rays */ its4.t = SSEConstants::p_inf; if (EXPECT_TAKEN(primCoherent)) { primRay4.signs[0][0] = primSignsX ? 1 : 0; primRay4.signs[1][0] = primSignsY ? 1 : 0; primRay4.signs[2][0] = primSignsZ ? 1 : 0; m_kdtree->rayIntersectPacket(primRay4, itv4, its4, temp); } else { m_kdtree->rayIntersectPacketIncoherent(primRay4, itv4, its4, temp); } numRays += 4; /* Generate secondary rays */ secRay4.o[0].ps = _mm_add_ps(primRay4.o[0].ps, _mm_mul_ps(its4.t.ps, primRay4.d[0].ps)); secRay4.o[1].ps = _mm_add_ps(primRay4.o[1].ps, _mm_mul_ps(its4.t.ps, primRay4.d[1].ps)); secRay4.o[2].ps = _mm_add_ps(primRay4.o[2].ps, _mm_mul_ps(its4.t.ps, primRay4.d[2].ps)); secRay4.d[0].ps = _mm_sub_ps(lumPos[0], secRay4.o[0].ps); secRay4.d[1].ps = _mm_sub_ps(lumPos[1], secRay4.o[1].ps); secRay4.d[2].ps = _mm_sub_ps(lumPos[2], secRay4.o[2].ps); /* Normalization */ const __m128 lengthSquared = _mm_add_ps(_mm_add_ps( _mm_mul_ps(secRay4.d[0].ps, secRay4.d[0].ps), _mm_mul_ps(secRay4.d[1].ps, secRay4.d[1].ps)), _mm_mul_ps(secRay4.d[2].ps, secRay4.d[2].ps)), invLength = _mm_rsqrt_ps(lengthSquared); invLengthSquared.ps = _mm_min_ps(_mm_rcp_ps(lengthSquared), clamping); nSecD[0].ps = _mm_mul_ps(secRay4.d[0].ps, invLength); nSecD[1].ps = _mm_mul_ps(secRay4.d[1].ps, invLength); nSecD[2].ps = _mm_mul_ps(secRay4.d[2].ps, invLength); secRay4.dRcp[0].ps = _mm_div_ps(SSEConstants::one.ps, secRay4.d[0].ps); secRay4.dRcp[1].ps = _mm_div_ps(SSEConstants::one.ps, secRay4.d[1].ps); secRay4.dRcp[2].ps = _mm_div_ps(SSEConstants::one.ps, secRay4.d[2].ps); cosThetaLight.ps = _mm_sub_ps(_mm_setzero_ps(), _mm_add_ps(_mm_add_ps( _mm_mul_ps(nSecD[0].ps, lumDir[0]), _mm_mul_ps(nSecD[1].ps, lumDir[1])), _mm_mul_ps(nSecD[2].ps, lumDir[2]))); secItv4.maxt.ps = _mm_set1_ps(1-ShadowEpsilon); /* Shading (scalar) --- this is way too much work and should be rewritten to be smarter in special cases */ for (int idx=0; idx<4; ++idx) { if (EXPECT_NOT_TAKEN(its4.t.f[idx] == std::numeric_limits<float>::infinity())) { /* Don't trace a secondary ray */ secItv4.maxt.f[idx] = 0; emitted[idx] = m_scene->LeBackground(Ray( Point(primRay4.o[0].f[idx], primRay4.o[1].f[idx], primRay4.o[2].f[idx]), Vector(primRay4.d[0].f[idx], primRay4.d[1].f[idx], primRay4.d[2].f[idx]), 0.0f )) * m_backgroundScale; memset(&direct[idx], 0, sizeof(Spectrum)); continue; } const unsigned int primIndex = its4.primIndex.i[idx]; const Shape *shape = (*m_shapes)[its4.shapeIndex.i[idx]]; const BSDF *bsdf = shape->getBSDF(); if (EXPECT_NOT_TAKEN(!bsdf)) { memset(&emitted[idx], 0, sizeof(Spectrum)); memset(&direct[idx], 0, sizeof(Spectrum)); continue; } if (EXPECT_TAKEN(primIndex != KNoTriangleFlag)) { const TriMesh *mesh = static_cast<const TriMesh *>(shape); const Triangle &t = mesh->getTriangles()[primIndex]; const Normal *normals = mesh->getVertexNormals(); const Point2 *texcoords = mesh->getVertexTexcoords(); const Spectrum *colors = mesh->getVertexColors(); const TangentSpace * tangents = mesh->getVertexTangents(); const Float beta = its4.u.f[idx], gamma = its4.v.f[idx], alpha = 1.0f - beta - gamma; const uint32_t idx0 = t.idx[0], idx1 = t.idx[1], idx2 = t.idx[2]; if (EXPECT_TAKEN(normals)) { const Normal &n0 = normals[idx0], &n1 = normals[idx1], &n2 = normals[idx2]; its.shFrame.n = normalize(n0 * alpha + n1 * beta + n2 * gamma); } else { const Point *positions = mesh->getVertexPositions(); const Point &p0 = positions[idx0], &p1 = positions[idx1], &p2 = positions[idx2]; Vector sideA = p1 - p0, sideB = p2 - p0; Vector n = cross(sideA, sideB); Float nLengthSqr = n.lengthSquared(); if (nLengthSqr != 0) n /= std::sqrt(nLengthSqr); its.shFrame.n = Normal(n); } if (EXPECT_TAKEN(texcoords)) { const Point2 &t0 = texcoords[idx0], &t1 = texcoords[idx1], &t2 = texcoords[idx2]; its.uv = t0 * alpha + t1 * beta + t2 * gamma; } else { its.uv = Point2(0.0f); } if (EXPECT_NOT_TAKEN(colors)) { const Spectrum &c0 = colors[idx0], &c1 = colors[idx1], &c2 = colors[idx2]; its.color = c0 * alpha + c1 * beta + c2 * gamma; } if (EXPECT_NOT_TAKEN(tangents)) { const TangentSpace &t0 = tangents[idx0], &t1 = tangents[idx1], &t2 = tangents[idx2]; its.dpdu = t0.dpdu * alpha + t1.dpdu * beta + t2.dpdu * gamma; its.dpdv = t0.dpdv * alpha + t1.dpdv * beta + t2.dpdv * gamma; } } else { Ray ray( Point(primRay4.o[0].f[idx], primRay4.o[1].f[idx], primRay4.o[2].f[idx]), Vector(primRay4.d[0].f[idx], primRay4.d[1].f[idx], primRay4.d[2].f[idx]), 0.0f ); its.t = its4.t.f[idx]; shape->fillIntersectionRecord(ray, temp + idx * MTS_KD_INTERSECTION_TEMP + 8, its); bsdf = its.shape->getBSDF(); } wo.x = nSecD[0].f[idx]; wo.y = nSecD[1].f[idx]; wo.z = nSecD[2].f[idx]; if (EXPECT_TAKEN(!shape->isLuminaire())) { memset(&emitted[idx], 0, sizeof(Spectrum)); } else { Vector d(-primRay4.d[0].f[idx], -primRay4.d[1].f[idx], -primRay4.d[2].f[idx]); emitted[idx] = shape->getLuminaire()->Le(ShapeSamplingRecord(its.p, its.shFrame.n), d); } if (EXPECT_TAKEN(bsdf->getType() == BSDF::EDiffuseReflection && diffuseVPL)) { /* Fast path */ direct[idx] = (bsdf->getDiffuseReflectance(its) * vplWeight) * (std::max((Float) 0.0f, dot(wo, its.shFrame.n)) * (vplOnSurface ? (std::max(cosThetaLight.f[idx], (Float) 0.0f) * INV_PI) : INV_PI) * invLengthSquared.f[idx]); } else { wi.x = -primRay4.d[0].f[idx]; wi.y = -primRay4.d[1].f[idx]; wi.z = -primRay4.d[2].f[idx]; its.p.x = secRay4.o[0].f[idx]; its.p.y = secRay4.o[1].f[idx]; its.p.z = secRay4.o[2].f[idx]; if (EXPECT_NOT_TAKEN(bsdf->getType() & BSDF::EAnisotropic)) { its.shFrame.s = normalize(its.dpdu - its.shFrame.n * dot(its.shFrame.n, its.dpdu)); its.shFrame.t = cross(its.shFrame.n, its.shFrame.s); } else { coordinateSystem(its.shFrame.n, its.shFrame.s, its.shFrame.t); } const Float ctLight = cosThetaLight.f[idx]; wi = normalize(wi); its.wi = its.toLocal(wi); wo = its.toLocal(wo); if (!diffuseVPL) { if (m_vpl.type == ESurfaceVPL) { BSDFQueryRecord bRec(m_vpl.its, m_vpl.its.toLocal(wi)); bRec.quantity = EImportance; vplWeight = m_vpl.its.shape->getBSDF()->eval(bRec) * m_vpl.P; } else { EmissionRecord eRec(m_vpl.luminaire, ShapeSamplingRecord(m_vpl.its.p, m_vpl.its.shFrame.n), wi); eRec.type = EmissionRecord::EPreview; vplWeight = m_vpl.luminaire->evalDirection(eRec) * m_vpl.P; } } if (EXPECT_TAKEN(ctLight >= 0)) { direct[idx] = (bsdf->eval(BSDFQueryRecord(its, wo)) * vplWeight * ((vplOnSurface ? std::max(ctLight, (Float) 0.0f) : 1.0f) * invLengthSquared.f[idx])); } else { memset(&direct[idx], 0, sizeof(Spectrum)); } } ++numRays; } /* Shoot the secondary rays */ const int secSignsX = _mm_movemask_ps(secRay4.d[0].ps); const int secSignsY = _mm_movemask_ps(secRay4.d[1].ps); const int secSignsZ = _mm_movemask_ps(secRay4.d[2].ps); const bool secCoherent = (secSignsX == 0 || secSignsX == 0xF) && (secSignsY == 0 || secSignsY == 0xF) && (secSignsZ == 0 || secSignsZ == 0xF); /* Shoot the secondary rays */ secIts4.t = SSEConstants::p_inf; if (EXPECT_TAKEN(secCoherent)) { secRay4.signs[0][0] = secSignsX ? 1 : 0; secRay4.signs[1][0] = secSignsY ? 1 : 0; secRay4.signs[2][0] = secSignsZ ? 1 : 0; m_kdtree->rayIntersectPacket(secRay4, secItv4, secIts4, temp); } else { m_kdtree->rayIntersectPacketIncoherent(secRay4, secItv4, secIts4, temp); } for (int idx=0; idx<4; ++idx) { if (EXPECT_TAKEN(secIts4.t.f[idx] == std::numeric_limits<float>::infinity())) block->setPixel(pos+pixelOffset[idx], direct[idx]+emitted[idx]); else block->setPixel(pos+pixelOffset[idx], emitted[idx]); } } } block->setExtra(numRays); #else Log(EError, "Coherent raytracing support was not compiled into this binary!"); #endif }
void preprocess(const Scene *scene) { /* Create a sample generator for the preprocess step */ Sampler *sampler = static_cast<Sampler *>( NoriObjectFactory::createInstance("independent", PropertyList())); Emitter* distantsDisk = scene->getDistantEmitter(); if(distantsDisk != nullptr ) { float lngstDir = scene->getBoundingBox().getLongestDirection(); distantsDisk->setMaxRadius(lngstDir); } /* Allocate memory for the photon map */ m_photonMap = std::unique_ptr<PhotonMap>(new PhotonMap()); m_photonMap->reserve(m_photonCount); /* Estimate a default photon radius */ if (m_photonRadius == 0) m_photonRadius = scene->getBoundingBox().getExtents().norm() / 500.0f; int storedPhotons = 0; const std::vector<Emitter *> lights = scene->getEmitters(); int nLights = lights.size(); Color3f tp(1.0f, 1.0f, 1.0f); cout << "Starting to create "<< m_photonCount << " photons!" << endl; int percentDone= 0; int onePercent = int(floor(m_photonCount / 100.0)); // create the expected number of photons while(storedPhotons < m_photonCount) { //uniformly sample 1 light (assuming that we only have area lights) int var = int(std::min(sampler->next1D()*nLights, float(nLights) - 1.0f)); const areaLight* curLight = static_cast<const areaLight *> (lights[var]); //sample a photon Photon curPhoton; Vector3f unQuantDir(0.0f,0.0f,0.0f); curLight->samplePhoton(sampler, curPhoton, 1, nLights, unQuantDir); Color3f alpha = curPhoton.getPower(); Color3f tp(1.0f, 1.0f, 1.0f); //trace the photon Intersection its; Ray3f photonRay(curPhoton.getPosition(), unQuantDir); m_shootedRays++; if (scene->rayIntersect(photonRay, its)) { while(true) { const BSDF* curBSDF = its.mesh->getBSDF(); if (curBSDF->isDiffuse()) { //store the photon m_photonMap->push_back(Photon( its.p /* Position */, -photonRay.d /* Direction*/, tp * alpha /* Power */ )); storedPhotons++; } if(!(storedPhotons < m_photonCount)) break; BSDFQueryRecord query = BSDFQueryRecord(its.toLocal(-photonRay.d), Vector3f(0.0f), EMeasure::ESolidAngle); Color3f fi = curBSDF->sample(query, sampler->next2D()); if(fi.maxCoeff() == 0.0f) break; tp *= fi; Vector3f wo = its.toWorld(query.wo); photonRay = Ray3f(its.p, wo); //ray escapes the scene if (!scene->rayIntersect(photonRay, its)) break; //stop critirium russian roulette float q = tp.maxCoeff(); if(q < sampler->next1D()) break; tp /= q; } } if(onePercent != 0) { if(storedPhotons % onePercent == 0){ int percent = int(floor(storedPhotons / onePercent)); if(percent % 10 == 0 && percentDone != percent){ percentDone = percent; cout << percent << "%" << endl; } } } } /* Build the photon map */ m_photonMap->build(); }
Color3f Li(const Scene *scene, Sampler *sampler, const Ray3f &ray) const { /* Find the surface that is visible in the requested direction */ Intersection its; //check if the ray intersects the scene if (!scene->rayIntersect(ray, its)) { return Color3f(0.0f); } Color3f tp(1.0f, 1.0f, 1.0f); Color3f L(0.0f, 0.0f, 0.0f); Ray3f pathRay(ray.o, ray.d); while(true) { //get the radiance of hitten object if (its.mesh->isEmitter() ) { const Emitter* areaLightEM = its.mesh->getEmitter(); const areaLight* aEM = static_cast<const areaLight *> (areaLightEM); L += tp * aEM->sampleL(-pathRay.d, its.shFrame.n, its); } //get the asigned BSDF const BSDF* curBSDF = its.mesh->getBSDF(); //transform to the local frame BSDFQueryRecord query = BSDFQueryRecord(its.toLocal(-pathRay.d), Vector3f(0.0f), EMeasure::ESolidAngle); //Normal3f n = its.shFrame.n; if(curBSDF->isDiffuse()) { std::vector<uint32_t> results; m_photonMap->search(its.p, m_photonRadius, results); Color3f Li(0.0f, 0.0f, 0.0f); int k = results.size(); //cout << k << endl; if(k > 0) { //cout << results.size() << " Photons found!" << endl; //get the power from all photons //for (uint32_t i : results) //const Photon &photonk = (*m_photonMap)[k-1]; Color3f Lindir(0.0f, 0.0f, 0.0f); for (int i = 0; i < k; ++i) { const Photon &photon = (*m_photonMap)[results[i]]; Vector3f wi = its.toLocal(photon.getDirection()); Vector3f wo = its.toLocal(its.shFrame.n); BSDFQueryRecord dummy = BSDFQueryRecord(wi, wo, EMeasure::ESolidAngle); Color3f f = curBSDF->eval(dummy); Lindir += (tp * f) * photon.getPower() / (M_PI * m_photonRadius * m_photonRadius); } Li += Lindir; //cout << "Li = " << Li.toString() << endl; if(Li.maxCoeff() > 0.0f) L += Li / m_shootedRays; } break; } //sample the BRDF Color3f fi = curBSDF->sample(query, sampler->next2D()); //check for black brdf if(fi.maxCoeff() > 0.0f) { tp *= fi; } else { //stop // hit a black brdf break; } Vector3f wo = its.toWorld(query.wo); pathRay = Ray3f(its.p, wo); //ray escapes the scene if (!scene->rayIntersect(pathRay, its)) break; //stop critirium russian roulette float maxCoeff = tp.maxCoeff(); float q = std::min(0.99f, maxCoeff); if(q < sampler->next1D()) break; tp /= q; } return L; }
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::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; }
Color3f Li(const Scene *scene, Sampler *sampler, const Ray3f &ray) const { /* Find the surface that is visible in the requested direction */ Intersection its; if (!scene->rayIntersect(ray, its)) return Color3f(0.0f); //get the Normal at the intersection point Vector3f n = Vector3f(its.shFrame.n); //get the Number of lights from the scene const std::vector<Emitter *> lights = scene->getEmitters(); uint32_t nLights = lights.size(); //check for lights if(nLights > 0) { //get the asigned BSDF const BSDF* curBSDF = its.mesh->getBSDF(); if(curBSDF) { Color3f totalLight(0.0f); //uterated over all lights //std::cout << "start light comp" << std::endl; for (uint32_t var = 0; var < nLights; ++var) { VisibilityTester vis; Vector3f wi; float pdf; const Point2f ls; //sample the light Color3f Ld =lights[var]->sampleL(its.p, Epsilon, ls, &wi, &pdf, &vis); //check if the light is visible if(vis.Unoccluded(scene)) { //create a query for the brdf Vector3f wo = - ray.d; //calculate the abs value of n dot wi float costerm = n.dot(wi); //transform to the local frame wo = its.toLocal(wo); wi = its.toLocal(wi); const BSDFQueryRecord query = BSDFQueryRecord(wi, wo, EMeasure::ESolidAngle); //calculate the BSDF Color3f f = curBSDF->eval(query); //add the light up totalLight += (Ld * f * std::abs(costerm)); } } return totalLight; } } return Color3f(0.0f); }
Color3f Li(const Scene *scene, Sampler *sampler, const Ray3f &r) const { /* Find the surface that is visible in the requested direction */ Intersection its; Ray3f ray(r); if (!scene->rayIntersect(ray, its)) return Color3f(0.0f); Color3f radiance(0.0f); bool specularBounce = false; Color3f pathThroughput(1.0f); for ( int bounces = 0; ; ++bounces ) { const Luminaire* luminaire = its.mesh->getLuminaire(); if ((bounces == 0 || specularBounce) && luminaire != NULL) { Vector3f wo = (-ray.d).normalized(); Color3f emission = luminaire->le(its.p, its.shFrame.n, wo); radiance += pathThroughput*emission; } const Texture* texture = its.mesh->getTexture(); Color3f texel(1.0f); if ( texture ) { texel = texture->lookUp(its.uv.x(), its.uv.y()); } const BSDF* bsdf = its.mesh->getBSDF(); // sample illumination from lights, add to path contribution if (!bsdf->isSpecular()){ radiance += pathThroughput*UniformSampleAllLights(scene, ray, its, sampler, m_samplePolicy)*texel; } // sample bsdf to get new path direction BSDFQueryRecord bRec(its.toLocal((-ray.d)).normalized()); Color3f f = bsdf->sample(bRec, sampler->next2D() ); if (f.isZero() ) { // farther path no contribution break; } specularBounce = bsdf->isSpecular(); Vector3f d = its.toWorld(bRec.wo); f *= texel; pathThroughput *= f; ray = Ray3f(its.p, d ); // possibly termination if (bounces > kSampleDepth) { #if 0 float continueProbability = std::min( 0.5f, pathThroughput.y() ); if ( sampler->next1D() > continueProbability ) { break; } #else float continueProbability = std::max(f.x(), std::max(f.y(), f.z())); if ( sampler->next1D() > continueProbability ) { break; } #endif pathThroughput /= continueProbability; } if (bounces == m_maxDepth) { break; } // find next vertex of path if ( !scene->rayIntersect(ray, its) ) { break; } } return radiance; }