Пример #1
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;
  }
Пример #2
0
    void sampleLightPos(const Scene* scene, const LightSample* l_sample, const point3* shdP,
                        LightPoint* lpos, uchar* EDF, float* areaPDF) {
        LightInfo lInfo = scene->lights[sampleDiscrete1D(scene->lightPowerDistribution, l_sample->uLight, areaPDF)];
        ushort lightPropPtr = USHRT_MAX;
        if (lInfo.atInfinity) {
            lpos->atInfinity = true;
            
            const uchar* lightsData_p = scene->materialsData + scene->environment->idx_envLightProperty;
            const LightPropertyInfo* lpInfo = (const LightPropertyInfo*)lightsData_p;
            
            //IBLの重ね合わせを考える場合は、複合BSDFからのサンプリングのように1sample MISを行った方が良い?
            //ただ全方位のIBLを重ね合わせたい需要はあんまり無さそうだからMISしなくても良いかも。
            *areaPDF *= 1.0f;//本当はここで複合IBLから1要素を確率的にサンプリングする。
            uint whichIBL = 0;
            
            float uvPDF;
            lightsData_p += sizeof(LightPropertyInfo);
            for (uint i = 0; i < lpInfo->numEEDFs; ++i) {
                AlignPtrG(&lightsData_p, 4);
                uchar EnvLPElemID = *lightsData_p;
                switch (EnvLPElemID) {
                    case EnvLPElem_ImageBased: {
                        const ImageBasedEnvLElem* llIBEnvElem = (const ImageBasedEnvLElem*)lightsData_p;
                        
                        if (whichIBL == i) {
                            lpos->uv = sampleContinuousConsts2D_H((const ContinuousConsts2D_H*)(scene->otherResourcesData + llIBEnvElem->idx_Dist2D),
                                                                  l_sample->uPos[0], l_sample->uPos[1], &uvPDF);
                            float theta = lpos->uv.s1 * M_PI_F;
                            float phi = lpos->uv.s0 * 2 * M_PI_F;
                            float sinTheta = sinf(theta);
                            lpos->p = point3(-sinf(phi) * sinTheta, cosf(theta), cosf(phi) * sinTheta);
                            *areaPDF *= uvPDF / (2 * M_PI_F * M_PI_F * sinTheta);
                            break;
                        }
                        
                        lightsData_p += sizeof(ImageBasedEnvLElem);
                        break;
                    }
                    default: {
                        break;
                    }
                }
            }
            
//            for (uint i = 0; i < lpInfo->numEEDFs; ++i) {
//                //各IBLが選択される確率の加重平均をとる処理。
//            }
        }
        else {
            lpos->atInfinity = false;
            
            lpos->faceID = lInfo.reference;
            const Face* face = scene->faces + lpos->faceID;
            const point3* p0 = scene->vertices + face->p0;
            const point3* p1 = scene->vertices + face->p1;
            const point3* p2 = scene->vertices + face->p2;
            
            float b0, b1, b2;
            uniformSampleTriangle(l_sample->uPos[0], l_sample->uPos[1], &b0, &b1);
            b2 = 1.0f - b0 - b1;
            
            vector3 ng = cross(*p1 - *p0, *p2 - *p0);
            
            float area = 0.5f * length(ng);
            *areaPDF *= 1.0f / area;
            
            lpos->p = b0 * *p0 + b1 * *p1 + b2 * *p2;
            lpos->gNormal = normalize(ng);
            
            bool hasVNormal = face->vn0 != UINT_MAX && face->vn1 != UINT_MAX && face->vn2 != UINT_MAX;
            if (hasVNormal)
                lpos->sNormal = normalize(b0 * *(scene->normals + face->vn0) +
                                          b1 * *(scene->normals + face->vn1) +
                                          b2 * *(scene->normals + face->vn2));
            else
                lpos->sNormal = lpos->gNormal;
            
            lpos->hasTangent = face->vt0 != UINT_MAX && face->vt1 != UINT_MAX && face->vt2 != UINT_MAX;
            if (lpos->hasTangent)
                lpos->sTangent = normalize(b0 * *(scene->tangents + face->vt0) +
                                           b1 * *(scene->tangents + face->vt1) +
                                           b2 * *(scene->tangents + face->vt2));
            
            bool hasUV = face->uv0 != UINT_MAX && face->uv1 != UINT_MAX && face->uv2 != UINT_MAX;
            if (hasUV) {
                float2 uv0 = *(scene->uvs + face->uv0);
                float2 uv1 = *(scene->uvs + face->uv1);
                float2 uv2 = *(scene->uvs + face->uv2);
                lpos->uv = b0 * uv0 + b1 * uv1 + b2 * uv2;
                
                float2 dUV0m2 = uv0 - uv2;
                float2 dUV1m2 = uv1 - uv2;
                float3 dP0m2 = *p0 - *p2;
                float3 dP1m2 = *p1 - *p2;
                float invDetUV = 1.0f / (dUV0m2.x * dUV1m2.y - dUV0m2.y * dUV1m2.x);
                float3 uDir = invDetUV * float3(dUV1m2.y * dP0m2.x - dUV0m2.y * dP1m2.x,
                                                dUV1m2.y * dP0m2.y - dUV0m2.y * dP1m2.y,
                                                dUV1m2.y * dP0m2.z - dUV0m2.y * dP1m2.z);
                if (hasVNormal)
                    lpos->uDir = normalize(cross(cross(lpos->sNormal, uDir), lpos->sNormal));
                else
                    lpos->uDir = normalize(uDir);
            }
            
            lightPropPtr = face->lightPtr;
        }
        EDFAlloc(scene, lightPropPtr, lpos, EDF);
    }