Example #1
0
	Spectrum Li(const RayDifferential &r, RadianceQueryRecord &rRec) const {
		/* Some aliases and local variables */
		const Scene *scene = rRec.scene;
		Intersection &its = rRec.its;
		RayDifferential ray(r);
		Spectrum Li(0.0f);
		bool scattered = false;

		/* Perform the first ray intersection (or ignore if the
		   intersection has already been provided). */
		rRec.rayIntersect(ray);
		ray.mint = Epsilon;

		Spectrum throughput(1.0f);
		Float eta = 1.0f;

		while (rRec.depth <= m_maxDepth || m_maxDepth < 0) {
			if (!its.isValid()) {
				/* If no intersection could be found, potentially return
				   radiance from a environment luminaire if it exists */
				if ((rRec.type & RadianceQueryRecord::EEmittedRadiance)
					&& (!m_hideEmitters || scattered))
					Li += throughput * scene->evalEnvironment(ray);
				break;
			}

			const BSDF *bsdf = its.getBSDF(ray);

			/* Possibly include emitted radiance if requested */
			if (its.isEmitter() && (rRec.type & RadianceQueryRecord::EEmittedRadiance)
				&& (!m_hideEmitters || scattered))
				Li += throughput * its.Le(-ray.d);

			/* Include radiance from a subsurface scattering model if requested */
			if (its.hasSubsurface() && (rRec.type & RadianceQueryRecord::ESubsurfaceRadiance))
				Li += throughput * its.LoSub(scene, rRec.sampler, -ray.d, rRec.depth);

			if ((rRec.depth >= m_maxDepth && m_maxDepth > 0)
				|| (m_strictNormals && dot(ray.d, its.geoFrame.n)
					* Frame::cosTheta(its.wi) >= 0)) {

				/* Only continue if:
				   1. The current path length is below the specifed maximum
				   2. If 'strictNormals'=true, when the geometric and shading
				      normals classify the incident direction to the same side */
				break;
			}

			/* ==================================================================== */
			/*                     Direct illumination sampling                     */
			/* ==================================================================== */

			/* Estimate the direct illumination if this is requested */
			DirectSamplingRecord dRec(its);

			if (rRec.type & RadianceQueryRecord::EDirectSurfaceRadiance &&
				(bsdf->getType() & BSDF::ESmooth)) {
				Spectrum value = scene->sampleEmitterDirect(dRec, rRec.nextSample2D());
				if (!value.isZero()) {
					const Emitter *emitter = static_cast<const Emitter *>(dRec.object);

					/* Allocate a record for querying the BSDF */
					BSDFSamplingRecord bRec(its, its.toLocal(dRec.d), ERadiance);

					/* Evaluate BSDF * cos(theta) */
					const Spectrum bsdfVal = bsdf->eval(bRec);

					/* Prevent light leaks due to the use of shading normals */
					if (!bsdfVal.isZero() && (!m_strictNormals
							|| dot(its.geoFrame.n, dRec.d) * Frame::cosTheta(bRec.wo) > 0)) {

						/* Calculate prob. of having generated that direction
						   using BSDF sampling */
						Float bsdfPdf = (emitter->isOnSurface() && dRec.measure == ESolidAngle)
							? bsdf->pdf(bRec) : 0;

						/* Weight using the power heuristic */
						Float weight = miWeight(dRec.pdf, bsdfPdf);
						Li += throughput * value * bsdfVal * weight;
					}
				}
			}

			/* ==================================================================== */
			/*                            BSDF sampling                             */
			/* ==================================================================== */

			/* Sample BSDF * cos(theta) */
			Float bsdfPdf;
			BSDFSamplingRecord bRec(its, rRec.sampler, ERadiance);
			Spectrum bsdfWeight = bsdf->sample(bRec, bsdfPdf, rRec.nextSample2D());
			if (bsdfWeight.isZero())
				break;

			scattered |= bRec.sampledType != BSDF::ENull;

			/* Prevent light leaks due to the use of shading normals */
			const Vector wo = its.toWorld(bRec.wo);
			Float woDotGeoN = dot(its.geoFrame.n, wo);
			if (m_strictNormals && woDotGeoN * Frame::cosTheta(bRec.wo) <= 0)
				break;

			bool hitEmitter = false;
			Spectrum value;

			/* Trace a ray in this direction */
			ray = Ray(its.p, wo, ray.time);
			if (scene->rayIntersect(ray, its)) {
				/* Intersected something - check if it was a luminaire */
				if (its.isEmitter()) {
					value = its.Le(-ray.d);
					dRec.setQuery(ray, its);
					hitEmitter = true;
				}
			} else {
				/* Intersected nothing -- perhaps there is an environment map? */
				const Emitter *env = scene->getEnvironmentEmitter();

				if (env) {
					if (m_hideEmitters && !scattered)
						break;

					value = env->evalEnvironment(ray);
					if (!env->fillDirectSamplingRecord(dRec, ray))
						break;
					hitEmitter = true;
				} else {
					break;
				}
			}

			/* Keep track of the throughput and relative
			   refractive index along the path */
			throughput *= bsdfWeight;
			eta *= bRec.eta;

			/* If a luminaire was hit, estimate the local illumination and
			   weight using the power heuristic */
			if (hitEmitter &&
				(rRec.type & RadianceQueryRecord::EDirectSurfaceRadiance)) {
				/* Compute the prob. of generating that direction using the
				   implemented direct illumination sampling technique */
				const Float lumPdf = (!(bRec.sampledType & BSDF::EDelta)) ?
					scene->pdfEmitterDirect(dRec) : 0;
				Li += throughput * value * miWeight(bsdfPdf, lumPdf);
			}

			/* ==================================================================== */
			/*                         Indirect illumination                        */
			/* ==================================================================== */

			/* Set the recursive query type. Stop if no surface was hit by the
			   BSDF sample or if indirect illumination was not requested */
			if (!its.isValid() || !(rRec.type & RadianceQueryRecord::EIndirectSurfaceRadiance))
				break;
			rRec.type = RadianceQueryRecord::ERadianceNoEmission;

			if (rRec.depth++ >= m_rrDepth) {
				/* Russian roulette: try to keep path weights equal to one,
				   while accounting for the solid angle compression at refractive
				   index boundaries. Stop with at least some probability to avoid
				   getting stuck (e.g. due to total internal reflection) */

				Float q = std::min(throughput.max() * eta * eta, (Float) 0.95f);
				if (rRec.nextSample1D() >= q)
					break;
				throughput /= q;
			}
		}

		/* Store statistics */
		avgPathLength.incrementBase();
		avgPathLength += rRec.depth;

		return Li;
	}
