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; }
void MixMaterial::Pdf(const HitPoint &hitPoint, const Vector &localLightDir, const Vector &localEyeDir, float *directPdfW, float *reversePdfW) const { const Frame frame(hitPoint.GetFrame()); const float weight2 = Clamp(mixFactor->GetFloatValue(hitPoint), 0.f, 1.f); const float weight1 = 1.f - weight2; float directPdfWMatA = 1.f; float reversePdfWMatA = 1.f; 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)); matA->Pdf(hitPointA, lightDirA, eyeDirA, &directPdfWMatA, &reversePdfWMatA); } float directPdfWMatB = 1.f; float reversePdfWMatB = 1.f; 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)); matB->Pdf(hitPointB, lightDirB, eyeDirB, &directPdfWMatB, &reversePdfWMatB); } if (directPdfW) *directPdfW = weight1 * directPdfWMatA + weight2 *directPdfWMatB; if (reversePdfW) *reversePdfW = weight1 * reversePdfWMatA + weight2 * reversePdfWMatB; }
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; }