Float Phong::GetKsWeight() const { Float ksAvg = Luminance(Ks->Avg()); Float kdAvg = Luminance(Kd->Avg()); Float sum = ksAvg + kdAvg; if (sum <= Float(0.0)) { return Float(0.0); } else { return ksAvg / sum; } }
float HeterogeneousVolume::pMedium(const Ray &inRay, float dist) const{ const float tau = HeterogeneousVolume::integrateDensity(inRay, dist); const vec3f sigmaAtT = isSubsurface ? lookUpSubSurfaceVolumeData(inRay.origin + inRay.direction * dist, EXTINCTION): extinctionCoeff*lookUpDensity(inRay.origin + inRay.direction * dist); return Luminance(sigmaAtT) * exp(-tau); }
float HeterogeneousVolume::integrateDensity(const Ray &inRay, float dist) const{ float densityAccumulation = 0; float intersectDist = std::numeric_limits<float>::max(); if(check(inRay, &intersectDist)){ return densityAccumulation; } dist = MIN(dist, intersectDist); vec3f p = inRay.origin; uint nSteps = std::ceil(dist / (2*stepSize)); double ss = dist / nSteps, multiplier = (1.0/6.0)*ss; const vec3f fullStep = inRay.direction * ss, halfStep = fullStep * 0.5; float node1 = isSubsurface ? Luminance(lookUpSubSurfaceVolumeData(p, EXTINCTION)) : lookUpDensity(p); for(uint i = 0; i < nSteps; i++){ float node2 = isSubsurface ? Luminance(lookUpSubSurfaceVolumeData(p+halfStep, EXTINCTION)) : lookUpDensity(p+halfStep), node3 = isSubsurface ? Luminance(lookUpSubSurfaceVolumeData(p+fullStep, EXTINCTION)) : lookUpDensity(p+fullStep); densityAccumulation += multiplier*(node1+node2*4+node3); node1 = node3; p += fullStep; } return densityAccumulation; }
bool Footprint(location loc, bitmap* bmp) { const int footprint = 5; // 9x9 footprint const int offset = footprint - 1; const rgb rgbWhite(255,255,255); if (loc.x - offset < 0 || loc.x + offset > bmp->max().x) return false; if (loc.y - offset < 0 || loc.y + offset > bmp->max().y) return false; int bottom_y = loc.y - offset; int top_y = loc.y + offset; int left_x = loc.x - offset; int right_x = loc.x + offset; for (int x = left_x; x <= right_x; x ++) for (int y = bottom_y; y <= top_y; y ++) if (Luminance(location(x,y),bmp) == false) return false; return true; }
// 0 - success // 1 - check fail // 2 - iter > 30 // 3 - can not make forward progress // 4 - finally failed. // return true: sample succeed, use pdfSuccess // false: sample fail, use pdfFailure bool HeterogeneousVolume::sampleDistance(const Ray &inRay, float &distance, float &pdfSuccess, float &pdfFailure) const{ float intersectDist; float desiredDensity = isSubsurface ? -log(1.0 - rng->genFloat()) : -log(1.0 - rng->genFloat()) / Luminance(extinctionCoeff); float t = 0, integratedDensity = 0, densityAtMinT = 0, densityAtT = 0; int flag = findDesiredIntegralDensity(inRay, desiredDensity, t, integratedDensity, densityAtMinT, densityAtT); float expVal = exp(-integratedDensity); bool sampleState = false; switch(flag){ case 0: // success // satisfying: [desiredDensity = integratedDensity], [denisityAtT is real], [sample distance = t]. pdfSuccess = expVal * densityAtT; distance = t; sampleState = true; break; case 1: // check fail // this one need extra calculation pdfFailure = expVal; distance = inRay.intersectDist; sampleState = false; break; case 2: // it > 30 // we may use the integratedDensity with errorbound pdfSuccess = expVal * densityAtT; distance = t; sampleState = true; break; case 3: // stuck in progress pdfFailure = expVal; distance = inRay.intersectDist; sampleState = false; break; case 4: // finally failed. pdfFailure = expVal; distance = inRay.intersectDist; sampleState = false; break; default: break; } return sampleState; }
int HeterogeneousVolume::findDesiredIntegralDensity(const Ray &inRay, const float desiredDensity, float &t, float &integratedDensity, float &densityAtMinT, float &densityAtT) const { float dist; if(check(inRay, &dist)){ return 1; } integratedDensity = 0; vec3f p = inRay.origin; uint nSteps = std::ceil(dist / (2*stepSize)); double ss = dist / nSteps, multiplier = (1.0/6.0)*ss; const vec3f fullStep = inRay.direction * ss, halfStep = fullStep * 0.5; float node1 = isSubsurface ? Luminance(lookUpSubSurfaceVolumeData(p, EXTINCTION)) : lookUpDensity(p); densityAtMinT = node1; for(uint i = 0; i < nSteps; i++){ float node2 = isSubsurface ? Luminance(lookUpSubSurfaceVolumeData(p+halfStep, EXTINCTION)) : lookUpDensity(p+halfStep), node3 = isSubsurface ? Luminance(lookUpSubSurfaceVolumeData(p+fullStep, EXTINCTION)) : lookUpDensity(p+fullStep); float newDensity = integratedDensity + multiplier*(node1+node2*4+node3); if(newDensity >= desiredDensity){ float a = 0, b = ss, x = a, fx = integratedDensity - desiredDensity, stepSizeSqr = ss * ss, temp = 1.0 / stepSizeSqr; int it = 1; while(true){ float dfx = temp * (node1 * stepSizeSqr - (3 * node1 - 4 * node2 + node3) * ss * x + 2 * (node1 - 2 * node2 + node3) * x * x); x -= fx / dfx; if(x <= a || x >= b || dfx == 0){ x = 0.5 * (b + a); } float intval = integratedDensity + temp * (1.0/6.0) * (x * (6 * node1 * stepSizeSqr - 3 * (3 * node1 - 4 * node2 + node3) * ss * x + 4 * (node1 - 2 * node2 + node3) * x * x)); fx = intval - desiredDensity; if(std::abs(fx) < NEWTON_BISECTION_EPS){ t = x + ss * i; integratedDensity = intval; densityAtT = temp * (node1 * stepSizeSqr - (3*node1 - 4*node2 + node3)*ss*x + 2*(node1 - 2*node2 + node3)*x*x); return 0; } else if(++it > 30){ // we still use the distance sample. t = x + ss * i; integratedDensity = intval; densityAtT = temp * (node1 * stepSizeSqr - (3*node1 - 4*node2 + node3)*ss*x + 2*(node1 - 2*node2 + node3)*x*x); /* std::cerr << "findDesiredIntegralDensity(): stuck in Newton-Bisection -- fx = " << fx << " dfx = " << dfx << " a = " << a << " b = " << b << " stepsize = " << ss << std::endl;*/ return 2; } if(fx > 0){ b = x; } else{ a = x; } } } vec3f next = p + fullStep; if(p == next){ // std::cerr << "findDesiredIntegralDensity(): can not make forward progress -- stepsize = " << ss << std::endl; return 3; } integratedDensity = newDensity; node1 = node3; p = next; } return 4; }
float HeterogeneousVolume::getAlbedo(const vec3f &p) const{ return Luminance(lookUpSubSurfaceVolumeData(p, SCATTERING)) / Luminance(lookUpSubSurfaceVolumeData(p, EXTINCTION)); }
float HeterogeneousVolume::getAlbedo() const{ return Luminance(scatteringCoeff) / Luminance(extinctionCoeff); }