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; }
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); }