예제 #1
0
static Spectrum L(const Scene *scene, const Renderer *renderer,
        const Camera *camera, MemoryArena &arena, RNG &rng, int maxDepth,
        bool ignoreDirect, const MLTSample &sample) {
    // Generate camera ray from Metropolis sample
    RayDifferential ray;
    float cameraWeight = camera->GenerateRayDifferential(sample.cameraSample,
                                                         &ray);
    Spectrum pathThroughput = cameraWeight, L = 0.;
    bool specularBounce = false, allSpecular = true;
    for (int pathLength = 0; pathLength < maxDepth; ++pathLength) {
        // Find next intersection in Metropolis light path
        Intersection isect;
        if (!scene->Intersect(ray, &isect)) {
            bool includeLe = ignoreDirect ? (specularBounce && !allSpecular) :
                                            (pathLength == 0 || specularBounce);
            if (includeLe)
                for (uint32_t i = 0; i < scene->lights.size(); ++i)
                   L += pathThroughput * scene->lights[i]->Le(ray);
            break;
        }
        if (ignoreDirect ? (specularBounce && !allSpecular) :
                           (specularBounce || pathLength == 0))
            L += pathThroughput * isect.Le(-ray.d);
        BSDF *bsdf = isect.GetBSDF(ray, arena);
        const Point &p = bsdf->dgShading.p;
        const Normal &n = bsdf->dgShading.nn;
        Vector wo = -ray.d;
        const PathSample &ps = sample.pathSamples[pathLength];
        // Sample direct illumination for Metropolis path vertex
        if (!ignoreDirect || pathLength > 0) {
            LightSample lightSample(ps.lightDir0, ps.lightDir1, ps.lightNum0);
            BSDFSample bsdfSample(ps.bsdfLightDir0, ps.bsdfLightDir1,
                                  ps.bsdfLightComponent);
            uint32_t lightNum = Floor2Int(ps.lightNum1 * scene->lights.size());
            lightNum = min(lightNum, (uint32_t)(scene->lights.size()-1));
            const Light *light = scene->lights[lightNum];
            L += pathThroughput *
                 EstimateDirect(scene, renderer, arena, light, p, n, wo,
                     isect.rayEpsilon, sample.cameraSample.time, bsdf, rng,
                     lightSample, bsdfSample);
        }

        // Sample direction for outgoing Metropolis path direction
        BSDFSample outgoingBSDFSample(ps.bsdfDir0, ps.bsdfDir1,
                                      ps.bsdfComponent);
        Vector wi;
        float pdf;
        BxDFType flags;
        Spectrum f = bsdf->Sample_f(wo, &wi, outgoingBSDFSample,
                                    &pdf, BSDF_ALL, &flags);
        if (f.IsBlack() || pdf == 0.)
            break;
        specularBounce = (flags & BSDF_SPECULAR) != 0;
        allSpecular &= specularBounce;
        pathThroughput *= f * AbsDot(wi, n) / pdf;
        ray = RayDifferential(p, wi, ray, isect.rayEpsilon);
        //pathThroughput *= renderer->Transmittance(scene, ray, NULL, rng, arena);
    }
    return L;
}
예제 #2
0
Spectrum SampleIntegrator::E(const Scene *scene, const Point &p, const Normal &n, Float time,
		const Medium *medium, Sampler *sampler, int nSamples, bool handleIndirect) const {
	Spectrum E(0.0f);
	LuminaireSamplingRecord lRec;
	RadianceQueryRecord rRec(scene, sampler);
	Frame frame(n);

	sampler->generate();
	for (int i=0; i<nSamples; i++) {
		rRec.newQuery(RadianceQueryRecord::ERadianceNoEmission, medium);

		/* Direct */
		if (scene->sampleAttenuatedLuminaire(p, time, medium, lRec, rRec.nextSample2D())) {
			Float dp = dot(lRec.d, n);
			if (dp < 0) 
				E -= lRec.value * dp;
		}

		/* Indirect */
		if (handleIndirect) {
			Vector d = frame.toWorld(squareToHemispherePSA(rRec.nextSample2D()));
			++rRec.depth;
			E += Li(RayDifferential(p, d, time), rRec) * M_PI;
		}
		sampler->advance();
	}
	return E / (Float) nSamples;
}
예제 #3
0
	Spectrum E(const Scene *scene, const Intersection &its, const Medium *medium,
			Sampler *sampler, int nSamples, bool handleIndirect) const {
		Spectrum EDir(0.0f), EIndir(0.0f);
		DirectSamplingRecord dRec(its);

		/* Sample the direct illumination component */
		for (int i=0; i<nSamples; i++) {
			int maxIntermediateInteractions = -1;
			Spectrum directRadiance = scene->sampleAttenuatedEmitterDirect(
				dRec, its, medium, maxIntermediateInteractions, sampler->next2D());

			if (!directRadiance.isZero()) {
				Float dp = dot(dRec.d, its.shFrame.n);
				if (dp > 0)
					EDir += directRadiance * dp;
			}
		}

		if (handleIndirect) {
			RadianceQueryRecord rRec(scene, sampler);
			rRec.newQuery(RadianceQueryRecord::ERadianceNoEmission, medium);
			rRec.its = its;
			if (!m_irrCache->get(rRec.its, EIndir))
				handleMiss(RayDifferential(), rRec, EIndir);
		}

		return (EDir / (Float) nSamples) + EIndir;
	}
예제 #4
0
float OrthoCamera::GenerateRayDifferential(const CameraSample &sample,
        RayDifferential *ray) const {
    // Compute main orthographic viewing ray

    // Generate raster and camera samples
    PbrtPoint Pras(sample.imageX, sample.imageY, 0);
    PbrtPoint Pcamera;
    RasterToCamera(Pras, &Pcamera);
    *ray = RayDifferential(Pcamera, Vector(0,0,1), 0., INFINITY);

    // Modify ray for depth of field
    if (lensRadius > 0.) {
        // Sample point on lens
        float lensU, lensV;
        ConcentricSampleDisk(sample.lensU, sample.lensV, &lensU, &lensV);
        lensU *= lensRadius;
        lensV *= lensRadius;

        // Compute point on plane of focus
        float ft = focalDistance / ray->d.z;
        PbrtPoint Pfocus = (*ray)(ft);

        // Update ray for effect of lens
        ray->o = PbrtPoint(lensU, lensV, 0.f);
        ray->d = Normalize(Pfocus - ray->o);
    }
    ray->time = Lerp(sample.time, shutterOpen, shutterClose);
    ray->rxOrigin = ray->o + dxCamera;
    ray->ryOrigin = ray->o + dyCamera;
    ray->rxDirection = ray->ryDirection = ray->d;
    ray->hasDifferentials = true;
    CameraToWorld(*ray, ray);
    return 1.f;
}
예제 #5
0
float PerspectiveCamera::GenerateRayDifferential(const CameraSample &sample,
                                                 RayDifferential *ray) const {
    // Generate raster and camera samples
    Point Pras(sample.imageX, sample.imageY, 0);
    Point Pcamera;
    RasterToCamera(Pras, &Pcamera);
    Vector dir = Normalize(Vector(Pcamera.x, Pcamera.y, Pcamera.z));
    *ray = RayDifferential(Point(0,0,0), dir, 0.f, INFINITY);
    // Modify ray for depth of field
    if (lensRadius > 0.) {
        // Sample point on lens
        float lensU, lensV;
        ConcentricSampleDisk(sample.lensU, sample.lensV, &lensU, &lensV);
        lensU *= lensRadius;
        lensV *= lensRadius;

        // Compute point on plane of focus
        float ft = focalDistance / ray->d.z;
        Point Pfocus = (*ray)(ft);

        // Update ray for effect of lens
        ray->o = Point(lensU, lensV, 0.f);
        ray->d = Normalize(Pfocus - ray->o);
    }

    // Compute offset rays for _PerspectiveCamera_ ray differentials
    ray->rxOrigin = ray->ryOrigin = ray->o;
    ray->rxDirection = Normalize(Vector(Pcamera) + dxCamera);
    ray->ryDirection = Normalize(Vector(Pcamera) + dyCamera);
    ray->time = Lerp(sample.time, shutterOpen, shutterClose);
    CameraToWorld(*ray, ray);
    ray->hasDifferentials = true;
    return 1.f;
}
예제 #6
0
Spectrum SamplingIntegrator::E(const Scene *scene, const Intersection &its,
		const Medium *medium, Sampler *sampler, int nSamples, bool handleIndirect) const {
	Spectrum E(0.0f);
	RadianceQueryRecord query(scene, sampler);
	DirectSamplingRecord dRec(its);
	Frame frame(its.shFrame.n);

	sampler->generate(Point2i(0));
	for (int i=0; i<nSamples; i++) {
		/* Sample the direct illumination component */
		int maxIntermediateInteractions = -1;
		Spectrum directRadiance = scene->sampleAttenuatedEmitterDirect(
			dRec, its, medium, maxIntermediateInteractions, query.nextSample2D());

		if (!directRadiance.isZero()) {
			Float dp = dot(dRec.d, its.shFrame.n);
			if (dp > 0)
				E += directRadiance * dp;
		}

		/* Sample the indirect illumination component */
		if (handleIndirect) {
			query.newQuery(RadianceQueryRecord::ERadianceNoEmission, medium);
			Vector d = frame.toWorld(Warp::squareToCosineHemisphere(query.nextSample2D()));
			++query.depth;
			query.medium = medium;
			E += Li(RayDifferential(its.p, d, its.time), query) * M_PI;
		}

		sampler->advance();
	}

	return E / (Float) nSamples;
}
예제 #7
0
	void process(const WorkUnit *workUnit, WorkResult *workResult,
		const bool &stop) {
		const RectangularWorkUnit *rect = static_cast<const RectangularWorkUnit *>(workUnit);
		IrradianceRecordVector *result = static_cast<IrradianceRecordVector *>(workResult);
		const SamplingIntegrator *integrator = m_subIntegrator.get();

		Intersection its;
		RadianceQueryRecord rRec(m_scene, m_sampler);

		const int sx = rect->getOffset().x,
				sy = rect->getOffset().y,
				ex = sx + rect->getSize().x,
				ey = sy + rect->getSize().y;
		result->clear();

		for (int y = sy; y < ey; y++) {
			for (int x = sx; x < ex; x++) {
				if (stop)
					break;
				Point2 pixelSample(x + .5f, y + .5f);
				RayDifferential ray;
				if (m_sensor->sampleRayDifferential(ray, pixelSample, Point2(0.5f), 0.5f).isZero())
					continue;
				if (m_scene->rayIntersect(ray, its)) {
					const BSDF *bsdf = its.getBSDF();
					if ((bsdf->getType() & BSDF::EAll) != BSDF::EDiffuseReflection)
						continue;

					Spectrum E;
					if (m_irrCache->get(its, E))
						continue;

					/* Irradiance cache miss - create a record. The following
					   generates stratified cosine-weighted samples and computes
					   rotational + translational gradients */
					m_hs->generateDirections(its);
					m_sampler->generate(Point2i(0));

					for (unsigned int j=0; j<m_hs->getM(); j++) {
						for (unsigned int k=0; k<m_hs->getN(); k++) {
							HemisphereSampler::SampleEntry &entry = (*m_hs)(j, k);
							entry.dist = std::numeric_limits<Float>::infinity();
							rRec.newQuery(RadianceQueryRecord::ERadianceNoEmission
								| RadianceQueryRecord::EDistance, m_sensor->getMedium());
							rRec.extra = RadianceQueryRecord::ECacheQuery;
							rRec.depth = 2;
							entry.L = integrator->Li(RayDifferential(its.p, entry.d, 0.0f), rRec);
							entry.dist = rRec.dist;
							m_sampler->advance();
						}
					}

					m_hs->process(its);
					result->put(m_irrCache->put(ray, its, *m_hs));
				}
			}
		}
	}