Example #2
0
void Fluence2ParticleTracer::process(const WorkUnit *workUnit, WorkResult *workResult,
    const bool &stop)
{
    const RangeWorkUnit *range = static_cast<const RangeWorkUnit *>(workUnit);
    m_result = static_cast<Fluence2WorkResult *>(workResult);
    m_result->clear();
    m_result->setRangeWorkUnit(range);

    /**
     * The following implementation is modified from ParticleTracer::process()
     */

    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 Medium *medium;

        Spectrum power;
        Ray ray;

        if ( m_mode == EMITTER_AREA )
        {
            const Emitter *emitter = NULL;
            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();
            }
        }
        else
        {
            Assert(!m_emissionEvents);
            Assert(m_scene->getMedia().size() == 1);

            Point p;
#ifdef VPL_FAST_MODE
            p = m_emitterAABB.min;
            p.x += m_emitterExtents.x*m_sampler->next1D();
            p.y += m_emitterExtents.y*m_sampler->next1D();
            p.z += m_emitterExtents.z*m_sampler->next1D();
#else
            bool done = false;
            for ( int i = 0; i < 500; ++i )
            {
                p = m_emitterAABB.min;
                p.x += m_emitterExtents.x*m_sampler->next1D();
                p.y += m_emitterExtents.y*m_sampler->next1D();
                p.z += m_emitterExtents.z*m_sampler->next1D();
                if ( m_densityVol->lookupFloat(p) > 0.1f )
                {
                    done = true;
                    break;
                }
            }
            if ( !done )
            {
                Log(EWarn, "Failed to locate a non-empty voxel in %s", m_emitterAABB.toString().c_str());
                continue;
            }
#endif

            ray.setTime(0.0f);
            ray.setOrigin(p);
            ray.setDirection(warp::squareToUniformSphere(m_sampler->next2D()));

            power = Spectrum(1.0f);
            medium = m_scene->getMedia()[0];
        }

        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;

                mRec.hasExtraInfo = true;
                mRec.extra = Point(ray.d);

                /* 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)
                {
                    Spectrum tmp = mRec.transmittance / mRec.pdfFailure;
                    //if ( std::abs(tmp.average() - 1.0f) > Epsilon )
                    //    Log(EWarn, "%s", tmp.toString().c_str());
                    throughput *= tmp;
                }

                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;
            }
        }
    }

    /**
     * End of ParticleTracer::process()
     */

    m_result = NULL;
}
void PSSMLTRenderer::SampleAndEvaluatePath( const std::shared_ptr<Sampler>& sampler, PathSampleRecord& record )
{
	Ray ray;
	Intersection isect;
	Vec3d throughput(1.0);
	int depth = 0;
	Vec3d L;

	// Raster position
	Vec2d rasterPos(sampler->Next(), sampler->Next());
	
	record.pixelPos.x = (int)(rasterPos.x * config->width);
	record.pixelPos.y = (int)(rasterPos.y * config->height);

	// Generate ray
	double _;
	scene->Camera()->SampleAndEvaluate(rasterPos, ray, _);

	// ----------------------------------------------------------------------

	// Initial intersection
	if (!scene->Intersect(ray, isect))
	{
		record.L = L;
		record.I = RenderUtils::Luminance(L);
		return;
	}

	if (isect.primitive->Light() != nullptr)
	{
		auto& light = isect.primitive->Light();
		L += light->Evaluate(-ray.d, isect.gn);
	}

	// ----------------------------------------------------------------------

	while (true)
	{
		auto& bsdf = isect.primitive->Bsdf();

		// Explicit (direct) light sampling
		// We do not handle the light path with length 1 (EL path)

		if (isect.primitive != nullptr)
		{
			auto positionSample = Vec2d(sampler->Next(), sampler->Next());

			// Sample a light
			std::shared_ptr<AreaLight> light;
			double lightSelectionPdf;
			scene->SampleLight(positionSample.x, light, lightSelectionPdf);

			// Sample a position on the light
			AreaLight::SampleRecord lightSampleRec;
			lightSampleRec.positionSample = positionSample;
			light->SamplePosition(lightSampleRec);

			// Check visibility
			Ray shadowRay;
			auto d = lightSampleRec.p - isect.p;
			shadowRay.d = Math::Normalize(d);
			shadowRay.o = isect.p;
			shadowRay.minT = isect.rayEpsilon;
			shadowRay.maxT = Math::Length(d) * (1.0 - Eps);

			Intersection shadowIsect;

			if (!scene->Intersect(shadowRay, shadowIsect))
			{
				// Evaluate Le (with cosine term)
				auto Le = light->EvaluateCos(-shadowRay.d, lightSampleRec.n) / lightSelectionPdf;

				// Convert to Le / p_\sigma
				auto dist2 = Math::Length2(d);
				Le /= Vec3d(dist2);

				// Prepare for BSDF evaluation
				BSDFRecord bsdfRec;
				bsdfRec.type = BSDFType::All;
				bsdfRec.adjoint = false;
				bsdfRec.wi = isect.worldToShading * -ray.d;
				bsdfRec.wo = isect.worldToShading * shadowRay.d;

				// Evaluate BSDF (with cosine term)
				auto f = bsdf->Evaluate(bsdfRec, isect);

				if (f != Vec3d())
				{
					// Calculate PDF for light and BSDF (in solid angle measure)
					double dDotN = Math::Dot(-shadowRay.d, lightSampleRec.n);
					double lightPdf =
						dDotN <= 0
							? 0.0
							: lightSelectionPdf *		// Selection
								lightSampleRec.pdf *	// p_A(x_n)
								dist2 / dDotN;			// Convert to p_\sigma(x_{n-1}\to x_n)

					if (lightPdf > 0)
					{
						// It should be positive
						double bsdfPdf = bsdf->Pdf(bsdfRec);

						// MIS weight (for direct light sampling)
						double w = lightPdf / (lightPdf + bsdfPdf);

						// Record color
						L += throughput * f * Le * w;
					}
				}
			}
		}

		// ----------------------------------------------------------------------

		// BSDF sampling

		BSDFSample bsdfSample;
		bsdfSample.u = Vec2d(sampler->Next(), sampler->Next());
		bsdfSample.uComponent = sampler->Next();

		BSDFRecord bsdfRec;
		bsdfRec.type = BSDFType::All;
		bsdfRec.adjoint = false;
		bsdfRec.wi = isect.worldToShading * -ray.d;

		double bsdfPdf;
		auto f = bsdf->SampleAndEvaluate(bsdfRec, bsdfSample, bsdfPdf, isect);

		if (bsdfPdf == 0.0 || f == Vec3d())
		{
			record.L = L;
			record.I = RenderUtils::Luminance(L);
			return;
		}

		// Convert to world coordinates
		bsdfRec.wo = isect.shadingToWorld * bsdfRec.wo;

		// Update throughput
		throughput *= f;

		// Setup next ray
		ray.d = bsdfRec.wo;
		ray.o = isect.p;
		ray.minT = isect.rayEpsilon;
		ray.maxT = Inf;

		// ----------------------------------------------------------------------

		// Check intersection
		if (!scene->Intersect(ray, isect))
		{
			record.L = L;
			record.I = RenderUtils::Luminance(L);
			return;
		}

		auto light = isect.primitive->Light();

		if (light != nullptr)
		{
			// Intersected with L

			// Evaluate Le
			auto Le = light->Evaluate(-ray.d, isect.gn);

			if ((bsdfRec.sampledType & BSDFType::Delta) != 0)
			{
				// Disable MIS if last intersection is specular interaction
				L += throughput * Le;
			}
			else
			{
				// Calculate PDF for light (in solid angle measure)
				double dist2 = Math::Length2(ray.o - isect.p);
				double dDotN = Math::Dot(-ray.d, isect.gn);
				double lightPdf =
					dDotN <= 0
						? 0.0
						: scene->LightSelectionPdf() *	// Selection
							light->PdfPosition() *		// p_A(x_n)
							dist2 / dDotN;				// Convert to p_\sigma(x_{n-1}\to x_n)

				// MIS weight (for BSDF sampling)
				double w = bsdfPdf / (lightPdf + bsdfPdf);

				// Record color
				L += throughput * Le * w;
			}
		}

		// ----------------------------------------------------------------------

		if (++depth >= config->rrDepth)
		{
			// Russian roulette for path termination
			double p = Math::Min(0.5, RenderUtils::Luminance(throughput));

			if (sampler->Next() > p)
			{
				break;
			}

			throughput /= Vec3d(p);
		}
	}

	record.L = L;
	record.I = RenderUtils::Luminance(L);
}
	Spectrum Li(const RayDifferential &r, RadianceQueryRecord &rRec) const {
		/* Some aliases and local variables */
		const Scene *scene = rRec.scene;
		Intersection &its = rRec.its;
		MediumSamplingRecord mRec;
		RayDifferential ray(r);
		Spectrum Li(0.0f);
		bool nullChain = true, scattered = false;
		Float eta = 1.0f;

		/* Perform the first ray intersection (or ignore if the
		   intersection has already been provided). */
		rRec.rayIntersect(ray);
		Spectrum throughput(1.0f);

		if (m_maxDepth == 1)
			rRec.type &= RadianceQueryRecord::EEmittedRadiance;

		/**
		 * Note: the logic regarding maximum path depth may appear a bit
		 * strange. This is necessary to get this integrator's output to
		 * exactly match the output of other integrators under all settings
		 * of this parameter.
		 */
		while (rRec.depth <= m_maxDepth || m_maxDepth < 0) {
			/* ==================================================================== */
			/*                 Radiative Transfer Equation sampling                 */
			/* ==================================================================== */
			if (rRec.medium && rRec.medium->sampleDistance(Ray(ray, 0, its.t), mRec, rRec.sampler)) {
				/* Sample the integral
				   \int_x^y tau(x, x') [ \sigma_s \int_{S^2} \rho(\omega,\omega') L(x,\omega') d\omega' ] dx'
				*/
				const PhaseFunction *phase = rRec.medium->getPhaseFunction();

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

				/* ==================================================================== */
				/*                     Direct illumination sampling                     */
				/* ==================================================================== */

				/* Estimate the single scattering component if this is requested */
				if (rRec.type & RadianceQueryRecord::EDirectMediumRadiance) {
					DirectSamplingRecord dRec(mRec.p, mRec.time);
					int maxInteractions = m_maxDepth - rRec.depth - 1;

					Spectrum value = scene->sampleAttenuatedEmitterDirect(
							dRec, rRec.medium, maxInteractions,
							rRec.nextSample2D(), rRec.sampler);

					if (!value.isZero())
						Li += throughput * value * phase->eval(
								PhaseFunctionSamplingRecord(mRec, -ray.d, dRec.d));
				}

				/* Stop if multiple scattering was not requested, or if the path gets too long */
				if ((rRec.depth + 1 >= m_maxDepth && m_maxDepth > 0) ||
					!(rRec.type & RadianceQueryRecord::EIndirectMediumRadiance))
					break;

				/* ==================================================================== */
				/*             Phase function sampling / Multiple scattering            */
				/* ==================================================================== */

				PhaseFunctionSamplingRecord pRec(mRec, -ray.d);
				Float phaseVal = phase->sample(pRec, rRec.sampler);
				if (phaseVal == 0)
					break;
				throughput *= phaseVal;

				/* Trace a ray in this direction */
				ray = Ray(mRec.p, pRec.wo, ray.time);
				ray.mint = 0;
				scene->rayIntersect(ray, its);
				nullChain = false;
				scattered = true;
			} 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 (rRec.medium)
					throughput *= mRec.transmittance / mRec.pdfFailure;

				if (!its.isValid()) {
					/* If no intersection could be found, possibly return
					   attenuated radiance from a background luminaire */
					if ((rRec.type & RadianceQueryRecord::EEmittedRadiance)
						&& (!m_hideEmitters || scattered)) {
						Spectrum value = throughput * scene->evalEnvironment(ray);
						if (rRec.medium)
							value *= rRec.medium->evalTransmittance(ray);
						Li += value;
					}
					break;
				}

				/* Possibly include emitted radiance if requested */
				if (its.isEmitter() && (rRec.type & RadianceQueryRecord::EEmittedRadiance)
					&& (!m_hideEmitters || scattered))
					Li += throughput * its.Le(-ray.d);

				/* Include radiance from a subsurface integrator if requested */
				if (its.hasSubsurface() && (rRec.type & RadianceQueryRecord::ESubsurfaceRadiance))
					Li += throughput * its.LoSub(scene, rRec.sampler, -ray.d, rRec.depth);

				/* Prevent light leaks due to the use of shading normals */
				Float wiDotGeoN = -dot(its.geoFrame.n, ray.d),
					  wiDotShN  = Frame::cosTheta(its.wi);
				if (m_strictNormals && wiDotGeoN * wiDotShN < 0)
					break;

				/* ==================================================================== */
				/*                     Direct illumination sampling                     */
				/* ==================================================================== */

				const BSDF *bsdf = its.getBSDF(ray);

				/* Estimate the direct illumination if this is requested */
				if (rRec.type & RadianceQueryRecord::EDirectSurfaceRadiance &&
						(bsdf->getType() & BSDF::ESmooth)) {
					DirectSamplingRecord dRec(its);
					int maxInteractions = m_maxDepth - rRec.depth - 1;

					Spectrum value = scene->sampleAttenuatedEmitterDirect(
							dRec, its, rRec.medium, maxInteractions,
							rRec.nextSample2D(), rRec.sampler);

					if (!value.isZero()) {
						/* Allocate a record for querying the BSDF */
						BSDFSamplingRecord bRec(its, its.toLocal(dRec.d));
						bRec.sampler = rRec.sampler;

						Float woDotGeoN = dot(its.geoFrame.n, dRec.d);
						/* Prevent light leaks due to the use of shading normals */
						if (!m_strictNormals ||
							woDotGeoN * Frame::cosTheta(bRec.wo) > 0)
							Li += throughput * value * bsdf->eval(bRec);
					}
				}

				/* ==================================================================== */
				/*                   BSDF sampling / Multiple scattering                */
				/* ==================================================================== */

				/* Sample BSDF * cos(theta) */
				BSDFSamplingRecord bRec(its, rRec.sampler, ERadiance);
				Spectrum bsdfVal = bsdf->sample(bRec, rRec.nextSample2D());
				if (bsdfVal.isZero())
					break;

				/* Recursively gather indirect illumination? */
				int recursiveType = 0;
				if ((rRec.depth + 1 < m_maxDepth || m_maxDepth < 0) &&
					(rRec.type & RadianceQueryRecord::EIndirectSurfaceRadiance))
					recursiveType |= RadianceQueryRecord::ERadianceNoEmission;

				/* Recursively gather direct illumination? This is a bit more
				   complicated by the fact that this integrator can create connection
				   through index-matched medium transitions (ENull scattering events) */
				if ((rRec.depth < m_maxDepth || m_maxDepth < 0) &&
					(rRec.type & RadianceQueryRecord::EDirectSurfaceRadiance) &&
					(bRec.sampledType & BSDF::EDelta) &&
					(!(bRec.sampledType & BSDF::ENull) || nullChain)) {
					recursiveType |= RadianceQueryRecord::EEmittedRadiance;
					nullChain = true;
				} else {
					nullChain &= bRec.sampledType == BSDF::ENull;
				}

				/* Potentially stop the recursion if there is nothing more to do */
				if (recursiveType == 0)
					break;
				rRec.type = recursiveType;

				/* Prevent light leaks due to the use of shading normals */
				const Vector wo = its.toWorld(bRec.wo);
				Float woDotGeoN = dot(its.geoFrame.n, wo);
				if (woDotGeoN * Frame::cosTheta(bRec.wo) <= 0 && m_strictNormals)
					break;

				/* Keep track of the throughput, medium, and relative
				   refractive index along the path */
				throughput *= bsdfVal;
				eta *= bRec.eta;
				if (its.isMediumTransition())
					rRec.medium = its.getTargetMedium(wo);

				/* In the next iteration, trace a ray in this direction */
				ray = Ray(its.p, wo, ray.time);
				scene->rayIntersect(ray, its);
				scattered |= bRec.sampledType != BSDF::ENull;
			}

			if (rRec.depth++ >= m_rrDepth) {
				/* Russian roulette: try to keep path weights equal to one,
				   while accounting for the solid angle compression at refractive
				   index boundaries. Stop with at least some probability to avoid
				   getting stuck (e.g. due to total internal reflection) */

				Float q = std::min(throughput.max() * eta * eta, (Float) 0.95f);
				if (rRec.nextSample1D() >= q)
					break;
				throughput /= q;
			}
		}
		avgPathLength.incrementBase();
		avgPathLength += rRec.depth;
		return Li;
	}
