public override SampledSpectrum Sample(Vector3 leaving, out Vector3 incoming) { var entering = CosTheta(ref leaving) > 0; float ei, et; if (entering) { ei = IndexOfRefractionIncident; et = IndexOfRefractionTransmitted; } else { et = IndexOfRefractionIncident; ei = IndexOfRefractionTransmitted; } var sinIncidentSquared = SinThetaSquared(ref leaving); var eta = ei / et; var sinTransmittedSquared = eta * eta * sinIncidentSquared; var cosTransmitted = (float)Math.Sqrt(1 - sinTransmittedSquared); if (entering) { cosTransmitted = -cosTransmitted; } var sinTOversinI = eta; incoming = new Vector3(sinTOversinI * -leaving.X, sinTOversinI * -leaving.Y, cosTransmitted); if (sinTransmittedSquared >= 1) { return(SampledSpectrum.Black()); } var f = _fresnel.Evaluate(CosTheta(ref leaving)); return((new SampledSpectrum(1) - f) * _s / AbsCosTheta(ref incoming) * (et * et) / (ei * ei)); }
public RgbColor Evaluate(Vector3 outDir, Vector3 inDir, bool isOnLightSubpath) { if (ShadingSpace.SameHemisphere(outDir, inDir)) { return(RgbColor.Black); // transmission only } float cosThetaO = ShadingSpace.CosTheta(outDir); float cosThetaI = ShadingSpace.CosTheta(inDir); if (cosThetaI == 0 || cosThetaO == 0) { return(RgbColor.Black); } // Compute the half vector float eta = ShadingSpace.CosTheta(outDir) > 0 ? (insideIOR / outsideIOR) : (outsideIOR / insideIOR); Vector3 wh = Vector3.Normalize(outDir + inDir * eta); if (ShadingSpace.CosTheta(wh) < 0) { wh = -wh; } if (Vector3.Dot(outDir, wh) * Vector3.Dot(inDir, wh) > 0) { return(RgbColor.Black); } var F = new RgbColor(FresnelDielectric.Evaluate(Vector3.Dot(outDir, wh), outsideIOR, insideIOR)); float sqrtDenom = Vector3.Dot(outDir, wh) + eta * Vector3.Dot(inDir, wh); float factor = isOnLightSubpath ? (1 / eta) : 1; var numerator = distribution.NormalDistribution(wh) * distribution.MaskingShadowing(outDir, inDir); numerator *= eta * eta * Math.Abs(Vector3.Dot(inDir, wh)) * Math.Abs(Vector3.Dot(outDir, wh)); numerator *= factor * factor; var denom = (cosThetaI * cosThetaO * sqrtDenom * sqrtDenom); Debug.Assert(float.IsFinite(denom)); return((RgbColor.White - F) * transmittance * Math.Abs(numerator / denom)); }