Esempio n. 1
0
        float ComputeOneDir(Vector3 outDir, Vector3 inDir)
        {
            // Compute the half vector
            float   eta = ShadingSpace.CosTheta(outDir) > 0 ? (insideIOR / outsideIOR) : (outsideIOR / insideIOR);
            Vector3 wh  = outDir + inDir * eta;

            if (wh == Vector3.Zero)
            {
                return(0);                    // Prevent NaN if outDir and inDir exactly align
            }
            wh = Vector3.Normalize(wh);

            if (Vector3.Dot(outDir, wh) * Vector3.Dot(inDir, wh) > 0)
            {
                return(0);
            }

            // Compute change of variables _dwh\_dinDir_ for microfacet transmission
            float sqrtDenom = Vector3.Dot(outDir, wh) + eta * Vector3.Dot(inDir, wh);

            if (sqrtDenom == 0)
            {
                return(0);                // Prevent NaN in corner case
            }
            float dwh_dinDir = Math.Abs((eta * eta * Vector3.Dot(inDir, wh)) / (sqrtDenom * sqrtDenom));

            float result = distribution.Pdf(outDir, wh) * dwh_dinDir;

            Debug.Assert(float.IsFinite(result));
            return(result);
        }
Esempio n. 2
0
        /// <summary>
        /// Warps the given primary sample to follow the pdf computed by <see cref="Pdf(Vector3, Vector3)"/>.
        /// </summary>
        /// <returns>The direction that corresponds to the given primary sample.</returns>
        public Vector3 Sample(Vector3 outDir, Vector2 primary)
        {
            bool flip = ShadingSpace.CosTheta(outDir) < 0;
            var  wh   = TrowbridgeReitzSample(flip ? -outDir : outDir, AlphaX, AlphaY, primary.X, primary.Y);

            if (flip)
            {
                wh = -wh;
            }
            return(wh);
        }
Esempio n. 3
0
        public Vector3?Sample(Vector3 outDir, bool isOnLightSubpath, Vector2 primarySample)
        {
            if (outDir.Z == 0)
            {
                return(null);
            }

            Vector3 wh = distribution.Sample(outDir, primarySample);

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

            float eta   = ShadingSpace.CosTheta(outDir) > 0 ? (outsideIOR / insideIOR) : (insideIOR / outsideIOR);
            var   inDir = ShadingSpace.Refract(outDir, wh, eta);

            return(inDir);
        }
Esempio n. 4
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));
        }
Esempio n. 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));
        }
Esempio n. 6
0
        static Vector3 TrowbridgeReitzSample(Vector3 wi, float alpha_x,
                                             float alpha_y, float U1, float U2)
        {
            // 1. stretch wi
            Vector3 wiStretched = Vector3.Normalize(new Vector3(alpha_x * wi.X, alpha_y * wi.Y, wi.Z));

            // 2. simulate P22_{wi}(x_slope, y_slope, 1, 1)
            float slope_x, slope_y;

            TrowbridgeReitzSample11(ShadingSpace.CosTheta(wiStretched), U1, U2, out slope_x, out slope_y);

            // 3. rotate
            float tmp = ShadingSpace.CosPhi(wiStretched) * slope_x - ShadingSpace.SinPhi(wiStretched) * slope_y;

            slope_y = ShadingSpace.SinPhi(wiStretched) * slope_x + ShadingSpace.CosPhi(wiStretched) * slope_y;
            slope_x = tmp;

            // 4. unstretch
            slope_x = alpha_x * slope_x;
            slope_y = alpha_y * slope_y;

            // 5. compute normal
            return(Vector3.Normalize(new Vector3(-slope_x, -slope_y, 1)));
        }