Example #5
0
void PhotonTracer::tracePhoton(SurfacePhotonRange &surfaceRange, VolumePhotonRange &volumeRange,
        PathSampleGenerator &sampler)
{
    float lightPdf;
    const Primitive *light = chooseLightAdjoint(sampler, lightPdf);

    PositionSample point;
    if (!light->samplePosition(sampler, point))
        return;
    DirectionSample direction;
    if (!light->sampleDirection(sampler, point, direction))
        return;
    sampler.advancePath();

    Ray ray(point.p, direction.d);
    Vec3f throughput(point.weight*direction.weight/lightPdf);

    SurfaceScatterEvent event;
    IntersectionTemporary data;
    IntersectionInfo info;
    Medium::MediumState state;
    state.reset();
    Vec3f emission(0.0f);
    const Medium *medium = nullptr; // TODO: Media

    int bounce = 0;
    bool wasSpecular = true;
    bool hitSurface = true;
    bool didHit = _scene->intersect(ray, data, info);
    while ((didHit || medium) && bounce < _settings.maxBounces - 1) {
        if (medium) {
            MediumSample mediumSample;
            if (!medium->sampleDistance(sampler, ray, state, mediumSample))
                break;
            throughput *= mediumSample.weight;
            hitSurface = mediumSample.exited;

            if (!hitSurface) {
                if (!volumeRange.full()) {
                    VolumePhoton &p = volumeRange.addPhoton();
                    p.pos = mediumSample.p;
                    p.dir = ray.dir();
                    p.power = throughput;
                }

                PhaseSample phaseSample;
                if (!mediumSample.phase->sample(sampler, ray.dir(), phaseSample))
                    break;
                ray = ray.scatter(mediumSample.p, phaseSample.w, 0.0f);
                ray.setPrimaryRay(false);
                throughput *= phaseSample.weight;
            }
        }

        if (hitSurface) {
            if (!info.bsdf->lobes().isPureSpecular() && !surfaceRange.full()) {
                Photon &p = surfaceRange.addPhoton();
                p.pos = info.p;
                p.dir = ray.dir();
                p.power = throughput*std::abs(info.Ns.dot(ray.dir())/info.Ng.dot(ray.dir()));
            }
        }

        if (volumeRange.full() && surfaceRange.full())
            break;

        if (hitSurface) {
            event = makeLocalScatterEvent(data, info, ray, &sampler);
            if (!handleSurface(event, data, info, medium, bounce,
                    true, false, ray, throughput, emission, wasSpecular, state))
                break;
        }

        if (throughput.max() == 0.0f)
            break;

        if (std::isnan(ray.dir().sum() + ray.pos().sum()))
            break;
        if (std::isnan(throughput.sum()))
            break;

        sampler.advancePath();
        bounce++;
        if (bounce < _settings.maxBounces)
            didHit = _scene->intersect(ray, data, info);
    }
}
Example #6
0
inline Vec3f TraceBase::generalizedShadowRayImpl(PathSampleGenerator &sampler,
                           Ray &ray,
                           const Medium *medium,
                           const Primitive *endCap,
                           int bounce,
                           bool startsOnSurface,
                           bool endsOnSurface,
                           float &pdfForward,
                           float &pdfBackward) const
{
    IntersectionTemporary data;
    IntersectionInfo info;

    float initialFarT = ray.farT();
    Vec3f throughput(1.0f);
    do {
        bool didHit = _scene->intersect(ray, data, info) && info.primitive != endCap;
        if (didHit) {
            if (!info.bsdf->lobes().hasForward())
                return Vec3f(0.0f);

            SurfaceScatterEvent event = makeLocalScatterEvent(data, info, ray, nullptr);

            // For forward events, the transport direction does not matter (since wi = -wo)
            Vec3f transparency = info.bsdf->eval(event.makeForwardEvent(), false);
            if (transparency == 0.0f)
                return Vec3f(0.0f);

            if (ComputePdfs) {
                float transparencyScalar = transparency.avg();
                pdfForward  *= transparencyScalar;
                pdfBackward *= transparencyScalar;
            }

            throughput *= transparency;
            bounce++;

            if (bounce >= _settings.maxBounces)
                return Vec3f(0.0f);
        }

        if (medium) {
            if (ComputePdfs) {
                float forward, backward;
                throughput *= medium->transmittanceAndPdfs(sampler, ray, startsOnSurface, didHit || endsOnSurface, forward, backward);
                pdfForward *= forward;
                pdfBackward *= backward;
            } else {
                throughput *= medium->transmittance(sampler, ray, startsOnSurface, endsOnSurface);
            }
        }
        if (info.primitive == nullptr || info.primitive == endCap)
            return bounce >= _settings.minBounces ? throughput : Vec3f(0.0f);
        medium = info.primitive->selectMedium(medium, !info.primitive->hitBackside(data));
        startsOnSurface = true;

        ray.setPos(ray.hitpoint());
        initialFarT -= ray.farT();
        ray.setNearT(info.epsilon);
        ray.setFarT(initialFarT);
    } while(true);
    return Vec3f(0.0f);
}
Example #7
0
/**
 * do_write - Write txbuf to fd
 * @serial:	Serial Test Context
 * @bytes:	amount of data to write
 */
