本文整理汇总了C++中Spectrum::Black方法的典型用法代码示例。如果您正苦于以下问题:C++ Spectrum::Black方法的具体用法?C++ Spectrum::Black怎么用?C++ Spectrum::Black使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类Spectrum
的用法示例。
在下文中一共展示了Spectrum::Black方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: Sample
Spectrum MixMaterial::Sample(const HitPoint &hitPoint,
const Vector &localFixedDir, Vector *localSampledDir,
const float u0, const float u1, const float passThroughEvent,
float *pdfW, float *absCosSampledDir, BSDFEvent *event,
const BSDFEvent requestedEvent) const {
const Frame frame(hitPoint.GetFrame());
HitPoint hitPointA(hitPoint);
matA->Bump(&hitPointA);
const Frame frameA(hitPointA.GetFrame());
const Vector fixedDirA = frameA.ToLocal(frame.ToWorld(localFixedDir));
HitPoint hitPointB(hitPoint);
matB->Bump(&hitPointB);
const Frame frameB(hitPointB.GetFrame());
const Vector fixedDirB = frameB.ToLocal(frame.ToWorld(localFixedDir));
const float weight2 = Clamp(mixFactor->GetFloatValue(hitPoint), 0.f, 1.f);
const float weight1 = 1.f - weight2;
const bool sampleMatA = (passThroughEvent < weight1);
const float weightFirst = sampleMatA ? weight1 : weight2;
const float weightSecond = sampleMatA ? weight2 : weight1;
const float passThroughEventFirst = sampleMatA ? (passThroughEvent / weight1) : (passThroughEvent - weight1) / weight2;
// Sample the first material, evaluate the second
const Material *matFirst = sampleMatA ? matA : matB;
const Material *matSecond = sampleMatA ? matB : matA;
HitPoint &hitPoint1 = sampleMatA ? hitPointA : hitPointB;
HitPoint &hitPoint2 = sampleMatA ? hitPointB : hitPointA;
const Frame &frame1 = sampleMatA ? frameA : frameB;
const Frame &frame2 = sampleMatA ? frameB : frameA;
const Vector &fixedDir1 = sampleMatA ? fixedDirA : fixedDirB;
const Vector &fixedDir2 = sampleMatA ? fixedDirB : fixedDirA;
// Sample the first material
Spectrum result = matFirst->Sample(hitPoint1, fixedDir1, localSampledDir,
u0, u1, passThroughEventFirst, pdfW, absCosSampledDir, event, requestedEvent);
if (result.Black())
return Spectrum();
*localSampledDir = frame1.ToWorld(*localSampledDir);
const Vector sampledDir2 = frame2.ToLocal(*localSampledDir);
*localSampledDir = frame.ToLocal(*localSampledDir);
*pdfW *= weightFirst;
result *= *pdfW;
// Evaluate the second material
const Vector &localLightDir = (hitPoint2.fromLight) ? fixedDir2 : sampledDir2;
const Vector &localEyeDir = (hitPoint2.fromLight) ? sampledDir2 : fixedDir2;
BSDFEvent eventSecond;
float pdfWSecond;
Spectrum evalSecond = matSecond->Evaluate(hitPoint2, localLightDir, localEyeDir, &eventSecond, &pdfWSecond);
if (!evalSecond.Black()) {
result += weightSecond * evalSecond;
*pdfW += weightSecond * pdfWSecond;
}
return result / *pdfW;
}
示例2: DirectHitInfiniteLight
void PathCPURenderThread::DirectHitInfiniteLight(
const bool lastSpecular, const Spectrum &pathThrouput,
const Vector &eyeDir, const float lastPdfW, Spectrum *radiance) {
PathCPURenderEngine *engine = (PathCPURenderEngine *)renderEngine;
Scene *scene = engine->renderConfig->scene;
// Infinite light
float directPdfW;
if (scene->envLight) {
const Spectrum envRadiance = scene->envLight->GetRadiance(scene, -eyeDir, &directPdfW);
if (!envRadiance.Black()) {
if(!lastSpecular) {
// MIS between BSDF sampling and direct light sampling
*radiance += pathThrouput * PowerHeuristic(lastPdfW, directPdfW) * envRadiance;
} else
*radiance += pathThrouput * envRadiance;
}
}
// Sun light
if (scene->sunLight) {
const Spectrum sunRadiance = scene->sunLight->GetRadiance(scene, -eyeDir, &directPdfW);
if (!sunRadiance.Black()) {
if(!lastSpecular) {
// MIS between BSDF sampling and direct light sampling
*radiance += pathThrouput * PowerHeuristic(lastPdfW, directPdfW) * sunRadiance;
} else
*radiance += pathThrouput * sunRadiance;
}
}
}
示例3: DirectHitInfiniteLight
void PathHybridState::DirectHitInfiniteLight(const Scene *scene, const Vector &eyeDir) {
// Infinite light
float directPdfW;
if (scene->envLight) {
const Spectrum envRadiance = scene->envLight->GetRadiance(*scene, -eyeDir, &directPdfW);
if (!envRadiance.Black()) {
if(!lastSpecular) {
// MIS between BSDF sampling and direct light sampling
sampleResults[0].radiance += throuput * PowerHeuristic(lastPdfW, directPdfW) * envRadiance;
} else
sampleResults[0].radiance += throuput * envRadiance;
}
}
// Sun light
if (scene->sunLight) {
const Spectrum sunRadiance = scene->sunLight->GetRadiance(*scene, -eyeDir, &directPdfW);
if (!sunRadiance.Black()) {
if(!lastSpecular) {
// MIS between BSDF sampling and direct light sampling
sampleResults[0].radiance += throuput * PowerHeuristic(lastPdfW, directPdfW) * sunRadiance;
} else
sampleResults[0].radiance += throuput * sunRadiance;
}
}
}
示例4: Evaluate
Spectrum MixMaterial::Evaluate(const HitPoint &hitPoint,
const Vector &localLightDir, const Vector &localEyeDir, BSDFEvent *event,
float *directPdfW, float *reversePdfW) const {
const Frame frame(hitPoint.GetFrame());
Spectrum result;
const float weight2 = Clamp(mixFactor->GetFloatValue(hitPoint), 0.f, 1.f);
const float weight1 = 1.f - weight2;
if (directPdfW)
*directPdfW = 0.f;
if (reversePdfW)
*reversePdfW = 0.f;
BSDFEvent eventMatA = NONE;
if (weight1 > 0.f) {
HitPoint hitPointA(hitPoint);
matA->Bump(&hitPointA);
const Frame frameA(hitPointA.GetFrame());
const Vector lightDirA = frameA.ToLocal(frame.ToWorld(localLightDir));
const Vector eyeDirA = frameA.ToLocal(frame.ToWorld(localEyeDir));
float directPdfWMatA, reversePdfWMatA;
const Spectrum matAResult = matA->Evaluate(hitPointA, lightDirA, eyeDirA, &eventMatA, &directPdfWMatA, &reversePdfWMatA);
if (!matAResult.Black()) {
result += weight1 * matAResult;
if (directPdfW)
*directPdfW += weight1 * directPdfWMatA;
if (reversePdfW)
*reversePdfW += weight1 * reversePdfWMatA;
}
}
BSDFEvent eventMatB = NONE;
if (weight2 > 0.f) {
HitPoint hitPointB(hitPoint);
matB->Bump(&hitPointB);
const Frame frameB(hitPointB.GetFrame());
const Vector lightDirB = frameB.ToLocal(frame.ToWorld(localLightDir));
const Vector eyeDirB = frameB.ToLocal(frame.ToWorld(localEyeDir));
float directPdfWMatB, reversePdfWMatB;
const Spectrum matBResult = matB->Evaluate(hitPointB, lightDirB, eyeDirB, &eventMatB, &directPdfWMatB, &reversePdfWMatB);
if (!matBResult.Black()) {
result += weight2 * matBResult;
if (directPdfW)
*directPdfW += weight2 * directPdfWMatB;
if (reversePdfW)
*reversePdfW += weight2 * reversePdfWMatB;
}
}
*event = eventMatA | eventMatB;
return result;
}
示例5: DirectLightSampling
void PathCPURenderThread::DirectLightSampling(
const float u0, const float u1, const float u2,
const float u3, const float u4,
const Spectrum &pathThrouput, const BSDF &bsdf,
const int depth, Spectrum *radiance) {
PathCPURenderEngine *engine = (PathCPURenderEngine *)renderEngine;
Scene *scene = engine->renderConfig->scene;
if (!bsdf.IsDelta()) {
// Pick a light source to sample
float lightPickPdf;
const LightSource *light = scene->SampleAllLights(u0, &lightPickPdf);
Vector lightRayDir;
float distance, directPdfW;
Spectrum lightRadiance = light->Illuminate(scene, bsdf.hitPoint,
u1, u2, u3, &lightRayDir, &distance, &directPdfW);
if (!lightRadiance.Black()) {
BSDFEvent event;
float bsdfPdfW;
Spectrum bsdfEval = bsdf.Evaluate(lightRayDir, &event, &bsdfPdfW);
if (!bsdfEval.Black()) {
const float epsilon = Max(MachineEpsilon::E(bsdf.hitPoint), MachineEpsilon::E(distance));
Ray shadowRay(bsdf.hitPoint, lightRayDir,
epsilon,
distance - epsilon);
RayHit shadowRayHit;
BSDF shadowBsdf;
Spectrum connectionThroughput;
// Check if the light source is visible
if (!scene->Intersect(device, false, u4, &shadowRay,
&shadowRayHit, &shadowBsdf, &connectionThroughput)) {
const float cosThetaToLight = AbsDot(lightRayDir, bsdf.shadeN);
const float directLightSamplingPdfW = directPdfW * lightPickPdf;
const float factor = cosThetaToLight / directLightSamplingPdfW;
if (depth >= engine->rrDepth) {
// Russian Roulette
bsdfPdfW *= Max(bsdfEval.Filter(), engine->rrImportanceCap);
}
// MIS between direct light sampling and BSDF sampling
const float weight = PowerHeuristic(directLightSamplingPdfW, bsdfPdfW);
*radiance += (weight * factor) * pathThrouput * connectionThroughput * lightRadiance * bsdfEval;
}
}
}
}
}
示例6: FinalizeRay
bool PathHybridState::FinalizeRay(const PathHybridRenderThread *renderThread,
const Ray *ray, const RayHit *rayHit, BSDF *bsdf, const float u0, Spectrum *radiance) {
if (rayHit->Miss())
return true;
else {
PathHybridRenderEngine *renderEngine = (PathHybridRenderEngine *)renderThread->renderEngine;
Scene *scene = renderEngine->renderConfig->scene;
// I have to check if it is an hit over a pass-through point
bsdf->Init(false, *scene, *ray, *rayHit, u0);
// Check if it is pass-through point
Spectrum t = bsdf->GetPassThroughTransparency();
if (!t.Black()) {
*radiance *= t;
// It is a pass-through material, continue to trace the ray. I do
// this on the CPU.
Ray newRay(*ray);
newRay.mint = rayHit->t + MachineEpsilon::E(rayHit->t);
RayHit newRayHit;
Spectrum connectionThroughput;
if (scene->Intersect(renderThread->device, false, u0, &newRay, &newRayHit,
bsdf, &connectionThroughput)) {
// Something was hit
return false;
} else {
*radiance *= connectionThroughput;
return true;
}
} else
return false;
}
}
示例7: DirectHitFiniteLight
void PathCPURenderThread::DirectHitFiniteLight(
const bool lastSpecular, const Spectrum &pathThrouput,
const float distance, const BSDF &bsdf, const float lastPdfW,
Spectrum *radiance) {
PathCPURenderEngine *engine = (PathCPURenderEngine *)renderEngine;
Scene *scene = engine->renderConfig->scene;
float directPdfA;
const Spectrum emittedRadiance = bsdf.GetEmittedRadiance(scene, &directPdfA);
if (!emittedRadiance.Black()) {
float weight;
if (!lastSpecular) {
const float lightPickProb = scene->PickLightPdf();
const float directPdfW = PdfAtoW(directPdfA, distance,
AbsDot(bsdf.fixedDir, bsdf.shadeN));
// MIS between BSDF sampling and direct light sampling
weight = PowerHeuristic(lastPdfW, directPdfW * lightPickProb);
} else
weight = 1.f;
*radiance += pathThrouput * weight * emittedRadiance;
}
}
示例8: EstimateIrradianceDirect
Spectrum EstimateIrradianceDirect(const Scene* scene,
const Light* light, const Point& p,
const Normal& n,
int lightSamp,
u_int sampleNum)
{
Spectrum Ed(0.); // direct irradiance
// Find light and BSDF sample values for direct lighting estimate
float ls1, ls2;
ls1 = RandomFloat();
ls2 = RandomFloat();
// Sample light source with multiple importance sampling
Vector wi;
float lightPdf;
VisibilityTester visibility;
Spectrum Li = light->Sample_L(p, n, ls1, ls2, &wi, &lightPdf, &visibility);
//printf("got light sample ");
//Li.printSelf();
if (lightPdf > 0. && !Li.Black()) {
if (visibility.Unoccluded(scene)) {
// Add light's contribution to reflected radiance
Li *= visibility.Transmittance(scene);
Ed += Li * AbsDot(wi, n) / lightPdf;
}
}
return Ed;
}
示例9: DirectLightSampling
void PathHybridState::DirectLightSampling(const PathHybridRenderThread *renderThread,
const float u0, const float u1, const float u2,
const float u3, const BSDF &bsdf) {
if (!bsdf.IsDelta()) {
PathHybridRenderEngine *renderEngine = (PathHybridRenderEngine *)renderThread->renderEngine;
Scene *scene = renderEngine->renderConfig->scene;
// Pick a light source to sample
float lightPickPdf;
const LightSource *light = scene->SampleAllLights(u0, &lightPickPdf);
Vector lightRayDir;
float distance, directPdfW;
Spectrum lightRadiance = light->Illuminate(*scene, bsdf.hitPoint.p,
u1, u2, u3, &lightRayDir, &distance, &directPdfW);
if (!lightRadiance.Black()) {
BSDFEvent event;
float bsdfPdfW;
Spectrum bsdfEval = bsdf.Evaluate(lightRayDir, &event, &bsdfPdfW);
if (!bsdfEval.Black()) {
const float epsilon = Max(MachineEpsilon::E(bsdf.hitPoint.p), MachineEpsilon::E(distance));
directLightRay = Ray(bsdf.hitPoint.p, lightRayDir,
epsilon, distance - epsilon);
const float cosThetaToLight = AbsDot(lightRayDir, bsdf.hitPoint.shadeN);
const float directLightSamplingPdfW = directPdfW * lightPickPdf;
const float factor = cosThetaToLight / directLightSamplingPdfW;
if (depth >= renderEngine->rrDepth) {
// Russian Roulette
bsdfPdfW *= RenderEngine::RussianRouletteProb(bsdfEval, renderEngine->rrImportanceCap);
}
// MIS between direct light sampling and BSDF sampling
const float weight = PowerHeuristic(directLightSamplingPdfW, bsdfPdfW);
directLightRadiance = (weight * factor) * throuput * lightRadiance * bsdfEval;
} else
directLightRadiance = Spectrum();
} else
directLightRadiance = Spectrum();
} else
directLightRadiance = Spectrum();
}
示例10: Sample_f
// BSDF Method Definitions
Spectrum BSDF::Sample_f(const Vector &wo, Vector *wi, BxDFType flags,
BxDFType *sampledType) const {
float pdf;
Spectrum f = Sample_f(wo, wi, RandomFloat(), RandomFloat(),
RandomFloat(), &pdf, flags, sampledType);
if (!f.Black() && pdf > 0.) f /= pdf;
return f;
}
示例11:
// Mirror Method Definitions
BSDF *Mirror::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading) const {
// Allocate _BSDF_, possibly doing bump-mapping with _bumpMap_
DifferentialGeometry dgs;
if (bumpMap)
Bump(bumpMap, dgGeom, dgShading, &dgs);
else
dgs = dgShading;
BSDF *bsdf = BSDF_ALLOC(BSDF)(dgs, dgGeom.nn);
Spectrum R = Kr->Evaluate(dgs).Clamp();
if (!R.Black())
bsdf->Add(BSDF_ALLOC(SpecularReflection)(R,
BSDF_ALLOC(FresnelNoOp)()));
return bsdf;
}
示例12: DirectHitFiniteLight
void PathHybridState::DirectHitFiniteLight(const Scene *scene, const float distance, const BSDF &bsdf) {
float directPdfA;
const Spectrum emittedRadiance = bsdf.GetEmittedRadiance(&directPdfA);
if (!emittedRadiance.Black()) {
float weight;
if (!lastSpecular) {
const float lightPickProb = scene->PickLightPdf();
const float directPdfW = PdfAtoW(directPdfA, distance,
AbsDot(bsdf.hitPoint.fixedDir, bsdf.hitPoint.shadeN));
// MIS between BSDF sampling and direct light sampling
weight = PowerHeuristic(lastPdfW, directPdfW * lightPickProb);
} else
weight = 1.f;
sampleResults[0].radiance += throuput * weight * emittedRadiance;
}
}
示例13: ConnectToEye
void LightCPURenderThread::ConnectToEye(const float u0,
const BSDF &bsdf, const Point &lensPoint, const Spectrum &flux,
vector<SampleResult> &sampleResults) {
LightCPURenderEngine *engine = (LightCPURenderEngine *)renderEngine;
Scene *scene = engine->renderConfig->scene;
Vector eyeDir(bsdf.hitPoint - lensPoint);
const float eyeDistance = eyeDir.Length();
eyeDir /= eyeDistance;
BSDFEvent event;
Spectrum bsdfEval = bsdf.Evaluate(-eyeDir, &event);
if (!bsdfEval.Black()) {
const float epsilon = Max(MachineEpsilon::E(lensPoint), MachineEpsilon::E(eyeDistance));
Ray eyeRay(lensPoint, eyeDir,
epsilon,
eyeDistance - epsilon);
float scrX, scrY;
if (scene->camera->GetSamplePosition(lensPoint, eyeDir, eyeDistance, &scrX, &scrY)) {
RayHit eyeRayHit;
BSDF bsdfConn;
Spectrum connectionThroughput;
if (!scene->Intersect(device, true, u0, &eyeRay, &eyeRayHit, &bsdfConn, &connectionThroughput)) {
// Nothing was hit, the light path vertex is visible
const float cosToCamera = Dot(bsdf.shadeN, -eyeDir);
const float cosAtCamera = Dot(scene->camera->GetDir(), eyeDir);
const float cameraPdfW = 1.f / (cosAtCamera * cosAtCamera * cosAtCamera *
scene->camera->GetPixelArea());
const float cameraPdfA = PdfWtoA(cameraPdfW, eyeDistance, cosToCamera);
const float fluxToRadianceFactor = cameraPdfA;
const Spectrum radiance = connectionThroughput * flux * fluxToRadianceFactor * bsdfEval;
AddSampleResult(sampleResults, PER_SCREEN_NORMALIZED, scrX, scrY,
radiance, 1.f);
}
}
}
}
示例14: generatePath
int BidirIntegrator::generatePath(const Scene *scene, const Ray &r,
const Sample *sample, const int *bsdfOffset,
const int *bsdfCompOffset,
BidirVertex *vertices, int maxVerts) const {
int nVerts = 0;
RayDifferential ray(r.o, r.d);
while (nVerts < maxVerts) {
// Find next vertex in path and initialize _vertices_
Intersection isect;
if (!scene->Intersect(ray, &isect))
break;
BidirVertex &v = vertices[nVerts];
v.bsdf = isect.GetBSDF(ray); // do before Ns is set!
v.p = isect.dg.p;
v.ng = isect.dg.nn;
v.ns = v.bsdf->dgShading.nn;
v.wi = -ray.d;
++nVerts;
// Possibly terminate bidirectional path sampling
if (nVerts > 2) {
float rrProb = .2f;
if (RandomFloat() > rrProb)
break;
v.rrWeight = 1.f / rrProb;
}
// Initialize _ray_ for next segment of path
float u1 = sample->twoD[bsdfOffset[nVerts-1]][0];
float u2 = sample->twoD[bsdfOffset[nVerts-1]][1];
float u3 = sample->oneD[bsdfCompOffset[nVerts-1]][0];
Spectrum fr = v.bsdf->Sample_f(v.wi, &v.wo, u1, u2, u3,
&v.bsdfWeight, BSDF_ALL, &v.flags);
if (fr.Black() && v.bsdfWeight == 0.f)
break;
ray = RayDifferential(v.p, v.wo);
}
// Initialize additional values in _vertices_
for (int i = 0; i < nVerts-1; ++i)
vertices[i].dAWeight = vertices[i].bsdfWeight *
AbsDot(-vertices[i].wo, vertices[i+1].ng) /
DistanceSquared(vertices[i].p, vertices[i+1].p);
return nVerts;
}
示例15: IndirectLo
Spectrum IrradianceCache::IndirectLo(const Point &p,
const Normal &n, const Vector &wo, BSDF *bsdf,
BxDFType flags, const Sample *sample,
const Scene *scene) const {
if (bsdf->NumComponents(flags) == 0)
return Spectrum(0.);
Spectrum E;
if (!InterpolateIrradiance(scene, p, n, &E)) {
// Compute irradiance at current point
u_int scramble[2] = { RandomUInt(), RandomUInt() };
float sumInvDists = 0.;
for (int i = 0; i < nSamples; ++i) {
// Trace ray to sample radiance for irradiance estimate
// Update irradiance statistics for rays traced
static StatsCounter nIrradiancePaths("Irradiance Cache",
"Paths followed for irradiance estimates");
++nIrradiancePaths;
float u[2];
Sample02(i, scramble, u);
Vector w = CosineSampleHemisphere(u[0], u[1]);
RayDifferential r(p, bsdf->LocalToWorld(w));
if (Dot(r.d, n) < 0) r.d = -r.d;
Spectrum L(0.);
// Do path tracing to compute radiance along ray for estimate
{
// Declare common path integration variables
Spectrum pathThroughput = 1.;
RayDifferential ray(r);
bool specularBounce = false;
for (int pathLength = 0; ; ++pathLength) {
// Find next vertex of path
Intersection isect;
if (!scene->Intersect(ray, &isect))
break;
if (pathLength == 0)
r.maxt = ray.maxt;
pathThroughput *= scene->Transmittance(ray);
// Possibly add emitted light at path vertex
if (specularBounce)
L += pathThroughput * isect.Le(-ray.d);
// Evaluate BSDF at hit point
BSDF *bsdf = isect.GetBSDF(ray);
// Sample illumination from lights to find path contribution
const Point &p = bsdf->dgShading.p;
const Normal &n = bsdf->dgShading.nn;
Vector wo = -ray.d;
L += pathThroughput *
UniformSampleOneLight(scene, p, n, wo, bsdf, sample);
if (pathLength+1 == maxIndirectDepth) break;
// Sample BSDF to get new path direction
// Get random numbers for sampling new direction, \mono{bs1}, \mono{bs2}, and \mono{bcs}
float bs1 = RandomFloat(), bs2 = RandomFloat(), bcs = RandomFloat();
Vector wi;
float pdf;
BxDFType flags;
Spectrum f = bsdf->Sample_f(wo, &wi, bs1, bs2, bcs,
&pdf, BSDF_ALL, &flags);
if (f.Black() || pdf == 0.)
break;
specularBounce = (flags & BSDF_SPECULAR) != 0;
pathThroughput *= f * AbsDot(wi, n) / pdf;
ray = RayDifferential(p, wi);
// Possibly terminate the path
if (pathLength > 3) {
float continueProbability = .5f;
if (RandomFloat() > continueProbability)
break;
pathThroughput /= continueProbability;
}
}
}
E += L;
float dist = r.maxt * r.d.Length();
sumInvDists += 1.f / dist;
}
E *= M_PI / float(nSamples);
// Add computed irradiance value to cache
// Update statistics for new irradiance sample
static StatsCounter nSamplesComputed("Irradiance Cache",
"Irradiance estimates computed");
++nSamplesComputed;
// Compute bounding box of irradiance sample's contribution region
static float minMaxDist =
.001f * powf(scene->WorldBound().Volume(), 1.f/3.f);
static float maxMaxDist =
.125f * powf(scene->WorldBound().Volume(), 1.f/3.f);
float maxDist = nSamples / sumInvDists;
if (minMaxDist > 0.f)
maxDist = Clamp(maxDist, minMaxDist, maxMaxDist);
maxDist *= maxError;
BBox sampleExtent(p);
sampleExtent.Expand(maxDist);
octree->Add(IrradianceSample(E, p, n, maxDist),
sampleExtent);
}
return .5f * bsdf->rho(wo, flags) * E;
}