예제 #8
0
Spectrum MetropolisRenderer::PathL(const MLTSample &sample,
        const Scene *scene, MemoryArena &arena, const Camera *camera,
        const Distribution1D *lightDistribution,
        PathVertex *cameraPath, PathVertex *lightPath,
        RNG &rng) const {
    // Generate camera path from camera path samples
    PBRT_STARTED_GENERATING_CAMERA_RAY((CameraSample *)(&sample.cameraSample));
    RayDifferential cameraRay;
    float cameraWt = camera->GenerateRayDifferential(sample.cameraSample,
                                                     &cameraRay);
    cameraRay.ScaleDifferentials(1.f / sqrtf(nPixelSamples));
    PBRT_FINISHED_GENERATING_CAMERA_RAY((CameraSample *)(&sample.cameraSample), &cameraRay, cameraWt);
    RayDifferential escapedRay;
    Spectrum escapedAlpha;
    uint32_t cameraLength = GeneratePath(cameraRay, cameraWt, scene, arena,
        sample.cameraPathSamples, cameraPath, &escapedRay, &escapedAlpha);
    if (!bidirectional) {
        // Compute radiance along path using path tracing
        return Lpath(scene, cameraPath, cameraLength, arena,
                     sample.lightingSamples, rng, sample.cameraSample.time,
                     lightDistribution, escapedRay, escapedAlpha);
    }
    else {
        // Sample light ray and apply bidirectional path tracing

        // Choose light and sample ray to start light path
        PBRT_MLT_STARTED_SAMPLE_LIGHT_FOR_BIDIR();
        float lightPdf, lightRayPdf;
        uint32_t lightNum = lightDistribution->SampleDiscrete(sample.lightNumSample,
                                                              &lightPdf);
        const Light *light = scene->lights[lightNum];
        Ray lightRay;
        Normal Nl;
        LightSample lrs(sample.lightRaySamples[0], sample.lightRaySamples[1],
                        sample.lightRaySamples[2]);
        Spectrum lightWt = light->Sample_L(scene, lrs, sample.lightRaySamples[3],
            sample.lightRaySamples[4], sample.cameraSample.time, &lightRay,
            &Nl, &lightRayPdf);
        PBRT_MLT_FINISHED_SAMPLE_LIGHT_FOR_BIDIR();
        if (lightWt.IsBlack() || lightRayPdf == 0.f) {
            // Compute radiance along path using path tracing
            return Lpath(scene, cameraPath, cameraLength, arena,
                         sample.lightingSamples, rng, sample.cameraSample.time,
                         lightDistribution, escapedRay, escapedAlpha);
        }
        else {
            // Compute radiance along paths using bidirectional path tracing
            lightWt *= AbsDot(Normalize(Nl), lightRay.d) / (lightPdf * lightRayPdf);
            uint32_t lightLength = GeneratePath(RayDifferential(lightRay), lightWt,
                scene, arena, sample.lightPathSamples, lightPath, NULL, NULL);
            
            return Lbidir(scene, cameraPath, cameraLength, lightPath, lightLength,
                arena, sample.lightingSamples, rng, sample.cameraSample.time,
                lightDistribution, escapedRay, escapedAlpha);
        }
    }
}
예제 #9
0
// Metropolis Method Definitions
static uint32_t GeneratePath(const RayDifferential &r,
        const Spectrum &a, const Scene *scene, MemoryArena &arena,
        const vector<PathSample> &samples, PathVertex *path,
        RayDifferential *escapedRay, Spectrum *escapedAlpha) {
    PBRT_MLT_STARTED_GENERATE_PATH();
    RayDifferential ray = r;
    Spectrum alpha = a;
    if (escapedAlpha) *escapedAlpha = 0.f;
    uint32_t length = 0;
    for (; length < samples.size(); ++length) {
        // Try to generate next vertex of ray path
        PathVertex &v = path[length];
        if (!scene->Intersect(ray, &v.isect)) {
            // Handle ray that leaves the scene during path generation
            if (escapedAlpha) *escapedAlpha = alpha;
            if (escapedRay)   *escapedRay = ray;
            break;
        }

        // Record information for current path vertex
        v.alpha = alpha;
        BSDF *bsdf = v.isect.GetBSDF(ray, arena);
        v.bsdf = bsdf;
        v.wPrev = -ray.d;

        // Sample direction for outgoing Metropolis path direction
        float pdf;
        BxDFType flags;
        Spectrum f = bsdf->Sample_f(-ray.d, &v.wNext, samples[length].bsdfSample,
                                    &pdf, BSDF_ALL, &flags);
        v.specularBounce = (flags & BSDF_SPECULAR) != 0;
        v.nSpecularComponents = bsdf->NumComponents(BxDFType(BSDF_SPECULAR |
                                         BSDF_REFLECTION | BSDF_TRANSMISSION));
        if (f.IsBlack() || pdf == 0.f)
        {
            PBRT_MLT_FINISHED_GENERATE_PATH();
            return length+1;
        }

        // Terminate path with RR or prepare for finding next vertex
        const Point &p = bsdf->dgShading.p;
        const Normal &n = bsdf->dgShading.nn;
        Spectrum pathScale = f * AbsDot(v.wNext, n) / pdf;
        float rrSurviveProb = min(1.f, pathScale.y());
        if (samples[length].rrSample > rrSurviveProb)
        {
            PBRT_MLT_FINISHED_GENERATE_PATH();
            return length+1;
        }
        alpha *= pathScale / rrSurviveProb;
        //alpha *= renderer->Transmittance(scene, ray, NULL, rng, arena);
        ray = RayDifferential(p, v.wNext, ray, v.isect.rayEpsilon);
    }
    PBRT_MLT_FINISHED_GENERATE_PATH();
    return length;
}
예제 #10
0
Spectrum IrradianceCacheIntegrator::pathL(Ray &r, const Scene *scene,
        const Renderer *renderer, const Sample *sample, MemoryArena &arena) const {
    Spectrum L(0.f);
    Spectrum pathThroughput = 1.;
    RayDifferential ray(r);
    bool specularBounce = false;
    for (int pathLength = 0; ; ++pathLength) {
        // Find next vertex of path
        Intersection isect;
        if (!scene->Intersect(ray, &isect))
            break;
        if (pathLength == 0)
            r.maxt = ray.maxt;
        else if (pathLength == 1)
            pathThroughput *= renderer->Transmittance(scene, ray, sample, arena, NULL);
        else
            pathThroughput *= renderer->Transmittance(scene, ray, NULL, arena, sample->rng);
        // Possibly add emitted light at path vertex
        if (specularBounce)
            L += pathThroughput * isect.Le(-ray.d);
        // Evaluate BSDF at hit point
        BSDF *bsdf = isect.GetBSDF(ray, arena);
        // Sample illumination from lights to find path contribution
        const Point &p = bsdf->dgShading.p;
        const Normal &n = bsdf->dgShading.nn;
        Vector wo = -ray.d;
        L += pathThroughput *
            UniformSampleOneLight(scene, renderer, arena, p, n, wo, isect.rayEpsilon,
                                  bsdf, sample);
        if (pathLength+1 == maxIndirectDepth) break;
        // Sample BSDF to get new path direction
        // Get random numbers for sampling new direction, \mono{bs1}, \mono{bs2}, and \mono{bcs}
        Vector wi;
        float pdf;
        BxDFType flags;
        Spectrum f = bsdf->Sample_f(wo, &wi, BSDFSample(*sample->rng),
            &pdf, BSDF_ALL, &flags);
        if (f.IsBlack() || pdf == 0.)
            break;
        specularBounce = (flags & BSDF_SPECULAR) != 0;
        pathThroughput *= f * AbsDot(wi, n) / pdf;
        ray = RayDifferential(p, wi, ray, isect.rayEpsilon);
        // Possibly terminate the path
        if (pathLength > 2) {
            float rrProb = min(1.f, pathThroughput.y());
            if (sample->rng->RandomFloat() > rrProb)
                break;
            pathThroughput /= rrProb;
        }
    }
    return L;
}
예제 #11
0
Float PerspectiveCamera::GenerateRayDifferential(const CameraSample &sample,
                                                 RayDifferential *ray) const {
    ProfilePhase prof(Prof::GenerateCameraRay);
    // Compute raster and camera sample positions
    Point3f pFilm = Point3f(sample.pFilm.x, sample.pFilm.y, 0);
    Point3f pCamera = RasterToCamera(pFilm);
    Vector3f dir = Normalize(Vector3f(pCamera.x, pCamera.y, pCamera.z));
    *ray = RayDifferential(Point3f(0, 0, 0), dir);
    // Modify ray for depth of field
    if (lensRadius > 0) {
        // Sample point on lens
        Point2f pLens = lensRadius * ConcentricSampleDisk(sample.pLens);

        // Compute point on plane of focus
        Float ft = focalDistance / ray->d.z;
        Point3f pFocus = (*ray)(ft);

        // Update ray for effect of lens
        ray->o = Point3f(pLens.x, pLens.y, 0);
        ray->d = Normalize(pFocus - ray->o);
    }

    // Compute offset rays for _PerspectiveCamera_ ray differentials
    if (lensRadius > 0) {
        // Compute _PerspectiveCamera_ ray differentials accounting for lens

        // Sample point on lens
        Point2f pLens = lensRadius * ConcentricSampleDisk(sample.pLens);
        Vector3f dx = Normalize(Vector3f(pCamera + dxCamera));
        Float ft = focalDistance / dx.z;
        Point3f pFocus = Point3f(0, 0, 0) + (ft * dx);
        ray->rxOrigin = Point3f(pLens.x, pLens.y, 0);
        ray->rxDirection = Normalize(pFocus - ray->rxOrigin);

        Vector3f dy = Normalize(Vector3f(pCamera + dyCamera));
        ft = focalDistance / dy.z;
        pFocus = Point3f(0, 0, 0) + (ft * dy);
        ray->ryOrigin = Point3f(pLens.x, pLens.y, 0);
        ray->ryDirection = Normalize(pFocus - ray->ryOrigin);
    } else {
        ray->rxOrigin = ray->ryOrigin = ray->o;
        ray->rxDirection = Normalize(Vector3f(pCamera) + dxCamera);
        ray->ryDirection = Normalize(Vector3f(pCamera) + dyCamera);
    }
    ray->time = Lerp(sample.time, shutterOpen, shutterClose);
    ray->medium = medium;
    *ray = CameraToWorld(*ray);
    ray->hasDifferentials = true;
    return 1;
}
예제 #12
0
Float OrthographicCamera::GenerateRayDifferential(const CameraSample &sample,
                                                  RayDifferential *ray) const {
    ProfilePhase prof(Prof::GenerateCameraRay);
    // Compute main orthographic viewing ray

    // Compute raster and camera sample positions
    Point3f pFilm = Point3f(sample.pFilm.x, sample.pFilm.y, 0);
    Point3f pCamera = RasterToCamera(pFilm);
    *ray = RayDifferential(pCamera, Vector3f(0, 0, 1));

    // Modify ray for depth of field
    if (lensRadius > 0) {
        // Sample point on lens
        Point2f pLens = lensRadius * ConcentricSampleDisk(sample.pLens);

        // Compute point on plane of focus
        Float ft = focalDistance / ray->d.z;
        Point3f pFocus = (*ray)(ft);

        // Update ray for effect of lens
        ray->o = Point3f(pLens.x, pLens.y, 0);
        ray->d = Normalize(pFocus - ray->o);
    }

    // Compute ray differentials for _OrthographicCamera_
    if (lensRadius > 0) {
        // Compute _OrthographicCamera_ ray differentials accounting for lens

        // Sample point on lens
        Point2f pLens = lensRadius * ConcentricSampleDisk(sample.pLens);
        Float ft = focalDistance / ray->d.z;

        Point3f pFocus = pCamera + dxCamera + (ft * Vector3f(0, 0, 1));
        ray->rxOrigin = Point3f(pLens.x, pLens.y, 0);
        ray->rxDirection = Normalize(pFocus - ray->rxOrigin);

        pFocus = pCamera + dyCamera + (ft * Vector3f(0, 0, 1));
        ray->ryOrigin = Point3f(pLens.x, pLens.y, 0);
        ray->ryDirection = Normalize(pFocus - ray->ryOrigin);
    } else {
        ray->rxOrigin = ray->o + dxCamera;
        ray->ryOrigin = ray->o + dyCamera;
        ray->rxDirection = ray->ryDirection = ray->d;
    }
    ray->time = Lerp(sample.time, shutterOpen, shutterClose);
    ray->hasDifferentials = true;
    ray->medium = medium;
    *ray = CameraToWorld(*ray);
    return 1;
}
예제 #13
0
int BidirIntegrator::generatePath(const Scene *scene, const Ray &r,
		const Sample *sample, const int *bsdfOffset,
		const int *bsdfCompOffset,
		BidirVertex *vertices, int maxVerts) const {
	int nVerts = 0;
	RayDifferential ray(r.o, r.d);
	while (nVerts < maxVerts) {
		// Find next vertex in path and initialize _vertices_
		Intersection isect;
		if (!scene->Intersect(ray, &isect))
			break;
		BidirVertex &v = vertices[nVerts];
		v.bsdf = isect.GetBSDF(ray); // do before Ns is set!
		v.p = isect.dg.p;
		v.ng = isect.dg.nn;
		v.ns = v.bsdf->dgShading.nn;
		v.wi = -ray.d;
		++nVerts;
		// Possibly terminate bidirectional path sampling
		if (nVerts > 2) {
			float rrProb = .2f;
			if (RandomFloat() > rrProb)
				break;
			v.rrWeight = 1.f / rrProb;
		}
		// Initialize _ray_ for next segment of path
		float u1 = sample->twoD[bsdfOffset[nVerts-1]][0];
		float u2 = sample->twoD[bsdfOffset[nVerts-1]][1];
		float u3 = sample->oneD[bsdfCompOffset[nVerts-1]][0];
		Spectrum fr = v.bsdf->Sample_f(v.wi, &v.wo, u1, u2, u3,
			 &v.bsdfWeight, BSDF_ALL, &v.flags);
		if (fr.Black() && v.bsdfWeight == 0.f)
			break;
		ray = RayDifferential(v.p, v.wo);
	}
	// Initialize additional values in _vertices_
	for (int i = 0; i < nVerts-1; ++i)
		vertices[i].dAWeight = vertices[i].bsdfWeight *
			AbsDot(-vertices[i].wo, vertices[i+1].ng) /
			DistanceSquared(vertices[i].p, vertices[i+1].p);
	return nVerts;
}
예제 #14
0
	void handleMiss(RayDifferential ray, const RadianceQueryRecord &rRec,
			Spectrum &E) const {
		/* Handle an irradiance cache miss */
		HemisphereSampler *hs = m_hemisphereSampler.get();
		Sampler *sampler = m_sampleGenerator.get();
		RadianceQueryRecord rRec2;
		if (hs == NULL) {
			Properties props("independent");
			sampler = static_cast<Sampler *> (PluginManager::getInstance()->
				createObject(MTS_CLASS(Sampler), props));
			hs = new HemisphereSampler(m_resolution, 2 * m_resolution);
			m_hemisphereSampler.set(hs);
			m_sampleGenerator.set(sampler);
		}

		/* Generate stratified cosine-weighted samples and compute
		   rotational + translational gradients */
		hs->generateDirections(rRec.its);
		sampler->generate(Point2i(0));

		for (unsigned int j=0; j<hs->getM(); j++) {
			for (unsigned int k=0; k<hs->getN(); k++) {
				HemisphereSampler::SampleEntry &entry = (*hs)(j, k);
					entry.dist = std::numeric_limits<Float>::infinity();
				rRec2.recursiveQuery(rRec,
					RadianceQueryRecord::ERadianceNoEmission | RadianceQueryRecord::EDistance);
				rRec2.extra = 1;
				rRec2.sampler = sampler;
				entry.L = m_subIntegrator->Li(RayDifferential(rRec.its.p, entry.d, ray.time), rRec2);
				entry.dist = rRec2.dist;
				sampler->advance();
			}
		}

		hs->process(rRec.its);
		/* Undo ray differential scaling done by the integrator */
		if (ray.hasDifferentials)
			ray.scaleDifferential(m_diffScaleFactor);
		m_irrCache->put(ray, rRec.its, *hs);
		E = hs->getIrradiance();
	}
