예제 #1
0
        public bool Hit(Ray ray, float tMin, float tMax, ref HitRecord hitRecord)
        {
            var   tempHitRecord = new HitRecord();
            bool  hitAnything   = false;
            float closestSoFar  = tMax;

            foreach (var hitable in _hitables)
            {
                if (hitable.Hit(ray, tMin, closestSoFar, ref tempHitRecord))
                {
                    hitAnything  = true;
                    closestSoFar = tempHitRecord.T;
                    hitRecord    = tempHitRecord;
                }
            }

            return(hitAnything);
        }
예제 #2
0
        // Checks for collisions with all hittable objects
        public bool Hit(Ray r, double tMin, double tMax, HitRecord record)
        {
            HitRecord tempRecord   = new HitRecord();
            bool      hitAnything  = false;
            double    closestSoFar = tMax;

            foreach (Hittable hittable in HittableObjects)
            {
                if (hittable.Hit(r, tMin, closestSoFar, tempRecord))
                {
                    hitAnything  = true;
                    closestSoFar = tempRecord.T;
                    record.Set(tempRecord);
                }
            }

            return(hitAnything);
        }
예제 #3
0
        public bool Hit(Ray ray, float tMin, float tMax, ref HitRecord hitRecord)
        {
            var currentCenter = Center(ray.Time);

            Vector3 oc    = ray.Origin - currentCenter;
            var     a     = ray.Direction.LengthSquared();
            var     halfB = Vector3.Dot(oc, ray.Direction);
            var     c     = oc.LengthSquared() - Radius * Radius;

            float discriminant = halfB * halfB - a * c;

            if (discriminant < 0.0f)
            {
                return(false);
            }

            // Find the nearest root that lies in the acceptable range.
            float sqrtD = MathF.Sqrt(discriminant);
            float root  = (-halfB - sqrtD) / a;

            if (root < tMin || root > tMax)
            {
                root = (-halfB + sqrtD) / a;
                if (root < tMin || root > tMax)
                {
                    return(false);
                }
            }

            hitRecord.T     = root;
            hitRecord.Point = ray.At(hitRecord.T);
            var outwardNormal = (hitRecord.Point - currentCenter) / Radius;

            hitRecord.SetFaceNormal(ray, outwardNormal);
            hitRecord.Material = _material;

            return(true);
        }
예제 #4
0
        public bool Hit(Ray r, double tMin, double tMax, HitRecord record)
        {
            Vector3 oc    = r.Origin - Center;
            double  a     = r.Direction.LengthSquared();
            double  halfB = oc.Dot(r.Direction);
            double  c     = oc.LengthSquared() - Radius * Radius;

            double discriminant = halfB * halfB - a * c;

            if (discriminant < 0)
            {
                return(false);
            }
            double sqrtDiscriminant = Math.Sqrt(discriminant);

            // Find the nearest root that lies in the acceptable range
            double root = (-halfB - sqrtDiscriminant) / a;

            if (root < tMin || tMax < root)
            {
                root = (-halfB + sqrtDiscriminant) / a;
                if (root < tMin || tMax < root)
                {
                    return(false);
                }
            }

            record.T      = root;
            record.Point  = r.At(record.T);
            record.Normal = (record.Point - Center) / Radius;
            Vector3 outwardNormal = (record.Point - Center) / Radius;

            record.SetFaceNormal(r, outwardNormal);
            record.Material = Material;

            return(true);
        }
예제 #5
0
        public bool Scatter(Ray rIn, HitRecord record, Vector3 attenuation, Ray scattered, Random rand)
        {
            attenuation.Set(new Vector3(1.0, 1.0, 1.0));
            double refractionRatio = record.FrontFace ? (1.0 / RefractionIndex) : RefractionIndex;

            Vector3 unitDirection = rIn.Direction.Normalize();
            double  cosTheta      = Math.Min(record.Normal.Dot(-unitDirection), 1.0);
            double  sinTheta      = Math.Sqrt(1.0 - cosTheta * cosTheta);

            bool    cannotRefract = refractionRatio * sinTheta > 1.0;
            Vector3 direction;

            if (cannotRefract || reflectance(cosTheta, refractionRatio) > rand.NextDouble())
            {
                direction = Vector3.Reflect(unitDirection, record.Normal);
            }
            else
            {
                direction = Vector3.Refract(unitDirection, record.Normal, refractionRatio);
            }

            scattered.Set(new Ray(record.Point, direction));
            return(true);
        }
예제 #6
0
        public bool Scatter(Ray ray, HitRecord hitRecord, ref Vector3 attentuation, ref Ray scattered)
        {
            attentuation = Vector3.One;
            float refractionRatio = hitRecord.FrontFace ? (1.0f / RefactionIndex) : RefactionIndex;

            var   unitDir  = Vector3.Normalize(ray.Direction);
            float cosTheta = Math.Min(Vector3.Dot(-unitDir, hitRecord.Normal), 1.0f);
            float sinTheta = MathF.Sqrt(1.0f - cosTheta * cosTheta);

            bool    cannotRefract = refractionRatio * sinTheta > 1.0f;
            Vector3 direction;

            if (cannotRefract || Reflectance(cosTheta, refractionRatio) > MathExt.RandomFloat())
            {
                direction = Vector3.Reflect(unitDir, hitRecord.Normal);
            }
            else
            {
                direction = Vector3Ext.Refract(unitDir, hitRecord.Normal, refractionRatio);
            }

            scattered = new Ray(hitRecord.Point, direction, ray.Time);
            return(true);
        }
예제 #7
0
        private Vec3 Color(Ray ray, Hitable world, int depth, Random random)
        {
            var record = new HitRecord();

            if (world.Hit(ray, this.tMin, this.tMax, ref record))
            {
                Ray  scatteredRay = null;
                Vec3 attenuation  = null;
                if (depth < this.maxBounceDepth && record.Material.Scatter(ray, record, ref attenuation, ref scatteredRay, random))
                {
                    return(attenuation * Color(scatteredRay, this.world, depth + 1, random));
                }
                else
                {
                    return(this.black);
                }
            }
            else
            {
                var   unitDirection = ray.Direction.Normalized;
                float t             = 0.5f * (unitDirection.Y + 1);
                return(Vec3.Lerp(t, white, lightBlue));
            }
        }