float GlossyMaterial::getDirectionSampleProbDensity(const Ray& inRay, const Ray& outRay) const { if(!outRay.contactObject) return 0; LocalFrame lf; vec3f normal = outRay.getContactNormal(); vec3f reflDir = -normal.dot(inRay.direction)*normal*2 + inRay.direction; lf.buildFromNormal(reflDir); vec3f coeff = coeffTex.getColor(outRay.contactObject->getTexCoord(outRay.contactObjectTriangleID, outRay.origin)); return cosineSphericalSampler.getProbDensity(lf, outRay.direction, coeff.x); }
vec3f IptTracer::colorByConnectingLights(Ray lastRay , Ray ray , bool dirIlluWeight) { Ray lightRay = genEmissiveSurfaceSample(true , false); lightRay.direction = (ray.origin - lightRay.origin); Real dist = lightRay.direction.length(); dist = max(dist , 1e-6f); Real dist2 = dist * dist; lightRay.direction.normalize(); Ray outRay = ray; outRay.direction = -lightRay.direction; vec3f decayFactor = outRay.getRadianceDecay(dist); if(!testVisibility(outRay, lightRay)) return vec3f(0.f); //outRay.direction = -cameraState.lastRay->direction; //vec3f bsdfFactor2 = lightRay.getBSDF(outRay); vec3f bsdfFactor = lastRay.getBSDF(outRay); if (y(bsdfFactor) < 1e-7f) return vec3f(0.f); Real cosAtLight = clampf(lightRay.getContactNormal().dot(lightRay.direction) , 0.f , 1.f); Real cosToLight = clampf(ray.getContactNormal().dot(-lightRay.direction) , 0.f , 1.f); if (cosAtLight < 1e-6f || cosToLight < 1e-6f) return vec3f(0.f); vec3f tmp = lightRay.color * cosAtLight * bsdfFactor * cosToLight / (lightRay.originProb * dist2); //fprintf(fp , "weight = %.8f , bsdfToLightPdf = %.8f , cosAtLight = %.8f ,\ntoLightOriginPdf = %.8f , originProb = %.8f , dist = %.8f\n" , // weightFactor , bsdfToLightPdf , cosAtLight , toLightOriginPdf , lightRay.originProb , dist); vec3f res = tmp * decayFactor; if (dirIlluWeight && useRayMarching) { Real p1 = lightRay.originProb; Real p2 = lightRay.originProb * (cosAtLight / M_PI) * cosToLight / dist2 * (partialPathNum * gatherRadius * gatherRadius * M_PI); Real weightFactor = p1 / (p1 + p2); res *= weightFactor; } if (dirIlluWeight && !useRayMarching) { Real p1 = lastRay.getDirectionSampleProbDensity(outRay); Real p2 = lightRay.originProb * dist2 / cosAtLight; Real weightFactor = p2 / (p1 + p2); res *= weightFactor; } //printf("sur weight = %.8f\n" , weightFactor); /* vec3f resx = camera.eliminateVignetting(res , cameraState.index) * pixelNum; if (cameraState.ray->contactObject)//(resx[0] + resx[1] + resx[2] >= 2) { fprintf(fp , "=====================\n"); fprintf(fp , "cosAtLight = %.8f, cosToLight = %.8f, originPdf = %.8f, pdf = %.8f, weight=%.8f,\nres=(%.10f,%.10f,%.10f)\nbsdf=(%.10f,%.10f,%.10f)\n" , cosAtLight , cosToLight , originProb , pdf , weightFactor , resx[0] , resx[1] , resx[2] , bsdfFactor[0] , bsdfFactor[1] , bsdfFactor[2]); } */ return res; }
Ray SceneObject::emit(bool isUniformOrigin , bool isUniformDir) const { Ray ray; if(!areaValues.size()) { ray.direction = vec3f(0, 0, 0); ray.directionProb = 1; ray.color = vec3f(0, 0, 0); return ray; } if (isUniformOrigin) { float rnd = RandGenerator::genFloat()*totalArea; unsigned index = (lower_bound(areaValues.begin(), areaValues.end(), rnd)-areaValues.begin()); if(index >= areaValues.size()) index = areaValues.size() - 1; ray.contactObject = (SceneObject*)this; ray.contactObjectTriangleID = index; ray.origin = genRandTrianglePosition(ray.contactObjectTriangleID); ray.originProb = weight / totalArea; } else { float rnd = RandGenerator::genFloat()*totalEnergy; unsigned index = (lower_bound(energyDensity.begin(), energyDensity.end(), rnd)-energyDensity.begin()); if(index >= energyDensity.size()) index = energyDensity.size() - 1; ray.contactObject = (SceneObject*)this; ray.contactObjectTriangleID = index; ray.origin = genRandTrianglePosition(ray.contactObjectTriangleID); float prob; if (index == 0) prob = energyDensity[index] / totalEnergy; else prob = (energyDensity[index] - energyDensity[index - 1]) / totalEnergy; ray.originProb = weight * prob / areaValues[index]; } UniformSphericalSampler uniformSphericalSampler; CosineSphericalSampler cosineSphericalSampler; LocalFrame lf = ray.contactObject->getAutoGenWorldLocalFrame(ray.contactObjectTriangleID, ray.origin); if (isUniformDir) ray.direction = uniformSphericalSampler.genSample(lf); else ray.direction = cosineSphericalSampler.genSample(lf); if(ray.getContactNormal().dot(ray.direction) < 0) ray.direction = -ray.direction; ray.insideObject = scene->findInsideObject(ray, ray.contactObject); ray.current_tid = scene->getContactTreeTid(ray); ray.color = ray.getBSDF(ray); if(!emissive()) ray.color = vec3f(1, 1, 1); if (isUniformDir) ray.directionProb = uniformSphericalSampler.getProbDensity(lf , ray.direction) * 2.f; else ray.directionProb = cosineSphericalSampler.getProbDensity(lf, ray.direction); ray.directionSampleType = ray.originSampleType = Ray::RANDOM; if(!scene->usingGPU()) { Scene::ObjSourceInformation osi; NoSelfIntersectionCondition condition(scene, ray); float dist = scene->intersect(ray, osi, &condition); if(dist > 0) { ray.intersectDist = dist; ray.intersectObject = scene->objects[osi.objID]; ray.intersectObjectTriangleID = osi.triangleID; } } return ray; }
void MCRenderer::samplePathIter(Path& path, Ray& prevRay, unsigned depth, bool isLightPath, bool firstDiff) const { if(prevRay.directionSampleType == Ray::RANDOM && firstDiff){ path.push_back(prevRay); return ; } Ray termRay; termRay.origin = prevRay.origin; termRay.direction = vec3f(0, 0, 0); termRay.color = vec3f(0, 0, 0); termRay.directionProb = 1; termRay.directionSampleType = Ray::DEFINITE; termRay.insideObject = termRay.contactObject = termRay.intersectObject = NULL; path.push_back(prevRay); Ray nextRay; if(prevRay.insideObject) { nextRay = prevRay.insideObject->scatter(prevRay , isLightPath , true); } else if(prevRay.intersectObject) { nextRay = prevRay.intersectObject->scatter(prevRay , isLightPath , true); } else { path.push_back(termRay); return; } if (nextRay.direction.length() > 0.5 && nextRay.insideObject == NULL && nextRay.contactObject != NULL) { vec3f geoN = nextRay.getContactNormal(false); vec3f shdN = nextRay.getContactNormal(true); vec3f wi = -prevRay.direction; vec3f wo = nextRay.direction; float wiDotGeoN = geoN.dot(wi); float woDotGeoN = geoN.dot(wo); float wiDotShdN = shdN.dot(wi); float woDotShdN = shdN.dot(wo); // prevent light leak due to shading normals if (wiDotGeoN * wiDotShdN <= 0 || woDotGeoN * woDotShdN <= 0) { //printf("wi: %.6f %.6f, wo: %.6f %.6f\n" , wiDotGeoN , wiDotShdN , woDotGeoN , woDotShdN); nextRay.direction = vec3f(0.f); nextRay.color = vec3f(0.f); } // adjoint bsdf correction // if (isLightPath) // { // float denom = wiDotGeoN * woDotShdN; // if (std::abs(denom) < 1e-2) // { // nextRay.direction = vec3f(0.f); // nextRay.color = vec3f(0.f); // } // else // { // float correction = std::abs((wiDotShdN * woDotGeoN) / (denom)); // nextRay.color *= correction; // } // } } // if (!isLightPath) // { // std::string str; // // if (nextRay.contactObject != NULL) str = nextRay.contactObject->getType(); // else str = "X"; // // if (str != "T") printf("%s, pos = (%.6f,%.6f,%.6f)\n" , str.c_str() , // nextRay.origin.x , nextRay.origin.y , nextRay.origin.z); // } if(nextRay.direction.length() < 0.5) { path.push_back(nextRay); return; } if(depth+1 > maxDepth) { path.push_back(termRay); return; } NoSelfIntersectionCondition condition(&renderer->scene, nextRay); Scene::ObjSourceInformation osi; float dist; dist = renderer->scene.intersect(nextRay, osi, &condition); if(dist < 0) { path.push_back(nextRay); path.push_back(termRay); return; } else { nextRay.intersectObject = renderer->scene.objects[osi.objID]; nextRay.intersectObjectTriangleID = osi.triangleID; nextRay.intersectDist = dist; } //if (nextRay.contactObject && nextRay.contactObjectTriangleID >= nextRay.contactObject->faceVertexIndexList.size()) //{ // printf("sample path error, %d , %d\n" , (int)nextRay.contactObjectTriangleID , (int)nextRay.contactObject->faceVertexIndexList.size()); //} samplePathIter(path, nextRay, depth + 1, isLightPath , firstDiff); }