Skip to content

Instantly share code, notes, and snippets.

@bachi95
Created January 25, 2015 01:55
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