// we force to connect eye path to light path 
Color3 BidirPathTracing::connectVertices(BidirPathState& lightState , 
	BSDF& cameraBsdf , const Vector3& hitPos , 
	BidirPathState& cameraState)
{
	Vector3 dir = lightState.pos - hitPos;
	Real dist2 = dir.sqrLength();
	Real dist = std::sqrt(dist2);
	dir = dir / dist;

	Color3 res(0);

	Real cosAtCamera , cameraBsdfDirPdf , cameraBsdfRevPdf;
	Color3 cameraBsdfFactor = cameraBsdf.f(scene , dir , cosAtCamera ,
		&cameraBsdfDirPdf , &cameraBsdfRevPdf);

	if (cameraBsdfFactor.isBlack())
		return res;

	Real cameraContProb = cameraBsdf.continueProb;
	cameraBsdfDirPdf *= cameraContProb;
	cameraBsdfRevPdf *= cameraContProb;

	Real cosAtLight , lightBsdfDirPdf , lightBsdfRevPdf;
	Color3 lightBsdfFactor = lightState.bsdf.f(scene , -dir , cosAtLight ,
		&lightBsdfDirPdf , &lightBsdfRevPdf);

	if (lightBsdfFactor.isBlack())
		return res;

	Real lightContProb = lightState.bsdf.continueProb;
	lightBsdfDirPdf *= lightContProb;
	lightBsdfRevPdf *= lightContProb;

	Real geometryTerm = cosAtLight * cosAtCamera / dist2;

	if (cmp(geometryTerm) < 0)
		return res;

	Real cameraBsdfDirPdfArea = pdfWtoA(cameraBsdfDirPdf , dist , cosAtLight);
	Real lightBsdfDirPdfArea = pdfWtoA(lightBsdfDirPdf , dist , cosAtCamera);

	res = (cameraBsdfFactor | lightBsdfFactor) * geometryTerm;

	if (res.isBlack() || scene.occluded(hitPos , dir , 
		hitPos + dir * dist))
		return Color3(0);

	Real wLight = mis(cameraBsdfDirPdfArea) * 
		(lightState.dVCM + mis(lightBsdfRevPdf) * lightState.dVC);
	Real wCamera = mis(lightBsdfDirPdfArea) *
		(cameraState.dVCM + mis(cameraBsdfRevPdf) * cameraState.dVC);
	Real weight = 1.f / (wLight + 1.f + wCamera);

	return res * weight;
}
Exemplo n.º 2
0
static Color3 finalGathering(KdTree<Photon> *map , Scene& scene , 
							 Intersection& inter , RNG& rng , const Vector3& wo ,
                             int gatherSamples , int knn , Real maxSqrDis)
{
    Color3 res = Color3(0.0 , 0.0 , 0.0);
    for (int i = 0; i < gatherSamples; i++)
    {
		Real pdf;
        Vector3 wi = sampleCosHemisphere(rng.randVector3() , &pdf);
        Ray ray = Ray(inter.p + wi * EPS , wi);

        Intersection _inter;
        
        Geometry *_g = scene.intersect(ray , _inter);

        if (_g == NULL)
            continue;
        
        Color3 tmp = estimate(map , 0 , knn , scene , _inter , -wi , maxSqrDis);

		BSDF bsdf(wi , _inter , scene);
		Real cosine , bsdfPdf;
        Color3 brdf = bsdf.f(scene , wo , cosine , &bsdfPdf);
		if (brdf.isBlack())
			continue;
		pdf *= bsdfPdf;
        res = res + (tmp | brdf) * (cosine / pdf);
    }
    res = res / gatherSamples;
    return res;
}
Color3 BidirPathTracing::getLightRadiance(AbstractLight *light , 
	BidirPathState& cameraState , const Vector3& hitPos , 
	const Vector3& rayDir)
{
	int lightCount = scene.lights.size();
	Real lightPickProb = 1.f / lightCount;

	Real directPdfArea , emissionPdf;
	Color3 radiance = light->getRadiance(scene.sceneSphere ,
		rayDir , hitPos , &directPdfArea , &emissionPdf);

	Color3 res(0);

	if (radiance.isBlack())
		return res;

	if (cameraState.pathLength == 1)
		return radiance;

	directPdfArea *= lightPickProb;
	emissionPdf *= lightPickProb;

 	Real wCamera = mis(directPdfArea) * cameraState.dVCM + 
 		mis(emissionPdf) * cameraState.dVC;

	Real weight = 1.f / (1.f + wCamera);

	return radiance * weight;
}
Color3 BidirPathTracing::connectToCamera(BidirPathState& lightState , 
	const Vector3& hitPos , BSDF& bsdf)
{
	Color3 res(0);

	Camera& camera = scene.camera;
	Vector3 dirToCamera = camera.pos - hitPos;

	if (((-dirToCamera) ^ camera.forward) <= 0)
		return res;

	Real distEye2 = dirToCamera.sqrLength();
	Real dist = std::sqrt(distEye2);
	dirToCamera = dirToCamera / dist;

	Real cosToCamera , bsdfDirPdf , bsdfRevPdf;

	Color3 bsdfFactor = bsdf.f(scene , dirToCamera , cosToCamera ,
		&bsdfDirPdf , &bsdfRevPdf);

	if (bsdfFactor.isBlack())
		return res;

	bsdfRevPdf *= bsdf.continueProb;

	Real cosAtCamera = ((-dirToCamera) ^ camera.forward);
	Real imagePointToCameraDist = camera.imagePlaneDist / cosAtCamera;
	Real imageToSolidAngleFactor = SQR(imagePointToCameraDist) / cosAtCamera;
	Real imageToSurfaceFactor = imageToSolidAngleFactor * std::abs(cosToCamera) / distEye2;

	Real cameraPdfA = imageToSurfaceFactor /* * 1.f */; // pixel area is 1
	
	Real surfaceToImageFactor = 1.f / imageToSurfaceFactor;

	// We divide the contribution by surfaceToImageFactor to convert the (already
	// divided) pdf from surface area to image plane area, w.r.t. which the
	// pixel integral is actually defined. We also divide by the number of samples
	// this technique makes
	res = (lightState.throughput | bsdfFactor) /
		(lightPathNum * surfaceToImageFactor);
    
    if (res.isBlack())
		return res;

	if (scene.occluded(hitPos , dirToCamera , camera.pos))
		return Color3(0);

	Real wLight = mis(cameraPdfA / lightPathNum) * (lightState.dVCM + 
		mis(bsdfRevPdf) * lightState.dVC);

	Real weight = 1.f / (wLight + 1.f);

	//fprintf(fp , "weight = %.6f\n" , weight);

	return res * weight;
}
bool BidirPathTracing::sampleScattering(BSDF& bsdf , 
	const Vector3& hitPos , BidirPathState& pathState)
{
	Real bsdfDirPdf , cosWo;
	int sampledBSDFType;
	Color3 bsdfFactor = bsdf.sample(scene , rng.randVector3() ,
		pathState.dir , bsdfDirPdf , cosWo , &sampledBSDFType);

	if (bsdfFactor.isBlack())
		return 0;

	Real bsdfRevPdf = bsdfDirPdf;
	if ((sampledBSDFType & BSDF_SPECULAR) == 0)
		bsdfRevPdf = bsdf.pdf(scene , pathState.dir , 1);

	Real contProb = bsdf.continueProb;
	if (rng.randFloat() > contProb)
		return 0;

	bsdfDirPdf *= contProb;
	bsdfRevPdf *= contProb;

	// Partial sub-path MIS quantities
	// the evaluation is completed when the actual hit point is known!
	// i.e. after tracing the ray, out of the procedure
	if (sampledBSDFType & BSDF_SPECULAR)
	{
		pathState.specularVertexNum++;

		pathState.dVCM = 0.f;
		pathState.dVC *= mis(cosWo);
	}
	else
	{
		pathState.specularPath &= 0;

		pathState.dVC = mis(1.f / bsdfDirPdf) * (pathState.dVCM +
			pathState.dVC * mis(bsdfRevPdf));
		pathState.dVCM = mis(1.f / bsdfDirPdf);
	}

	pathState.origin = hitPos;
	pathState.throughput = (pathState.throughput | bsdfFactor) *
		(cosWo / bsdfDirPdf);

	return 1;
}
Exemplo n.º 6
0
static Color3 directIllumination(Scene& scene , Intersection& inter ,
                           RNG& rng , const Vector3& visionDir)
{
    Color3 res = Color3(0.0 , 0.0 , 0.0);
    Vector3 lightDir;
    Real cosine;
    Color3 brdf;
    Ray ray;
    
	BSDF bsdf(visionDir , inter , scene);

	int N = 1;
    for (int i = 0; i < N; i++)
    {
        int k = rand() % scene.lights.size();
		AbstractLight *l = scene.lights[k];
		
		Vector3 dirToLight;
		Real dist , directPdf;

		Color3 illu = l->illuminance(scene.sceneSphere , inter.p , rng.randVector3() ,
			dirToLight , dist , directPdf);

		illu = illu / (directPdf / scene.lights.size());

        if (scene.occluded(inter.p + dirToLight * EPS , dirToLight ,
			inter.p + dirToLight * (inter.t - EPS)))
            continue;
        
		Real bsdfPdf;
        brdf = bsdf.f(scene , dirToLight , cosine , &bsdfPdf);
		if (brdf.isBlack())
			continue;
        res = res + (illu | brdf) * (cosine / bsdfPdf);
    }
    res = res / N;
    return res;
}
Exemplo n.º 7
0
void PhotonIntegrator::buildPhotonMap(Scene& scene)
{
    if (scene.lights.size() <= 0)
        return;

    causticPhotons.clear();
    indirectPhotons.clear();
    
    bool causticDone = 0 , indirectDone = 0;
    int nShot = 0;

    bool specularPath;
    int nIntersections;
    Intersection inter;
    Real lightPickProb = 1.f / scene.lights.size();

    while (!causticDone || !indirectDone)
    {
        nShot++;

        /* generate initial photon ray */
        int k = (int)(rng.randFloat() * scene.lights.size());

		Vector3 lightPos , lightDir;
		Real emissionPdf , directPdfArea , cosAtLight;
		Color3 alpha;

		AbstractLight *l = scene.lights[k];
		alpha = l->emit(scene.sceneSphere , rng.randVector3() , rng.randVector3() ,
			lightPos , lightDir , emissionPdf , &directPdfArea ,
			&cosAtLight);

		alpha = alpha * cosAtLight / (emissionPdf * lightPickProb);
        
		Ray photonRay(lightPos , lightDir);

        if (!alpha.isBlack())
        {
            specularPath = 1;
            nIntersections = 0;
            Geometry *g = scene.intersect(photonRay , inter);
            while (g != NULL && inter.matId > 0)
            {
				BSDF bsdf(-photonRay.dir , inter , scene);

                nIntersections++;
                bool hasNonSpecular = (cmp(bsdf.componentProb.diffuseProb) > 0 ||
                                      cmp(bsdf.componentProb.glossyProb) > 0);
                if (hasNonSpecular)
                {
                    Photon photon(inter.p , -photonRay.dir , alpha);
                    if (specularPath && nIntersections > 1)
                    {
                        if (!causticDone)
                        {
                            causticPhotons.push_back(photon);
                            if (causticPhotons.size() == nCausticPhotons)
                            {
                                causticDone = 1;
                                nCausticPaths = nShot;
                                causticMap = new KdTree<Photon>(causticPhotons);
                            }
                        }
                    }
                    else
                    {
                        if (nIntersections > 1 && !indirectDone)
                        {
                            indirectPhotons.push_back(photon);
                            if (indirectPhotons.size() == nIndirectPhotons)
                            {
                                indirectDone = 1;
                                nIndirectPaths = nShot;
                                indirectMap = new KdTree<Photon>(indirectPhotons);
                            }
                        }
                    }
                }
                if (nIntersections > maxPathLength)
                    break;

                /* find new photon ray direction */
                /* handle specular reflection and transmission first */
				Real pdf , cosWo;
				int sampledType;

				Color3 bsdfFactor = bsdf.sample(scene , rng.randVector3() ,
					photonRay.dir , pdf , cosWo , &sampledType);

				if (bsdfFactor.isBlack())
					break;

				if (sampledType & BSDF_NON_SPECULAR)
					specularPath = 0;

				// Russian Roulette
				Real contProb = bsdf.continueProb;
				
				if (cmp(contProb - 1.f) < 0)
				{
					if (cmp(rng.randFloat() - contProb) > 0)
						break;
					pdf *= contProb;
				}

				alpha = (alpha | bsdfFactor) * (cosWo / pdf);

				photonRay.origin = inter.p + photonRay.dir * EPS;
				photonRay.tmin = 0.f; photonRay.tmax = INF;

                g = scene.intersect(photonRay , inter);
            }
        }
    }
}
Exemplo n.º 8
0
Color3 PhotonIntegrator::raytracing(const Ray& ray , int dep)
{
    Color3 res = Color3(0.0 , 0.0 , 0.0);

    if (dep > 2)
        return res;

    Geometry *g = NULL;
	Intersection inter;
    Ray reflectRay , transRay;

    g = scene.intersect(ray , inter);

    if (g == NULL)
        return res;

	if (inter.matId < 0)
	{
		AbstractLight *l = scene.lights[-inter.matId - 1];
		return l->getIntensity() * 100.f;
	}
    
    res = res + directIllumination(scene , inter , rng , -ray.dir);
      
    res = res + estimate(indirectMap , nIndirectPaths , knnPhotons , scene , inter , -ray.dir , maxSqrDis);

	// final gathering is too slow!

    //res = res + finalGathering(indirectMap , scene , inter , rng , -ray.dir , 50 , knnPhotons , maxSqrDis);
    
    res = res + estimate(causticMap , nCausticPaths , knnPhotons , scene , inter , -ray.dir , maxSqrDis);

	BSDF bsdf(-ray.dir , inter , scene);

	Real pdf , cosWo;
	int sampledType;
	Ray newRay;

	Color3 bsdfFactor = bsdf.sample(scene , rng.randVector3() ,
		newRay.dir , pdf , cosWo , &sampledType);

	if (bsdfFactor.isBlack())
		return res;

	// Russian Roulette
	Real contProb = bsdf.continueProb;

	if (cmp(contProb - 1.f) < 0)
	{
		if (cmp(rng.randFloat() - contProb) > 0)
			return res;
		pdf *= contProb;
	}
    
	newRay.origin = inter.p + newRay.dir * EPS;
	newRay.tmin = 0; newRay.tmax = INF;

	Color3 contrib = raytracing(newRay , dep + 1);

	res = res + (contrib | bsdfFactor) * (cosWo / pdf);

    return res;
}
Exemplo n.º 9
0
static Color3 estimate(KdTree<Photon> *map , int nPaths , int knn ,
                                  Scene& scene , Intersection& inter , 
								  const Vector3& wo , Real maxSqrDis)
{
    Color3 res = Color3(0.0 , 0.0 , 0.0);
    
    if (map == NULL)
        return res;
    
    Photon photon;
    photon.pos = inter.p;

	ClosePhotonQuery query(knn , 0);

    Real searchSqrDis = maxSqrDis;
    Real msd; /* max square distance */
    while (query.kPhotons.size() < knn)
    {
        msd = searchSqrDis;
        query.init(msd);
        map->searchKnn(0 , photon.pos , query);
        searchSqrDis *= 2.0;
    }
    
    int nFoundPhotons = query.kPhotons.size();

    if (nFoundPhotons == 0)
        return res;
    
    Vector3 nv;
    if (cmp(wo ^ inter.n) < 0)
        nv = -inter.n;
    else
        nv = inter.n;

    Real scale = 1.0 / (PI * msd * nFoundPhotons);
    
	BSDF bsdf(wo , inter , scene);
	Real cosTerm , pdf;
    for (int i = 0; i < nFoundPhotons; i++)
    {
        /*
        Real k = kernel(kPhotons[i].photon , p , msd);
        k = 1.0 / PI;
        Real scale = k / (nPaths * msd);
        */
        if (cmp(nv ^ query.kPhotons[i].photon->wi) > 0)
        {
            Color3 brdf = bsdf.f(scene , query.kPhotons[i].photon->wi , 
				cosTerm , &pdf);
			if (brdf.isBlack())
				continue;
            res = res + (brdf | query.kPhotons[i].photon->alpha) * 
				(cosTerm * scale / pdf);
        }
        else
        {
			Vector3 wi(query.kPhotons[i].photon->wi);
			wi.z *= -1.f;
			Color3 brdf = bsdf.f(scene , wi , cosTerm , &pdf);
			if (brdf.isBlack())
				continue;
			res = res + (brdf | query.kPhotons[i].photon->alpha) * 
				(cosTerm * scale / pdf);
        }
    }
    return res;
}
Color3 BidirPathTracing::getDirectIllumination(BidirPathState& cameraState , 
	const Vector3& hitPos , BSDF& bsdf)
{
	Color3 res(0);

	Real weight = 0.f;

	int lightCount = scene.lights.size();
	Real lightPickProb = 1.f / lightCount;

	int lightId = (int)(rng.randFloat() * lightCount);
	AbstractLight *light = scene.lights[lightId];

	Vector3 dirToLight;
	Real dist , directPdf , emissionPdf , cosAtLight , cosAtSurface;
	int sampledBSDFType;

	Color3 illu = light->illuminance(scene.sceneSphere ,
		hitPos , rng.randVector3() , dirToLight , dist ,
		directPdf , &emissionPdf , &cosAtLight);

	Real bsdfDirPdf , bsdfRevPdf , cosToLight;

	if (!illu.isBlack() && directPdf > 0)
	{
		Color3 bsdfFactor = bsdf.f(scene , dirToLight ,
			cosToLight , &bsdfDirPdf , &bsdfRevPdf);

		Color3 tmp;

		if (!bsdfFactor.isBlack())
		{	
			Real contProb = bsdf.continueProb;

			bsdfDirPdf *= light->isDelta() ? 0.f : contProb;
			bsdfRevPdf *= contProb;
            
			tmp = (illu | bsdfFactor) * cosToLight / (directPdf * lightPickProb);

			if (!tmp.isBlack() && !scene.occluded(hitPos , dirToLight ,
				hitPos + dirToLight * dist))
			{
				Real wLight = mis(bsdfDirPdf) / mis(directPdf * lightPickProb);
				Real wCamera = mis(emissionPdf * cosToLight / (directPdf * cosAtLight)) *
					(cameraState.dVCM + mis(bsdfRevPdf) * cameraState.dVC);
				weight = 1.f / (wLight + 1.f + wCamera);

				//fprintf(fp , "weight = %.6f\n" , weight);

				if (light->isDelta())
				{
					res = res + tmp;
				}
				else
				{
					Real _weight = mis(directPdf) / 
						(mis(directPdf) + mis(bsdfDirPdf));

					res = res + tmp * _weight;
				}
			}
		}
	}

	if (!light->isDelta())
	{
		Color3 bsdfFactor = bsdf.sample(scene , rng.randVector3() ,
			dirToLight , directPdf , cosAtSurface , &sampledBSDFType);

		if (!bsdfFactor.isBlack() && directPdf > 0)
		{
			Real weight = 1.f;

			Real lightPdf;
			if (!(sampledBSDFType & BSDF_SPECULAR))
			{
				illu = light->getRadiance(scene.sceneSphere , dirToLight , hitPos ,
					&lightPdf , &emissionPdf);

				if (cmp(lightPdf) == 0)
					return res;

				weight = mis(directPdf) /
					(mis(directPdf) + mis(lightPdf));
			}

			Intersection lightInter;
			Color3 tmp(0.f);
			Ray ray(hitPos + dirToLight * EPS , dirToLight);

			if (scene.intersect(ray , lightInter) != NULL)
			{
				if (lightInter.matId < 0)
				{
					if (light != scene.lights[-lightInter.matId - 1])
					{
						illu = Color3(0.f);
					}
				}
				else
				{
					illu = Color3(0.f);
				}
			}
			else
			{
				illu = Color3(0.f);
				if (scene.background != NULL)
				{
					illu = getLightRadiance(scene.background ,
							cameraState , Vector3(0) , ray.dir);
				}
			}

			if (!illu.isBlack())
			{
				tmp = (illu | bsdfFactor) * cosAtSurface /
					(directPdf);
				res = res + tmp * weight;
			}
		}
	}
    
	return res * weight;
}