Exemple #1
0
void Raytracer::forwardTrace(Photon* photon, const int bouncesLeft, const int numberOfPhotons) 
{
	if (bouncesLeft > 0)
	{
		Tri::Intersector intersector;
		float distance = inf();
		Ray photonRay(photon->position, photon->direction);

		if (_triTree.intersectRay(photonRay, intersector, distance))
		{
			Color3 pixelColor;
			Vector3 position, normal;
			Vector2 texCoord;
			intersector.getResult(position, normal, texCoord);
			photon->position = position + normal * 0.0001f;

			Photon* photonCopy = new Photon(photon);
			//if (bouncesLeft != _settings._forwardBounces)
			{
				_photonMap->insert(photon);
			}

			SurfaceSample surfaceSample(intersector);
			if (scatter(intersector, photonCopy))
			{
				forwardTrace(photonCopy, bouncesLeft - 1, numberOfPhotons);
			}
		}
	}
}
Exemple #2
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_
            LightSample ls(u[1], u[2], u[3]);
            LightInfo2 li = light->Sample_L(scene, ls, u[4], u[5], time);
            Spectrum Le(li.L);
            RayDifferential photonRay(li.ray);
            Normal Nl(li.N);
            if (li.pdf == 0.f || Le.IsBlack()) continue;
            Spectrum alpha = (AbsDot(Nl, photonRay.d) * Le) / (li.pdf * lightPdf);
            if (!alpha.IsBlack()) {
                // Follow photon path through scene and record intersections
                PBRT_PHOTON_MAP_STARTED_RAY_PATH(&photonRay, &alpha);
                bool specularPath = true;
                int nIntersections = 0;
                auto optPhotonIsect = scene.Intersect(photonRay);
                while (optPhotonIsect) {
                    ++nIntersections;
                    // Handle photon/surface intersection
                    alpha *= renderer->Transmittance(scene, photonRay, NULL, rng, arena);
                    BSDF *photonBSDF = optPhotonIsect->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(optPhotonIsect->dg.p, alpha, wo);
                        bool depositedPhoton = false;
                        if (specularPath && nIntersections > 1) {
                            if (!causticDone) {
                                PBRT_PHOTON_MAP_DEPOSITED_CAUSTIC_PHOTON(&optPhotonIsect->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(&optPhotonIsect->dg, &alpha, &wo);
                                depositedPhoton = true;
                                localDirectPhotons.push_back(photon);
                            }
                            else if (nIntersections > 1 && !indirectDone) {
                                PBRT_PHOTON_MAP_DEPOSITED_INDIRECT_PHOTON(&optPhotonIsect->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 = optPhotonIsect->dg.nn;
                            n = Faceforward(n, -photonRay.d);
                            localRadiancePhotons.push_back(RadiancePhoton(optPhotonIsect->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(optPhotonIsect->dg.p, wi, photonRay,
                                                optPhotonIsect->rayEpsilon);
                    optPhotonIsect = scene.Intersect(photonRay);
                }
                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;
    }
}
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);
            }
        }
    }
}
Exemple #4
0
    void preprocess(const Scene *scene) {
        /* Create a sample generator for the preprocess step */
        Sampler *sampler = static_cast<Sampler *>(
            NoriObjectFactory::createInstance("independent", PropertyList()));

        Emitter* distantsDisk = scene->getDistantEmitter();
        if(distantsDisk != nullptr ) {
            float lngstDir = scene->getBoundingBox().getLongestDirection();
            distantsDisk->setMaxRadius(lngstDir);
        }

        /* Allocate memory for the photon map */
        m_photonMap = std::unique_ptr<PhotonMap>(new PhotonMap());
        m_photonMap->reserve(m_photonCount);

		/* Estimate a default photon radius */
		if (m_photonRadius == 0)
			m_photonRadius = scene->getBoundingBox().getExtents().norm() / 500.0f;

        int storedPhotons = 0;

        const  std::vector<Emitter *> lights = scene->getEmitters();
        int nLights = lights.size();
        Color3f tp(1.0f, 1.0f, 1.0f);

        cout << "Starting to create "<< m_photonCount << " photons!" << endl;
        int percentDone= 0;
        int onePercent = int(floor(m_photonCount / 100.0));

        // create the expected number of photons
        while(storedPhotons < m_photonCount) {
            //uniformly sample 1 light (assuming that we only have area lights)
            int var = int(std::min(sampler->next1D()*nLights, float(nLights) - 1.0f));
            const areaLight* curLight = static_cast<const areaLight *> (lights[var]);

            //sample a photon
            Photon curPhoton;
            Vector3f unQuantDir(0.0f,0.0f,0.0f);
            curLight->samplePhoton(sampler, curPhoton, 1, nLights, unQuantDir);
            Color3f alpha = curPhoton.getPower();
            Color3f tp(1.0f, 1.0f, 1.0f);


            //trace the photon
            Intersection its;
            Ray3f photonRay(curPhoton.getPosition(), unQuantDir);
            m_shootedRays++;
            if (scene->rayIntersect(photonRay, its)) {
                while(true) {
                    const BSDF* curBSDF = its.mesh->getBSDF();


                    if (curBSDF->isDiffuse()) {
                        //store the photon
                        m_photonMap->push_back(Photon(
                            its.p  /* Position */,
                            -photonRay.d /* Direction*/,
                            tp * alpha  /* Power */
                        ));
                        storedPhotons++;
                    }

                    if(!(storedPhotons < m_photonCount)) break;

                    BSDFQueryRecord query = BSDFQueryRecord(its.toLocal(-photonRay.d), Vector3f(0.0f), EMeasure::ESolidAngle);
                    Color3f fi =  curBSDF->sample(query, sampler->next2D());

                    if(fi.maxCoeff() == 0.0f) break;

                    tp *= fi;

                    Vector3f wo = its.toWorld(query.wo);
                    photonRay = Ray3f(its.p, wo);

                    //ray escapes the scene
                    if (!scene->rayIntersect(photonRay, its)) break;

                    //stop critirium russian roulette
                    float q = tp.maxCoeff();
                    if(q < sampler->next1D()) break;
                    tp /= q;
                }

            }
            if(onePercent != 0) {
                if(storedPhotons % onePercent == 0){
                    int percent = int(floor(storedPhotons / onePercent));
                    if(percent % 10 == 0 && percentDone != percent){
                        percentDone = percent;
                        cout << percent << "%" << endl;
                    }
                }
            }
        }

		/* Build the photon map */
        m_photonMap->build();
    }