Logo Search packages:      
Sourcecode: yafaray version File versions  Download package

bool photonIntegrator_t::preprocess (  ) [virtual]

gets called before the scene rendering (i.e. before first call to integrate)

Returns:
false when preprocessing could not be done properly, true otherwise

Reimplemented from surfaceIntegrator_t.

Definition at line 127 of file photonintegr.cc.

References mcIntegrator_t::background, mcIntegrator_t::causticMap, renderState_t::chromatic, pSample_t::color, progressBar_t::done(), dsRadius, material_t::getReflectivity(), material_t::getVolumeHandler(), progressBar_t::init(), material_t::initBSDF(), mcIntegrator_t::lightPowerD, mcIntegrator_t::lights, lookupRad, surfacePoint_t::material, mcIntegrator_t::maxBounces, surfacePoint_t::N, mcIntegrator_t::nCausPhotons, surfacePoint_t::Ng, mcIntegrator_t::nPaths, surfacePoint_t::P, radianceMap, material_t::scatterPhoton(), mcIntegrator_t::sDepth, progressBar_t::setTag(), mcIntegrator_t::trShad, progressBar_t::update(), renderState_t::userdata, and renderState_t::wavelength.

{
      std::stringstream set;
      gTimer.addEvent("prepass");
      gTimer.start("prepass");

      Y_INFO << integratorName << ": Starting preprocess..." << yendl;

      if(trShad)
      {
            set << "ShadowDepth [" << sDepth << "]";
      }
      if(!set.str().empty()) set << "+";
      set << "RayDepth [" << rDepth << "]";

      diffuseMap.clear();
      causticMap.clear();
      background = scene->getBackground();
      lights = scene->lights;
      std::vector<light_t*> tmplights;

      if(!set.str().empty()) set << "+";
      
      set << "DiffPhotons [" << nDiffusePhotons << "]+CausPhotons[" << nCausPhotons << "]";
      
      if(finalGather)
      {
            set << "+FG[" << nPaths << ", " << gatherBounces << "]";
      }
      
      settings = set.str();
      
      ray_t ray;
      float lightNumPdf, lightPdf, s1, s2, s3, s4, s5, s6, s7, sL;
      int numCLights = 0;
      int numDLights = 0;
      float fNumLights = 0.f;
      float *energies = NULL;
      color_t pcol;

      tmplights.clear();

      for(int i=0;i<(int)lights.size();++i)
      {
            if(lights[i]->shootsDiffuseP())
            {
                  numDLights++;
                  tmplights.push_back(lights[i]);
            }
      }
      
      fNumLights = (float)numDLights;
      energies = new float[numDLights];

      for(int i=0;i<numDLights;++i) energies[i] = tmplights[i]->totalEnergy().energy();

      lightPowerD = new pdf1D_t(energies, numDLights);
      
      Y_INFO << integratorName << ": Light(s) photon color testing for diffuse map:" << yendl;
      for(int i=0;i<numDLights;++i)
      {
            pcol = tmplights[i]->emitPhoton(.5, .5, .5, .5, ray, lightPdf);
            lightNumPdf = lightPowerD->func[i] * lightPowerD->invIntegral;
            pcol *= fNumLights*lightPdf/lightNumPdf; //remember that lightPdf is the inverse of the pdf, hence *=...
            Y_INFO << integratorName << ": Light [" << i+1 << "] Photon col:" << pcol << " | lnpdf: " << lightNumPdf << yendl;
      }
      
      delete[] energies;
      
      //shoot photons
      bool done=false;
      unsigned int curr=0;
      // for radiance map:
      preGatherData_t pgdat(&diffuseMap);
      
      surfacePoint_t sp;
      renderState_t state;
      unsigned char userdata[USER_DATA_SIZE+7];
      state.userdata = (void *)( &userdata[7] - ( ((size_t)&userdata[7])&7 ) ); // pad userdata to 8 bytes
      state.cam = scene->getCamera();
      progressBar_t *pb;
      int pbStep;
      if(intpb) pb = intpb;
      else pb = new ConsoleProgressBar_t(80);
      
      Y_INFO << integratorName << ": Building diffuse photon map..." << yendl;
      
      pb->init(128);
      pbStep = std::max(1U, nDiffusePhotons / 128);
      pb->setTag("Building diffuse photon map...");
      //Pregather diffuse photons

      float invDiffPhotons = 1.f / (float)nDiffusePhotons;
      
      while(!done)
      {
            if(scene->getSignals() & Y_SIG_ABORT) {  pb->done(); if(!intpb) delete pb; return false; }

            s1 = RI_vdC(curr);
            s2 = scrHalton(2, curr);
            s3 = scrHalton(3, curr);
            s4 = scrHalton(4, curr);

            sL = float(curr) * invDiffPhotons;
            int lightNum = lightPowerD->DSample(sL, &lightNumPdf);
            if(lightNum >= numDLights)
            {
                  Y_ERROR << integratorName << ": lightPDF sample error! " << sL << "/" << lightNum << "... stopping now." << yendl;
                  delete lightPowerD;
                  return false;
            }

            pcol = tmplights[lightNum]->emitPhoton(s1, s2, s3, s4, ray, lightPdf);
            ray.tmin = MIN_RAYDIST;
            ray.tmax = -1.0;
            pcol *= fNumLights*lightPdf/lightNumPdf; //remember that lightPdf is the inverse of th pdf, hence *=...
            
            if(pcol.isBlack())
            {
                  ++curr;
                  done = (curr >= nDiffusePhotons);
                  continue;
            }

            int nBounces=0;
            bool causticPhoton = false;
            bool directPhoton = true;
            const material_t *material = NULL;
            BSDF_t bsdfs;

            while( scene->intersect(ray, sp) )
            {
                  if(isnan(pcol.R) || isnan(pcol.G) || isnan(pcol.B))
                  {
                        Y_WARNING << integratorName << ": NaN  on photon color for light" << lightNum + 1 << "." << yendl;
                        continue;
                  }
                  
                  color_t transm(1.f);
                  color_t vcol(0.f);
                  const volumeHandler_t* vol = NULL;
                  
                  if(material)
                  {
                        if((bsdfs&BSDF_VOLUMETRIC) && (vol=material->getVolumeHandler(sp.Ng * -ray.dir < 0)))
                        {
                              if(vol->transmittance(state, ray, vcol)) transm = vcol;
                        }
                  }
                  
                  vector3d_t wi = -ray.dir, wo;
                  material = sp.material;
                  material->initBSDF(state, sp, bsdfs);
                  
                  if(bsdfs & (BSDF_DIFFUSE))
                  {
                        //deposit photon on surface
                        if(!causticPhoton)
                        {
                              photon_t np(wi, sp.P, pcol);
                              diffuseMap.pushPhoton(np);
                              diffuseMap.setNumPaths(curr);
                        }
                        // create entry for radiance photon:
                        // don't forget to choose subset only, face normal forward; geometric vs. smooth normal?
                        if(finalGather && ourRandom() < 0.125 && !causticPhoton )
                        {
                              vector3d_t N = FACE_FORWARD(sp.Ng, sp.N, wi);
                              radData_t rd(sp.P, N);
                              rd.refl = material->getReflectivity(state, sp, BSDF_DIFFUSE | BSDF_GLOSSY | BSDF_REFLECT);
                              rd.transm = material->getReflectivity(state, sp, BSDF_DIFFUSE | BSDF_GLOSSY | BSDF_TRANSMIT);
                              pgdat.rad_points.push_back(rd);
                        }
                  }
                  // need to break in the middle otherwise we scatter the photon and then discard it => redundant
                  if(nBounces == maxBounces) break;
                  // scatter photon
                  int d5 = 3*nBounces + 5;

                  s5 = scrHalton(d5, curr);
                  s6 = scrHalton(d5+1, curr);
                  s7 = scrHalton(d5+2, curr);
                  
                  pSample_t sample(s5, s6, s7, BSDF_ALL, pcol, transm);

                  bool scattered = material->scatterPhoton(state, sp, wi, wo, sample);
                  if(!scattered) break; //photon was absorped.

                  pcol = sample.color;

                  causticPhoton = ((sample.sampledFlags & (BSDF_GLOSSY | BSDF_SPECULAR | BSDF_DISPERSIVE)) && directPhoton) ||
                                          ((sample.sampledFlags & (BSDF_GLOSSY | BSDF_SPECULAR | BSDF_FILTER | BSDF_DISPERSIVE)) && causticPhoton);
                  directPhoton = (sample.sampledFlags & BSDF_FILTER) && directPhoton;

                  ray.from = sp.P;
                  ray.dir = wo;
                  ray.tmin = MIN_RAYDIST;
                  ray.tmax = -1.0;
                  ++nBounces;
            }
            ++curr;
            if(curr % pbStep == 0) pb->update();
            done = (curr >= nDiffusePhotons);
      }
      pb->done();
      pb->setTag("Diffuse photon map built.");
      Y_INFO << integratorName << ": Diffuse photon map built." << yendl;
      Y_INFO << integratorName << ": Shot "<<curr<<" photons from " << numDLights << " light(s)" << yendl;

      delete lightPowerD;

      tmplights.clear();

      for(int i=0;i<(int)lights.size();++i)
      {
            if(lights[i]->shootsCausticP())
            {
                  numCLights++;
                  tmplights.push_back(lights[i]);
            }
      }

      if(numCLights > 0)
      {
            
            done = false;
            curr=0;

            fNumLights = (float)numCLights;
            energies = new float[numCLights];

            for(int i=0;i<numCLights;++i) energies[i] = tmplights[i]->totalEnergy().energy();

            lightPowerD = new pdf1D_t(energies, numCLights);
            
            Y_INFO << integratorName << ": Light(s) photon color testing for caustics map:" << yendl;
            for(int i=0;i<numCLights;++i)
            {
                  pcol = tmplights[i]->emitPhoton(.5, .5, .5, .5, ray, lightPdf);
                  lightNumPdf = lightPowerD->func[i] * lightPowerD->invIntegral;
                  pcol *= fNumLights*lightPdf/lightNumPdf; //remember that lightPdf is the inverse of the pdf, hence *=...
                  Y_INFO << integratorName << ": Light [" << i+1 << "] Photon col:" << pcol << " | lnpdf: " << lightNumPdf << yendl;
            }
            
            delete[] energies;

            Y_INFO << integratorName << ": Building caustics photon map..." << yendl;
            pb->init(128);
            pbStep = std::max(1U, nCausPhotons / 128);
            pb->setTag("Building caustics photon map...");
            //Pregather caustic photons
            
            float invCaustPhotons = 1.f / (float)nCausPhotons;
            
            while(!done)
            {
                  if(scene->getSignals() & Y_SIG_ABORT) { pb->done(); if(!intpb) delete pb; return false; }
                  state.chromatic = true;
                  state.wavelength = scrHalton(5,curr);

                  s1 = RI_vdC(curr);
                  s2 = scrHalton(2, curr);
                  s3 = scrHalton(3, curr);
                  s4 = scrHalton(4, curr);

                  sL = float(curr) * invCaustPhotons;
                  int lightNum = lightPowerD->DSample(sL, &lightNumPdf);
                  
                  if(lightNum >= numCLights)
                  {
                        Y_ERROR << integratorName << ": lightPDF sample error! "<<sL<<"/"<<lightNum<<"... stopping now." << yendl;
                        delete lightPowerD;
                        return false;
                  }

                  pcol = tmplights[lightNum]->emitPhoton(s1, s2, s3, s4, ray, lightPdf);
                  ray.tmin = MIN_RAYDIST;
                  ray.tmax = -1.0;
                  pcol *= fNumLights*lightPdf/lightNumPdf; //remember that lightPdf is the inverse of th pdf, hence *=...
                  if(pcol.isBlack())
                  {
                        ++curr;
                        done = (curr >= nCausPhotons);
                        continue;
                  }
                  int nBounces=0;
                  bool causticPhoton = false;
                  bool directPhoton = true;
                  const material_t *material = NULL;
                  BSDF_t bsdfs;

                  while( scene->intersect(ray, sp) )
                  {
                        if(isnan(pcol.R) || isnan(pcol.G) || isnan(pcol.B))
                        {
                              Y_WARNING << integratorName << ": NaN  on photon color for light" << lightNum + 1 << "." << yendl;
                              continue;
                        }
                        
                        color_t transm(1.f);
                        color_t vcol(0.f);
                        const volumeHandler_t* vol = NULL;
                        
                        if(material)
                        {
                              if((bsdfs&BSDF_VOLUMETRIC) && (vol=material->getVolumeHandler(sp.Ng * -ray.dir < 0)))
                              {
                                    if(vol->transmittance(state, ray, vcol)) transm = vcol;
                              }
                        }
                        
                        vector3d_t wi = -ray.dir, wo;
                        material = sp.material;
                        material->initBSDF(state, sp, bsdfs);

                        if(bsdfs & BSDF_DIFFUSE)
                        {
                              if(causticPhoton)
                              {
                                    photon_t np(wi, sp.P, pcol);
                                    causticMap.pushPhoton(np);
                                    causticMap.setNumPaths(curr);
                              }
                        }
                        
                        // need to break in the middle otherwise we scatter the photon and then discard it => redundant
                        if(nBounces == maxBounces) break;
                        // scatter photon
                        int d5 = 3*nBounces + 5;

                        s5 = scrHalton(d5, curr);
                        s6 = scrHalton(d5+1, curr);
                        s7 = scrHalton(d5+2, curr);

                        pSample_t sample(s5, s6, s7, BSDF_ALL, pcol, transm);

                        bool scattered = material->scatterPhoton(state, sp, wi, wo, sample);
                        if(!scattered) break; //photon was absorped.

                        pcol = sample.color;

                        causticPhoton = ((sample.sampledFlags & (BSDF_GLOSSY | BSDF_SPECULAR | BSDF_DISPERSIVE)) && directPhoton) ||
                                                ((sample.sampledFlags & (BSDF_GLOSSY | BSDF_SPECULAR | BSDF_FILTER | BSDF_DISPERSIVE)) && causticPhoton);
                        directPhoton = (sample.sampledFlags & BSDF_FILTER) && directPhoton;
                        
                        if(state.chromatic && (sample.sampledFlags & BSDF_DISPERSIVE))
                        {
                              state.chromatic=false;
                              color_t wl_col;
                              wl2rgb(state.wavelength, wl_col);
                              pcol *= wl_col;
                        }
                        
                        ray.from = sp.P;
                        ray.dir = wo;
                        ray.tmin = MIN_RAYDIST;
                        ray.tmax = -1.0;
                        ++nBounces;
                  }
                  ++curr;
                  if(curr % pbStep == 0) pb->update();
                  done = (curr >= nCausPhotons);
            }
            
            pb->done();
            pb->setTag("Caustics photon map built.");
            delete lightPowerD;
      }
      else
      {
            Y_INFO << integratorName << ": No caustic source lights found, skiping caustic gathering..." << yendl;
      }
      
      Y_INFO << integratorName << ": Shot "<<curr<<" caustic photons from " << numCLights <<" light(s)." << yendl;
      Y_INFO << integratorName << ": Stored caustic photons: " << causticMap.nPhotons() << yendl;
      Y_INFO << integratorName << ": Stored diffuse photons: " << diffuseMap.nPhotons() << yendl;
      
      if(diffuseMap.nPhotons() > 0)
      {
            Y_INFO << integratorName << ": Building diffuse photons kd-tree:" << yendl;
            pb->setTag("Building diffuse photons kd-tree...");
            diffuseMap.updateTree();
            Y_INFO << integratorName << ": Done." << yendl;
      }

      if(causticMap.nPhotons() > 0)
      {
            Y_INFO << integratorName << ": Building caustic photons kd-tree:" << yendl;
            pb->setTag("Building caustic photons kd-tree...");
            causticMap.updateTree();
            Y_INFO << integratorName << ": Done." << yendl;
      }

      if(diffuseMap.nPhotons() < 50)
      {
            Y_ERROR << integratorName << ": Too few diffuse photons, stopping now." << yendl;
            return false;
      }
      
      lookupRad = 4*dsRadius*dsRadius;
      
      tmplights.clear();

      if(!intpb) delete pb;
      
      if(finalGather) //create radiance map:
      {
#ifdef USING_THREADS
            // == remove too close radiance points ==//
            kdtree::pointKdTree< radData_t > *rTree = new kdtree::pointKdTree< radData_t >(pgdat.rad_points);
            std::vector< radData_t > cleaned;
            for(unsigned int i=0; i<pgdat.rad_points.size(); ++i)
            {
                  if(pgdat.rad_points[i].use)
                  {
                        cleaned.push_back(pgdat.rad_points[i]);
                        eliminatePhoton_t elimProc(pgdat.rad_points[i].normal);
                        PFLOAT maxrad = 0.01f*dsRadius; // 10% of diffuse search radius
                        rTree->lookup(pgdat.rad_points[i].pos, elimProc, maxrad);
                  }
            }
            pgdat.rad_points.swap(cleaned);
            // ================ //
            int nThreads = scene->getNumThreads();
            pgdat.radianceVec.resize(pgdat.rad_points.size());
            if(intpb) pgdat.pbar = intpb;
            else pgdat.pbar = new ConsoleProgressBar_t(80);
            pgdat.pbar->init(pgdat.rad_points.size());
            pgdat.pbar->setTag("Pregathering radiance data for final gathering...");
            std::vector<preGatherWorker_t *> workers;
            for(int i=0; i<nThreads; ++i) workers.push_back(new preGatherWorker_t(&pgdat, dsRadius, nDiffuseSearch));
            
            for(int i=0;i<nThreads;++i) workers[i]->run();
            for(int i=0;i<nThreads;++i)   workers[i]->wait();
            for(int i=0;i<nThreads;++i)   delete workers[i];
            
            radianceMap.swapVector(pgdat.radianceVec);
            pgdat.pbar->done();
            pgdat.pbar->setTag("Pregathering radiance data done...");
            if(!intpb) delete pgdat.pbar;
#else
            if(radianceMap.nPhotons() != 0)
            {
                  Y_WARNING << integratorName << ": radianceMap not empty!" << yendl;
                  radianceMap.clear();
            }
            
            Y_INFO << integratorName << ": Creating radiance map..." << yendl;
            progressBar_t *pbar;
            if(intpb) pbar = intpb;
            else pbar = new ConsoleProgressBar_t(80);
            pbar->init(pgdat.rad_points.size());
            foundPhoton_t *gathered = (foundPhoton_t *)malloc(nDifuseSearch * sizeof(foundPhoton_t));
            PFLOAT dsRadius_2 = dsRadius*dsRadius;
            for(unsigned int n=0; n< pgdat.rad_points.size(); ++n)
            {
                  PFLOAT radius = dsRadius_2; //actually the square radius...
                  int nGathered = diffuseMap.gather(pgdat.rad_points[n].pos, gathered, nDifuseSearch, radius);
                  color_t sum(0.0);
                  if(nGathered > 0)
                  {
                        color_t surfCol = pgdat.rad_points[n].refl;
                        vector3d_t rnorm = pgdat.rad_points[n].normal;
                        float scale = 1.f / ( float(diffuseMap.nPaths()) * radius * M_PI);
                        
                        if(isnan(scale))
                        {
                              Y_WARNING << integratorName << ": NaN on (scale)" << yendl;
                              break;
                        }
                        
                        for(int i=0; i<nGathered; ++i)
                        {
                              vector3d_t pdir = gathered[i].photon->direction();
                              
                              if( rnorm * pdir > 0.f ) sum += surfCol * scale * gathered[i].photon->color();
                              else sum += pgdat.rad_points[n].transm * scale * gathered[i].photon->color();
                        }
                  }
                  photon_t radP(pgdat.rad_points[n].normal, pgdat.rad_points[n].pos, sum);
                  radianceMap.pushPhoton(radP);
                  if(n && !(n&7)) pbar->update(8);
            }
            pbar->done();
            if(!pbar) delete pbar;
            free(gathered);
#endif
            Y_INFO << integratorName << ": Radiance tree built... Updating the tree..." << yendl;
            radianceMap.updateTree();
            Y_INFO << integratorName << ": Done." << yendl;
      }

      gTimer.stop("prepass");
      Y_INFO << integratorName << ": Photonmap building time: " << gTimer.getTime("prepass") << yendl;

      return true;
}

Here is the call graph for this function:


Generated by  Doxygen 1.6.0   Back to index