Created
January 25, 2015 01:55
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Color Renderer::LbssrdfSingle(const ScenePtr& scene, | |
const Fragment& fragment, const BSSRDF* bssrdf, const Vector3& wo, | |
const Sample& sample, | |
const BSSRDFSampleIndex* bssrdfSampleIndex, | |
WorldDebugData* debugData) const { | |
const Vector3& pwo = fragment.getPosition(); | |
const Vector3& no = fragment.getNormal(); | |
float coso = absdot(wo, fragment.getNormal()); | |
float eta = bssrdf->getEta(); | |
float Ft = 1.0f - Material::fresnelDieletric(coso, 1.0f, eta); | |
float sigmaTr = bssrdf->getSigmaTr(fragment).luminance(); | |
Color scatter = bssrdf->getScatter(fragment); | |
Color sigmaT = bssrdf->getAttenuation(fragment); | |
Vector3 woRefract = Goblin::specularRefract(wo, no, 1.0f, eta); | |
const vector<Light*>& lights = scene->getLights(); | |
Color Lsinglescatter(0.0f); | |
// single scattering part | |
for(uint32_t i = 0; i < bssrdfSampleIndex->samplesNum; ++i) { | |
const BSSRDFSample bssrdfSample(sample, *bssrdfSampleIndex, i); | |
// sample a distance with exponential falloff | |
float d = exponentialSample(bssrdfSample.uSingleScatter, sigmaTr); | |
Vector3 pSample = pwo + d * woRefract; | |
float samplePdf = exponentialPdf(d, sigmaTr); | |
// sample a light from pSample | |
float pickLightPdf; | |
int lightIndex = mPowerDistribution->sampleDiscrete( | |
bssrdfSample.uPickLight, &pickLightPdf); | |
const Light* light = lights[lightIndex]; | |
Vector3 wi; | |
float epsilon, lightPdf; | |
Ray shadowRay; | |
Color L = light->sampleL(pSample, 1e-5f, bssrdfSample.ls, | |
&wi, &lightPdf, &shadowRay); | |
if(L == Color::Black || lightPdf == 0.0f) { | |
continue; | |
} | |
// preserve the maxt since the next intersection test will modify | |
// it to the closest intersection, but we still need this maxt to | |
// cast shadow ray from that intersection to light | |
float maxt = shadowRay.maxt; | |
Intersection wiIntersect; | |
// TODO we can use a material indexed lookup table to query | |
// surface with this particular BSSRDF instead of doing a whole | |
// scene intersaction test | |
if(scene->intersect(shadowRay, &epsilon, &wiIntersect)) { | |
// if not, the pSample is out of the BSSRDF geometry already | |
if(wiIntersect.getMaterial()->getBSSRDF() == bssrdf) { | |
// update shadow ray to start from pwi | |
const Fragment& fwi = wiIntersect.fragment; | |
const Vector3& pwi = fwi.getPosition(); | |
const Vector3& ni = fwi.getNormal(); | |
shadowRay.mint = shadowRay.maxt + epsilon; | |
shadowRay.maxt = maxt; | |
if(!scene->intersect(shadowRay)) { | |
float p = bssrdf->phase(wi, woRefract); | |
float cosi = absdot(ni, wi); | |
float Fti = 1.0f - | |
Material::fresnelDieletric(cosi, 1.0f, eta); | |
Color sigmaTi = bssrdf->getAttenuation(fwi); | |
float G = absdot(ni, woRefract) / cosi; | |
Color sigmaTC = sigmaT + G * sigmaTi; | |
float di = length(pwi - pSample); | |
float et = 1.0f / eta; | |
float diPrime = di * absdot(wi, ni) / | |
sqrt(1.0f - et * et * (1.0f - cosi * cosi)); | |
Lsinglescatter += (Ft * Fti * p * scatter / sigmaTC) * | |
expColor(-diPrime * sigmaTi) * | |
expColor(-d * sigmaT) * L / | |
(lightPdf * pickLightPdf * samplePdf); | |
} | |
} | |
} | |
} | |
Lsinglescatter /= (float)bssrdfSampleIndex->samplesNum; | |
return Lsinglescatter; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment