Пример #1
0
        /// <summary>
        /// This implementation of intersect uses the fastest ray-sphere intersection algorithm I could find
        /// on the internet.
        /// </summary>
        /// <param name="ray"></param>
        /// <returns></returns>
        public override IntersectInfo Intersect(Ray ray)
        {
            IntersectInfo info = new IntersectInfo();

            info.Element = this;

            Vector dst = ray.Position - this.Position;
            double B   = dst.Dot(ray.Direction);
            double C   = dst.Dot(dst) - (R * R);
            double D   = B * B - C;

            if (D > 0) // yes, that's it, we found the intersection!
            {
                info.IsHit    = true;
                info.Distance = -B - (double)Math.Sqrt(D);
                info.Position = ray.Position + ray.Direction * info.Distance;
                info.Normal   = (info.Position - Position).Normalize();

                if (Material.HasTexture)
                {
                    Vector vn = new Vector(0, 1, 0).Normalize();        // north pole / up
                    Vector ve = new Vector(0, 0, 1).Normalize();        // equator / sphere orientation
                    Vector vp = (info.Position - Position).Normalize(); //points from center of sphere to intersection

                    double phi = Math.Acos(-vp.Dot(vn));
                    double v   = (phi * 2 / Math.PI) - 1;

                    double sinphi = ve.Dot(vp) / Math.Sin(phi);
                    sinphi = sinphi < -1 ? -1 : sinphi > 1 ? 1 : sinphi;
                    double theta = Math.Acos(sinphi) * 2 / Math.PI;

                    double u;

                    if (vn.Cross(ve).Dot(vp) > 0)
                    {
                        u = theta;
                    }
                    else
                    {
                        u = 1 - theta;
                    }

                    // alternative but worse implementation
                    //double u = Math.Atan2(vp.x, vp.z);
                    //double v = Math.Acos(vp.y);
                    info.Color = this.Material.GetColor(u, v);
                }
                else
                {
                    // skip uv calculation, just get the color
                    info.Color = this.Material.GetColor(0, 0);
                }
            }
            else
            {
                info.IsHit = false;
            }
            return(info);
        }
Пример #2
0
        private IntersectInfo IntersectSlab(Ray ray, Vector P1, Vector P2, Vector P3)
        {
            Vector        N    = (P1 - P3).Cross(P2 - P3).Normalize();
            double        d    = N.Dot(P1);
            IntersectInfo info = new IntersectInfo();
            double        Vd   = N.Dot(ray.Direction);

            if (Vd == 0)
            {
                return(info);         // no intersection
            }
            double t = -(N.Dot(ray.Position) - d) / Vd;

            if (t <= 0)
            {
                return(info);
            }
            Vector hit = ray.Position + ray.Direction * t;

            if ((hit.x < P1.x || hit.x > P2.x) && (P1.x != P2.x))
            {
                return(info);
            }
            if ((hit.y < P3.y || hit.y > P1.y) && (P1.y != P2.y))
            {
                return(info);
            }
            //if ((hit.z < P1.z || hit.z > P3.z) && (P1.z != P3.z)) return info;
            if ((hit.z < P1.z || hit.z > P2.z) && (P1.z != P2.z))
            {
                return(info);
            }


            info.Element  = this;
            info.IsHit    = true;
            info.Position = hit;
            info.Normal   = N;// *-1;
            info.Distance = t;

            if (Material.HasTexture)
            {
                //Vector vecU = new Vector(hit.y - Position.y, hit.z - Position.z, Position.x-hit.x);
                Vector vecU = new Vector((P1.y + P2.y) / 2 - Position.y, (P1.z + P2.z) / 2 - Position.z, Position.x - (P1.x + P2.x) / 2).Normalize();
                Vector vecV = vecU.Cross((P1 + P2) / 2 - Position).Normalize();

                double u = info.Position.Dot(vecU);
                double v = info.Position.Dot(vecV);
                info.Color = Material.GetColor(u, v);
            }
            else
            {
                info.Color = Material.GetColor(0, 0);
            }

            return(info);
        }
Пример #3
0
        /// <summary>
        /// this implementation is used for debugging purposes.
        /// the color is calculated following the normal raytrace procedure
        /// execpt it is calculated for 1 particula ray
        /// </summary>
        /// <param name="ray">the ray for which to calculate the color</param>
        /// <param name="scene">the scene which is raytraced</param>
        /// <returns></returns>
        public Color CalculateColor(Ray ray, Scene scene)
        {
            IntersectInfo info = TestIntersection(ray, scene, null);

            if (info.IsHit)
            {
                // execute the actual raytrace algorithm
                Color c = RayTrace(info, ray, scene, 0);
                return(c);
            }

            return(scene.Background.Color);
        }
