BSDF *custom_material_phong::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading) const { //not sure about this yet DifferentialGeometry dgs=dgShading; //or this: //allocate memory for BSDF, poiting bsdf to a new BSDF BSDF *bsdf = BSDF_ALLOC(BSDF)(dgs, dgGeom.nn); //allocate to diff a custom BxDF with reflection spectrum kd Spectrum kd = Kd->Evaluate(dgs).Clamp(); BxDF *diff = BSDF_ALLOC(custom_BxDF_phongDiffuse)(kd); //my specular reflectance Spectrum ks = Ks->Evaluate(dgs).Clamp(); BxDF *spec = BSDF_ALLOC(custom_BxDF_phongSpecular)(ks,float(n)); //add both diff and spec BSDFS to the BSDF of this material //***sets the BSDF of this material bsdf->Add(diff); bsdf->Add(spec); return bsdf; }

static Spectrum L(const Scene *scene, const Renderer *renderer, const Camera *camera, MemoryArena &arena, RNG &rng, int maxDepth, bool ignoreDirect, const MLTSample &sample) { // Generate camera ray from Metropolis sample RayDifferential ray; float cameraWeight = camera->GenerateRayDifferential(sample.cameraSample, &ray); Spectrum pathThroughput = cameraWeight, L = 0.; bool specularBounce = false, allSpecular = true; for (int pathLength = 0; pathLength < maxDepth; ++pathLength) { // Find next intersection in Metropolis light path Intersection isect; if (!scene->Intersect(ray, &isect)) { bool includeLe = ignoreDirect ? (specularBounce && !allSpecular) : (pathLength == 0 || specularBounce); if (includeLe) for (uint32_t i = 0; i < scene->lights.size(); ++i) L += pathThroughput * scene->lights[i]->Le(ray); break; } if (ignoreDirect ? (specularBounce && !allSpecular) : (specularBounce || pathLength == 0)) L += pathThroughput * isect.Le(-ray.d); BSDF *bsdf = isect.GetBSDF(ray, arena); const Point &p = bsdf->dgShading.p; const Normal &n = bsdf->dgShading.nn; Vector wo = -ray.d; const PathSample &ps = sample.pathSamples[pathLength]; // Sample direct illumination for Metropolis path vertex if (!ignoreDirect || pathLength > 0) { LightSample lightSample(ps.lightDir0, ps.lightDir1, ps.lightNum0); BSDFSample bsdfSample(ps.bsdfLightDir0, ps.bsdfLightDir1, ps.bsdfLightComponent); uint32_t lightNum = Floor2Int(ps.lightNum1 * scene->lights.size()); lightNum = min(lightNum, (uint32_t)(scene->lights.size()-1)); const Light *light = scene->lights[lightNum]; L += pathThroughput * EstimateDirect(scene, renderer, arena, light, p, n, wo, isect.rayEpsilon, sample.cameraSample.time, bsdf, rng, lightSample, bsdfSample); } // Sample direction for outgoing Metropolis path direction BSDFSample outgoingBSDFSample(ps.bsdfDir0, ps.bsdfDir1, ps.bsdfComponent); Vector wi; float pdf; BxDFType flags; Spectrum f = bsdf->Sample_f(wo, &wi, outgoingBSDFSample, &pdf, BSDF_ALL, &flags); if (f.IsBlack() || pdf == 0.) break; specularBounce = (flags & BSDF_SPECULAR) != 0; allSpecular &= specularBounce; pathThroughput *= f * AbsDot(wi, n) / pdf; ray = RayDifferential(p, wi, ray, isect.rayEpsilon); //pathThroughput *= renderer->Transmittance(scene, ray, NULL, rng, arena); } return L; }

Spectrum DiffusePRTIntegrator::Li(const Scene *scene, const Renderer *, const RayDifferential &ray, const Intersection &isect, const Sample *sample, MemoryArena &arena) const { Spectrum L = 0.f; Vector wo = -ray.d; // Compute emitted light if ray hit an area light source L += isect.Le(wo); // Evaluate BSDF at hit point BSDF *bsdf = isect.GetBSDF(ray, arena); const Point &p = bsdf->dgShading.p; const Normal &n = bsdf->dgShading.nn; // Compute reflected radiance using diffuse PRT // Project diffuse transfer function at point to SH Spectrum *c_transfer = arena.Alloc<Spectrum>(SHTerms(lmax)); SHComputeDiffuseTransfer(p, Faceforward(n, wo), isect.rayEpsilon, scene, *sample->rng, nSamples, lmax, c_transfer); // Compute integral of product of incident radiance and transfer function Spectrum LT = 0.f; for (int i = 0; i < SHTerms(lmax); ++i) LT += c_in[i] * c_transfer[i]; // Compute reflectance at point for diffuse transfer const int sqrtRhoSamples = 6; float rhoRSamples[2*sqrtRhoSamples*sqrtRhoSamples]; StratifiedSample2D(rhoRSamples, sqrtRhoSamples, sqrtRhoSamples, *sample->rng); Spectrum Kd = bsdf->rho(wo, sqrtRhoSamples*sqrtRhoSamples, rhoRSamples, BSDF_ALL_REFLECTION) * INV_PI; return L + Kd * LT.Clamp(); }

// Primer Method Definitions BSDF *Primer::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading) const { // Declare primer coefficients static float diffuse[3] = { 0.118230f, 0.121218f, 0.133209f}; static float xy0[3] = { -0.399286f, -1.033473f, -1.058104f}; static float z0[3] = { 0.167504f, 0.009545f, -0.068002f}; static float e0[3] = { 2.466633f, 7.637253f, 8.117645f}; static float xy1[3] = { -1.041861f, -1.100108f, -1.087779f}; static float z1[3] = { 0.014375f, -0.198147f, -0.053605f}; static float e1[3] = { 7.993722f, 29.446268f, 41.988990f}; static float xy2[3] = { -1.098605f, -0.379883f, -0.449038f}; static float z2[3] = { -0.145110f, 0.159127f, 0.173224f}; static float e2[3] = { 31.899719f, 2.372852f, 2.636161f}; static Spectrum xy[3] = { Spectrum(xy0), Spectrum(xy1), Spectrum(xy2) }; static Spectrum z[3] = { Spectrum(z0), Spectrum(z1), Spectrum(z2) }; static Spectrum e[3] = { Spectrum(e0), Spectrum(e1), Spectrum(e2) }; // 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); bsdf->Add(BSDF_ALLOC(Lafortune)(Spectrum(diffuse), 3, xy, xy, z, e, BxDFType(BSDF_REFLECTION | BSDF_DIFFUSE))); return bsdf; }

// BrushedMetal Method Definitions BSDF *BrushedMetal::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading) const { // Declare brushedmetal coefficients static float diffuse[3] = { 0, 0, 0 }; static float xy0[3] = { -1.11854f, -1.11845f, -1.11999f }; static float z0[3] = { 1.01272f, 1.01469f, 1.01942f }; static float e0[3] = { 15.8708f, 15.6489f, 15.4571f }; static float xy1[3] = { -1.05334f, -1.06409f, -1.08378f }; static float z1[3] = { 0.69541f, 0.662178f, 0.626672f }; static float e1[3] = { 111.267f, 88.9222f, 65.2179f }; static float xy2[3] = { -1.01684f, -1.01635f, -1.01529f }; static float z2[3] = { 1.00132f, 1.00112f, 1.00108f }; static float e2[3] = { 180.181f, 184.152f, 195.773f }; static Spectrum xy[3] = { Spectrum(xy0), Spectrum(xy1), Spectrum(xy2) }; static Spectrum z[3] = { Spectrum(z0), Spectrum(z1), Spectrum(z2) }; static Spectrum e[3] = { Spectrum(e0), Spectrum(e1), Spectrum(e2) }; // 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); bsdf->Add(BSDF_ALLOC(Lafortune)(Spectrum(*diffuse), 3, xy, xy, z, e, BxDFType(BSDF_REFLECTION | BSDF_GLOSSY))); return bsdf; }

// Skin Method Definitions BSDF *Skin::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading) const { // Declare skin coefficients static float diffuse[3] = { 0.428425f, 0.301341f, 0.331054f}; static float xy0[3] = { -1.131747f, -1.016939f, -0.966018f}; static float z0[3] = { -1.209182f, -1.462488f, -1.222419f}; static float e0[3] = { 6.421658f, 3.699932f, 3.524889f}; static float xy1[3] = { -0.546570f, -0.643533f, -0.638934f}; static float z1[3] = { 0.380123f, 0.410559f, 0.437367f}; static float e1[3] = { 3.685044f, 4.266495f, 4.539742f}; static float xy2[3] = { -0.998888f, -1.020153f, -1.027479f}; static float z2[3] = { 0.857998f, 0.703913f, 0.573625f}; static float e2[3] = { 64.208486f, 63.919687f, 43.809866f}; static Spectrum xy[3] = { Spectrum(xy0), Spectrum(xy1), Spectrum(xy2) }; static Spectrum z[3] = { Spectrum(z0), Spectrum(z1), Spectrum(z2) }; static Spectrum e[3] = { Spectrum(e0), Spectrum(e1), Spectrum(e2) }; // 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); bsdf->Add(BSDF_ALLOC(Lafortune)(Spectrum(diffuse), 3, xy, xy, z, e, BxDFType(BSDF_REFLECTION | BSDF_DIFFUSE))); return bsdf; }

// TranslucentMaterial Method Definitions BSDF *TranslucentMaterial::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) const { float ior = 1.5f; DifferentialGeometry dgs; if (bumpMap) Bump(bumpMap, dgGeom, dgShading, &dgs); else dgs = dgShading; BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn, ior); Spectrum r = reflect->Evaluate(dgs).Clamp(); Spectrum t = transmit->Evaluate(dgs).Clamp(); if (r.IsBlack() && t.IsBlack()) return bsdf; Spectrum kd = Kd->Evaluate(dgs).Clamp(); if (!kd.IsBlack()) { if (!r.IsBlack()) bsdf->Add(BSDF_ALLOC(arena, Lambertian)(r * kd)); if (!t.IsBlack()) bsdf->Add(BSDF_ALLOC(arena, BRDFToBTDF)(BSDF_ALLOC(arena, Lambertian)(t * kd))); } Spectrum ks = Ks->Evaluate(dgs).Clamp(); if (!ks.IsBlack()) { float rough = roughness->Evaluate(dgs); if (!r.IsBlack()) { Fresnel *fresnel = BSDF_ALLOC(arena, FresnelDielectric)(ior, 1.f); bsdf->Add(BSDF_ALLOC(arena, Microfacet)(r * ks, fresnel, BSDF_ALLOC(arena, Blinn)(1.f / rough))); } if (!t.IsBlack()) { Fresnel *fresnel = BSDF_ALLOC(arena, FresnelDielectric)(ior, 1.f); bsdf->Add(BSDF_ALLOC(arena, BRDFToBTDF)(BSDF_ALLOC(arena, Microfacet)(t * ks, fresnel, BSDF_ALLOC(arena, Blinn)(1.f / rough)))); } } return bsdf; }

BSDF *Material::getBSDF(SurfacePoint &pt) { BSDF *bsdf = NULL; if (m_bsdf == "diffuse") { bsdf = new DiffuseBSDF(pt, this); } else if (m_bsdf == "dielectric") { bsdf = new DielectricBSDF(pt, this); } else if (m_bsdf == "modifiedPhong" || m_bsdf == "phong") { bsdf = new ModifiedPhongBSDF(pt, this); } else if (m_bsdf == "absorbent") { bsdf = new AbsorbentBSDF(pt, this); } else if (m_bsdf == "specular") { (*this)["transparency"] = 0.0; bsdf = new DielectricBSDF(pt, this); } else if (m_bsdf == "transmissive") { (*this)["transparency"] = 1.0; bsdf = new DielectricBSDF(pt, this); } else { cerr << "invalid material (BSDF type): " << m_bsdf << endl; ASSERT(0 && "Found Invalid Material (BSDF type)"); return NULL; } bsdf->init(); return bsdf; }

// BluePaint Method Definitions BSDF *BluePaint::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading) const { // Declare bluepaint coefficients static float diffuse[3] = { 0.3094f, 0.39667f, 0.70837f }; static float xy0[3] = { 0.870567f, 0.857255f, 0.670982f }; static float z0[3] = { 0.803624f, 0.774290f, 0.586674f }; static float e0[3] = { 21.820103f, 18.597755f, 7.472717f }; static float xy1[3] = { -0.451218f, -0.406681f, -0.477976f }; static float z1[3] = { 0.023123f, 0.017625f, 0.227295f }; static float e1[3] = { 2.774499f, 2.581499f, 3.677653f }; static float xy2[3] = { -1.031545f, -1.029426f, -1.026588f }; static float z2[3] = { 0.706734f, 0.696530f, 0.687715f }; static float e2[3] = { 66.899060f, 63.767912f, 57.489181f }; static Spectrum xy[3] = { Spectrum(xy0), Spectrum(xy1), Spectrum(xy2) }; static Spectrum z[3] = { Spectrum(z0), Spectrum(z1), Spectrum(z2) }; static Spectrum e[3] = { Spectrum(e0), Spectrum(e1), Spectrum(e2) }; // 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); bsdf->Add(BSDF_ALLOC(Lafortune)(Spectrum(diffuse), 3, xy, xy, z, e, BxDFType(BSDF_REFLECTION | BSDF_DIFFUSE))); return bsdf; }

bool PathVolumeInfo::ContinueToTrace(const BSDF &bsdf) const { // Check if the volume priority system has to be applied if (bsdf.GetEventTypes() & TRANSMIT) { // Ok, the surface can transmit so check if volume priority // system is telling me to continue to trace the ray // I have to continue to trace the ray if: // // 1) I'm entering an object and the interior volume has a // lower priority than the current one (or is the same volume). // // 2) I'm exiting an object and I'm not leaving the current volume. const Volume *bsdfInteriorVol = bsdf.GetMaterialInteriorVolume(); // Condition #1 if (bsdf.hitPoint.intoObject && CompareVolumePriorities(currentVolume, bsdfInteriorVol)) return true; // Condition #2 // // I have to calculate the potentially new currentVolume in order // to check if I'm leaving the current one if ((!bsdf.hitPoint.intoObject) && currentVolume && (SimulateRemoveVolume(bsdfInteriorVol) == currentVolume)) return true; } return false; }

// MirrorMaterial Method Definitions BSDF *MirrorMaterial::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) 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(arena, BSDF)(dgs, dgGeom.nn); Spectrum R = Kr->Evaluate(dgs).Clamp(); if (!R.IsBlack()) { float x,y,z; x = dgs.p.x; y = dgs.p.y; z = dgs.p.z; float rad = sqrt((x-(-4))*(x-(-4)) + (y-1)*(y-1) + (z-15)*(z-15)); float c = 15.f; // if (rad < c) {// 11->20, 14 bsdf->Add(BSDF_ALLOC(arena, SpecularReflection)(R, BSDF_ALLOC(arena, FresnelNoOp)())); // } else { // bsdf->Add(BSDF_ALLOC(arena, SpecularReflection)(R, // BSDF_ALLOC(arena, FresnelNoOp)())); // } } return bsdf; }

// Felt Method Definitions BSDF *Felt::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading) const { // Declare felt coefficients static float diffuse[3] = { 0.025865f, 0.025865f, 0.025865f}; static float xy0[3] = { -0.304075f, -0.304075f, -0.304075f}; static float z0[3] = { -0.065992f, -0.065992f, -0.065992f}; static float e0[3] = { 3.047892f, 3.047892f, 3.047892f}; static float xy1[3] = { -0.749561f, -0.749561f, -0.749561f}; static float z1[3] = { -1.167929f, -1.167929f, -1.167929f}; static float e1[3] = { 6.931827f, 6.931827f, 6.931827f}; static float xy2[3] = { 1.004921f, 1.004921f, 1.004921f}; static float z2[3] = { -0.205529f, -0.205529f, -0.205529f}; static float e2[3] = { 94.117332f, 94.117332f, 94.117332f}; static Spectrum xy[3] = { Spectrum(xy0), Spectrum(xy1), Spectrum(xy2) }; static Spectrum z[3] = { Spectrum(z0), Spectrum(z1), Spectrum(z2) }; static Spectrum e[3] = { Spectrum(e0), Spectrum(e1), Spectrum(e2) }; // 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); bsdf->Add(BSDF_ALLOC(Lafortune)(Spectrum(diffuse), 3, xy, xy, z, e, BxDFType(BSDF_REFLECTION | BSDF_DIFFUSE))); return bsdf; }

// PlasticMaterial Method Definitions BSDF *PlasticMaterial::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) 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(arena, BSDF)(dgs, dgGeom.nn); Spectrum kd = Kd->Evaluate(dgs).Clamp(); if (!kd.IsBlack()) { BxDF *diff = BSDF_ALLOC(arena, Lambertian)(kd); bsdf->Add(diff); } Spectrum ks = Ks->Evaluate(dgs).Clamp(); if (!ks.IsBlack()) { Fresnel *fresnel = BSDF_ALLOC(arena, FresnelDielectric)(1.5f, 1.f); float rough = roughness->Evaluate(dgs); BxDF *spec = BSDF_ALLOC(arena, Microfacet) (ks, fresnel, BSDF_ALLOC(arena, Blinn)(1.f / rough)); bsdf->Add(spec); } return bsdf; }

// custom_material Method Definitions BSDF *custom_material::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading) const { //issue debugging warning //Warning("custom_material\n"); //declare geometry that will be used in BRDF DifferentialGeometry dgs; //if there is to be a bump map, call Bump, which modifies dgs if (bumpMap) Bump(bumpMap, dgGeom, dgShading, &dgs); else dgs = dgShading; //allocate memory for BSDF, poiting bsdf to a new BSDF BSDF *bsdf = BSDF_ALLOC(BSDF)(dgs, dgGeom.nn); //set a spectrum kd to the spectrum stored in texure Kd //***gets color spectrum of diffuse reflection*** Spectrum kd = Kd->Evaluate(dgs).Clamp(); //allocate to diff a custom BxDF with reflection spectrum kd //***diffuse reflection characteristics*** BxDF *diff = BSDF_ALLOC(custom_BxDF3)(kd); /* commented dpl 10 august 2005 // specular reflectance from pbrt's plastic model //allocate to (temp) fresnes a fresneldielectric bsdf with //parameters (1.5, 1) //***will set part of specular reflection properties*** Fresnel *fresnel = BSDF_ALLOC(FresnelDielectric)(1.5f, 1.f); //set a spectrum ks to the spectrum stored in the texture Ks //***gets color spectrum of specular reflection*** Spectrum ks = Ks->Evaluate(dgs).Clamp(); //get the roughness from roughness (?) float rough = roughness->Evaluate(dgs); //allocate memory for specular reflection BSDF //***sets specular BSDF according to microfacet model //with color params ks, fresnel and blinn models (?) *** BxDF *spec = BSDF_ALLOC(Microfacet)(ks, fresnel, BSDF_ALLOC(Blinn)(1.f / rough)); */ //my specular reflectance Spectrum ks = Ks->Evaluate(dgs).Clamp(); BxDF *spec = BSDF_ALLOC(custom_BxDF2)(ks); //add both diff and spec BSDFS to the BSDF of this material //***sets the BSDF of this material bsdf->Add(diff); bsdf->Add(spec); return bsdf; }

void addChild(const std::string &name, ConfigurableObject *child) { if (child->getClass()->derivesFrom(MTS_CLASS(BSDF))) { BSDF *bsdf = static_cast<BSDF *>(child); m_bsdfs.push_back(bsdf); bsdf->incRef(); } else { BSDF::addChild(name, child); } }

// Metropolis Method Definitions static uint32_t GeneratePath(const RayDifferential &r, const Spectrum &a, const Scene *scene, MemoryArena &arena, const vector<PathSample> &samples, PathVertex *path, RayDifferential *escapedRay, Spectrum *escapedAlpha) { PBRT_MLT_STARTED_GENERATE_PATH(); RayDifferential ray = r; Spectrum alpha = a; if (escapedAlpha) *escapedAlpha = 0.f; uint32_t length = 0; for (; length < samples.size(); ++length) { // Try to generate next vertex of ray path PathVertex &v = path[length]; if (!scene->Intersect(ray, &v.isect)) { // Handle ray that leaves the scene during path generation if (escapedAlpha) *escapedAlpha = alpha; if (escapedRay) *escapedRay = ray; break; } // Record information for current path vertex v.alpha = alpha; BSDF *bsdf = v.isect.GetBSDF(ray, arena); v.bsdf = bsdf; v.wPrev = -ray.d; // Sample direction for outgoing Metropolis path direction float pdf; BxDFType flags; Spectrum f = bsdf->Sample_f(-ray.d, &v.wNext, samples[length].bsdfSample, &pdf, BSDF_ALL, &flags); v.specularBounce = (flags & BSDF_SPECULAR) != 0; v.nSpecularComponents = bsdf->NumComponents(BxDFType(BSDF_SPECULAR | BSDF_REFLECTION | BSDF_TRANSMISSION)); if (f.IsBlack() || pdf == 0.f) { PBRT_MLT_FINISHED_GENERATE_PATH(); return length+1; } // Terminate path with RR or prepare for finding next vertex const Point &p = bsdf->dgShading.p; const Normal &n = bsdf->dgShading.nn; Spectrum pathScale = f * AbsDot(v.wNext, n) / pdf; float rrSurviveProb = min(1.f, pathScale.y()); if (samples[length].rrSample > rrSurviveProb) { PBRT_MLT_FINISHED_GENERATE_PATH(); return length+1; } alpha *= pathScale / rrSurviveProb; //alpha *= renderer->Transmittance(scene, ray, NULL, rng, arena); ray = RayDifferential(p, v.wNext, ray, v.isect.rayEpsilon); } PBRT_MLT_FINISHED_GENERATE_PATH(); return length; }

BSDF* Phong::GetBSDF(const Vector& normal, const Vector& incident) const { BSDF* bsdf = new BSDF(); bsdf->Add(new Ambient(baseColor * ca)); bsdf->Add(new Lambert(cd, baseColor)); bsdf->Add(new Specular(exp, specularColor)); return bsdf; }

MixtureBSDF(Stream *stream, InstanceManager *manager) : BSDF(stream, manager) { size_t bsdfCount = stream->readSize(); m_weights.resize(bsdfCount); for (size_t i=0; i<bsdfCount; ++i) { m_weights[i] = stream->readFloat(); BSDF *bsdf = static_cast<BSDF *>(manager->getInstance(stream)); bsdf->incRef(); m_bsdfs.push_back(bsdf); } configure(); }

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; } } } } }

