예제 #1
0
std::vector<double> randomshift_on_sphere(const std::vector<double> &insamples, int num_pts){

    std::vector<double> output(3*num_pts, 0.0);

    //Find two random vectors on the sphere
    double rx=0,ry=0,rz=0;
    uniformSampleSphere(drand48(), drand48(), &rx, &ry, &rz);
    double temp1[] = {rx, ry, rz};
    uniformSampleSphere(drand48(), drand48(), &rx, &ry, &rz);
    double temp2[]  = {rx, ry, rz};

    //Compute a quaternion from these vectors
    double quat[] = {0,0,0,1};
    QuaternionFromTwoVectors(temp1, temp2, quat);

    //Use the above quaternion to rotate all samples.
    for(int b = 0; b < num_pts; b++){
        double qmat[16], qvout[4];
        double qvec[] = {insamples[3*b+0], insamples[3*b+1], insamples[3*b+2],1};
        ConvertQuaternionToMatrix(quat, qmat);
        MultiplyVecMat(qmat, qvec, qvout);

        //rotated samples are here
        output[3*b+0] = (qvout[0]);
        output[3*b+1] = (qvout[1]);
        output[3*b+2] = (qvout[2]);
    }

    return output;
}
예제 #2
0
  void BackendScene::generateVPL( size_t vplNum, const char* vplFile,size_t vpldepth )
  {
    this->vpls.clear();
    SET_CLAMPING_DISTANCE( 0.05 * sceneradius );

    //------------------------- READ FILE IF IT DOES EXIST--------------------------------------
    if( strcmp(vplFile,"")){
      FILE *ptr;
      ptr = fopen(vplFile,"rb");  
      if (ptr)
      {
        size_t siz;
        fread(&siz,sizeof(size_t),1,ptr);
        vpls.resize(siz);
        for (size_t i = 0 ; i<siz; ++i)
          vpls[i].read(ptr);

        fclose(ptr);
        std::cout << "Vpl file read. Total # of vpls:"<< vpls.size()<<std::endl;
        return;
      }
      else  std::cout << "Unable to read vpl file."<< std::endl;
    }

    //------------------------- OTHERWISE GENERATE VPLS--------------------------------------

    Random rnd(RND_SEED);

    // Place VPLs that substitute the original lights (direct VPLs)
    std::vector<Ref<Light> >::iterator it = allLights.begin();
    for ( ; it !=allLights.end(); ++it)
    {
      // Replace TriangleLight
      if( (*it).dynamicCast<TriangleLight>() )
      {
        Ref<TriangleLight> tr = (*it).dynamicCast<TriangleLight>();
        Color I = tr->L * length(cross(tr->e1,tr->e2)) * 0.5;
        int triangleSamples = 1024;
        // HACK to avoid too many VPLs for many quads...
        if (allLights.size() > 2000)
          triangleSamples = 100;
        for (int i=0 ; i < triangleSamples ; ++i)
        {
          Vector3f pos = uniformSampleTriangle(rnd.getFloat(),rnd.getFloat(),tr->v0,tr->v1,tr->v2);
          this->vpls.push_back(vplVPL(pos, -tr->Ng, I * rcp((float)triangleSamples) ) );
        }
      }
      // Replace SpotLight
      else if ((*it).dynamicCast<SpotLight>())
      {
        Ref<SpotLight> sl = (*it).dynamicCast<SpotLight>();
        if ( sl->cosAngleMax >= 0.05 || sl->cosAngleMin <= 0.95 )
          throw std::runtime_error("Not supporting spotlights with other than 90 degree falloff for VPL generation.");

        this->vpls.push_back(vplVPL(sl->P,sl->_D,sl->I));
      }
      // Replace environment map
      else if ((*it).dynamicCast<HDRILight>())
      {
        Ref<HDRILight> hd = (*it).dynamicCast<HDRILight>();
        int envmapSamples = 32768;
        float dirlightdistance = DIR_LIGHT_DISTANCE;
        for (int i=0 ; i < envmapSamples ; ++i)
        {
          Vector3f pos(uniformSampleSphere(rnd.getFloat(),rnd.getFloat()));
          Vector3f dir = -pos;
          pos *= dirlightdistance; pos += scenecenter;
          // CHECK below line later it is not completely precise
          Color I = hd->Le(-dir) * four_pi * rcp((float)envmapSamples) * dirlightdistance * dirlightdistance;               
          this->vpls.push_back(vplVPL(pos, -dir , I ));
        }
      }
      else if ((*it).dynamicCast<DirectionalLight>())
      {
        Ref<DirectionalLight> sl = (*it).dynamicCast<DirectionalLight>();
        float distance = 100000;
        this->vpls.push_back(vplVPL(sl->_wo*distance,sl->_wo,sl->E*distance*distance));
      }
      else
        throw std::runtime_error("Not supported light type for VPL generation.");
    }

    // Place VPLs  (indirect VPLs)
    size_t direct = this->vpls.size();
    size_t orig = this->allLights.size();
    if (vpldepth <=1) return;
    while (this->vpls.size() < (vplNum+direct))
    {
      // Sample orig lights for photons
      Ref<Light> vp = this->allLights[rnd.getInt(orig)];
      Vector3f pos; 
      Sample3f dir;
      Vec2f vr(rnd.getFloat(),rnd.getFloat());
      Vec2f vs(rnd.getFloat(),rnd.getFloat());

      Color I = vp->samplePhoton(dir,pos,vr,vs,sceneradius,scenecenter);
      if (dir.pdf==0.0f) continue;
      I *= (float) orig  *  rcp(dir.pdf);

      // Generate a path for the photon and add VPLs 
      int maxdepth = int(vpldepth) - 1;   // -1 because 1 for pt means only direct light
      while ( maxdepth-- && (I != zero ) )
      {
        Ray ray (pos,dir,32*std::numeric_limits<float>::epsilon(), inf);
        DifferentialGeometry dg;
        rtcIntersect(this->scene,(RTCRay&)ray);
        this->postIntersect(ray,dg);

        if (!ray)//nothing is hit
          break;
        /*! face forward normals */
        if (dot(dg.Ng, ray.dir) > 0)
        {
          dg.Ng = -dg.Ng; dg.Ns = -dg.Ns;
        }
        CompositedBRDF brdfs;
        if (dg.material) dg.material->shade(ray, Medium::Vacuum(), dg, brdfs);
        BRDFType diffuseBRDFTypes = (BRDFType)(DIFFUSE); 
        Vec2f s = Vec2f(rnd.getFloat(),rnd.getFloat());
        Color c = brdfs.sample(-ray.dir,dg, dir,diffuseBRDFTypes,s,rnd.getFloat(),diffuseBRDFTypes);
        if (c==zero || dir.pdf==0.0f) break;

        // the dot prod should not be zero since then c would be zero
        float dott = dot(dir,dg.Ns);
        if (dott==0.0f) break;
        Color contrib = I * c * rcp(dott) * rcp((float)vplNum) ;
        //if (std::isnan(contrib.r) || std::isnan(contrib.g) || std::isnan(contrib.b))
        //  break;

        this->vpls.push_back(vplVPL(dg.P,-dg.Ns,contrib));

        Color contribScale =  c * rcp(dir.pdf);
        float rrProb = min(1.0f, reduce_avg(contribScale));
        if(rrProb == 0.0f)break;
        if (rnd.getFloat() > rrProb)
          break;

        I *= contribScale * rcp(rrProb);
        pos = dg.P;
      }
    }

    //------------------------------PERTURB VPLS WITH THE SAME POSITION-----------------------------------------------------------
    auto vplComp = [] (const vplVPL& vp1,const vplVPL& vp2) { return vp1.P < vp2.P; };
    std::sort(this->vpls.begin(),this->vpls.end(),vplComp);
    std::vector<vplVPL>::iterator itt = this->vpls.begin();
    while(itt != ( vpls.end() - 1 ) && itt != vpls.end())
    {
      vplVPL& v1 = *itt, & v2 = *(itt+1);
      if(v1.P == v2.P)
      {
        v2.I += v1.I;
        itt = this->vpls.erase(itt);
      }
      else
        ++itt;
    }

    //------------------------------WRITE OUT VPLS INTO A FILE-----------------------------------------------------------

    // writing out the VPLs
    FILE *ptr;
    ptr = fopen(vplFile,"wb");  
    if (ptr)
    {
      size_t siz = this->vpls.size();
      fwrite(&siz,sizeof(size_t),1,ptr);
      if (vpls.size())
        for (size_t i = 0 ; i<siz; ++i)
          vpls[i].write(ptr);

      fclose(ptr);
      std::cout << "Vpl file written. Total # of vpls:"<< vpls.size()<<std::endl;
    }
    else std::cout << "Unable to write vpl file. Total # of vpls: "<<vpls.size() << std::endl;

    return;
  }