Exemple #1
0
 public (float, float) Pdf(Vector3 outDir, Vector3 inDir, bool isOnLightSubpath)
 {
     if (ShadingSpace.SameHemisphere(outDir, inDir))
     {
         return(0, 0);
     }
     return(ComputeOneDir(outDir, inDir), ComputeOneDir(inDir, outDir));
 }
Exemple #2
0
        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));
        }
Exemple #3
0
        public (float, float) Pdf(Vector3 outDir, Vector3 inDir, bool isOnLightSubpath)
        {
            if (!ShadingSpace.SameHemisphere(outDir, inDir))
            {
                return(0, 0);
            }

            var halfVector = outDir + inDir;

            // catch NaN causing corner cases
            if (halfVector == Vector3.Zero)
            {
                return(0, 0);
            }

            halfVector = Vector3.Normalize(halfVector);
            var pdfForward = distribution.Pdf(outDir, halfVector) / Math.Abs(4 * Vector3.Dot(outDir, halfVector));
            var pdfReverse = distribution.Pdf(inDir, halfVector) / Math.Abs(4 * Vector3.Dot(inDir, halfVector));

            return(pdfForward, pdfReverse);
        }
Exemple #4
0
        public Vector3?Sample(Vector3 outDir, bool isOnLightSubpath, Vector2 primarySample)
        {
            if (outDir.Z == 0)
            {
                return(null);
            }

            var halfVector = distribution.Sample(outDir, primarySample);

            if (Vector3.Dot(halfVector, outDir) < 0)
            {
                return(null);
            }

            var inDir = ShadingSpace.Reflect(outDir, halfVector);

            if (!ShadingSpace.SameHemisphere(outDir, inDir))
            {
                return(null);
            }

            return(inDir);
        }
Exemple #5
0
        public RgbColor Evaluate(Vector3 outDir, Vector3 inDir, bool isOnLightSubpath)
        {
            if (!ShadingSpace.SameHemisphere(outDir, inDir))
            {
                return(RgbColor.Black);
            }

            float   cosThetaO  = ShadingSpace.AbsCosTheta(outDir);
            float   cosThetaI  = ShadingSpace.AbsCosTheta(inDir);
            Vector3 halfVector = inDir + outDir;

            // Handle degenerate cases for microfacet reflection
            if (cosThetaI == 0 || cosThetaO == 0)
            {
                return(RgbColor.Black);
            }
            if (halfVector.X == 0 && halfVector.Y == 0 && halfVector.Z == 0)
            {
                return(RgbColor.Black);
            }

            // For the Fresnel call, make sure that wh is in the same hemisphere
            // as the surface normal, so that total internal reflection is handled correctly.
            halfVector = Vector3.Normalize(halfVector);
            if (ShadingSpace.CosTheta(halfVector) < 0)
            {
                halfVector = -halfVector;
            }

            var cosine = Vector3.Dot(inDir, halfVector);
            var f      = fresnel.Evaluate(cosine);

            var nd = distribution.NormalDistribution(halfVector);
            var ms = distribution.MaskingShadowing(outDir, inDir);

            return(tint * nd * ms * f / (4 * cosThetaI * cosThetaO));
        }