void PathCPURenderThread::DirectHitInfiniteLight(
		const bool lastSpecular, const Spectrum &pathThrouput,
		const Vector &eyeDir, const float lastPdfW, Spectrum *radiance) {
	PathCPURenderEngine *engine = (PathCPURenderEngine *)renderEngine;
	Scene *scene = engine->renderConfig->scene;

	// Infinite light
	float directPdfW;
	if (scene->envLight) {
		const Spectrum envRadiance = scene->envLight->GetRadiance(scene, -eyeDir, &directPdfW);
		if (!envRadiance.Black()) {
			if(!lastSpecular) {
				// MIS between BSDF sampling and direct light sampling
				*radiance += pathThrouput * PowerHeuristic(lastPdfW, directPdfW) * envRadiance;
			} else
				*radiance += pathThrouput * envRadiance;
		}
	}

	// Sun light
	if (scene->sunLight) {
		const Spectrum sunRadiance = scene->sunLight->GetRadiance(scene, -eyeDir, &directPdfW);
		if (!sunRadiance.Black()) {
			if(!lastSpecular) {
				// MIS between BSDF sampling and direct light sampling
				*radiance += pathThrouput * PowerHeuristic(lastPdfW, directPdfW) * sunRadiance;
			} else
				*radiance += pathThrouput * sunRadiance;
		}
	}
}
예제 #2
0
Spectrum EstimateDirect(const Scene *scene, const Renderer *renderer,
        MemoryArena &arena, const Light *light, const Point &p,
        const Normal &n, const Vector &wo, float rayEpsilon, float time,
        const BSDF *bsdf, RNG &rng, const LightSample &lightSample,
        const BSDFSample &bsdfSample, BxDFType flags) {
    Spectrum Ld(0.);
    // Sample light source with multiple importance sampling
    Vector wi;
    float lightPdf, bsdfPdf;
    VisibilityTester visibility;
    Spectrum Li = light->Sample_L(p, rayEpsilon, lightSample, time,
                                  &wi, &lightPdf, &visibility);
    if (lightPdf > 0. && !Li.IsBlack()) {
        Spectrum f = bsdf->f(wo, wi, flags);
        if (!f.IsBlack() && visibility.Unoccluded(scene)) {
            // Add light's contribution to reflected radiance
            Li *= visibility.Transmittance(scene, renderer, NULL, rng, arena);
            if (light->IsDeltaLight())
                Ld += f * Li * (AbsDot(wi, n) / lightPdf);
            else {
                bsdfPdf = bsdf->Pdf(wo, wi, flags);
                float weight = PowerHeuristic(1, lightPdf, 1, bsdfPdf);
                Ld += f * Li * (AbsDot(wi, n) * weight / lightPdf);
            }
        }
    }

    // Sample BSDF with multiple importance sampling
    if (!light->IsDeltaLight()) {
        BxDFType sampledType;
        Spectrum f = bsdf->Sample_f(wo, &wi, bsdfSample, &bsdfPdf, flags,
                                    &sampledType);
        if (!f.IsBlack() && bsdfPdf > 0.) {
            float weight = 1.f;
            if (!(sampledType & BSDF_SPECULAR)) {
                lightPdf = light->Pdf(p, wi);
                if (lightPdf == 0.)
                    return Ld;
                weight = PowerHeuristic(1, bsdfPdf, 1, lightPdf);
            }
            // Add light contribution from BSDF sampling
            Intersection lightIsect;
            Spectrum Li(0.f);
            RayDifferential ray(p, wi, rayEpsilon, INFINITY, time);
            if (scene->Intersect(ray, &lightIsect)) {
                if (lightIsect.primitive->GetAreaLight() == light)
                    Li = lightIsect.Le(-wi);
            }
            else
                //Li = light->Le(ray,);
            	Li = Spectrum(0.);
            if (!Li.IsBlack()) {
                Li *= renderer->Transmittance(scene, ray, NULL, rng, arena);
                Ld += f * Li * AbsDot(wi, n) * weight / bsdfPdf;
            }
        }
    }
    return Ld;
}
void PathCPURenderThread::DirectHitFiniteLight(
		const bool lastSpecular, const Spectrum &pathThrouput,
		const float distance, const BSDF &bsdf, const float lastPdfW,
		Spectrum *radiance) {
	PathCPURenderEngine *engine = (PathCPURenderEngine *)renderEngine;
	Scene *scene = engine->renderConfig->scene;

	float directPdfA;
	const Spectrum emittedRadiance = bsdf.GetEmittedRadiance(scene, &directPdfA);

	if (!emittedRadiance.Black()) {
		float weight;
		if (!lastSpecular) {
			const float lightPickProb = scene->PickLightPdf();
			const float directPdfW = PdfAtoW(directPdfA, distance,
				AbsDot(bsdf.fixedDir, bsdf.shadeN));

			// MIS between BSDF sampling and direct light sampling
			weight = PowerHeuristic(lastPdfW, directPdfW * lightPickProb);
		} else
			weight = 1.f;

		*radiance +=  pathThrouput * weight * emittedRadiance;
	}
}
예제 #4
0
파일: main.cpp 프로젝트: nakdai/samples
float ComputeHeuristic(float fpdf, float gpdf)
{
#if 0
    return BalanceHeuristic(fpdf, gpdf);
#else
    return PowerHeuristic(fpdf, gpdf);
#endif
}
void PathCPURenderThread::DirectLightSampling(
		const float u0, const float u1, const float u2,
		const float u3, const float u4,
		const Spectrum &pathThrouput, const BSDF &bsdf,
		const int depth, Spectrum *radiance) {
	PathCPURenderEngine *engine = (PathCPURenderEngine *)renderEngine;
	Scene *scene = engine->renderConfig->scene;
	
	if (!bsdf.IsDelta()) {
		// Pick a light source to sample
		float lightPickPdf;
		const LightSource *light = scene->SampleAllLights(u0, &lightPickPdf);

		Vector lightRayDir;
		float distance, directPdfW;
		Spectrum lightRadiance = light->Illuminate(scene, bsdf.hitPoint,
				u1, u2, u3, &lightRayDir, &distance, &directPdfW);

		if (!lightRadiance.Black()) {
			BSDFEvent event;
			float bsdfPdfW;
			Spectrum bsdfEval = bsdf.Evaluate(lightRayDir, &event, &bsdfPdfW);

			if (!bsdfEval.Black()) {
				const float epsilon = Max(MachineEpsilon::E(bsdf.hitPoint), MachineEpsilon::E(distance));
				Ray shadowRay(bsdf.hitPoint, lightRayDir,
						epsilon,
						distance - epsilon);
				RayHit shadowRayHit;
				BSDF shadowBsdf;
				Spectrum connectionThroughput;
				// Check if the light source is visible
				if (!scene->Intersect(device, false, u4, &shadowRay,
						&shadowRayHit, &shadowBsdf, &connectionThroughput)) {
					const float cosThetaToLight = AbsDot(lightRayDir, bsdf.shadeN);
					const float directLightSamplingPdfW = directPdfW * lightPickPdf;
					const float factor = cosThetaToLight / directLightSamplingPdfW;

					if (depth >= engine->rrDepth) {
						// Russian Roulette
						bsdfPdfW *= Max(bsdfEval.Filter(), engine->rrImportanceCap);
					}

					// MIS between direct light sampling and BSDF sampling
					const float weight = PowerHeuristic(directLightSamplingPdfW, bsdfPdfW);

					*radiance += (weight * factor) * pathThrouput * connectionThroughput * lightRadiance * bsdfEval;
				}
			}
		}
	}
}
// MIS: sampling BRDF
glm::vec3 BidirectionalIntegrator::MIS_SampleBRDF(Intersection &intersection, Ray &r, Geometry* &light)
{
    if(Number_BRDF == 0)
        return glm::vec3(0);

    // Direct light estimator: sample BRDF
    glm::vec3 sum_brdf_sample(0.0f);
    for(int i = 0; i < Number_BRDF; i++)
    {
        glm::vec3 wo_local = intersection.ToLocalNormalCoordinate(-r.direction);
        glm::vec3 wj_local;
        float pdf_brdf;
        glm::vec3 F = intersection.object_hit->material->SampleAndEvaluateScatteredEnergy(intersection,wo_local,wj_local,pdf_brdf);

        glm::vec3 wj_world = intersection.ToWorldNormalCoordinate(wj_local);
        glm::vec3 wo_world = - r.direction;

        Intersection isxOnLight = intersection_engine->GetIntersection(Ray(intersection.point+float(1e-3)*intersection.normal, wj_world));

        if(isxOnLight.t > 0 && isxOnLight.object_hit == light && pdf_brdf > 0)
        {
            float temp,pdf_light = light->RayPDF(intersection, Ray(intersection.point, wj_world));
            float W = PowerHeuristic(pdf_brdf,float(Number_BRDF),pdf_light,float(Number_Light));
            glm::vec3 Ld = light->material->EvaluateScatteredEnergy(isxOnLight,wo_world,-wj_world,temp);

            if(pdf_light > 0 )
            {
                if(isinf(pdf_brdf)) // delta specular surface
                {
                    sum_brdf_sample = sum_brdf_sample +
                            F * Ld * float(fabs(glm::dot(wj_world, intersection.normal))) / pdf_light;
                }
                else
                {
                    sum_brdf_sample = sum_brdf_sample +
                            W * F * Ld * float(fabs(glm::dot(wj_world,intersection.normal))) / pdf_brdf;
                }
            }
        }

    }
    return sum_brdf_sample / float(Number_BRDF);
}
// MIS: sampling light source
glm::vec3 BidirectionalIntegrator::MIS_SampleLight(Intersection &intersection, Ray &r, Geometry* &light)
{
    if(Number_Light == 0)
        return glm::vec3(0);

    // Direct light estimator: sample Light source
    glm::vec3 sum_light_sample(0);
    for(int i = 0; i < Number_Light; i++)
    {
        float u = uniform_distribution(generator);
        float v = uniform_distribution(generator);

        Intersection lightSample = light->SampleOnGeometrySurface(u, v, intersection.point + 1e-3f * intersection.normal);
        //Intersection lightSample = light->RandomSampleOnSurface(u,v);
        glm::vec3 wj = glm::normalize(lightSample.point - intersection.point);
        glm::vec3 wo = - r.direction;
        glm::vec3 P = intersection.point;
        glm::vec3 N = intersection.normal;

        float pdf_light = light->RayPDF(intersection, Ray(P + float(1e-3)*N, wj));

        Intersection lightIntersection = intersection_engine->GetIntersection(Ray(P + float(1e-3)*N, wj));
        float temp, pdf_brdf;

        glm::vec3 wo_local = intersection.ToLocalNormalCoordinate(wo);
        glm::vec3 wj_local = intersection.ToLocalNormalCoordinate(wj);

        glm::vec3 F = intersection.object_hit->material->EvaluateScatteredEnergy(intersection, wo_local, wj_local, pdf_brdf);
        // reach light directly && pdf(wj) > 0
        if(lightIntersection.t > 0 && lightIntersection.object_hit == light && pdf_light > 0 && pdf_brdf > 0)
        {

            glm::vec3 Ld = light->material->EvaluateScatteredEnergy(lightSample, wo, -wj, temp);
            float W = PowerHeuristic(pdf_light, float(Number_Light), pdf_brdf, float(Number_BRDF)); // cause shadow in center

            sum_light_sample = sum_light_sample +
                                  W * F * Ld * float(fabs(glm::dot(wj, N))) / pdf_light;

        }
    }
    return sum_light_sample / float(Number_Light);
}
예제 #8
0
	Color RayTracer::EstimateDirect(const Scene *scene, const Ray& ray, const LocalGeo& geom, const Light *light, const Sample *lightsample, const Sample *bsdfsample){
		Vec3 wo = -ray.dir;		// dir to camera
		Ray lightray;
		float light_pdf, bsdf_pdf;
		Color color, lightcolor, surfacecolor;

		// sample light sources with multiple importance sampling
		light->SampleDirect(geom.point, lightsample, &lightray, &lightcolor, &light_pdf);
		if (light_pdf > 0.f && lightcolor != Color::BLACK){
			surfacecolor = geom.bsdf->Eval(lightray.dir, wo, geom, BSDFType(BSDF_ALL & ~BSDF_SPECULAR));
			if (surfacecolor != Color::BLACK && !scene->Occlude(lightray)){
				if (light->IsDelta())
					color = surfacecolor * lightcolor * (Math::AbsDot(lightray.dir, geom.normal));
				else{
					bsdf_pdf = geom.bsdf->Pdf(wo, lightray.dir, geom);
					color = surfacecolor * lightcolor * (Math::AbsDot(lightray.dir, geom.normal) / light_pdf * PowerHeuristic(1, light_pdf, 1, bsdf_pdf));
				}
			}
		}

		if (light->IsDelta())
			return color;

		// sample bsdf with multiple importance sampling
		surfacecolor = geom.bsdf->SampleDirect(wo, geom, *bsdfsample, &(lightray.dir), &bsdf_pdf, BSDFType(BSDF_ALL & ~BSDF_SPECULAR));
		if (bsdf_pdf > 0.f && surfacecolor != Color::BLACK){
			lightcolor = Color::BLACK;
			LocalGeo geom_light;
			if (scene->Intersect(lightray, geom_light)){
				if (light == geom_light.prim->GetAreaLight()){
					scene->PostIntersect(lightray, geom_light);
					light_pdf = geom_light.prim->Pdf(geom_light.triId, geom.point, lightray.dir);
					geom_light.Emit(-lightray.dir, &lightcolor);
				}
			}
			//else
			//	light->Emit(lightray, &lightcolor);
			if (lightcolor != Color::BLACK){
				color += surfacecolor * lightcolor * (Math::AbsDot(lightray.dir, geom.normal) / bsdf_pdf * PowerHeuristic(1, bsdf_pdf, 1, light_pdf));
			}
		}
		return color;
	}
