コード例 #1
0
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]);
}
コード例 #2
0
ファイル: direct_mats.cpp プロジェクト: valdersoul/NoriV2
    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;
    }
コード例 #3
0
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);
	}
}
コード例 #4
0
ファイル: bsdf.hpp プロジェクト: ennis/path-tracer
	virtual Vec sample(
		Intersection const &isect,
		float u1, float u2, 
		Vec& WiW, 
		float& pdfResult, 
		int &bxdfType) const 
	{
		pdfResult = 1.f;
		WiW = isect.toWorld(cosineSampleHemisphere(u1, u2));
		bxdfType = BxDF_DIFFUSE;
		return isect.texSample;
	}
コード例 #5
0
ファイル: bsdf.hpp プロジェクト: ennis/path-tracer
	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;
	}
コード例 #6
0
ファイル: bsdf.hpp プロジェクト: ennis/path-tracer
	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);
	}
コード例 #7
0
ファイル: vpl.cpp プロジェクト: blckshrk/IFT6042
size_t generateVPLs(const Scene *scene, Random *random,
		size_t offset, size_t count, int maxDepth, bool prune, std::deque<VPL> &vpls) {
	if (maxDepth <= 1)
		return 0;

	static Sampler *sampler = NULL;
	if (!sampler) {
		Properties props("halton");
		props.setInteger("scramble", 0);
		sampler = static_cast<Sampler *> (PluginManager::getInstance()->
			createObject(MTS_CLASS(Sampler), props));
		sampler->configure();
	}

	const Sensor *sensor = scene->getSensor();
	Float time = sensor->getShutterOpen()
		+ 0.5f * sensor->getShutterOpenTime();

	const Frame stdFrame(Vector(1,0,0), Vector(0,1,0), Vector(0,0,1));

	while (vpls.size() < count) {
		sampler->setSampleIndex(++offset);

		PositionSamplingRecord pRec(time);
		DirectionSamplingRecord dRec;
		Spectrum weight = scene->sampleEmitterPosition(pRec,
			sampler->next2D());

		size_t start = vpls.size();

		/* Sample an emitted particle */
		const Emitter *emitter = static_cast<const Emitter *>(pRec.object);

		if (!emitter->isEnvironmentEmitter() && emitter->needsDirectionSample()) {
			VPL lumVPL(EPointEmitterVPL, weight);
			lumVPL.its.p = pRec.p;
			lumVPL.its.shFrame = pRec.n.isZero() ? stdFrame : Frame(pRec.n);
			lumVPL.emitter = emitter;
			appendVPL(scene, random, lumVPL, prune, vpls);

			weight *= emitter->sampleDirection(dRec, pRec, sampler->next2D());
		} else {
			/* Hack to get the proper information for directional VPLs */
			DirectSamplingRecord diRec(
				scene->getKDTree()->getAABB().getCenter(), pRec.time);

			Spectrum weight2 = emitter->sampleDirect(diRec, sampler->next2D())
				/ scene->pdfEmitterDiscrete(emitter);

			if (weight2.isZero())
				continue;

			VPL lumVPL(EDirectionalEmitterVPL, weight2);
			lumVPL.its.p = Point(0.0);
			lumVPL.its.shFrame = Frame(-diRec.d);
			lumVPL.emitter = emitter;
			appendVPL(scene, random, lumVPL, false, vpls);
			dRec.d = -diRec.d;

			Point2 offset = Warp::squareToUniformDiskConcentric(sampler->next2D());
			Vector perpOffset = Frame(diRec.d).toWorld(Vector(offset.x, offset.y, 0));
			BSphere geoBSphere = scene->getKDTree()->getAABB().getBSphere();
			pRec.p = geoBSphere.center + (perpOffset - dRec.d) * geoBSphere.radius;
			weight = weight2 * M_PI * geoBSphere.radius * geoBSphere.radius;
		}

		int depth = 2;
		Ray ray(pRec.p, dRec.d, time);
		Intersection its;

		while (!weight.isZero() && (depth < maxDepth || maxDepth == -1)) {
			if (!scene->rayIntersect(ray, its))
				break;

			const BSDF *bsdf = its.getBSDF();
			BSDFSamplingRecord bRec(its, sampler, EImportance);
			Spectrum bsdfVal = bsdf->sample(bRec, sampler->next2D());
			if (bsdfVal.isZero())
				break;

			/* Assuming that BSDF importance sampling is perfect,
				the following should equal the maximum albedo
				over all spectral samples */
			Float approxAlbedo = std::min((Float) 0.95f, bsdfVal.max());
			if (sampler->next1D() > approxAlbedo)
				break;
			else
				weight /= approxAlbedo;

			VPL vpl(ESurfaceVPL, weight);
			vpl.its = its;

			if (BSDF::getMeasure(bRec.sampledType) == ESolidAngle)
				appendVPL(scene, random, vpl, prune, vpls);

			weight *= bsdfVal;

			Vector wi = -ray.d, wo = its.toWorld(bRec.wo);
			ray = Ray(its.p, wo, 0.0f);

			/* 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)
				break;

			/* Disabled for now -- this increases VPL weights
			   and accuracy is not really a big requirement */
			#if 0
				/* Adjoint BSDF for shading normals -- [Veach, p. 155] */
				weight *= std::abs(
					(Frame::cosTheta(bRec.wi) * woDotGeoN)/
					(Frame::cosTheta(bRec.wo) * wiDotGeoN));
			#endif

			++depth;
		}

		size_t end = vpls.size();
		for (size_t i=start; i<end; ++i)
			vpls[i].emitterScale = 1.0f / (end - start);
	}

	return offset;
}
コード例 #8
0
ファイル: path_mis.cpp プロジェクト: valdersoul/NoriV2
    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;

    }