예제 #15
0
Spectrum InfiniteAreaLightIS::Sample_L(const Scene *scene,
		float u1, float u2, float u3, float u4,
		Ray *ray, float *pdf) const {
	// Choose two points _p1_ and _p2_ on scene bounding sphere
	Point worldCenter;
	float worldRadius;
	scene->WorldBound().BoundingSphere(&worldCenter,
		&worldRadius);
	worldRadius *= 1.01f;
	Point p1 = worldCenter + worldRadius *
		UniformSampleSphere(u1, u2);
	Point p2 = worldCenter + worldRadius *
		UniformSampleSphere(u3, u4);
	// Construct ray between _p1_ and _p2_
	ray->o = p1;
	ray->d = Normalize(p2-p1);
	// Compute _InfiniteAreaLightIS_ ray weight
	Vector to_center = Normalize(worldCenter - p1);
	float costheta = AbsDot(to_center,ray->d);
	*pdf =
		costheta / ((4.f * M_PI * worldRadius * worldRadius));
	return Le(RayDifferential(ray->o, -ray->d));
}
예제 #16
0
void PhotonShootingTask::Run() {
    // Declare local variables for _PhotonShootingTask_
    MemoryArena arena;
    RNG rng(31 * taskNum);
    vector<Photon> localDirectPhotons, localIndirectPhotons, localCausticPhotons;
    vector<RadiancePhoton> localRadiancePhotons;
    uint32_t totalPaths = 0;
    bool causticDone = (integrator->nCausticPhotonsWanted == 0);
    bool indirectDone = (integrator->nIndirectPhotonsWanted == 0);
    PermutedHalton halton(6, rng);
    vector<Spectrum> localRpReflectances, localRpTransmittances;
    while (true) {
        // Follow photon paths for a block of samples
        const uint32_t blockSize = 4096;
        for (uint32_t i = 0; i < blockSize; ++i) {
            float u[6];
            halton.Sample(++totalPaths, u);
            // Choose light to shoot photon from
            float lightPdf;
            int lightNum = lightDistribution->SampleDiscrete(u[0], &lightPdf);
            const Light *light = scene->lights[lightNum];

            // Generate _photonRay_ from light source and initialize _alpha_
            RayDifferential photonRay;
            float pdf;
            LightSample ls(u[1], u[2], u[3]);
            Normal Nl;
            Spectrum Le = light->Sample_L(scene, ls, u[4], u[5],
                                          time, &photonRay, &Nl, &pdf);
            if (pdf == 0.f || Le.IsBlack()) continue;
            Spectrum alpha = (AbsDot(Nl, photonRay.d) * Le) / (pdf * lightPdf);
            if (!alpha.IsBlack()) {
                // Follow photon path through scene and record intersections
                PBRT_PHOTON_MAP_STARTED_RAY_PATH(&photonRay, &alpha);
                bool specularPath = true;
                Intersection photonIsect;
                int nIntersections = 0;
                while (scene->Intersect(photonRay, &photonIsect)) {
                    ++nIntersections;
                    // Handle photon/surface intersection
                    alpha *= renderer->Transmittance(scene, photonRay, NULL, rng, arena);
                    BSDF *photonBSDF = photonIsect.GetBSDF(photonRay, arena);
                    BxDFType specularType = BxDFType(BSDF_REFLECTION |
                                            BSDF_TRANSMISSION | BSDF_SPECULAR);
                    bool hasNonSpecular = (photonBSDF->NumComponents() >
                                           photonBSDF->NumComponents(specularType));
                    Vector wo = -photonRay.d;
                    if (hasNonSpecular) {
                        // Deposit photon at surface
                        Photon photon(photonIsect.dg.p, alpha, wo);
                        bool depositedPhoton = false;
                        if (specularPath && nIntersections > 1) {
                            if (!causticDone) {
                                PBRT_PHOTON_MAP_DEPOSITED_CAUSTIC_PHOTON(&photonIsect.dg, &alpha, &wo);
                                depositedPhoton = true;
                                localCausticPhotons.push_back(photon);
                            }
                        }
                        else {
                            // Deposit either direct or indirect photon
                            // stop depositing direct photons once indirectDone is true; don't
                            // want to waste memory storing too many if we're going a long time
                            // trying to get enough caustic photons desposited.
                            if (nIntersections == 1 && !indirectDone && integrator->finalGather) {
                                PBRT_PHOTON_MAP_DEPOSITED_DIRECT_PHOTON(&photonIsect.dg, &alpha, &wo);
                                depositedPhoton = true;
                                localDirectPhotons.push_back(photon);
                            }
                            else if (nIntersections > 1 && !indirectDone) {
                                PBRT_PHOTON_MAP_DEPOSITED_INDIRECT_PHOTON(&photonIsect.dg, &alpha, &wo);
                                depositedPhoton = true;
                                localIndirectPhotons.push_back(photon);
                            }
                        }

                        // Possibly create radiance photon at photon intersection point
                        if (depositedPhoton && integrator->finalGather &&
                                rng.RandomFloat() < .125f) {
                            Normal n = photonIsect.dg.nn;
                            n = Faceforward(n, -photonRay.d);
                            localRadiancePhotons.push_back(RadiancePhoton(photonIsect.dg.p, n));
                            Spectrum rho_r = photonBSDF->rho(rng, BSDF_ALL_REFLECTION);
                            localRpReflectances.push_back(rho_r);
                            Spectrum rho_t = photonBSDF->rho(rng, BSDF_ALL_TRANSMISSION);
                            localRpTransmittances.push_back(rho_t);
                        }
                    }
                    if (nIntersections >= integrator->maxPhotonDepth) break;

                    // Sample new photon ray direction
                    Vector wi;
                    float pdf;
                    BxDFType flags;
                    Spectrum fr = photonBSDF->Sample_f(wo, &wi, BSDFSample(rng),
                                                       &pdf, BSDF_ALL, &flags);
                    if (fr.IsBlack() || pdf == 0.f) break;
                    Spectrum anew = alpha * fr *
                        AbsDot(wi, photonBSDF->dgShading.nn) / pdf;

                    // Possibly terminate photon path with Russian roulette
                    float continueProb = min(1.f, anew.y() / alpha.y());
                    if (rng.RandomFloat() > continueProb)
                        break;
                    alpha = anew / continueProb;
                    specularPath &= ((flags & BSDF_SPECULAR) != 0);
                    
                    if (indirectDone && !specularPath) break;
                    photonRay = RayDifferential(photonIsect.dg.p, wi, photonRay,
                                                photonIsect.rayEpsilon);
                }
                PBRT_PHOTON_MAP_FINISHED_RAY_PATH(&photonRay, &alpha);
            }
            arena.FreeAll();
        }

        // Merge local photon data with data in _PhotonIntegrator_
        { MutexLock lock(mutex);

        // Give up if we're not storing enough photons
        if (abortTasks)
            return;
        if (nshot > 500000 &&
            (unsuccessful(integrator->nCausticPhotonsWanted,
                                      causticPhotons.size(), blockSize) ||
             unsuccessful(integrator->nIndirectPhotonsWanted,
                                      indirectPhotons.size(), blockSize))) {
            Error("Unable to store enough photons.  Giving up.\n");
            causticPhotons.erase(causticPhotons.begin(), causticPhotons.end());
            indirectPhotons.erase(indirectPhotons.begin(), indirectPhotons.end());
            radiancePhotons.erase(radiancePhotons.begin(), radiancePhotons.end());
            abortTasks = true;
            return;
        }
        progress.Update(localIndirectPhotons.size() + localCausticPhotons.size());
        nshot += blockSize;

        // Merge indirect photons into shared array
        if (!indirectDone) {
            integrator->nIndirectPaths += blockSize;
            for (uint32_t i = 0; i < localIndirectPhotons.size(); ++i)
                indirectPhotons.push_back(localIndirectPhotons[i]);
            localIndirectPhotons.erase(localIndirectPhotons.begin(),
                                       localIndirectPhotons.end());
            if (indirectPhotons.size() >= integrator->nIndirectPhotonsWanted)
                indirectDone = true;
            nDirectPaths += blockSize;
            for (uint32_t i = 0; i < localDirectPhotons.size(); ++i)
                directPhotons.push_back(localDirectPhotons[i]);
            localDirectPhotons.erase(localDirectPhotons.begin(),
                                     localDirectPhotons.end());
        }

        // Merge direct, caustic, and radiance photons into shared array
        if (!causticDone) {
            integrator->nCausticPaths += blockSize;
            for (uint32_t i = 0; i < localCausticPhotons.size(); ++i)
                causticPhotons.push_back(localCausticPhotons[i]);
            localCausticPhotons.erase(localCausticPhotons.begin(), localCausticPhotons.end());
            if (causticPhotons.size() >= integrator->nCausticPhotonsWanted)
                causticDone = true;
        }
        
        for (uint32_t i = 0; i < localRadiancePhotons.size(); ++i)
            radiancePhotons.push_back(localRadiancePhotons[i]);
        localRadiancePhotons.erase(localRadiancePhotons.begin(), localRadiancePhotons.end());
        for (uint32_t i = 0; i < localRpReflectances.size(); ++i)
            rpReflectances.push_back(localRpReflectances[i]);
        localRpReflectances.erase(localRpReflectances.begin(), localRpReflectances.end());
        for (uint32_t i = 0; i < localRpTransmittances.size(); ++i)
            rpTransmittances.push_back(localRpTransmittances[i]);
        localRpTransmittances.erase(localRpTransmittances.begin(), localRpTransmittances.end());
        }

        // Exit task if enough photons have been found
        if (indirectDone && causticDone)
            break;
    }
}
예제 #17
0
	void distributedRTPass(Scene *scene, std::vector<SerializableObject *> &samplers) {
		ref<Camera> camera = scene->getCamera();
		bool needsLensSample = camera->needsLensSample();
		bool needsTimeSample = camera->needsTimeSample();
		ref<Film> film = camera->getFilm();
		Vector2i cropSize = film->getCropSize();
		Point2i cropOffset = film->getCropOffset();

		/* Process the image in parallel using blocks for better memory locality */
		Log(EInfo, "Creating %i gather points", cropSize.x*cropSize.y);
		#pragma omp parallel for schedule(dynamic)
		for (int i=-1; i<(int) m_gatherBlocks.size(); ++i) {
			std::vector<GatherPoint> &gatherPoints = m_gatherBlocks[i];
#if !defined(__OSX__) && defined(_OPENMP)
			Sampler *sampler = static_cast<Sampler *>(samplers[omp_get_thread_num()]);
#else
			Sampler *sampler = static_cast<Sampler *>(samplers[0]);
#endif
			int xofs = m_offset[i].x, yofs = m_offset[i].y;
			int index = 0;
			for (int yofsInt = 0; yofsInt < m_blockSize; ++yofsInt) {
				if (yofsInt + yofs - cropOffset.y >= cropSize.y)
					continue;
				for (int xofsInt = 0; xofsInt < m_blockSize; ++xofsInt) {
					if (xofsInt + xofs - cropOffset.x >= cropSize.x)
						continue;
					Point2 lensSample, sample;
					Float timeSample = 0.0f;
					GatherPoint &gatherPoint = gatherPoints[index++];
					sampler->generate();
					if (needsLensSample)
						lensSample = sampler->next2D();
					if (needsTimeSample)
						timeSample = sampler->next1D();
					gatherPoint.pos = Point2i(xofs + xofsInt, yofs + yofsInt);
					sample = sampler->next2D();
					sample += Vector2((Float) gatherPoint.pos.x, (Float) gatherPoint.pos.y);
					RayDifferential ray;
					camera->generateRayDifferential(sample, lensSample, timeSample, ray);
					Spectrum weight(1.0f);
					int depth = 1;

					while (true) {
						if (depth > m_maxDepth) {
							gatherPoint.depth = -1;
							break;
						}
						if (scene->rayIntersect(ray, gatherPoint.its)) {
							const BSDF *bsdf = gatherPoint.its.shape->getBSDF();
							/* Create hit point if this is a diffuse material or a glossy
							   one, and there has been a previous interaction with
							   a glossy material */
							if (bsdf->getType() == BSDF::EDiffuseReflection || 
								bsdf->getType() == BSDF::EDiffuseTransmission) {
								gatherPoint.weight = weight;
								gatherPoint.depth = depth;
								if (gatherPoint.its.isLuminaire())
									gatherPoint.emission = gatherPoint.its.Le(-ray.d);
								else
									gatherPoint.emission = Spectrum(0.0f);
								break;
							} else {
								/* Recurse for dielectric materials and (specific to SPPM):
								   recursive "final gathering" for glossy materials */
								BSDFQueryRecord bRec(gatherPoint.its);
								weight *= bsdf->sampleCos(bRec, sampler->next2D());
								if (weight.isZero()) {
									gatherPoint.depth = -1;
									break;
								}
								ray = RayDifferential(gatherPoint.its.p, 
									gatherPoint.its.toWorld(bRec.wo), ray.time);
								++depth;
							}
						} else {
							/* Generate an invalid sample */
							gatherPoint.depth = -1;
							break;
						}
					}
					sampler->advance();
				}
			}
		}
	}