Spectrum IrradianceCacheIntegrator::pathL(Ray &r, const Scene *scene, const Renderer *renderer, const Sample *sample, MemoryArena &arena) const { Spectrum L(0.f); 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; else if (pathLength == 1) pathThroughput *= renderer->Transmittance(scene, ray, sample, arena, NULL); else pathThroughput *= renderer->Transmittance(scene, ray, NULL, arena, sample->rng); // 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, arena); // 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, renderer, arena, p, n, wo, isect.rayEpsilon, 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} Vector wi; float pdf; BxDFType flags; Spectrum f = bsdf->Sample_f(wo, &wi, BSDFSample(*sample->rng), &pdf, BSDF_ALL, &flags); if (f.IsBlack() || pdf == 0.) break; specularBounce = (flags & BSDF_SPECULAR) != 0; pathThroughput *= f * AbsDot(wi, n) / pdf; ray = RayDifferential(p, wi, ray, isect.rayEpsilon); // Possibly terminate the path if (pathLength > 2) { float rrProb = min(1.f, pathThroughput.y()); if (sample->rng->RandomFloat() > rrProb) break; pathThroughput /= rrProb; } } return L; }

BSDF* GlassMaterial::get_bsdf(const DifferentialGeometry &dg, MemoryPool &pool) const { BSDF *bsdf = pool.alloc<BSDF>(dg, refr_index); Colorf refl = reflect->sample(dg); if (!refl.is_black()){ bsdf->add(pool.alloc<SpecularReflection>(refl, pool.alloc<FresnelDielectric>(1.f, refr_index))); } Colorf trans = transmit->sample(dg); if (!trans.is_black()){ bsdf->add(pool.alloc<SpecularTransmission>(trans, pool.alloc<FresnelDielectric>(1.f, refr_index))); } return bsdf; }

// 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; }

void PathVolumeInfo::Update(const BSDFEvent eventType, const BSDF &bsdf) { // Update only if it isn't a volume scattering and the material can TRANSMIT if (bsdf.IsVolume()) scatteredStart = true; else { scatteredStart = false; if(eventType & TRANSMIT) { if (bsdf.hitPoint.intoObject) AddVolume(bsdf.GetMaterialInteriorVolume()); else RemoveVolume(bsdf.GetMaterialInteriorVolume()); } } }

BSDF* GlassMaterial::GetBSDF( const Vector2f& uv , const Point3f& point , const Vector3f& normal ) const { BSDF* bsdf = new BSDF(); Spectrum R = Kr->Evalute( uv , point ); Spectrum T = Kt->Evalute( uv , point ); Spectrum ior = RefraIndex->Evalute( uv , point ); bsdf->Add( new SpecularReflection( R , new FresnelDielectric( 1.0 , ior[0] ) ) ); bsdf->Add( new SpecularTransmission( 1.0 , ior[0] , T ) ); return bsdf; }

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; } }

