public override bool Intersect(Ray ray, out float distance)
        {
            V3 centerDirection = Center - ray.Origin;

            V3 n = Normal();
            float t = (centerDirection * n) / (ray.Direction * n);

            if (t > DIST_THRES) {
                distance = t;

                V3 collisionPoint = ray.Origin + (ray.Direction * distance);
                V3 cornerPoint = Center - VB/2 - VA/2;

                V3 v = collisionPoint - cornerPoint;

                bool inRectangle = (VA * v >= 0) &&
                                   (VA * v <= VA.Norm2()) &&
                                   (VB * v >= 0) &&
                                   (VB * v <= VB.Norm2());

                return inRectangle;
            }

            distance = float.MaxValue;
            return false;
        }
        public override bool Intersect(Ray ray, out float distance)
        {
            V3 centerDirection = ray.Origin - Center;

            float a = 1;
            float b = 2 * centerDirection * ray.Direction;
            float c = (centerDirection * centerDirection) - (Radius * Radius);

            float delta = (b * b) - 4 * a * c;

            distance = float.MaxValue;
            if (delta >= 0) {
                float d1 = (-b + Mathf.Sqrt(delta))/(2 * a);
                float d2 = (-b - Mathf.Sqrt(delta))/(2 * a);

                if (d1 < DIST_THRES && d2 < DIST_THRES) {
                    return false;
                }
                else if (d1 < DIST_THRES || d2 < DIST_THRES) {
                    distance = Math.Max(d1,d2);
                }
                else {
                    distance = Math.Min(d1,d2);
                }

                return true;
            }

            return false;
        }
        /// Casts a ray and checks if it intersects any object. We can then
        /// compute the color of the point corresponding to the closest
        /// intersected object.
        private Color Raycast(Ray ray)
        {
            Object3D collidedObj = ray.ClosestIntersectedObject(Scene.Objects);

            // If the ray previously encountered an object, compute the pixel's
            // color.
            if (collidedObj != null) {
                V3 collisionPoint = ray.CollisionPoint();
                V2 collisionUV = collidedObj.UV(collisionPoint);

                float shadowCoeff = Occultation(collidedObj, collisionPoint);

                return shadowCoeff * Scene.IlluModel.Compute(
                    Scene.Lights, collidedObj, collisionPoint, collisionUV
                );
            }

            return null;
        }
        /// Casts a ray and checks if it intersects any object. We can then
        /// compute the color of the point corresponding to the closest
        /// intersected object. If the intersected object is transparent or
        /// reflective, new rays are cast from the collision point.
        private Color Raytrace(Ray ray, int depth)
        {
            if (depth <= 0) { return null; }

            Object3D collidedObj = ray.ClosestIntersectedObject(Scene.Objects);

            // If the ray previously encountered an object, compute the pixel's
            // color.
            if (collidedObj != null) {
                V3 collisionPoint = ray.CollisionPoint();
                V2 collisionUV = collidedObj.UV(collisionPoint);

                float shadowCoeff = Occultation(collidedObj, collisionPoint);

                Color directComponent = Scene.IlluModel.Compute(
                    Scene.Lights, collidedObj, collisionPoint, collisionUV
                );

                // reflected light component
                Color reflectionColor = ReflectionColor(
                    -ray.Direction, collisionPoint, collisionUV,
                    collidedObj, depth
                );

                // refracted light component
                Color refractionColor = RefractionColor(
                    ray.Direction, collisionPoint, collisionUV,
                    collidedObj, depth
                );

                return shadowCoeff * (
                    directComponent + reflectionColor + refractionColor
                );
            }

            return null;
        }
        /// Recursivly raytrace to get the color resulting from the refracted
        /// light component for the specified collisionPoint.
        private Color RefractionColor(
            V3 incidentVec, V3 collisionPoint, V2 collisionUV,
            Object3D collidedObj, int depth
        )
        {
            if (!collidedObj.Material.IsTransparent()) { return Color.Black; }

            V3 normal = collidedObj.Normal(collisionPoint, collisionUV);

            Ray refractionRay = new Ray(
                origin: collisionPoint,
                direction: incidentVec.RefractedVector(
                    normalVec: normal,
                    n1: Scene.RefractiveIndex,
                    n2: collidedObj.Material.RefractiveIndex
                ),
                originObject: null
            );

            Color refractionColor = Raytrace(refractionRay, depth - 1);
            if (refractionColor == null) { return Color.Black; }

            return collidedObj.Material.Transparency * refractionColor;
        }
        /// Recursivly raytrace to get the color resulting from the reflected
        /// light component for the specified collisionPoint.
        private Color ReflectionColor(
            V3 incidentVec, V3 collisionPoint, V2 collisionUV,
            Object3D collidedObj, int depth
        )
        {
            if (!collidedObj.Material.IsReflective()) { return Color.Black; }

            V3 normal = collidedObj.Normal(collisionPoint, collisionUV);
            Ray reflectionRay = new Ray(
                origin:       collisionPoint,
                direction:    incidentVec.ReflectedVector(normal),
                originObject: collidedObj
            );

            Color reflectionColor = Raytrace(reflectionRay, depth - 1);
            if (reflectionColor == null) { return Color.Black; }

            return collidedObj.Material.Reflection * reflectionColor;
        }
 public abstract bool Intersect(Ray ray, out float distance);
 public bool Intersect(Ray ray)
 {
     float distance;
     return Intersect(ray, out distance);
 }