예제 #18
0
void SurfacePointTask::Run() {
    // Declare common variables for _SurfacePointTask::Run()_
    RNG rng(37 * taskNum);
    MemoryArena arena;
    vector<SurfacePoint> candidates;
    while (true) {
        int pathsTraced, raysTraced = 0;
        for (pathsTraced = 0; pathsTraced < 20000; ++pathsTraced) {
            // Follow ray path and attempt to deposit candidate sample points
            Vector dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat());
            Ray ray(origin, dir, 0.f, INFINITY, time);
            while (ray.depth < 30) {
                // Find ray intersection with scene geometry or bounding sphere
                ++raysTraced;
                bool hitOnSphere = false;
                auto optIsect = scene.Intersect(ray);
                if (!optIsect) {
                    optIsect = sphere.Intersect(ray);
                    if (!optIsect)
                        break;
                    hitOnSphere = true;
                }
                DifferentialGeometry &hitGeometry = optIsect->dg;
                hitGeometry.nn = Faceforward(hitGeometry.nn, -ray.d);

                // Store candidate sample point at ray intersection if appropriate
                if (!hitOnSphere && ray.depth >= 3 &&
                    optIsect->GetBSSRDF(RayDifferential(ray), arena) != NULL) {
                    float area = M_PI * (minSampleDist / 2.f) * (minSampleDist / 2.f);
                    candidates.push_back(SurfacePoint(hitGeometry.p, hitGeometry.nn,
                                                      area, optIsect->rayEpsilon));
                }

                // Generate random ray from intersection point
                Vector dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat());
                dir = Faceforward(dir, hitGeometry.nn);
                ray = Ray(hitGeometry.p, dir, ray, optIsect->rayEpsilon);
            }
            arena.FreeAll();
        }
        // Make first pass through candidate points with reader lock
        vector<bool> candidateRejected;
        candidateRejected.reserve(candidates.size());
        RWMutexLock lock(mutex, READ);
        for (uint32_t i = 0; i < candidates.size(); ++i) {
            PoissonCheck check(minSampleDist, candidates[i].p);
            octree.Lookup(candidates[i].p, check);
            candidateRejected.push_back(check.failed);
        }

        // Make second pass through points with writer lock and update octree
        lock.UpgradeToWrite();
        if (repeatedFails >= maxFails)
            return;
        totalPathsTraced += pathsTraced;
        totalRaysTraced += raysTraced;
        int oldMaxRepeatedFails = maxRepeatedFails;
        for (uint32_t i = 0; i < candidates.size(); ++i) {
            if (candidateRejected[i]) {
                // Update for rejected candidate point
                ++repeatedFails;
                maxRepeatedFails = max(maxRepeatedFails, repeatedFails);
                if (repeatedFails >= maxFails)
                    return;
            }
            else {
                // Recheck candidate point and possibly add to octree
                SurfacePoint &sp = candidates[i];
                PoissonCheck check(minSampleDist, sp.p);
                octree.Lookup(sp.p, check);
                if (check.failed) {
                    // Update for rejected candidate point
                    ++repeatedFails;
                    maxRepeatedFails = max(maxRepeatedFails, repeatedFails);
                    if (repeatedFails >= maxFails)
                        return;
                }
                else {
                    ++numPointsAdded;
                    repeatedFails = 0;
                    Vector delta(minSampleDist, minSampleDist, minSampleDist);
                    octree.Add(sp, BBox(sp.p-delta, sp.p+delta));
                    PBRT_SUBSURFACE_ADDED_POINT_TO_OCTREE(&sp, minSampleDist);
                    surfacePoints.push_back(sp);
                }
            }
        }

        // Stop following paths if not finding new points
        if (repeatedFails > oldMaxRepeatedFails) {
            int delta = repeatedFails - oldMaxRepeatedFails;
            prog.Update(delta);
        }
        if (totalPathsTraced > 50000 && numPointsAdded == 0) {
            Warning("There don't seem to be any objects with BSSRDFs "
                    "in this scene.  Giving up.");
            return;
        }
        candidates.erase(candidates.begin(), candidates.end());
    }
}
예제 #19
0
파일: igi.cpp 프로젝트: ChiahungTai/pbrt-v2
void IGIIntegrator::Preprocess(const Scene *scene, const Camera *camera,
                               const Renderer *renderer) {
    if (scene->lights.size() == 0) return;
    MemoryArena arena;
    RNG rng;
    // Compute samples for emitted rays from lights
    vector<float> lightNum(nLightPaths * nLightSets);
    vector<float> lightSampPos(2 * nLightPaths * nLightSets, 0.f);
    vector<float> lightSampComp(nLightPaths * nLightSets, 0.f);
    vector<float> lightSampDir(2 * nLightPaths * nLightSets, 0.f);
    LDShuffleScrambled1D(nLightPaths, nLightSets, &lightNum[0], rng);
    LDShuffleScrambled2D(nLightPaths, nLightSets, &lightSampPos[0], rng);
    LDShuffleScrambled1D(nLightPaths, nLightSets, &lightSampComp[0], rng);
    LDShuffleScrambled2D(nLightPaths, nLightSets, &lightSampDir[0], rng);

    // Precompute information for light sampling densities
    Distribution1D *lightDistribution = ComputeLightSamplingCDF(scene);
    for (uint32_t s = 0; s < nLightSets; ++s) {
        for (uint32_t i = 0; i < nLightPaths; ++i) {
            // Follow path _i_ from light to create virtual lights
            int sampOffset = s*nLightPaths + i;

            // Choose light source to trace virtual light path from
            float lightPdf;
            int ln = lightDistribution->SampleDiscrete(lightNum[sampOffset],
                                                       &lightPdf);
            Light *light = scene->lights[ln];

            // Sample ray leaving light source for virtual light path
            RayDifferential ray;
            float pdf;
            LightSample ls(lightSampPos[2*sampOffset], lightSampPos[2*sampOffset+1],
                           lightSampComp[sampOffset]);
            Normal Nl;
            Spectrum alpha = light->Sample_L(scene, ls, lightSampDir[2*sampOffset],
                                             lightSampDir[2*sampOffset+1],
                                             camera->shutterOpen, &ray, &Nl, &pdf);
            if (pdf == 0.f || alpha.IsBlack()) continue;
            alpha /= pdf * lightPdf;
            Intersection isect;
            while (scene->Intersect(ray, &isect) && !alpha.IsBlack()) {
                // Create virtual light and sample new ray for path
                alpha *= renderer->Transmittance(scene, RayDifferential(ray), NULL,
                                                 rng, arena);
                Vector wo = -ray.d;
                BSDF *bsdf = isect.GetBSDF(ray, arena);

                // Create virtual light at ray intersection point
                Spectrum contrib = alpha * bsdf->rho(wo, rng) / M_PI;
                virtualLights[s].push_back(VirtualLight(isect.dg.p, isect.dg.nn, contrib,
                                                        isect.rayEpsilon));

                // Sample new ray direction and update weight for virtual light path
                Vector wi;
                float pdf;
                BSDFSample bsdfSample(rng);
                Spectrum fr = bsdf->Sample_f(wo, &wi, bsdfSample, &pdf);
                if (fr.IsBlack() || pdf == 0.f)
                    break;
                Spectrum contribScale = fr * AbsDot(wi, bsdf->dgShading.nn) / pdf;

                // Possibly terminate virtual light path with Russian roulette
                float rrProb = min(1.f, contribScale.y());
                if (rng.RandomFloat() > rrProb)
                    break;
                alpha *= contribScale / rrProb;
                ray = RayDifferential(isect.dg.p, wi, ray, isect.rayEpsilon);
            }
            arena.FreeAll();
        }
    }
    delete lightDistribution;
}
void PhotonIntegrator::Preprocess(const Scene *scene) {
	if (scene->lights.size() == 0) return;
	ProgressReporter progress(nCausticPhotons+nDirectPhotons+ // NOBOOK
		nIndirectPhotons, "Shooting photons"); // NOBOOK
	vector<Photon> causticPhotons;
	vector<Photon> directPhotons;
	vector<Photon> indirectPhotons;
	causticPhotons.reserve(nCausticPhotons); // NOBOOK
	directPhotons.reserve(nDirectPhotons); // NOBOOK
	indirectPhotons.reserve(nIndirectPhotons); // NOBOOK
	// Initialize photon shooting statistics
	static StatsCounter nshot("Photon Map",
		"Number of photons shot from lights");
	bool causticDone = (nCausticPhotons == 0);
	bool directDone = (nDirectPhotons == 0);
	bool indirectDone = (nIndirectPhotons == 0);
	while (!causticDone || !directDone || !indirectDone) {
		++nshot;
		// Give up if we're not storing enough photons
		if (nshot > 500000 &&
			(unsuccessful(nCausticPhotons,
			              causticPhotons.size(),
						  nshot) ||
			 unsuccessful(nDirectPhotons,
			              directPhotons.size(),
						  nshot) ||
			 unsuccessful(nIndirectPhotons,
			              indirectPhotons.size(),
						  nshot))) {
			Error("Unable to store enough photons.  Giving up.\n");
			return;
		}
		// Trace a photon path and store contribution
		// Choose 4D sample values for photon
		float u[4];
		u[0] = (float)RadicalInverse((int)nshot+1, 2);
		u[1] = (float)RadicalInverse((int)nshot+1, 3);
		u[2] = (float)RadicalInverse((int)nshot+1, 5);
		u[3] = (float)RadicalInverse((int)nshot+1, 7);
		// Choose light to shoot photon from
		int nLights = int(scene->lights.size());
		int lightNum =
			min(Floor2Int(nLights * (float)RadicalInverse((int)nshot+1, 11)),
			nLights-1);
		Light *light = scene->lights[lightNum];
		float lightPdf = 1.f / nLights;
		// Generate _photonRay_ from light source and initialize _alpha_
		RayDifferential photonRay;
		float pdf;
		Spectrum alpha =
			light->Sample_L(scene, u[0], u[1], u[2], u[3],
				&photonRay, &pdf);
		if (pdf == 0.f || alpha.Black()) continue;
		alpha /= pdf * lightPdf;
		if (!alpha.Black()) {
			// Follow photon path through scene and record intersections
			bool specularPath = false;
			Intersection photonIsect;
			int nIntersections = 0;
			while (scene->Intersect(photonRay, &photonIsect)) {
				++nIntersections;
				// Handle photon/surface intersection
				alpha *= scene->Transmittance(photonRay);
				Vector wo = -photonRay.d;
				BSDF *photonBSDF = photonIsect.GetBSDF(photonRay);
				BxDFType specularType = BxDFType(BSDF_REFLECTION |
					BSDF_TRANSMISSION | BSDF_SPECULAR);
				bool hasNonSpecular = (photonBSDF->NumComponents() >
					photonBSDF->NumComponents(specularType));
				if (hasNonSpecular) {
					// Deposit photon at surface
					Photon photon(photonIsect.dg.p, alpha, wo);
					if (nIntersections == 1) {
						// Process direct lighting photon intersection
						if (!directDone) {
							directPhotons.push_back(photon);
							if (directPhotons.size() == nDirectPhotons) {
								directDone = true;
								nDirectPaths = (int)nshot;
								directMap =
									new KdTree<Photon,
											   PhotonProcess>(directPhotons);
							}
							progress.Update(); // NOBOOK
						}
					}
					else if (specularPath) {
						// Process caustic photon intersection
						if (!causticDone) {
							causticPhotons.push_back(photon);
							if (causticPhotons.size() == nCausticPhotons) {
								causticDone = true;
								nCausticPaths = (int)nshot;
								causticMap =
									new KdTree<Photon,
										       PhotonProcess>(causticPhotons);
							}
							progress.Update();
						}
					}
					else {
						// Process indirect lighting photon intersection
						if (!indirectDone) {
							indirectPhotons.push_back(photon);
							if (indirectPhotons.size() == nIndirectPhotons) {
								indirectDone = true;
								nIndirectPaths = (int)nshot;
								indirectMap =
									new KdTree<Photon,
											   PhotonProcess>(indirectPhotons);
							}
							progress.Update();
						}
					}
				}
				// Sample new photon ray direction
				Vector wi;
				float pdf;
				BxDFType flags;
				// Get random numbers for sampling outgoing photon direction
				float u1, u2, u3;
				if (nIntersections == 1) {
					u1 = (float)RadicalInverse((int)nshot+1, 13);
					u2 = (float)RadicalInverse((int)nshot+1, 17);
					u3 = (float)RadicalInverse((int)nshot+1, 19);
				}
				else {
					u1 = RandomFloat();
					u2 = RandomFloat();
					u3 = RandomFloat();
				}
				Spectrum fr = photonBSDF->Sample_f(wo, &wi, u1, u2, u3,
					&pdf, BSDF_ALL, &flags);
				if (fr.Black() || pdf == 0.f)
					break;
				specularPath = (nIntersections == 1 || specularPath) &&
					((flags & BSDF_SPECULAR) != 0);
				alpha *= fr * AbsDot(wi, photonBSDF->dgShading.nn) / pdf;
				photonRay = RayDifferential(photonIsect.dg.p, wi);
				// Possibly terminate photon path
				if (nIntersections > 3) {
					float continueProbability = .5f;
					if (RandomFloat() > continueProbability)
						break;
					alpha /= continueProbability;
				}
			}
		}
		BSDF::FreeAll();
	}
	progress.Done(); // NOBOOK
}
void ExPhotonIntegrator::Preprocess(const Scene *scene) {
	if (scene->lights.size() == 0) return;
	ProgressReporter progress(nCausticPhotons+ // NOBOOK
		nIndirectPhotons, "Shooting photons"); // NOBOOK
	vector<Photon> causticPhotons;
	vector<Photon> indirectPhotons;
	vector<Photon> directPhotons;
	vector<RadiancePhoton> radiancePhotons;
	causticPhotons.reserve(nCausticPhotons); // NOBOOK
	indirectPhotons.reserve(nIndirectPhotons); // NOBOOK
	// Initialize photon shooting statistics
	static StatsCounter nshot("Photon Map",
		"Number of photons shot from lights");
	bool causticDone = (nCausticPhotons == 0);
	bool indirectDone = (nIndirectPhotons == 0);

	// Compute light power CDF for photon shooting
	int nLights = int(scene->lights.size());
	float *lightPower = (float *)alloca(nLights * sizeof(float));
	float *lightCDF = (float *)alloca((nLights+1) * sizeof(float));
	for (int i = 0; i < nLights; ++i)
		lightPower[i] = scene->lights[i]->Power(scene).y();
	float totalPower;
	ComputeStep1dCDF(lightPower, nLights, &totalPower, lightCDF);
	// Declare radiance photon reflectance arrays
	vector<Spectrum> rpReflectances, rpTransmittances;

	while (!causticDone || !indirectDone) {
		++nshot;
		// Give up if we're not storing enough photons
		if (nshot > 500000 &&
			(unsuccessful(nCausticPhotons,
			              causticPhotons.size(),
						  nshot) ||
			 unsuccessful(nIndirectPhotons,
			              indirectPhotons.size(),
						  nshot))) {
			Error("Unable to store enough photons.  Giving up.\n");
			return;
		}
		// Trace a photon path and store contribution
		// Choose 4D sample values for photon
		float u[4];
		u[0] = RadicalInverse((int)nshot+1, 2);
		u[1] = RadicalInverse((int)nshot+1, 3);
		u[2] = RadicalInverse((int)nshot+1, 5);
		u[3] = RadicalInverse((int)nshot+1, 7);

		// Choose light to shoot photon from
		float lightPdf;
		float uln = RadicalInverse((int)nshot+1, 11);
		int lightNum = Floor2Int(SampleStep1d(lightPower, lightCDF,
				totalPower, nLights, uln, &lightPdf) * nLights);
		lightNum = min(lightNum, nLights-1);
		const Light *light = scene->lights[lightNum];
		// Generate _photonRay_ from light source and initialize _alpha_
		RayDifferential photonRay;
		float pdf;
		Spectrum alpha = light->Sample_L(scene, u[0], u[1], u[2], u[3],
			&photonRay, &pdf);
		if (pdf == 0.f || alpha.Black()) continue;
		alpha /= pdf * lightPdf;

		if (!alpha.Black()) {
			// Follow photon path through scene and record intersections
			bool specularPath = false;
			Intersection photonIsect;
			int nIntersections = 0;
			while (scene->Intersect(photonRay, &photonIsect)) {
				++nIntersections;
				// Handle photon/surface intersection
				alpha *= scene->Transmittance(photonRay);
				Vector wo = -photonRay.d;
				BSDF *photonBSDF = photonIsect.GetBSDF(photonRay);
				BxDFType specularType = BxDFType(BSDF_REFLECTION |
					BSDF_TRANSMISSION | BSDF_SPECULAR);
				bool hasNonSpecular = (photonBSDF->NumComponents() >
					photonBSDF->NumComponents(specularType));
				if (hasNonSpecular) {
					// Deposit photon at surface
					Photon photon(photonIsect.dg.p, alpha, wo);
					if (nIntersections == 1) {
						// Deposit direct photon
						directPhotons.push_back(photon);
					}
					else {
						// Deposit either caustic or indirect photon
						if (specularPath) {
							// Process caustic photon intersection
							if (!causticDone) {
								causticPhotons.push_back(photon);
								if (causticPhotons.size() == nCausticPhotons) {
									causticDone = true;
									nCausticPaths = (int)nshot;
									causticMap = new KdTree<Photon, PhotonProcess>(causticPhotons);
								}
								progress.Update();
							}
						}
						else {
							// Process indirect lighting photon intersection
							if (!indirectDone) {
								indirectPhotons.push_back(photon);
								if (indirectPhotons.size() == nIndirectPhotons) {
									indirectDone = true;
									nIndirectPaths = (int)nshot;
									indirectMap = new KdTree<Photon, PhotonProcess>(indirectPhotons);
								}
								progress.Update();
							}
						}
					}
					if (finalGather && RandomFloat() < .125f) {
						// Store data for radiance photon
						static StatsCounter rp("Photon Map", "Radiance photons created"); // NOBOOK
						++rp; // NOBOOK
						Normal n = photonIsect.dg.nn;
						if (Dot(n, photonRay.d) > 0.f) n = -n;
						radiancePhotons.push_back(RadiancePhoton(photonIsect.dg.p, n));
						Spectrum rho_r = photonBSDF->rho(BSDF_ALL_REFLECTION);
						rpReflectances.push_back(rho_r);
						Spectrum rho_t = photonBSDF->rho(BSDF_ALL_TRANSMISSION);
						rpTransmittances.push_back(rho_t);
					}
				}
				// Sample new photon ray direction
				Vector wi;
				float pdf;
				BxDFType flags;
				// Get random numbers for sampling outgoing photon direction
				float u1, u2, u3;
				if (nIntersections == 1) {
					u1 = RadicalInverse((int)nshot+1, 13);
					u2 = RadicalInverse((int)nshot+1, 17);
					u3 = RadicalInverse((int)nshot+1, 19);
				}
				else {
					u1 = RandomFloat();
					u2 = RandomFloat();
					u3 = RandomFloat();
				}

				// Compute new photon weight and possibly terminate with RR
				Spectrum fr = photonBSDF->Sample_f(wo, &wi, u1, u2, u3,
				                                   &pdf, BSDF_ALL, &flags);
				if (fr.Black() || pdf == 0.f)
					break;
				Spectrum anew = alpha * fr *
					AbsDot(wi, photonBSDF->dgShading.nn) / pdf;
				float continueProb = min(1.f, anew.y() / alpha.y());
				if (RandomFloat() > continueProb || nIntersections > 10)
					break;
				alpha = anew / continueProb;
				specularPath = (nIntersections == 1 || specularPath) &&
					((flags & BSDF_SPECULAR) != 0);
				photonRay = RayDifferential(photonIsect.dg.p, wi);
			}
		}
		BSDF::FreeAll();
	}

	progress.Done(); // NOBOOK

	// Precompute radiance at a subset of the photons
	KdTree<Photon, PhotonProcess> directMap(directPhotons);
	int nDirectPaths = nshot;
	if (finalGather) {
		ProgressReporter p2(radiancePhotons.size(), "Computing photon radiances"); // NOBOOK
		for (u_int i = 0; i < radiancePhotons.size(); ++i) {
			// Compute radiance for radiance photon _i_
			RadiancePhoton &rp = radiancePhotons[i];
			const Spectrum &rho_r = rpReflectances[i];
			const Spectrum &rho_t = rpTransmittances[i];
			Spectrum E;
			Point p = rp.p;
			Normal n = rp.n;
			if (!rho_r.Black()) {
				E = estimateE(&directMap,  nDirectPaths,   p, n) +
					estimateE(indirectMap, nIndirectPaths, p, n) +
					estimateE(causticMap,  nCausticPaths,  p, n);
				rp.Lo += E * INV_PI * rho_r;
			}
			if (!rho_t.Black()) {
				E = estimateE(&directMap,  nDirectPaths,   p, -n) +
					estimateE(indirectMap, nIndirectPaths, p, -n) +
					estimateE(causticMap,  nCausticPaths,  p, -n);
				rp.Lo += E * INV_PI * rho_t;
			}
			p2.Update(); // NOBOOK
		}
		radianceMap = new KdTree<RadiancePhoton,
			RadiancePhotonProcess>(radiancePhotons);
		p2.Done(); // NOBOOK
	}
}
예제 #22
0
void IGIIntegrator::Preprocess(const Scene *scene) {
	if (scene->lights.size() == 0) return;
	// Compute samples for emitted rays from lights
	float *lightNum = new float[nLightPaths * nLightSets];
	float *lightSamp0 = new float[2 * nLightPaths *	nLightSets];
	float *lightSamp1 = new float[2 * nLightPaths * nLightSets];
	LDShuffleScrambled1D(nLightPaths, nLightSets, lightNum);
	LDShuffleScrambled2D(nLightPaths, nLightSets, lightSamp0);
	LDShuffleScrambled2D(nLightPaths, nLightSets, lightSamp1);
	// Precompute information for light sampling densities
	int nLights = int(scene->lights.size());
	float *lightPower = (float *)alloca(nLights * sizeof(float));
	float *lightCDF = (float *)alloca((nLights+1) * sizeof(float));
	for (int i = 0; i < nLights; ++i)
		lightPower[i] = scene->lights[i]->Power(scene).y();
	float totalPower;
	ComputeStep1dCDF(lightPower, nLights, &totalPower, lightCDF);
	for (u_int s = 0; s < nLightSets; ++s) {
		for (u_int i = 0; i < nLightPaths; ++i) {
			// Follow path _i_ from light to create virtual lights
			int sampOffset = s*nLightPaths + i;
			// Choose light source to trace path from
			float lightPdf;
			int lNum = Floor2Int(SampleStep1d(lightPower, lightCDF,
				totalPower, nLights, lightNum[sampOffset], &lightPdf) * nLights);
//			fprintf(stderr, "samp %f -> num %d\n", lightNum[sampOffset], lNum);
			Light *light = scene->lights[lNum];
			// Sample ray leaving light source
			RayDifferential ray;
			float pdf;
			Spectrum alpha =
				light->Sample_L(scene, lightSamp0[2*sampOffset],
						lightSamp0[2*sampOffset+1],
						lightSamp1[2*sampOffset],
						lightSamp1[2*sampOffset+1],
						&ray, &pdf);
			if (pdf == 0.f || alpha.Black()) continue;
			alpha /= pdf * lightPdf;
//			fprintf(stderr, "initial alpha %f, light # %d\n", alpha.y(), lNum);
			Intersection isect;
			int nIntersections = 0;
			while (scene->Intersect(ray, &isect) && !alpha.Black()) {
				++nIntersections;
				alpha *= scene->Transmittance(ray);
				Vector wo = -ray.d;
				BSDF *bsdf = isect.GetBSDF(ray);
				// Create virtual light at ray intersection point
				static StatsCounter vls("IGI Integrator", "Virtual Lights Created"); //NOBOOK
				++vls; //NOBOOK
				Spectrum Le = alpha * bsdf->rho(wo) / M_PI;
//				fprintf(stderr, "\tmade light with le y %f\n", Le.y());
				virtualLights[s].push_back(VirtualLight(isect.dg.p, isect.dg.nn, Le));
				// Sample new ray direction and update weight
				Vector wi;
				float pdf;
				BxDFType flags;
				Spectrum fr = bsdf->Sample_f(wo, &wi, RandomFloat(),
								 RandomFloat(), RandomFloat(),
								 &pdf, BSDF_ALL, &flags);
				if (fr.Black() || pdf == 0.f)
					break;
				Spectrum anew = alpha * fr * AbsDot(wi, bsdf->dgShading.nn) / pdf;
				float r = anew.y() / alpha.y();
//				fprintf(stderr, "\tr = %f\n", r);
				if (RandomFloat() > r)
					break;
				alpha = anew / r;
//				fprintf(stderr, "\tnew alpha %f\n", alpha.y());
				ray = RayDifferential(isect.dg.p, wi);
			}
			BSDF::FreeAll();
		}
	}
	delete[] lightNum; // NOBOOK
	delete[] lightSamp0; // NOBOOK
	delete[] lightSamp1; // NOBOOK
}
예제 #23
0
파일: path.cpp 프로젝트: sungsoo/pbrt-v2
Spectrum PathIntegrator::Li(const Scene *scene, const Renderer *renderer,
        const RayDifferential &r, const Intersection &isect,
        const Sample *sample, MemoryArena &arena) const {
    // Declare common path integration variables
    Spectrum pathThroughput = 1., L = 0.;
    RayDifferential ray(r);
    bool specularBounce = false;
    Intersection localIsect;
    const Intersection *isectp = &isect;
    for (int pathLength = 0; ; ++pathLength) {
        // Possibly add emitted light at path vertex
        if (pathLength == 0 || specularBounce)
            L += pathThroughput * isectp->Le(-ray.d);

        // Sample illumination from lights to find path contribution
        BSDF *bsdf = isectp->GetBSDF(ray, arena);
        const Point &p = bsdf->dgShading.p;
        const Normal &n = bsdf->dgShading.nn;
        Vector wo = -ray.d;
        if (pathLength < SAMPLE_DEPTH)
            L += pathThroughput *
                 UniformSampleOneLight(scene, renderer, arena, p, n, wo,
                     isectp->RayEpsilon, bsdf, sample, lightNumOffset[pathLength],
                     &lightSampleOffsets[pathLength], &bsdfSampleOffsets[pathLength]);
        else
            L += pathThroughput *
                 UniformSampleOneLight(scene, renderer, arena, p, n, wo,
                     isectp->RayEpsilon, bsdf, sample);

        // Sample BSDF to get new path direction

        // Get _outgoingBSDFSample_ for sampling new path direction
        BSDFSample outgoingBSDFSample;
        if (pathLength < SAMPLE_DEPTH)
            outgoingBSDFSample = BSDFSample(sample, pathSampleOffsets[pathLength], 0);
        else
            outgoingBSDFSample = BSDFSample(*sample->rng);
        Vector wi;
        float pdf;
        BxDFType flags;
        Spectrum f = bsdf->Sample_f(wo, &wi, outgoingBSDFSample,
                                    &pdf, BSDF_ALL, &flags);
        if (f.IsBlack() || pdf == 0.)
            break;
        specularBounce = (flags & BSDF_SPECULAR) != 0;
        pathThroughput *= f * AbsDot(wi, n) / pdf;
        ray = RayDifferential(p, wi, ray, isectp->RayEpsilon);

        // Possibly terminate the path
        if (pathLength > 3) {
            float continueProbability = min(.5f, pathThroughput.y());
            if (sample->rng->RandomFloat() > continueProbability)
                break;
            pathThroughput /= continueProbability;
        }
        if (pathLength == maxDepth)
            break;

        // Find next vertex of path
        if (!scene->Intersect(ray, &localIsect)) {
            if (specularBounce) {
                for (u_int i = 0; i < scene->lights.size(); ++i)
                   L += pathThroughput * scene->lights[i]->Le(ray);
            }
            break;
        }
        if (pathLength > 1)
            pathThroughput *= renderer->Transmittance(scene, ray, NULL, arena, sample->rng);
        isectp = &localIsect;
    }
    return L;
}
예제 #24
0
Spectrum_d PhotonLTEIntegrator::_FinalGather(const Intersection &i_intersection, const Vector3D_d &i_incident, const BSDF *ip_bsdf, const Sample *ip_sample, ThreadSpecifics i_ts) const
  {
  ASSERT(ip_bsdf);
  ASSERT(mp_irradiance_map);
  ASSERT(i_incident.IsNormalized());
  MemoryPool *p_pool = i_ts.mp_pool;
  RandomGenerator<double> *p_rng = i_ts.mp_random_generator;
  Vector3D_d shading_normal = ip_bsdf->GetShadingNormal();

  const double cos_gather_angle = 0.9848; // 10 degrees
  const double cone_pdf = SamplingRoutines::UniformConePDF(cos_gather_angle);

  BxDFType non_specular = BxDFType(BSDF_REFLECTION | BSDF_TRANSMISSION | BSDF_DIFFUSE | BSDF_GLOSSY);
  size_t gather_samples = m_params.m_gather_samples_num;
  if (gather_samples == 0)
    return Spectrum_d();

  // Maybe it is worth to put this block out of the _FinalGather() method to improve the performance.
  const size_t samples_num_sqrt = 5;
  Point2D_d bsdf_scattering_samples[samples_num_sqrt*samples_num_sqrt];
  SamplesSequence2D bsdf_scattering_sequence(bsdf_scattering_samples, bsdf_scattering_samples + samples_num_sqrt*samples_num_sqrt);
  SamplingRoutines::StratifiedSampling2D(bsdf_scattering_sequence.m_begin, samples_num_sqrt, samples_num_sqrt, false);

  SamplesSequence1D bsdf_1D_samples, direction_1D_samples;
  SamplesSequence2D bsdf_2D_samples, direction_2D_samples;
  if (ip_sample)
    {
    bsdf_1D_samples = ip_sample->GetSamplesSequence1D(m_bsdf_1D_samples_id);
    bsdf_2D_samples = ip_sample->GetSamplesSequence2D(m_bsdf_2D_samples_id);

    direction_1D_samples = ip_sample->GetSamplesSequence1D(m_direction_1D_samples_id);
    direction_2D_samples = ip_sample->GetSamplesSequence2D(m_direction_2D_samples_id);
    }
  else
    {
    size_t gather_samples_sqrt = (size_t) ceil(sqrt((double)gather_samples));
    gather_samples = gather_samples_sqrt*gather_samples_sqrt;

    // BSDF samples.
    double *bsdf_samples_1D = (double *)p_pool->Alloc( gather_samples * sizeof(double) );
    Point2D_d *bsdf_samples_2D = (Point2D_d *)p_pool->Alloc( gather_samples * sizeof(Point2D_d) );

    bsdf_1D_samples = SamplesSequence1D(bsdf_samples_1D, bsdf_samples_1D+gather_samples);
    bsdf_2D_samples = SamplesSequence2D(bsdf_samples_2D, bsdf_samples_2D+gather_samples);

    SamplingRoutines::StratifiedSampling1D(bsdf_1D_samples.m_begin, gather_samples, true, p_rng);
    SamplingRoutines::StratifiedSampling2D(bsdf_2D_samples.m_begin, gather_samples_sqrt, gather_samples_sqrt, true, p_rng);

    // Direction samples.
    double *direction_samples_1D = (double *)p_pool->Alloc( gather_samples * sizeof(double) );
    Point2D_d *direction_samples_2D = (Point2D_d *)p_pool->Alloc( gather_samples * sizeof(Point2D_d) );

    direction_1D_samples = SamplesSequence1D(direction_samples_1D, direction_samples_1D+gather_samples);
    direction_2D_samples = SamplesSequence2D(direction_samples_2D, direction_samples_2D+gather_samples);

    SamplingRoutines::StratifiedSampling1D(direction_1D_samples.m_begin, gather_samples, true, p_rng);
    SamplingRoutines::StratifiedSampling2D(direction_2D_samples.m_begin, gather_samples_sqrt, gather_samples_sqrt, true, p_rng);
    }

  // Allocate array for the nearest photons.
  size_t photons_found = 0;
  NearestPhoton *p_nearest_photons = (NearestPhoton*)p_pool->Alloc(32 * sizeof(NearestPhoton));

  // Search for nearest indirect photons.
  if (mp_photon_maps->GetIndirectMap() && mp_photon_maps->GetIndirectMap()->GetNumberOfPoints()>0)
    {
    double indirect_photon_area = m_scene_total_area / mp_photon_maps->GetIndirectMap()->GetNumberOfPoints();
    double max_lookup_dist = sqrt(indirect_photon_area*32*INV_PI);
    PhotonFilter filter(i_intersection.m_dg.m_point, ip_bsdf->GetGeometricNormal(), MAX_NORMAL_DEVIATION_COS);
    photons_found = mp_photon_maps->GetIndirectMap()->GetNearestPoints(i_intersection.m_dg.m_point, 32, p_nearest_photons, filter, max_lookup_dist);
    }
  double inv_photons_found = (photons_found>0) ? 1.0/photons_found : 0.0;

  // Copy photon directions to a local array.
  Vector3D_d *photon_directions = (Vector3D_d*)p_pool->Alloc(photons_found * sizeof(Vector3D_d));
  for (size_t i=0;i<photons_found;++i)
    photon_directions[i] = p_nearest_photons[i].mp_point->m_incident_direction.ToVector3D<double>();

  size_t gather_rays = 0;
  Vector3D_d *p_gather_directions = (Vector3D_d*)p_pool->Alloc( 2 * gather_samples * sizeof(Vector3D_d) );
  SpectrumCoef_d *p_gather_weights = (SpectrumCoef_d*)p_pool->Alloc( 2 * gather_samples * sizeof(SpectrumCoef_d) );

  // Sample BSDF.
  SamplesSequence1D::Iterator iterator_1D = bsdf_1D_samples.m_begin;
  SamplesSequence2D::Iterator iterator_2D = bsdf_2D_samples.m_begin;
  for (size_t i=0;i<gather_samples;++i)
    {
    double component_sample = *iterator_1D;
    Point2D_d bxdf_sample = *iterator_2D;

    double bsdf_pdf = 0.0;
    BxDFType sampled_type;
    Vector3D_d exitant;
    SpectrumCoef_d reflectance = ip_bsdf->Sample(i_incident, exitant, bxdf_sample, component_sample, bsdf_pdf, sampled_type, BxDFType(BSDF_ALL & ~BSDF_SPECULAR));
    if (bsdf_pdf>0.0 && reflectance.IsBlack()==false)
      {
      // Compute PDF for photon-sampling for the sampled direction.
      // We construct a cone around each photon and sample directions in the cone uniformly.
      double photon_pdf = 0.0;
      for (size_t j=0;j<photons_found;++j)
        if (photon_directions[j]*exitant > cos_gather_angle)
          photon_pdf += cone_pdf;
      photon_pdf *= inv_photons_found;

      double weight = SamplingRoutines::PowerHeuristic(gather_samples, bsdf_pdf, gather_samples, photon_pdf);

      p_gather_directions[gather_rays] = exitant;
      p_gather_weights[gather_rays] = reflectance * (weight * fabs(exitant*shading_normal) / bsdf_pdf);
      ++gather_rays;
      }

    ++iterator_1D;
    ++iterator_2D;
    }

  // Sample nearby photons.
  iterator_1D = direction_1D_samples.m_begin;
  iterator_2D = direction_2D_samples.m_begin;
  for (size_t i=0;i<gather_samples && photons_found>0;++i)
    {
    size_t sampled_index = (size_t)( (*iterator_1D) * photons_found);

    // Sample gather ray direction.
    Vector3D_d e2, e3;
    MathRoutines::CoordinateSystem(photon_directions[sampled_index], e2, e3);
    Vector3D_d direction_local = SamplingRoutines::UniformConeSampling(*iterator_2D, cos_gather_angle);
    Vector3D_d exitant = direction_local[0]*e2 + direction_local[1]*e3 + direction_local[2]*photon_directions[sampled_index];

    SpectrumCoef_d reflectance = ip_bsdf->Evaluate(i_incident, exitant);
    if (reflectance.IsBlack()==false)
      {
      double bsdf_pdf = ip_bsdf->PDF(i_incident, exitant);

      // Compute PDF for photon-sampling of direction exitant.
      // We construct a cone around each photon and sample directions in the cone uniformly.
      double photon_pdf = 0.0;
      for (size_t j=0;j<photons_found;++j)
        if (photon_directions[j]*exitant > cos_gather_angle)
          photon_pdf += cone_pdf;
      photon_pdf *= inv_photons_found;

      double weight = SamplingRoutines::PowerHeuristic(gather_samples, photon_pdf, gather_samples, bsdf_pdf);

      p_gather_directions[gather_rays] = exitant;
      p_gather_weights[gather_rays] = reflectance * (weight * fabs(exitant*shading_normal) / photon_pdf);
      ++gather_rays;
      }

    ++iterator_1D;
    ++iterator_2D;
    }

  // Trace final gather rays and compute the radiance.
  Spectrum_d radiance;
  for(size_t i=0;i<gather_rays;++i)
    {
    Ray bounce_ray(i_intersection.m_dg.m_point, p_gather_directions[i]);
    bounce_ray.m_min_t = CoreUtils::GetNextMinT(i_intersection, p_gather_directions[i]);
  
    Intersection gather_isect;
    if (mp_scene->Intersect(RayDifferential(bounce_ray), gather_isect, &bounce_ray.m_max_t))
      {
      // Compute exitant radiance at the final gather intersection.
      Vector3D_d gather_direction = bounce_ray.m_direction*(-1.0);
      const BSDF *p_gather_BSDF = gather_isect.mp_primitive->GetBSDF(gather_isect.m_dg, gather_isect.m_triangle_index, *p_pool);
      Vector3D_d gather_geometric_normal = p_gather_BSDF->GetGeometricNormal();

      IrradiancePhotonFilter filter(gather_isect.m_dg.m_point, gather_geometric_normal, MAX_NORMAL_DEVIATION_COS);
      const IrradiancePhoton *p_irradiance_photon = mp_irradiance_map->GetNearestPoint(gather_isect.m_dg.m_point, filter, m_max_irradiance_lookup_dist);
      if (p_irradiance_photon == NULL)
        continue;

      Spectrum_d tmp;
      if (gather_direction*gather_geometric_normal > 0.0)
        {
        tmp += p_gather_BSDF->TotalScattering(gather_direction, bsdf_scattering_sequence, BxDFType(BSDF_ALL_REFLECTION))  *Convert<double>(p_irradiance_photon->m_external_irradiance);
        tmp += p_gather_BSDF->TotalScattering(gather_direction, bsdf_scattering_sequence, BxDFType(BSDF_ALL_TRANSMISSION))*Convert<double>(p_irradiance_photon->m_internal_irradiance);
        }
      else
        {
        tmp += p_gather_BSDF->TotalScattering(gather_direction, bsdf_scattering_sequence, BxDFType(BSDF_ALL_REFLECTION))  *Convert<double>(p_irradiance_photon->m_internal_irradiance);
        tmp += p_gather_BSDF->TotalScattering(gather_direction, bsdf_scattering_sequence, BxDFType(BSDF_ALL_TRANSMISSION))*Convert<double>(p_irradiance_photon->m_external_irradiance);
        }

      tmp *= INV_PI;
      radiance += tmp * _MediaTransmittance(bounce_ray, i_ts) * p_gather_weights[i];
      }
    }

  return radiance / (double)gather_samples;
  }