예제 #9
0
Spectrum PhotonIntegrator::Li(const Scene *scene, const Renderer *renderer,
        const RayDifferential &ray, const Intersection &isect,
        const Sample *sample, RNG &rng, MemoryArena &arena) const {
    Spectrum L(0.);
    Vector wo = -ray.d;
    // Compute emitted light if ray hit an area light source
    L += isect.Le(wo);

    // Evaluate BSDF at hit pbrt::Point
    BSDF *bsdf = isect.GetBSDF(ray, arena);
    const pbrt::Point &p = bsdf->dgShading.p;
    const Normal &n = bsdf->dgShading.nn;
    L += UniformSampleAllLights(scene, renderer, arena, p, n,
        wo, isect.rayEpsilon, ray.time, bsdf, sample, rng,
        lightSampleOffsets, bsdfSampleOffsets);
    // Compute caustic lighting for photon map integrator
    ClosePhoton *lookupBuf = arena.Alloc<ClosePhoton>(nLookup);
    L += LPhoton(causticMap, nCausticPaths, nLookup, lookupBuf, bsdf,
                 rng, isect, wo, maxDistSquared);

    // Compute indirect lighting for photon map integrator
    if (finalGather && indirectMap != NULL) {
    #if 1
        // Do one-bounce final gather for photon map
        BxDFType nonSpecular = BxDFType(BSDF_REFLECTION |
            BSDF_TRANSMISSION | BSDF_DIFFUSE | BSDF_GLOSSY);
        if (bsdf->NumComponents(nonSpecular) > 0) {
            // Find indirect photons around point for importance sampling
            const uint32_t nIndirSamplePhotons = 50;
            PhotonProcess proc(nIndirSamplePhotons,
                               arena.Alloc<ClosePhoton>(nIndirSamplePhotons));
            float searchDist2 = maxDistSquared;
            while (proc.nFound < nIndirSamplePhotons) {
                float md2 = searchDist2;
                proc.nFound = 0;
                indirectMap->Lookup(p, proc, md2);
                searchDist2 *= 2.f;
            }

            // Copy photon directions to local array
            Vector *photonDirs = arena.Alloc<Vector>(nIndirSamplePhotons);
            for (uint32_t i = 0; i < nIndirSamplePhotons; ++i)
                photonDirs[i] = proc.photons[i].photon->wi;

            // Use BSDF to do final gathering
            Spectrum Li = 0.;
            for (int i = 0; i < gatherSamples; ++i) {
                // Sample random direction from BSDF for final gather ray
                Vector wi;
                float pdf;
                BSDFSample bsdfSample(sample, bsdfGatherSampleOffsets, i);
                Spectrum fr = bsdf->Sample_f(wo, &wi, bsdfSample,
                                             &pdf, BxDFType(BSDF_ALL & ~BSDF_SPECULAR));
                if (fr.IsBlack() || pdf == 0.f) continue;
                Assert(pdf >= 0.f);

                // Trace BSDF final gather ray and accumulate radiance
                RayDifferential bounceRay(p, wi, ray, isect.rayEpsilon);
                Intersection gatherIsect;
                if (scene->Intersect(bounceRay, &gatherIsect)) {
                    // Compute exitant radiance _Lindir_ using radiance photons
                    Spectrum Lindir = 0.f;
                    Normal nGather = gatherIsect.dg.nn;
                    nGather = Faceforward(nGather, -bounceRay.d);
                    RadiancePhotonProcess proc(nGather);
                    float md2 = INFINITY;
                    radianceMap->Lookup(gatherIsect.dg.p, proc, md2);
                    if (proc.photon != NULL)
                        Lindir = proc.photon->Lo;
                    Lindir *= renderer->Transmittance(scene, bounceRay, NULL, rng, arena);

                    // Compute MIS weight for BSDF-sampled gather ray

                    // Compute PDF for photon-sampling of direction _wi_
                    float photonPdf = 0.f;
                    float conePdf = UniformConePdf(cosGatherAngle);
                    for (uint32_t j = 0; j < nIndirSamplePhotons; ++j)
                        if (Dot(photonDirs[j], wi) > .999f * cosGatherAngle)
                            photonPdf += conePdf;
                    photonPdf /= nIndirSamplePhotons;
                    float wt = PowerHeuristic(gatherSamples, pdf, gatherSamples, photonPdf);
                    Li += fr * Lindir * (AbsDot(wi, n) * wt / pdf);
                }
            }
            L += Li / gatherSamples;

            // Use nearby photons to do final gathering
            Li = 0.;
            for (int i = 0; i < gatherSamples; ++i) {
                // Sample random direction using photons for final gather ray
                BSDFSample gatherSample(sample, indirGatherSampleOffsets, i);
                int photonNum = min((int)nIndirSamplePhotons - 1,
                    Floor2Int(gatherSample.uComponent * nIndirSamplePhotons));

                // Sample gather ray direction from _photonNum_
                Vector vx, vy;
                CoordinateSystem(photonDirs[photonNum], &vx, &vy);
                Vector wi = UniformSampleCone(gatherSample.uDir[0], gatherSample.uDir[1],
                                              cosGatherAngle, vx, vy, photonDirs[photonNum]);

                // Trace photon-sampled final gather ray and accumulate radiance
                Spectrum fr = bsdf->f(wo, wi);
                if (fr.IsBlack()) continue;
                RayDifferential bounceRay(p, wi, ray, isect.rayEpsilon);
                Intersection gatherIsect;
                PBRT_PHOTON_MAP_STARTED_GATHER_RAY(&bounceRay);
                if (scene->Intersect(bounceRay, &gatherIsect)) {
                    // Compute exitant radiance _Lindir_ using radiance photons
                    Spectrum Lindir = 0.f;
                    Normal nGather = gatherIsect.dg.nn;
                    nGather = Faceforward(nGather, -bounceRay.d);
                    RadiancePhotonProcess proc(nGather);
                    float md2 = INFINITY;
                    radianceMap->Lookup(gatherIsect.dg.p, proc, md2);
                    if (proc.photon != NULL)
                        Lindir = proc.photon->Lo;
                    Lindir *= renderer->Transmittance(scene, bounceRay, NULL, rng, arena);

                    // Compute PDF for photon-sampling of direction _wi_
                    float photonPdf = 0.f;
                    float conePdf = UniformConePdf(cosGatherAngle);
                    for (uint32_t j = 0; j < nIndirSamplePhotons; ++j)
                        if (Dot(photonDirs[j], wi) > .999f * cosGatherAngle)
                            photonPdf += conePdf;
                    photonPdf /= nIndirSamplePhotons;

                    // Compute MIS weight for photon-sampled gather ray
                    float bsdfPdf = bsdf->Pdf(wo, wi);
                    float wt = PowerHeuristic(gatherSamples, photonPdf, gatherSamples, bsdfPdf);
                    Li += fr * Lindir * AbsDot(wi, n) * wt / photonPdf;
                }
                PBRT_PHOTON_MAP_FINISHED_GATHER_RAY(&bounceRay);
            }
            L += Li / gatherSamples;
        }
    #else
        // for debugging / examples: use the photon map directly
        Normal nn = Faceforward(n, -ray.d);
        RadiancePhotonProcess proc(nn);
        float md2 = INFINITY;
        radianceMap->Lookup(p, proc, md2);
        if (proc.photon)
            L += proc.photon->Lo;
    #endif
    }
    else
        L += LPhoton(indirectMap, nIndirectPaths, nLookup, lookupBuf,
                     bsdf, rng, isect, wo, maxDistSquared);
    if (ray.depth+1 < maxSpecularDepth) {
        Vector wi;
        // Trace rays for specular reflection and refraction
        L += SpecularReflect(ray, bsdf, rng, isect, renderer, scene, sample,
                             arena);
        L += SpecularTransmit(ray, bsdf, rng, isect, renderer, scene, sample,
                              arena);
    }
    return L;
}
Spectrum ExPhotonIntegrator::Li(const Scene *scene,
		const RayDifferential &ray, const Sample *sample,
		float *alpha) const {
	// Compute reflected radiance with photon map
	Spectrum L(0.);
	Intersection isect;
	if (scene->Intersect(ray, &isect)) {
		if (alpha) *alpha = 1.;
		Vector wo = -ray.d;
		// Compute emitted light if ray hit an area light source
		L += isect.Le(wo);
		// Evaluate BSDF at hit point
		BSDF *bsdf = isect.GetBSDF(ray);
		const Point &p = bsdf->dgShading.p;
		const Normal &n = bsdf->dgShading.nn;
		L += UniformSampleAllLights(scene, p, n,
			wo, bsdf, sample,
			lightSampleOffset, bsdfSampleOffset,
			bsdfComponentOffset);

		// Compute indirect lighting for photon map integrator
		L += LPhoton(causticMap, nCausticPaths, nLookup, bsdf,
			isect, wo, maxDistSquared);
		if (finalGather) {
#if 1
			// Do one-bounce final gather for photon map
			BxDFType nonSpecular = BxDFType(BSDF_REFLECTION |
				BSDF_TRANSMISSION | BSDF_DIFFUSE | BSDF_GLOSSY);
			if (bsdf->NumComponents(nonSpecular) > 0) {
				// Find indirect photons around point for importance sampling
				u_int nIndirSamplePhotons = 50;
				PhotonProcess proc(nIndirSamplePhotons, p);
				proc.photons = (ClosePhoton *)alloca(nIndirSamplePhotons *
					sizeof(ClosePhoton));
				float searchDist2 = maxDistSquared;
				while (proc.foundPhotons < nIndirSamplePhotons) {
					float md2 = searchDist2;
					proc.foundPhotons = 0;
					indirectMap->Lookup(p, proc, md2);
					searchDist2 *= 2.f;
				}
				// Copy photon directions to local array
				Vector *photonDirs = (Vector *)alloca(nIndirSamplePhotons *
					sizeof(Vector));
				for (u_int i = 0; i < nIndirSamplePhotons; ++i)
					photonDirs[i] = proc.photons[i].photon->wi;
				// Use BSDF to do final gathering
				Spectrum Li = 0.;
				static StatsCounter gatherRays("Photon Map", // NOBOOK
					"Final gather rays traced"); // NOBOOK
				for (int i = 0; i < gatherSamples; ++i) {
					// Sample random direction from BSDF for final gather ray
					Vector wi;
					float u1 = sample->twoD[gatherSampleOffset[0]][2*i];
					float u2 = sample->twoD[gatherSampleOffset[0]][2*i+1];
					float u3 = sample->oneD[gatherComponentOffset[0]][i];
					float pdf;
					Spectrum fr = bsdf->Sample_f(wo, &wi, u1, u2, u3,
						&pdf, BxDFType(BSDF_ALL & (~BSDF_SPECULAR)));
					if (fr.Black() || pdf == 0.f) continue;
					// Trace BSDF final gather ray and accumulate radiance
					RayDifferential bounceRay(p, wi);
					++gatherRays; // NOBOOK
					Intersection gatherIsect;
					if (scene->Intersect(bounceRay, &gatherIsect)) {
						// Compute exitant radiance using precomputed irradiance
						Spectrum Lindir = 0.f;
						Normal n = gatherIsect.dg.nn;
						if (Dot(n, bounceRay.d) > 0) n = -n;
						RadiancePhotonProcess proc(gatherIsect.dg.p, n);
						float md2 = INFINITY;
						radianceMap->Lookup(gatherIsect.dg.p, proc, md2);
						if (proc.photon)
							Lindir = proc.photon->Lo;
						Lindir *= scene->Transmittance(bounceRay);
						// Compute MIS weight for BSDF-sampled gather ray
						// Compute PDF for photon-sampling of direction _wi_
						float photonPdf = 0.f;
						float conePdf = UniformConePdf(cosGatherAngle);
						for (u_int j = 0; j < nIndirSamplePhotons; ++j)
							if (Dot(photonDirs[j], wi) > .999f * cosGatherAngle)
								photonPdf += conePdf;
						photonPdf /= nIndirSamplePhotons;
						float wt = PowerHeuristic(gatherSamples, pdf,
							gatherSamples, photonPdf);
						Li += fr * Lindir * AbsDot(wi, n) * wt / pdf;
					}
				}
				L += Li / gatherSamples;
				// Use nearby photons to do final gathering
				Li = 0.;
				for (int i = 0; i < gatherSamples; ++i) {
					// Sample random direction using photons for final gather ray
					float u1 = sample->oneD[gatherComponentOffset[1]][i];
					float u2 = sample->twoD[gatherSampleOffset[1]][2*i];
					float u3 = sample->twoD[gatherSampleOffset[1]][2*i+1];
					int photonNum = min((int)nIndirSamplePhotons - 1,
						Floor2Int(u1 * nIndirSamplePhotons));
					// Sample gather ray direction from _photonNum_
					Vector vx, vy;
					CoordinateSystem(photonDirs[photonNum], &vx, &vy);
					Vector wi = UniformSampleCone(u2, u3, cosGatherAngle, vx, vy,
						photonDirs[photonNum]);
					// Trace photon-sampled final gather ray and accumulate radiance
					Spectrum fr = bsdf->f(wo, wi);
					if (fr.Black()) continue;
					// Compute PDF for photon-sampling of direction _wi_
					float photonPdf = 0.f;
					float conePdf = UniformConePdf(cosGatherAngle);
					for (u_int j = 0; j < nIndirSamplePhotons; ++j)
						if (Dot(photonDirs[j], wi) > .999f * cosGatherAngle)
							photonPdf += conePdf;
					photonPdf /= nIndirSamplePhotons;
					RayDifferential bounceRay(p, wi);
					++gatherRays; // NOBOOK
					Intersection gatherIsect;
					if (scene->Intersect(bounceRay, &gatherIsect)) {
						// Compute exitant radiance using precomputed irradiance
						Spectrum Lindir = 0.f;
						Normal n = gatherIsect.dg.nn;
						if (Dot(n, bounceRay.d) > 0) n = -n;
						RadiancePhotonProcess proc(gatherIsect.dg.p, n);
						float md2 = INFINITY;
						radianceMap->Lookup(gatherIsect.dg.p, proc, md2);
						if (proc.photon)
							Lindir = proc.photon->Lo;
						Lindir *= scene->Transmittance(bounceRay);
						// Compute MIS weight for photon-sampled gather ray
						float bsdfPdf = bsdf->Pdf(wo, wi);
						float wt = PowerHeuristic(gatherSamples, photonPdf,
								gatherSamples, bsdfPdf);
						Li += fr * Lindir * AbsDot(wi, n) * wt / photonPdf;
					}
				}
				L += Li / gatherSamples;
			}
#else
// look at radiance map directly..
Normal nn = n;
if (Dot(nn, ray.d) > 0.) nn = -n;
RadiancePhotonProcess proc(p, nn);
float md2 = INFINITY;
radianceMap->Lookup(p, proc, md2);
if (proc.photon)
	L += proc.photon->Lo;
#endif

		}
		else {
		    L += LPhoton(indirectMap, nIndirectPaths, nLookup,
				 bsdf, isect, wo, maxDistSquared);
		}
		if (specularDepth++ < maxSpecularDepth) {
			Vector wi;
			// Trace rays for specular reflection and refraction
			Spectrum f = bsdf->Sample_f(wo, &wi,
				BxDFType(BSDF_REFLECTION | BSDF_SPECULAR));
			if (!f.Black()) {
				// Compute ray differential _rd_ for specular reflection
				RayDifferential rd(p, wi);
				rd.hasDifferentials = true;
				rd.rx.o = p + isect.dg.dpdx;
				rd.ry.o = p + isect.dg.dpdy;
				// Compute differential reflected directions
				Normal dndx = bsdf->dgShading.dndu * bsdf->dgShading.dudx +
					bsdf->dgShading.dndv * bsdf->dgShading.dvdx;
				Normal dndy = bsdf->dgShading.dndu * bsdf->dgShading.dudy +
					bsdf->dgShading.dndv * bsdf->dgShading.dvdy;
				Vector dwodx = -ray.rx.d - wo, dwody = -ray.ry.d - wo;
				float dDNdx = Dot(dwodx, n) + Dot(wo, dndx);
				float dDNdy = Dot(dwody, n) + Dot(wo, dndy);
				rd.rx.d = wi -
				          dwodx + 2 * Vector(Dot(wo, n) * dndx +
						  dDNdx * n);
				rd.ry.d = wi -
				          dwody + 2 * Vector(Dot(wo, n) * dndy +
						  dDNdy * n);
				L += scene->Li(rd, sample) * f * AbsDot(wi, n);
			}
			f = bsdf->Sample_f(wo, &wi,
				BxDFType(BSDF_TRANSMISSION | BSDF_SPECULAR));
			if (!f.Black()) {
				// Compute ray differential _rd_ for specular transmission
				RayDifferential rd(p, wi);
				rd.hasDifferentials = true;
				rd.rx.o = p + isect.dg.dpdx;
				rd.ry.o = p + isect.dg.dpdy;

				float eta = bsdf->eta;
				Vector w = -wo;
				if (Dot(wo, n) < 0) eta = 1.f / eta;

				Normal dndx = bsdf->dgShading.dndu * bsdf->dgShading.dudx + bsdf->dgShading.dndv * bsdf->dgShading.dvdx;
				Normal dndy = bsdf->dgShading.dndu * bsdf->dgShading.dudy + bsdf->dgShading.dndv * bsdf->dgShading.dvdy;

				Vector dwodx = -ray.rx.d - wo, dwody = -ray.ry.d - wo;
				float dDNdx = Dot(dwodx, n) + Dot(wo, dndx);
				float dDNdy = Dot(dwody, n) + Dot(wo, dndy);

				float mu = eta * Dot(w, n) - Dot(wi, n);
				float dmudx = (eta - (eta*eta*Dot(w,n))/Dot(wi, n)) * dDNdx;
				float dmudy = (eta - (eta*eta*Dot(w,n))/Dot(wi, n)) * dDNdy;

				rd.rx.d = wi + eta * dwodx - Vector(mu * dndx + dmudx * n);
				rd.ry.d = wi + eta * dwody - Vector(mu * dndy + dmudy * n);
				L += scene->Li(rd, sample) * f * AbsDot(wi, n);
			}
		}
		--specularDepth;
	}
	else {
		// Handle ray with no intersection
		if (alpha) *alpha = 0.;
		for (u_int i = 0; i < scene->lights.size(); ++i)
			L += scene->lights[i]->Le(ray);
		if (alpha && !L.Black()) *alpha = 1.;
		return L;
	}
	return L;
}
예제 #11
0
Spectrum EstimateDirect(const Interaction &it, const Point2f &uScattering,
                        const Light &light, const Point2f &uLight,
                        const Scene &scene, Sampler &sampler,
                        MemoryArena &arena, bool handleMedia, bool specular) {
    BxDFType bsdfFlags =
        specular ? BSDF_ALL : BxDFType(BSDF_ALL & ~BSDF_SPECULAR);
    Spectrum Ld(0.f);
    // Sample light source with multiple importance sampling
    Vector3f wi;
    Float lightPdf = 0, scatteringPdf = 0;
    VisibilityTester visibility;
    Spectrum Li = light.Sample_Li(it, uLight, &wi, &lightPdf, &visibility);
    if (lightPdf > 0 && !Li.IsBlack()) {
        // Compute BSDF or phase function's value for light sample
        Spectrum f;
        if (it.IsSurfaceInteraction()) {
            // Evaluate BSDF for light sampling strategy
            const SurfaceInteraction &isect = (const SurfaceInteraction &)it;
            f = isect.bsdf->f(isect.wo, wi, bsdfFlags) *
                AbsDot(wi, isect.shading.n);
            scatteringPdf = isect.bsdf->Pdf(isect.wo, wi, bsdfFlags);
        } else {
            // Evaluate phase function for light sampling strategy
            const MediumInteraction &mi = (const MediumInteraction &)it;
            Float p = mi.phase->p(mi.wo, wi);
            f = Spectrum(p);
            scatteringPdf = p;
        }
        if (!f.IsBlack()) {
            // Compute effect of visibility for light source sample
            if (handleMedia)
                Li *= visibility.Tr(scene, sampler);
            else if (!visibility.Unoccluded(scene))
                Li = Spectrum(0.f);

            // Add light's contribution to reflected radiance
            if (!Li.IsBlack()) {
                if (IsDeltaLight(light.flags))
                    Ld += f * Li / lightPdf;
                else {
                    Float weight =
                        PowerHeuristic(1, lightPdf, 1, scatteringPdf);
                    Ld += f * Li * weight / lightPdf;
                }
            }
        }
    }

    // Sample BSDF with multiple importance sampling
    if (!IsDeltaLight(light.flags)) {
        Spectrum f;
        bool sampledSpecular = false;
        if (it.IsSurfaceInteraction()) {
            // Sample scattered direction for surface interactions
            BxDFType sampledType;
            const SurfaceInteraction &isect = (const SurfaceInteraction &)it;
            f = isect.bsdf->Sample_f(isect.wo, &wi, uScattering, &scatteringPdf,
                                     bsdfFlags, &sampledType);
            f *= AbsDot(wi, isect.shading.n);
            sampledSpecular = sampledType & BSDF_SPECULAR;
        } else {
            // Sample scattered direction for medium interactions
            const MediumInteraction &mi = (const MediumInteraction &)it;
            Float p = mi.phase->Sample_p(mi.wo, &wi, uScattering);
            f = Spectrum(p);
            scatteringPdf = p;
        }
        if (!f.IsBlack() && scatteringPdf > 0) {
            // Account for light contributions along sampled direction _wi_
            Float weight = 1;
            if (!sampledSpecular) {
                lightPdf = light.Pdf_Li(it, wi);
                if (lightPdf == 0) return Ld;
                weight = PowerHeuristic(1, scatteringPdf, 1, lightPdf);
            }

            // Find intersection and compute transmittance
            SurfaceInteraction lightIsect;
            Ray ray = it.SpawnRay(wi);
            Spectrum Tr(1.f);
            bool foundSurfaceInteraction =
                handleMedia ? scene.IntersectTr(ray, sampler, &lightIsect, &Tr)
                            : scene.Intersect(ray, &lightIsect);

            // Add light contribution from material sampling
            Spectrum Li(0.f);
            if (foundSurfaceInteraction) {
                if (lightIsect.primitive->GetAreaLight() == &light)
                    Li = lightIsect.Le(-wi);
            } else
                Li = light.Le(ray);
            if (!Li.IsBlack()) Ld += f * Li * Tr * weight / scatteringPdf;
        }
    }
    return Ld;
}
예제 #12
0
float3 DiTracer::GetDi(World const& world, Light const& light, Sampler const& lightsampler, Sampler const& bsdfsampler, float3 const& wo, ShapeBundle::Hit& hit) const
{
    float3 radiance;
    // TODO: fix that later with correct heuristic
    assert(lightsampler.num_samples() == bsdfsampler.num_samples());
    
    // Sample light source first to apply MIS later
    {
        // Direction from the shading point to the light
        float3 lightdir;
        // PDF for BSDF sample
        float bsdfpdf = 0.f;
        // PDF for light sample
        float lightpdf = 0.f;
        // Sample numsamples times
        int numsamples = lightsampler.num_samples();
        // Allocate samples
        std::vector<float2> lightsamples(numsamples);
        std::vector<float2> bsdfsamples(numsamples);

        // Generate samples
        for (int i = 0; i < numsamples; ++i)
        {
            lightsamples[i] = lightsampler.Sample2D();
            bsdfsamples[i] = bsdfsampler.Sample2D();
        }
        
        // Cache singularity flag to avoid virtual call in the loop below
        bool singularlight = light.Singular();
        
        // Fetch the material
        Material const& mat = *world.materials_[hit.m];

        // Start sampling
        for (int i=0; i<numsamples; ++i)
        {
            lightpdf = 0.f;
            bsdfpdf = 0.f;
            
            // This is needed to support normal mapping.
            // Original intersection needs to be kept around since bsdf might alter the normal
            ShapeBundle::Hit hitlocal = hit;
            // Sample light source
            float3 le = light.GetSample(hitlocal, lightsamples[i], lightdir, lightpdf);
            
            // Continue if intensity > 0 and there is non-zero probability of sampling the point
            if (lightpdf > MINPDF && le.sqnorm() > 0.f)
            {
                // Normalize direction to light
                float3 wi = normalize(lightdir);
                // Calculate distance for shadow testing
                float  dist = sqrtf(lightdir.sqnorm());
                
                // Spawn shadow ray
                ray shadowray;
                // From an intersection point
                shadowray.o = hitlocal.p;
                // Into evaluated direction
                shadowray.d = wi;
                
                // TODO: move ray epsilon into some global options object
                shadowray.t = float2(0.01f, dist - 0.01f);
                
                // Check for an occlusion
                float shadow = world.Intersect(shadowray) ? 0.f : 1.f;
                
                // If we are not in shadow
                if (shadow > 0.f)
                {
                    // Evaluate BSDF
                    float3 bsdf = mat.Evaluate(hitlocal, wi, wo);
                    
                    // We can't apply MIS for singular lights, so use simple estimator
                    if (singularlight)
                    {
                        // Estimate with Monte-Carlo L(wo) = int{ Ld(wi, wo) * fabs(dot(n, wi)) * dwi }
                        radiance +=  le * bsdf * fabs(dot(hitlocal.n, wi)) * (1.f / lightpdf);
                        assert(!has_nans(radiance));
                    }
                    else
                    {
                        // Apply MIS
                        bsdfpdf = mat.GetPdf(hitlocal, wi, wo);
                        // Evaluate weight
                        float weight = PowerHeuristic(1, lightpdf, 1, bsdfpdf);
                        // Estimate with Monte-Carlo L(wo) = int{ Ld(wi, wo) * fabs(dot(n, wi)) * dwi }
                        radiance +=  le * bsdf * fabs(dot(hitlocal.n, wi)) * weight * (1.f / lightpdf);
                        assert(!has_nans(radiance));
                    }
                }
            }

            // Sample BSDF if the light is not singular
            if (!singularlight)
            {
                int bsdftype = 0;
                float3 wi;

                // Sample material
                float3 bsdf = mat.Sample(hitlocal, bsdfsamples[i], wo, wi, bsdfpdf, bsdftype);
                //assert(!has_nans(bsdf));
                //assert(!has_nans(bsdfpdf < 1000000.f));

                // Normalize wi
                wi = normalize(wi);
                
                // If something would be reflected
                if (bsdf.sqnorm() > 0.f && bsdfpdf > MINPDF)
                {
                    float weight = 1.f;
                
                    // Apply MIS if BSDF is not specular
                    if (! (bsdftype & Bsdf::SPECULAR))
                    {
                        // Evaluate light PDF
                        lightpdf = light.GetPdf(hitlocal, wi);

                        // If light PDF is zero skip to next sample
                        if (lightpdf < MINPDF)
                        {
                            continue;
                        }
                        
                        // Apply heuristic
                        weight = PowerHeuristic(1, bsdfpdf, 1, lightpdf);
                    }

                    // Spawn shadow ray
                    ray shadowray;
                    // From an intersection point
                    shadowray.o = hitlocal.p;
                    // Into evaluated direction
                    shadowray.d = wi;

                    // TODO: move ray epsilon into some global options object
                    shadowray.t = float2(0.01f, 10000000.f);

                    // Cast the ray into the scene
                    ShapeBundle::Hit shadowhit;
                    float3 le(0.f, 0.f, 0.f);
                    // If the ray intersects the scene check if we have intersected this light
                    // TODO: move that to area light class
                    if (world.Intersect(shadowray, shadowhit))
                    {
                        // Only sample if this is our light
                        if ((Light const*)shadowhit.bundle->GetAreaLight() == &light)
                        {
                            Material const& lightmat = *world.materials_[shadowhit.m];
                            // Get material emission properties
                            ShapeBundle::Sample sampledata(shadowhit);

                            float3 d = sampledata.p - hitlocal.p;

                            // If the object facing the light compute emission
                            if (dot(sampledata.n, -wi) > 0.f)
                            {
                                // Emissive power with squared fallof
                                float d2inv = 1.f / d.sqnorm();

                                // Return emission characteristic of the material
                                le = lightmat.GetLe(sampledata, -wi) * d2inv;
                            }
                        }
                    }
                    else
                    {
                        // This is to give a chance for IBL to contribute
                        le = light.GetLe(shadowray);
                    }
                    
                    if (le.sqnorm() > 0.f)
                    {
                        // Estimate with Monte-Carlo L(wo) = int{ Ld(wi, wo) * fabs(dot(n, wi)) * dwi }
                        radiance +=  le * bsdf * fabs(dot(hitlocal.n, wi)) * weight * (1.f / bsdfpdf);
                        //assert(!has_nans(radiance));
                    }
                }
            }
        }

        return (1.f / numsamples) * radiance;
    }
}
Spectrum EstimateDirect(const Scene *scene,
        const Light *light, const Point &p,
		const Normal &n, const Vector &wo,
		BSDF *bsdf, const Sample *sample, int lightSamp,
		int bsdfSamp, int bsdfComponent, u_int sampleNum) {
	Spectrum Ld(0.);
	// Find light and BSDF sample values for direct lighting estimate
	float ls1, ls2, bs1, bs2, bcs;
	if (lightSamp != -1 && bsdfSamp != -1 &&
		sampleNum < sample->n2D[lightSamp] &&
		sampleNum < sample->n2D[bsdfSamp]) {
		ls1 = sample->twoD[lightSamp][2*sampleNum];
		ls2 = sample->twoD[lightSamp][2*sampleNum+1];
		bs1 = sample->twoD[bsdfSamp][2*sampleNum];
		bs2 = sample->twoD[bsdfSamp][2*sampleNum+1];
		bcs = sample->oneD[bsdfComponent][sampleNum];
	}
	else {
		ls1 = RandomFloat();
		ls2 = RandomFloat();
		bs1 = RandomFloat();
		bs2 = RandomFloat();
		bcs = RandomFloat();
	}
	// Sample light source with multiple importance sampling
	Vector wi;
	float lightPdf, bsdfPdf;
	VisibilityTester visibility;
	Spectrum Li = light->Sample_L(p, n,
		ls1, ls2, &wi, &lightPdf, &visibility);
	if (lightPdf > 0. && !Li.Black()) {
		Spectrum f = bsdf->f(wo, wi);
		if (!f.Black() && visibility.Unoccluded(scene)) {
			// Add light's contribution to reflected radiance
			Li *= visibility.Transmittance(scene);
			if (light->IsDeltaLight())
				Ld += f * Li * AbsDot(wi, n) / lightPdf;
			else {
				bsdfPdf = bsdf->Pdf(wo, wi);
				float weight = PowerHeuristic(1, lightPdf, 1, bsdfPdf);
				Ld += f * Li * AbsDot(wi, n) * weight / lightPdf;
			}
		}
	}
	// Sample BSDF with multiple importance sampling
	if (!light->IsDeltaLight()) {
		BxDFType flags = BxDFType(BSDF_ALL & ~BSDF_SPECULAR);
		Spectrum f = bsdf->Sample_f(wo, &wi,
			bs1, bs2, bcs, &bsdfPdf, flags);
		if (!f.Black() && bsdfPdf > 0.) {
			lightPdf = light->Pdf(p, n, wi);
			if (lightPdf > 0.) {
				// Add light contribution from BSDF sampling
				float weight = PowerHeuristic(1, bsdfPdf, 1, lightPdf);
				Intersection lightIsect;
				Spectrum Li(0.f);
				RayDifferential ray(p, wi);
				if (scene->Intersect(ray, &lightIsect)) {
					if (lightIsect.primitive->GetAreaLight() == light)
						Li = lightIsect.Le(-wi);
				}
				else
					Li = light->Le(ray);
				if (!Li.Black()) {
					Li *= scene->Transmittance(ray);
					Ld += f * Li * AbsDot(wi, n) * weight / bsdfPdf;
				}
			}
		}
	}
	return Ld;
}