public virtual Color Compute(
            List<Light> lights, Object3D obj, V3 p, V2 uv
        )
        {
            Color illumination = new Color(0, 0, 0);

            foreach (Light l in lights) {
                if (l.GetType().Name == "AmbientLight") {
                    illumination += ComputeAmbientLight(
                        (AmbientLight) l, obj, p, uv
                    );
                }
                else if (l.GetType().Name == "PointLight") {
                    illumination += ComputePointLight(
                        (PointLight) l, obj, p, uv
                    );
                }
                else if (l.GetType().Name == "DirectionalLight") {
                    illumination += ComputeDirectionalLight(
                        (DirectionalLight) l, obj, p, uv
                    );
                }
            }

            return illumination;
        }
        /// Computes the diffuse and specular components of the Phong
        /// reflection model for a directional light.
        public override Color ComputeDirectionalLight(
            DirectionalLight dL, Object3D obj, V3 p, V2 uv
        )
        {
            V3 incidentVec = -dL.Direction;

            return ComputeDiffuseSpecular(dL, obj, p, uv, incidentVec);
        }
        /// Computes the diffuse and specular components of the Phong
        /// reflection model for a point light.
        public override Color ComputePointLight(
            PointLight pL, Object3D obj, V3 p, V2 uv
        )
        {
            V3 incidentVec = pL.Position - p;
            incidentVec.Normalize();

            return ComputeDiffuseSpecular(pL, obj, p, uv, incidentVec);
        }
        public Ray(V3 origin, V3 direction, Object3D originObject = null)
        {
            Origin = origin;

            Direction = direction;
            Direction.Normalize();

            OriginObject = originObject;

            Distance = float.MaxValue;
        }
        private Color ComputeDiffuse(
            Light l, V3 incidentVec, V3 normalVec, Object3D obj, V2 uv
        )
        {
            Color diffuseIllu = new Color(0, 0, 0);
            if (incidentVec * normalVec > 0.0f) {
                diffuseIllu = obj.TextureColor(uv) * l.Intensity *
                              obj.Material.KDiffuse * (incidentVec * normalVec);
            }

            return diffuseIllu;
        }
        /// Computes the diffuse and specular components of the Phong
        /// reflection model.
        /// @Note Avoids code duplication in ComputePointLight and
        /// ComputeDirectionalLight.
        private Color ComputeDiffuseSpecular(
            Light l, Object3D obj, V3 p, V2 uv, V3 incidentVec
        )
        {
            V3 normalVec = obj.Normal(p, uv);

            V3 reflectedVec = incidentVec.ReflectedVector(normalVec);
            reflectedVec.Normalize();

            V3 viewingVec = CameraPos - p;
            viewingVec.Normalize();

            Color diffuseIllu = ComputeDiffuse(
                l, incidentVec, normalVec, obj, uv
            );
            Color specularIllu = ComputeSpecular(
                l, reflectedVec, normalVec, obj, uv
            );

            return diffuseIllu + specularIllu;
        }
        /// Renders one object.
        private void RenderObject(Object3D obj)
        {
            for (float u = 0.0f ; u < 1.0f ; u += 0.001f) {
                for (float v = 0.0f ; v < 1.0f ; v += 0.001f) {
                    V2 uv = new V2(u,v);
                    V3 p = obj.Point(uv);

                    V3 pScreen = new V3(
                        x: p.X,
                        y: Canvas.Height - p.Z,
                        z: p.Y
                    );
                    bool objectVisible = Set(pScreen);

                    if (objectVisible) {
                        Color illumination = Scene.IlluModel.Compute(
                            Scene.Lights, obj, p, uv
                        );

                        Canvas.DrawPixel(pScreen, illumination);
                    }
                }
            }
        }
 /// Computes the ambient component of the Phong reflection model for
 /// an ambient light.
 public override Color ComputeAmbientLight(
     AmbientLight aL, Object3D obj, V3 p, V2 uv
 )
 {
     return obj.TextureColor(uv) * aL.Intensity * obj.Material.KAmbient;
 }
        /// 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;
        }
 public override Color ComputeAmbientLight(
     AmbientLight aL, Object3D obj, V3 p, V2 uv
 )
 {
     return new Color(0, 0, 0);
 }
 public abstract Color ComputePointLight(
     PointLight pL, Object3D obj, V3 p, V2 uv
 );
 public abstract Color ComputeDirectionalLight(
     DirectionalLight dL, Object3D obj, V3 p, V2 uv
 );
 public abstract Color ComputeAmbientLight(
     AmbientLight aL, Object3D obj, V3 p, V2 uv
 );
 public override Color ComputePointLight(
     PointLight pL, Object3D obj, V3 p, V2 uv
 )
 {
     return new Color(0, 0, 0);
 }
 public override Color ComputeDirectionalLight(
     DirectionalLight dL, Object3D obj, V3 p, V2 uv
 )
 {
     return new Color(0, 0, 0);
 }
        /// 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;
        }
        private Color ComputeSpecular(
            Light l, V3 reflectedVec, V3 viewingVec, Object3D obj, V2 uv
        )
        {
            Color specularIllu = new Color(0, 0, 0);
            if (reflectedVec * viewingVec > 0.0f) {
                specularIllu = l.Intensity * obj.Material.KSpecular *
                     Mathf.Pow(
                        reflectedVec * viewingVec,
                        obj.Material.Shininess
                     );
            }

            return specularIllu;
        }
 public override Color Compute(
     List<Light> lights, Object3D obj, V3 p, V2 uv
 )
 {
     return obj.TextureColor(uv);
 }