Пример #4
0
        public override IntersectInfo Intersect(Ray ray)
        {
            IntersectInfo info = new IntersectInfo();
            double        Vd   = Position.Dot(ray.Direction);

            if (Vd == 0)
            {
                return(info);         // no intersection
            }
            double t = -(Position.Dot(ray.Position) + D) / Vd;

            if (t <= 0)
            {
                return(info);
            }

            info.Element  = this;
            info.IsHit    = true;
            info.Position = ray.Position + ray.Direction * t;
            info.Normal   = Position;// *-1;
            info.Distance = t;

            if (Material.HasTexture)
            {
                Vector vecU = new Vector(Position.y, Position.z, -Position.x);
                Vector vecV = vecU.Cross(Position);

                double u = info.Position.Dot(vecU);
                double v = info.Position.Dot(vecV);
                info.Color = Material.GetColor(u, v);
            }
            else
            {
                info.Color = Material.GetColor(0, 0);
            }

            return(info);
        }
Пример #5
0
        /// <summary>
        /// this method tests for an intersection. It will try to find the closest
        /// object that intersects with the ray.
        /// it will inspect every object in the scene. also here there is room for increased performance.
        /// </summary>
        /// <param name="ray"></param>
        /// <param name="scene"></param>
        /// <param name="exclude"></param>
        /// <returns></returns>
        private IntersectInfo TestIntersection(Ray ray, Scene scene, IShape exclude)
        {
            int           hitcount = 0;
            IntersectInfo best     = new IntersectInfo();

            best.Distance = double.MaxValue;

            foreach (IShape elt in scene.Shapes)
            {
                if (elt == exclude)
                {
                    continue;
                }

                IntersectInfo info = elt.Intersect(ray);
                if (info.IsHit && info.Distance < best.Distance && info.Distance >= 0)
                {
                    best = info;
                    hitcount++;
                }
            }
            best.HitCount = hitcount;
            return(best);
        }
Пример #6
0
        public override IntersectInfo Intersect(Ray ray)
        {
            IntersectInfo best = new IntersectInfo();

            best.Distance = double.MaxValue;
            IntersectInfo info = null;

            //check each side of the box
            // this is quite a crude implementation and can be optimized

            Vector P1 = null;
            Vector P2 = null;
            Vector P3 = null;

            if (ray.Direction.z > 0)
            {
                //front
                P1   = UpperLeftFront;
                P2   = new Vector(LowerRightBack.x, LowerRightBack.y, P1.z);
                P3   = new Vector(P1.x, P2.y, P1.z);
                info = IntersectSlab(ray, P1, P2, P3);
                if (info.IsHit && info.Distance < best.Distance)
                {
                    best = info;
                }
            }
            else
            {
                //backside
                P1   = new Vector(UpperLeftFront.x, UpperLeftFront.y, LowerRightBack.z);
                P2   = LowerRightBack;
                P3   = new Vector(P1.x, P2.y, P1.z);
                info = IntersectSlab(ray, P1, P2, P3);
                if (info.IsHit && info.Distance < best.Distance)
                {
                    best = info;
                }
            }

            if (ray.Direction.x < 0)
            {
                //right side
                P1   = new Vector(LowerRightBack.x, UpperLeftFront.y, UpperLeftFront.z);
                P2   = LowerRightBack;
                P3   = new Vector(P1.x, P2.y, P1.z);
                info = IntersectSlab(ray, P1, P2, P3);
                if (info.IsHit && info.Distance < best.Distance)
                {
                    best = info;
                }
            }
            else
            {
                //left side
                P1   = UpperLeftFront;
                P2   = new Vector(UpperLeftFront.x, LowerRightBack.y, LowerRightBack.z);
                P3   = new Vector(P1.x, P2.y, P1.z);
                info = IntersectSlab(ray, P1, P2, P3);
                if (info.IsHit && info.Distance < best.Distance)
                {
                    best = info;
                }
            }

            if (ray.Direction.y < 0)
            {
                //top side
                P1   = UpperLeftFront;
                P2   = new Vector(LowerRightBack.x, UpperLeftFront.y, LowerRightBack.z);
                P3   = new Vector(P2.x, P1.y, P1.z);
                info = IntersectSlab(ray, P1, P2, P3);
                if (info.IsHit && info.Distance < best.Distance)
                {
                    best = info;
                }
            }
            else
            {
                //bottom side
                P1   = new Vector(UpperLeftFront.x, LowerRightBack.y, UpperLeftFront.z);
                P2   = LowerRightBack;
                P3   = new Vector(P2.x, P1.y, P1.z);
                info = IntersectSlab(ray, P1, P2, P3);
                if (info.IsHit && info.Distance < best.Distance)
                {
                    best = info;
                }
            }
            return(best);
        }
