public Color3 Calculate(Intersection intersection, bool ignoreLight)
        {
            Color3 result;
            switch (intersection.Material.MaterialType)
            {
                case MaterialType.Light:
                    if (_nee)
                    {
                        result = ignoreLight ? Color4.Black : intersection.Material.Color;
                    }
                    else
                    {
                        result = intersection.Material.Color;
                    }
                    break;
                case MaterialType.Diffuse:
                    result = Diffuse(intersection);
                    break;
                case MaterialType.Specular:
                    result = Specular(intersection);
                    break;
                case MaterialType.Dielectric:
                    result = Dielectric(intersection);
                    break;
                default:
                    throw new Exception("Materialtype is not supported");
            }

            //return result / (1 - Constants.RussianRouletteDieChance);
            return result;
        }
        public Color3 Calculate(Intersection intersection)
        {
            switch (intersection.Material.MaterialType)
            {
                case MaterialType.Light:
                case MaterialType.Diffuse:
                    return DirectIllumination(intersection);
                case MaterialType.Specular:
                    return Specular(intersection);
                case MaterialType.Dielectric:
                    return Dielectric(intersection);
            }

            throw new Exception("Materialtype is not supported");
        }
        public Color3 Dielectric(Intersection intersection)
        {
            var n1 = intersection.Ray.Medium.RefractiveIndex;
            var n2 = intersection.Material.RefractiveIndex;
            float n = n1 / n2;

            var ray = intersection.Ray;
            var normal = intersection.SurfaceNormal;

            float cost = Vector3.Dot(normal, -ray.Direction);
            float k = 1 - n * n * (1 - cost * cost);
            if (k < 0)
            {
                //internal reflection
                return Specular(intersection);
            }

            var T = n * ray.Direction + normal * (n * cost - (float)Math.Sqrt(k));

            var refracted = Ray.CreateFromIntersection(intersection, T, float.MaxValue, true);

            float R0 = (n1 - n2) / (n1 + n2);
            R0 *= R0;
            var a = 1 - cost;
            float Fr = R0 + (1 - R0) * a * a * a * a * a;
            float Ft = 1 - Fr;

            var transparency = new Vector3(1);
            if (intersection.InsidePrimitive)
            {
                var absorbance = intersection.Ray.Medium.Color * intersection.Ray.Medium.Absorbance * -intersection.Distance;
                transparency = new Vector3(
                    (float)Math.Exp(-absorbance.R),
                    (float)Math.Exp(-absorbance.G),
                    (float)Math.Exp(-absorbance.B));
            }

            //go inside
            if (_rng.RandomFloat() < Ft)
            {
                return transparency*_scene.Sample(refracted, _rng, false);
            }

            //reflect outside
            return transparency*Specular(intersection);
        }