// Substrate Method Definitions BSDF *Substrate::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 d = Kd->Evaluate(dgs).Clamp(); Spectrum s = Ks->Evaluate(dgs).Clamp(); float u = nu->Evaluate(dgs); float v = nv->Evaluate(dgs); bsdf->Add(BSDF_ALLOC(FresnelBlend)(d, s, BSDF_ALLOC(Anisotropic)(1.f/u, 1.f/v))); return bsdf; }

bool BidirPathTracing::sampleScattering(BSDF& bsdf , const Vector3& hitPos , BidirPathState& pathState) { Real bsdfDirPdf , cosWo; int sampledBSDFType; Color3 bsdfFactor = bsdf.sample(scene , rng.randVector3() , pathState.dir , bsdfDirPdf , cosWo , &sampledBSDFType); if (bsdfFactor.isBlack()) return 0; Real bsdfRevPdf = bsdfDirPdf; if ((sampledBSDFType & BSDF_SPECULAR) == 0) bsdfRevPdf = bsdf.pdf(scene , pathState.dir , 1); Real contProb = bsdf.continueProb; if (rng.randFloat() > contProb) return 0; bsdfDirPdf *= contProb; bsdfRevPdf *= contProb; // Partial sub-path MIS quantities // the evaluation is completed when the actual hit point is known! // i.e. after tracing the ray, out of the procedure if (sampledBSDFType & BSDF_SPECULAR) { pathState.specularVertexNum++; pathState.dVCM = 0.f; pathState.dVC *= mis(cosWo); } else { pathState.specularPath &= 0; pathState.dVC = mis(1.f / bsdfDirPdf) * (pathState.dVCM + pathState.dVC * mis(bsdfRevPdf)); pathState.dVCM = mis(1.f / bsdfDirPdf); } pathState.origin = hitPos; pathState.throughput = (pathState.throughput | bsdfFactor) * (cosWo / bsdfDirPdf); return 1; }

void Material::preview(Shape *shape) { SurfacePoint pt; pt.shape = shape; if (isEmitter()) { Emitter *emitter = getEmitter(pt); emitter->preview(shape); if (emitter != Material::s_nullEmitter) safeDelete(emitter); } BSDF *bsdf = getBSDF(pt); bsdf->preview(shape); safeDelete(bsdf); }

BSDF *MeasuredMaterial::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) 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(arena, BSDF)(dgs, dgGeom.nn); if (regularHalfangleData) bsdf->Add(BSDF_ALLOC(arena, RegularHalfangleBRDF) (regularHalfangleData, nThetaH, nThetaD, nPhiD)); else if (thetaPhiData) bsdf->Add(BSDF_ALLOC(arena, IrregIsotropicBRDF)(thetaPhiData)); return bsdf; }

// KdSubsurfaceMaterial Method Definitions BSDF *KdSubsurfaceMaterial::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) 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(arena, BSDF)(dgs, dgGeom.nn); Spectrum R = Kr->Evaluate(dgs).Clamp(); float ior = index->Evaluate(dgs); if (!R.IsBlack()) bsdf->Add(BSDF_ALLOC(arena, SpecularReflection)(R, BSDF_ALLOC(arena, FresnelDielectric)(1., ior))); return bsdf; }