예제 #1
0
        private Vector3 CastRay(Ray ray, int depth = 0)
        {
            (float i1, float i2)minIntersection = (float.MaxValue, float.MaxValue);
            IIntersectable minObj = null;

            // find closest intersection if it exists
            foreach (IIntersectable obj in objects)
            {
                (float i1, float i2)intersection = obj.Intersect(ray);
                if (intersection.i1 > 0 && intersection.i1 < minIntersection.i1)
                {
                    minIntersection = intersection;
                    minObj          = obj;
                }
            }

            if (minObj == null)
            {
                if (depth == 0)
                {
                    return(BackgroundColour);
                }
                else
                {
                    return(new Vector3(0));
                }
            }

            Vector3 iPoint  = ray.ToPoint(minIntersection.i1);
            Vector3 iNormal = minObj.CalcNormal(iPoint, true);

            Vector3 pointCol = minObj.Colour * minObj.Ambient;


            foreach (Light light in lights)
            {
                // cast shadow ray for each object. if collide, shadow
                Vector3 il    = (light.Pos - iPoint).Normalized();
                Ray     ilRay = new Ray(iPoint + iNormal, il);

                bool shadow = false;
                foreach (IIntersectable obj in objects)
                {
                    if (obj.Intersect(ilRay).i1 > 0)
                    {
                        shadow = true;
                        break;
                    }
                }

                // calculate actual lighting if not in shadow
                // based on https://en.wikipedia.org/wiki/Phong_reflection_model and https://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_reflection_model
                if (!shadow)
                {
                    float   angleCoeff = Math.Max(0f, Vector3.Dot(il, iNormal));
                    Vector3 diffuse    = minObj.Colour * angleCoeff * light.Brightness * minObj.Diffuse;

                    Vector3 lv       = il - ray.Dir;
                    Vector3 h        = lv / lv.Length;
                    float   nh       = Math.Max(0f, Vector3.Dot(iNormal, h));
                    Vector3 specular = minObj.SpecularColour * (float)Math.Pow(nh, minObj.Shininess) * minObj.Specular;

                    pointCol += diffuse * specular;
                }

                // handle reflective materials
                if (minObj.Reflectivity > 0 && depth < 5)
                {
                    Vector3 rVec = (il - 2 * Vector3.Dot(il, iNormal) * iNormal).Normalized();

                    Ray     subRay  = new Ray(iPoint + iNormal, rVec);
                    Vector3 rColour = CastRay(subRay, depth + 1);

                    pointCol += rColour * minObj.Reflectivity;
                }
            }

            return(pointCol);
        }