예제 #25
0
Spectrum IrradianceCache::IndirectLo(const Point &p,
		const Normal &n, const Vector &wo, BSDF *bsdf,
		BxDFType flags, const Sample *sample,
		const Scene *scene) const {
	if (bsdf->NumComponents(flags) == 0)
		return Spectrum(0.);
	Spectrum E;
	if (!InterpolateIrradiance(scene, p, n, &E)) {
		// Compute irradiance at current point
		u_int scramble[2] = { RandomUInt(), RandomUInt() };
		float sumInvDists = 0.;
		for (int i = 0; i < nSamples; ++i) {
			// Trace ray to sample radiance for irradiance estimate
			// Update irradiance statistics for rays traced
			static StatsCounter nIrradiancePaths("Irradiance Cache",
				"Paths followed for irradiance estimates");
			++nIrradiancePaths;
			float u[2];
			Sample02(i, scramble, u);
			Vector w = CosineSampleHemisphere(u[0], u[1]);
			RayDifferential r(p, bsdf->LocalToWorld(w));
			if (Dot(r.d, n) < 0) r.d = -r.d;
			Spectrum L(0.);
			// Do path tracing to compute radiance along ray for estimate
			{
			// Declare common path integration variables
			Spectrum pathThroughput = 1.;
			RayDifferential ray(r);
			bool specularBounce = false;
			for (int pathLength = 0; ; ++pathLength) {
				// Find next vertex of path
				Intersection isect;
				if (!scene->Intersect(ray, &isect))
					break;
				if (pathLength == 0)
					r.maxt = ray.maxt;
				pathThroughput *= scene->Transmittance(ray);
				// Possibly add emitted light at path vertex
				if (specularBounce)
					L += pathThroughput * isect.Le(-ray.d);
				// Evaluate BSDF at hit point
				BSDF *bsdf = isect.GetBSDF(ray);
				// Sample illumination from lights to find path contribution
				const Point &p = bsdf->dgShading.p;
				const Normal &n = bsdf->dgShading.nn;
				Vector wo = -ray.d;
				L += pathThroughput *
					UniformSampleOneLight(scene, p, n, wo, bsdf, sample);
				if (pathLength+1 == maxIndirectDepth) break;
				// Sample BSDF to get new path direction
				// Get random numbers for sampling new direction, \mono{bs1}, \mono{bs2}, and \mono{bcs}
				float bs1 = RandomFloat(), bs2 = RandomFloat(), bcs = RandomFloat();
				Vector wi;
				float pdf;
				BxDFType flags;
				Spectrum f = bsdf->Sample_f(wo, &wi, bs1, bs2, bcs,
					&pdf, BSDF_ALL, &flags);
				if (f.Black() || pdf == 0.)
					break;
				specularBounce = (flags & BSDF_SPECULAR) != 0;
				pathThroughput *= f * AbsDot(wi, n) / pdf;
				ray = RayDifferential(p, wi);
				// Possibly terminate the path
				if (pathLength > 3) {
					float continueProbability = .5f;
					if (RandomFloat() > continueProbability)
						break;
					pathThroughput /= continueProbability;
				}
			}
			}
			E += L;
			float dist = r.maxt * r.d.Length();
			sumInvDists += 1.f / dist;
		}
		E *= M_PI / float(nSamples);
		// Add computed irradiance value to cache
		// Update statistics for new irradiance sample
		static StatsCounter nSamplesComputed("Irradiance Cache",
			"Irradiance estimates computed");
		++nSamplesComputed;
		// Compute bounding box of irradiance sample's contribution region
		static float minMaxDist =
			.001f * powf(scene->WorldBound().Volume(), 1.f/3.f);
		static float maxMaxDist =
			.125f * powf(scene->WorldBound().Volume(), 1.f/3.f);
		float maxDist = nSamples / sumInvDists;
		if (minMaxDist > 0.f)
			maxDist = Clamp(maxDist, minMaxDist, maxMaxDist);
		maxDist *= maxError;
		BBox sampleExtent(p);
		sampleExtent.Expand(maxDist);
		octree->Add(IrradianceSample(E, p, n, maxDist),
			sampleExtent);
	}
	return .5f * bsdf->rho(wo, flags) * E;
}
예제 #26
0
파일: volpath.cpp 프로젝트: BlueBrain/pbrt
void VolumePatIntegrator::EyeRandomWalk(const Scene *scene, const Ray &eyeRay,
        VolumeVertexList& vertexList, RNG &rng) const {
    // Do a random walk for the eye ray in the volume
    Spectrum cummulative(1.f);

    // Find the intersection between the eye ray and the volume
    VolumeRegion *vr = scene->volumeRegion;
    float t0, t1;
    if (!vr || !vr->IntersectP(eyeRay, &t0, &t1) || (t1-t0) == 0.f || t0 < 0.f) {
        return;
    }

    // Find the intersection point between the sampled light ray and the volume
    RayDifferential ray(eyeRay);
    Point p = ray(t0), pPrev;
    uint64_t bounces = 0;
    while(vr->WorldBound().Inside(p)) {
        Vector wi = -ray.d;
        const Spectrum sigma_a = vr->Sigma_a(p, wi, eyeRay.time);
        const Spectrum sigma_s = vr->Sigma_s(p, wi, eyeRay.time);
        const Spectrum STER = vr->STER(p, wi, eyeRay.time);
        // Construct and add the _eyeVertex_ to the _vertexList_
        VolumeVertex eyeVertex(p, wi, sigma_a, sigma_s, cummulative, 1.0);
        vertexList.push_back(eyeVertex);

        // Sample the direction of the next event
        float directionPdf = 1.f;
        Vector wo;
        if(STER.y() > rng.RandomFloat()) {
            // Change the ray direction due to a scattering event at _p_
            if(!vr->SampleDirection(p, wi, wo, &directionPdf, rng)) {
                break; // Direction error
            }

            // Account for the losses due to the scattering event at _p_
            cummulative *= sigma_s * vr->p(p, wi, wo, ray.time);
        } else {
            // Account only for the trnsmittance between the previous and the
            // next events becuse there is no direction change.
            wo = ray.d;
        }

        // Sample the distance of the next event
        ray = RayDifferential(p, wo, 0, INFINITY);

        float tDist;
        float distancePdf = 1.f;
        Point Psample;
        if(!vr->SampleDistance(ray, &tDist, Psample, &distancePdf, rng)) {
            break; // The sampled point is outside the volume
        }

        // Account for the sampling Pdfs from sampling a direction and/or distance
        const float pdf = distancePdf * directionPdf;
        cummulative *= 1 / pdf;

        // Update the events and account for the transmittance between the events
        pPrev = p;
        p = Psample;
        const Ray tauRay(pPrev, p - pPrev, 0.f, 1.f, ray.time, ray.depth);
        const Spectrum stepTau = vr->tau(tauRay, .5f * stepSize, rng.RandomFloat());
        const Spectrum TrPP = Exp(-stepTau);
        cummulative *= TrPP;

        // Possibly terminate ray marching if _cummulative_ is small
        if (cummulative.y() < 1e-3) {
            const float continueProb = .5f;
            if (rng.RandomFloat() > continueProb) {
                cummulative = 0.f;
                break;
            }
            cummulative /= continueProb;
        }

        // Terminate if bounces are more than requested
        bounces++;
        if (bounces > maxDepth) {
            break;
        }
    }
}
예제 #27
0
파일: light.cpp 프로젝트: AI42/OM3D
Spectrum VisibilityTester::Transmittance(const Scene *scene,
        const Renderer *renderer, const Sample *sample,
        RNG &rng, MemoryArena &arena) const {
    return renderer->Transmittance(scene, RayDifferential(r), sample,
                                   rng, arena);
}
예제 #28
0
void LightShootingTask::Run() {
    // tady by mel byt kod z photon mappingu

    MemoryArena arena;
    uint32_t totalPaths = 0;
    RNG rng(seed);
    PermutedHalton halton(6, rng);
    while (true) {
        // Follow photon paths for a block of samples
        const uint32_t blockSize = 4096;
        for (uint32_t i = 0; i < blockSize; ++i) {
            float u[6];
            halton.Sample(++totalPaths, u);
            // Choose light to shoot photon from
            float lightPdf;
            int lightNum = lightDistribution->SampleDiscrete(u[0], &lightPdf);
            const Light *light = scene->lights[lightNum];

            // Generate _photonRay_ from light source and initialize _alpha_
            RayDifferential photonRay;
            float pdf;
            LightSample ls(u[1], u[2], u[3]);
            Normal Nl;
            Spectrum Le = light->Sample_L(scene, ls, u[4], u[5],time, &photonRay, &Nl, &pdf);
            if (pdf == 0.f || Le.IsBlack()) continue;
            Spectrum alpha = (AbsDot(Nl, photonRay.d) * Le) / (pdf * lightPdf);

            if (!alpha.IsBlack()) {
                // Follow photon path through scene and record intersections
                PBRT_PHOTON_MAP_STARTED_RAY_PATH(&photonRay, &alpha);
                bool specularPath = true;
                Intersection photonIsect;
                int nIntersections = 0;
                while (scene->Intersect(photonRay, &photonIsect)) {
                    ++nIntersections;
                    //MC tady by mel byt i kod pro volumetriku

                    // Handle photon/surface intersection
                    // alpha *= renderer->Transmittance(scene, photonRay, NULL, rng, arena);
                    BSDF *photonBSDF = photonIsect.GetBSDF(photonRay, arena);

                    Vector wo = -photonRay.d;
                    //MC tady se ukladaly photony takze tady bych mel ukladat samples do filmu kamery
                    //  // Deposit photon at surface
                    //Photon photon(photonIsect.dg.p, alpha, wo);
                    //tuhle metodu chci pouzit
                    //filmAddSample()

                    if (nIntersections >= maxDepth) break;

                    // Sample new photon ray direction
                    Vector wi;
                    float pdf;
                    BxDFType flags;
                    Spectrum fr = photonBSDF->Sample_f(wo, &wi, BSDFSample(rng),
                                                       &pdf, BSDF_ALL, &flags);

                    if (fr.IsBlack() || pdf == 0.f) break;
                    Spectrum anew = alpha * fr *
                                    AbsDot(wi, photonBSDF->dgShading.nn) / pdf;

                    // Possibly terminate photon path with Russian roulette
                    float continueProb = min(1.f, anew.y() / alpha.y());
                    if (rng.RandomFloat() > continueProb)
                        break;
                    alpha = anew / continueProb;
                    specularPath &= ((flags & BSDF_SPECULAR) != 0);

                    photonRay = RayDifferential(photonIsect.dg.p, wi, photonRay,
                                                photonIsect.rayEpsilon);

                }
                PBRT_PHOTON_MAP_FINISHED_RAY_PATH(&photonRay, &alpha);
            }

            arena.FreeAll();
        }

        //termination criteria ???
        if (totalPaths==maxPathCount) {
            break;
        }
    }
}