Exemple #4
0
        public static Intersection GetMinimumIntersection(Intersection i1, Intersection i2)
        {
            if (i1 == null)
            {
                return i2;
            }

            if (i2 == null)
            {
                return i1;
            }

            if (i1.Distance < i2.Distance)
            {
                return i1;
            }
            return i2;
        }
        public bool Intersect(Ray ray, out Intersection intersection)
        {
            intersection = null;
            var nodes = new Stack<BVHNode>(_logNumBoundables);
            nodes.Push(Root);
            while (nodes.Count > 0)
            {
                var node = nodes.Pop();
                if (node.IsLeaf)
                {
                    var i = IntersectionHelper.GetClosestIntersection(ray, node.Boundables);
                    intersection = IntersectionHelper.GetMinimumIntersection(intersection, i);
                }

                Intersection i1 = null, i2 = null;
                float t1 = float.MaxValue, t2 = float.MaxValue;
                var goLeft = node._left != null && node._left.BoundingBox.Intersect(ray, out t1);
                var goRight = node._right != null && node._right.BoundingBox.Intersect(ray, out t2);

                if (goLeft && goRight)
                {
                    //choose shortest
                    if (t1 < t2)
                    {
                        nodes.Push(node._right);
                        nodes.Push(node._left);
                    }
                    else
                    {
                        nodes.Push(node._left);
                        nodes.Push(node._right);
                    }
                }
                else if (goLeft)
                {
                    nodes.Push(node._left);
                }
                else if (goRight)
                {
                    nodes.Push(node._right);
                }
            }

            return intersection != null;
        }
        public Color3 DirectIllumination(Intersection intersection)
        {
            var totalIntensity = 0.0f;
            foreach (var light in _scene.PointLights)
            {
                var lightVector = light.Position - intersection.Location;
                var invLightDistance2 = 1/lightVector.LengthSquared;
                var shadowRay = Ray.CreateFromIntersection(intersection, lightVector, lightVector.LengthFast);
                if (IntersectionHelper.DoesIntersect(shadowRay, _scene.Objects) && !(intersection.IntersectsWith is DebugSphere)) //todo debug
                {
                    continue;
                }

                var intensity = Vector3.Dot(intersection.SurfaceNormal, shadowRay.Direction);
                totalIntensity += Math.Max(intensity, 0) * invLightDistance2*light.Intensity;
            }

            return totalIntensity * intersection.Material.CalculateColor(intersection.Location);
        }
        public Color3 Specular(Intersection intersection)
        {
            var mat = intersection.Material;
            var reflectedRay = Ray.Reflect(intersection.Ray, intersection);

            Color3 specColor = Color4.Black;
            foreach (var lightSource in _scene.PointLights)
            {
                var lightDir = (lightSource.Position - intersection.Location).Normalized();
                var h = (-intersection.Ray.Direction + lightDir).Normalized();
                var dot = Vector3.Dot(h, intersection.SurfaceNormal);
                if (dot > 0)
                {
                    var spec = (float)Math.Pow(dot, 32) * intersection.Material.Specularity;
                    specColor += lightSource.Color * spec;
                }
            }

            return mat.Specularity * (specColor + _scene.Sample(reflectedRay, _rng, false)) + (1 - mat.Specularity) * DirectIllumination(intersection);
        }
        private Color3 SampleLightDirectly(ISurfaceLight light, Color3 brdf, Intersection intersection)
        {
            var rPoint = light.GetRandomPoint(_rng, intersection); //get random point on light
            var l = rPoint.Location - intersection.Location; //vector to light
            var dist = l.LengthFast;
            l.Normalize();
            var lightRay = Ray.CreateFromIntersection(intersection, l, dist); //ray to light
            var nlightDotL = Vector3.Dot(rPoint.Normal, -l); //light normal dot light
            var nDotL = Vector3.Dot(intersection.SurfaceNormal, l); //normal dot light

            if (nDotL > 0 && nlightDotL > 0 && !IntersectionHelper.DoesIntersect(lightRay, _scene.Objects, light))
            {
                var solidAngle = (nlightDotL * light.Area) / (dist * dist); //light area on hemisphere
                return light.Color * solidAngle * brdf * nDotL;
            }

            return Color4.Black;
        }
 public Color3 Specular(Intersection intersection)
 {
     var reflectedRay = Ray.Reflect(intersection.Ray, intersection);
     return intersection.Material.CalculateColor(intersection) * _scene.Sample(reflectedRay, _rng, false);
 }
        public Color3 Diffuse(Intersection intersection)
        {
            float killChance = 0;
            if (_russianRoulette)
            {
                killChance = GetKillChance(intersection.Material.Color);
                if (_rng.TestChance(killChance))
                {
                    return Color4.Black;
                }
            }

            //random reflected ray
            Vector3 rDir;
            if (_cosineDist)
            {
                rDir = _rng.CosineDistributed(intersection.SurfaceNormal);
            }
            else
            {
                rDir = _rng.RandomVectorOnHemisphere(intersection.SurfaceNormal);
            }

            var reflected = Ray.CreateFromIntersection(intersection, rDir, goesIntoMaterial: true);

            //brdf of material
            var brdf = intersection.Material.CalculateColor(intersection)/MathHelper.Pi;

            //irradiance
            var nDotR = Vector3.Dot(intersection.SurfaceNormal, rDir);
            var Ei = _scene.Sample(reflected, _rng, true) * nDotR;

            Color3 Ld = Color4.Black;

            //use next event estimation?
            if (_nee)
            {
                if (_scene.SurfaceLights.Count > 0)
                {
                    //sample light directly - next event estimation
                    var ranLight = _scene.SurfaceLights.GetRandom(_rng.R); //get random light
                    Ld = SampleLightDirectly(ranLight, brdf, intersection)*_scene.SurfaceLights.Count*ranLight.Brightness;
                }
            }

            Color3 result;
            if (_cosineDist)
            {
                //probability density function
                var pdf = nDotR/MathHelper.Pi;
                result = brdf*Ei/pdf + Ld;
            }
            else
            {
                result = MathHelper.TwoPi * brdf * Ei + Ld;
            }

            return result/(1 - killChance);
        }