コード例 #9
0
ファイル: particleproc.cpp プロジェクト: blckshrk/IFT6042
void ParticleTracer::process(const WorkUnit *workUnit, WorkResult *workResult,
		const bool &stop) {
	const RangeWorkUnit *range = static_cast<const RangeWorkUnit *>(workUnit);
	MediumSamplingRecord mRec;
	Intersection its;
	ref<Sensor> sensor    = m_scene->getSensor();
	bool needsTimeSample  = sensor->needsTimeSample();
	PositionSamplingRecord pRec(sensor->getShutterOpen()
		+ 0.5f * sensor->getShutterOpenTime());
	Ray ray;

	m_sampler->generate(Point2i(0));

	for (size_t index = range->getRangeStart(); index <= range->getRangeEnd() && !stop; ++index) {
		m_sampler->setSampleIndex(index);

		/* Sample an emission */
		if (needsTimeSample)
			pRec.time = sensor->sampleTime(m_sampler->next1D());

		const Emitter *emitter = NULL;
		const Medium *medium;

		Spectrum power;
		Ray ray;

		if (m_emissionEvents) {
			/* Sample the position and direction component separately to
			   generate emission events */
			power = m_scene->sampleEmitterPosition(pRec, m_sampler->next2D());
			emitter = static_cast<const Emitter *>(pRec.object);
			medium = emitter->getMedium();

			/* Forward the sampling event to the attached handler */
			handleEmission(pRec, medium, power);

			DirectionSamplingRecord dRec;
			power *= emitter->sampleDirection(dRec, pRec,
					emitter->needsDirectionSample() ? m_sampler->next2D() : Point2(0.5f));
			ray.setTime(pRec.time);
			ray.setOrigin(pRec.p);
			ray.setDirection(dRec.d);
		} else {
			/* Sample both components together, which is potentially
			   faster / uses a better sampling strategy */

			power = m_scene->sampleEmitterRay(ray, emitter,
				m_sampler->next2D(), m_sampler->next2D(), pRec.time);
			medium = emitter->getMedium();
			handleNewParticle();
		}

		int depth = 1, nullInteractions = 0;
		bool delta = false;

		Spectrum throughput(1.0f); // unitless path throughput (used for russian roulette)
		while (!throughput.isZero() && (depth <= m_maxDepth || m_maxDepth < 0)) {
			m_scene->rayIntersectAll(ray, its);

            /* ==================================================================== */
            /*                 Radiative Transfer Equation sampling                 */
            /* ==================================================================== */
			if (medium && medium->sampleDistance(Ray(ray, 0, its.t), mRec, m_sampler)) {
				/* Sample the integral
				  \int_x^y tau(x, x') [ \sigma_s \int_{S^2} \rho(\omega,\omega') L(x,\omega') d\omega' ] dx'
				*/

				throughput *= mRec.sigmaS * mRec.transmittance / mRec.pdfSuccess;

				/* Forward the medium scattering event to the attached handler */
				handleMediumInteraction(depth, nullInteractions,
						delta, mRec, medium, -ray.d, throughput*power);

				PhaseFunctionSamplingRecord pRec(mRec, -ray.d, EImportance);

				throughput *= medium->getPhaseFunction()->sample(pRec, m_sampler);
				delta = false;

				ray = Ray(mRec.p, pRec.wo, ray.time);
				ray.mint = 0;
			} else if (its.t == std::numeric_limits<Float>::infinity()) {
				/* There is no surface in this direction */
				break;
			} else {
				/* Sample
					tau(x, y) (Surface integral). This happens with probability mRec.pdfFailure
					Account for this and multiply by the proper per-color-channel transmittance.
				*/
				if (medium)
					throughput *= mRec.transmittance / mRec.pdfFailure;

				const BSDF *bsdf = its.getBSDF();

				/* Forward the surface scattering event to the attached handler */
				handleSurfaceInteraction(depth, nullInteractions, delta, its, medium, throughput*power);

				BSDFSamplingRecord bRec(its, m_sampler, EImportance);
				Spectrum bsdfWeight = bsdf->sample(bRec, m_sampler->next2D());
				if (bsdfWeight.isZero())
					break;

				/* Prevent light leaks due to the use of shading normals -- [Veach, p. 158] */
				Vector wi = -ray.d, wo = its.toWorld(bRec.wo);
				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)
					break;

				/* Keep track of the weight, medium and relative
				   refractive index along the path */
				throughput *= bsdfWeight;
				if (its.isMediumTransition())
					medium = its.getTargetMedium(woDotGeoN);

				if (bRec.sampledType & BSDF::ENull)
					++nullInteractions;
				else
					delta = bRec.sampledType & BSDF::EDelta;

#if 0
				/* This is somewhat unfortunate: for accuracy, we'd really want the
				   correction factor below to match the path tracing interpretation
				   of a scene with shading normals. However, this factor can become
				   extremely large, which adds unacceptable variance to output
				   renderings.

				   So for now, it is disabled. The adjoint particle tracer and the
				   photon mapping variants still use this factor for the last
				   bounce -- just not for the intermediate ones, which introduces
				   a small (though in practice not noticeable) amount of error. This
				   is also what the implementation of SPPM by Toshiya Hachisuka does.

				   Ultimately, we'll need better adjoint BSDF sampling strategies
				   that incorporate these extra terms */

				/* Adjoint BSDF for shading normals -- [Veach, p. 155] */
				throughput *= std::abs(
					(Frame::cosTheta(bRec.wi) * woDotGeoN)/
					(Frame::cosTheta(bRec.wo) * wiDotGeoN));
#endif

				ray.setOrigin(its.p);
				ray.setDirection(wo);
				ray.mint = Epsilon;
			}

			if (depth++ >= m_rrDepth) {
				/* Russian roulette: try to keep path weights equal to one,
				   Stop with at least some probability to avoid
				   getting stuck (e.g. due to total internal reflection) */

				Float q = std::min(throughput.max(), (Float) 0.95f);
				if (m_sampler->next1D() >= q)
					break;
				throughput /= q;
			}
		}
	}
}
コード例 #10
0
ファイル: MisPathTracer.cpp プロジェクト: FallenShard/vesper
    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;
    }
コード例 #11
0
ファイル: photonmapper.cpp プロジェクト: valdersoul/NoriV2
    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();
    }
コード例 #12
0
ファイル: photonmapper.cpp プロジェクト: valdersoul/NoriV2
    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;
    }
コード例 #13
0
ファイル: path.cpp プロジェクト: shen-yang/nori
	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;
	}