Exemplo n.º 1
0
        public void NDF_Orthogonal()
        {
            float ax   = 0.5f;
            float ay   = 0.3f;
            var   dist = new TrowbridgeReitzDistribution()
            {
                AlphaX = ax, AlphaY = ay
            };
            var ndf = dist.NormalDistribution(new System.Numerics.Vector3(0, 0, 1));

            float expectedNdf = 1 / (MathF.PI * ax * ay);

            Assert.Equal(expectedNdf, ndf, 4);
        }
Exemplo n.º 2
0
        public void NDF_GrazingAngle()
        {
            float ax   = 0.5f;
            float ay   = 0.3f;
            var   dist = new TrowbridgeReitzDistribution()
            {
                AlphaX = ax, AlphaY = ay
            };
            var ndf = dist.NormalDistribution(new System.Numerics.Vector3(1, 0, 0));

            float expectedNdf = 0;

            Assert.Equal(expectedNdf, ndf, 4);
        }
Exemplo n.º 3
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));
        }
Exemplo n.º 4
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));
        }