static int do_write(struct usb_serial_test *serial, uint32_t bytes)
{
	int				transferred = 0;
	int				done = 0;
	int				ret;
	struct usbdevfs_bulktransfer	bulk;

	serial->txbuf[0] = (bytes >> 24) & 0xFF;
	serial->txbuf[1] = (bytes >> 16) & 0xFF;
	serial->txbuf[2] = (bytes >>  8) & 0xFF;
	serial->txbuf[3] = (bytes >>  0) & 0xFF;
	if (bytes > 4)
		serial->txbuf[bytes-1] = 0xff;

	gettimeofday(&start, NULL);
	while (done < bytes) {
		bulk.ep = serial->eptx;
		bulk.len = bytes - done;
		if (bulk.len > MAX_USBFS_BUFFER_SIZE)
			bulk.len = MAX_USBFS_BUFFER_SIZE;
		bulk.timeout = TIMEOUT;
		bulk.data = serial->txbuf + done;

		ret = ioctl(serial->udevh, USBDEVFS_BULK, &bulk);
		if (ret < 0) {
			DBG("%s: failed to send data\n", __func__);
			goto err;
		}
		transferred = ret;

		serial->transferred += transferred;
		done += transferred;
	}
	gettimeofday(&end, NULL);
	serial->write_tput = throughput(usecs(&start, &end), done);
	if (done > 0)
		serial->write_usecs += usecs(&start, &end);

	/* total average over duration of test */
	serial->write_avgtput = throughput(serial->write_usecs,
					serial->transferred);

	if (serial->write_tput > serial->write_maxtput)
		serial->write_maxtput = serial->write_tput;

	if (serial->write_tput < serial->write_mintput)
		serial->write_mintput = serial->write_tput;

	if (!(bytes % 512)) {
		bulk.ep = serial->eptx;
		bulk.len = 0;
		bulk.timeout = TIMEOUT;
		bulk.data = serial->txbuf + done;
		ret = ioctl(serial->udevh, USBDEVFS_BULK, &bulk);
		if (ret < 0) {
			DBG("%s: failed to send data\n", __func__);
			goto err;
		}
	}

	return 0;

err:
	return ret;
}