Beispiel #1
0
        Color sampleLight(Scene scene, Ray n, Random rand, IShape light)
        {
            Vector center;
            double radius;

            switch (light)
            {
            case Sphere sphere:
                radius = sphere.Radius;
                center = sphere.Center;
                break;

            default:
                Box box = light.BoundingBox();
                radius = box.OuterRadius();
                center = box.Center();
                break;
            }

            var point = center;

            if (SoftShadows)
            {
                for (; ;)
                {
                    var x = (rand.NextDouble() * 2) - 1;
                    var y = (rand.NextDouble() * 2) - 1;
                    if ((x * x) + (y * y) <= 1)
                    {
                        var l = center.Sub(n.Origin).Normalize();
                        var u = l.Cross(Vector.RandomUnitVector(rand)).Normalize();
                        var v = l.Cross(u);
                        point = new Vector();
                        point = point.Add(u.MulScalar(x * radius));
                        point = point.Add(v.MulScalar(y * radius));
                        point = point.Add(center);
                        break;
                    }
                }
            }
            // construct ray toward light point
            Ray ray = new Ray(n.Origin, point.Sub(n.Origin).Normalize());
            // get cosine term
            var diffuse = ray.Direction.Dot(n.Direction);

            if (diffuse <= 0)
            {
                return(Color.Black);
            }
            // check for light visibility
            Hit hit = scene.Intersect(ray);

            if (!hit.Ok() || hit.Shape != light)
            {
                return(Color.Black);
            }
            // compute solid angle (hemisphere coverage)
            var hyp      = center.Sub(n.Origin).Length();
            var opp      = radius;
            var theta    = Math.Asin(opp / hyp);
            var adj      = opp / Math.Tan(theta);
            var d        = Math.Cos(theta) * adj;
            var r        = Math.Sin(theta) * adj;
            var coverage = (r * r) / (d * d);

            if (hyp < opp)
            {
                coverage = 1;
            }
            coverage = Math.Min(coverage, 1);
            // get material properties from light
            Material material = Material.MaterialAt(light, point);
            // combine factors
            var m = material.Emittance * diffuse * coverage;

            return(material.Color.MulScalar(m));
        }