Пример #7
0
        /// <summary>
        /// This is the main RayTrace controller algorithm, the core of the RayTracer
        /// recursive method setup
        /// this does the actual tracing of the ray and determines the color of each pixel
        /// supports:
        /// - ambient lighting
        /// - diffuse lighting
        /// - Gloss lighting
        /// - shadows
        /// - reflections
        /// </summary>
        /// <param name="info"></param>
        /// <param name="ray"></param>
        /// <param name="scene"></param>
        /// <param name="depth"></param>
        /// <returns></returns>
        private Color RayTrace(IntersectInfo info, Ray ray, Scene scene, int depth)
        {
            // calculate ambient light
            Color  color     = info.Color * scene.Background.Ambience;
            double shininess = Math.Pow(10, info.Element.Material.Gloss + 1);

            foreach (Light light in scene.Lights)
            {
                // calculate diffuse lighting
                Vector v = (light.Position - info.Position).Normalize();

                if (RenderDiffuse)
                {
                    double L = v.Dot(info.Normal);
                    if (L > 0.0f)
                    {
                        color += info.Color * light.Color * L;
                    }
                }


                // this is the max depth of raytracing.
                // increasing depth will calculate more accurate color, however it will
                // also take longer (exponentially)
                if (depth < 3)
                {
                    // calculate reflection ray
                    if (RenderReflection && info.Element.Material.Reflection > 0)
                    {
                        Ray           reflectionray = GetReflectionRay(info.Position, info.Normal, ray.Direction);
                        IntersectInfo refl          = TestIntersection(reflectionray, scene, info.Element);
                        if (refl.IsHit && refl.Distance > 0)
                        {
                            // recursive call, this makes reflections expensive
                            refl.Color = RayTrace(refl, reflectionray, scene, depth + 1);
                        }
                        else // does not reflect an object, then reflect background color
                        {
                            refl.Color = scene.Background.Color;
                        }
                        color = color.Blend(refl.Color, info.Element.Material.Reflection);
                    }

                    //calculate refraction ray
                    if (RenderRefraction && info.Element.Material.Transparency > 0)
                    {
                        Ray           refractionray = GetRefractionRay(info.Position, info.Normal, ray.Direction, info.Element.Material.Refraction);
                        IntersectInfo refr          = info.Element.Intersect(refractionray);
                        if (refr.IsHit)
                        {
                            //refractionray = new Ray(refr.Position, ray.Direction);
                            refractionray = GetRefractionRay(refr.Position, refr.Normal, refractionray.Direction, refr.Element.Material.Refraction);
                            refr          = TestIntersection(refractionray, scene, info.Element);
                            if (refr.IsHit && refr.Distance > 0)
                            {
                                // recursive call, this makes refractions expensive
                                refr.Color = RayTrace(refr, refractionray, scene, depth + 1);
                            }
                            else
                            {
                                refr.Color = scene.Background.Color;
                            }
                        }
                        else
                        {
                            refr.Color = scene.Background.Color;
                        }
                        color = color.Blend(refr.Color, info.Element.Material.Transparency);
                    }
                }


                IntersectInfo shadow = new IntersectInfo();
                if (RenderShadow)
                {
                    // calculate shadow, create ray from intersection point to light
                    Ray shadowray = new Ray(info.Position, v);

                    // find any element in between intersection point and light
                    shadow = TestIntersection(shadowray, scene, info.Element);
                    if (shadow.IsHit && shadow.Element != info.Element)
                    {
                        // only cast shadow if the found interesection is another
                        // element than the current element
                        color *= 0.5 + 0.5 * Math.Pow(shadow.Element.Material.Transparency, 0.5); // Math.Pow(.5, shadow.HitCount);
                    }
                }

                // only show highlights if it is not in the shadow of another object
                if (RenderHighlights && !shadow.IsHit && info.Element.Material.Gloss > 0)
                {
                    // only show Gloss light if it is not in a shadow of another element.
                    // calculate Gloss lighting (Phong)
                    Vector Lv = (info.Element.Position - light.Position).Normalize();
                    Vector E  = (scene.Camera.Position - info.Element.Position).Normalize();
                    Vector H  = (E - Lv).Normalize();

                    double Glossweight = 0.0;
                    Glossweight = Math.Pow(Math.Max(info.Normal.Dot(H), 0), shininess);
                    color      += light.Color * (Glossweight);
                }
            }

            // normalize the color
            color.Limit();
            return(color);
        }