Example #1
0
        /*
         * Returns an array of colours representing the output image
         */
        public Colour[,] GetImage(WorldSpace world, int width, int height, int reflectiveBounces = 4)
        {
            CalculateCorners();
            for (int i = 0; i < world.objects.Count; i++)
            {
                world.objects[i].CalculateTriangles();
            }
            Colour[,] image = new Colour[width, height];
            Vector3 deltaWidth  = Vector3.Divide(Vector3.Subtract(transformedCorners[1], transformedCorners[0]), width);
            Vector3 deltaHeight = Vector3.Divide(Vector3.Subtract(transformedCorners[2], transformedCorners[0]), height);

            for (int i = 0; i < height; i++)
            {
                Vector3 heightPoint = Vector3.Add(transformedCorners[0], Vector3.Multiply(deltaHeight, i));
                for (int j = 0; j < width; j++)
                {
                    Vector3 point = Vector3.Add(heightPoint, Vector3.Multiply(deltaWidth, j));
                    Vector3 rayDir;
                    if (perspective)
                    {
                        rayDir = Vector3.Unit(Vector3.Subtract(point, origin));
                    }
                    else
                    {
                        rayDir = direction;
                    }
                    RayHit camHit = GetRayHitClipping(world, point, rayDir, near, far);
                    if (camHit.hit)
                    {
                        float    smallestDistance = camHit.distances[0];
                        Vector3  closestIntersect = camHit.intersects[0];
                        Triangle triangle         = camHit.triangles[0];
                        for (int k = 1; k < camHit.intersects.Count; k++)
                        {
                            if (camHit.distances[k] < smallestDistance)
                            {
                                smallestDistance = camHit.distances[k];
                                closestIntersect = camHit.intersects[k];
                                triangle         = camHit.triangles[k];
                            }
                        }
                        image[j, i] = RayTrace(world, rayDir, closestIntersect, triangle, reflectiveBounces);
                    }
                    else
                    {
                        image[j, i] = background;
                    }
                }
            }
            return(image);
        }
Example #2
0
        /*
         * Checks for intersections only if they are within a certain range of the camera
         */
        public RayHit GetRayHitClipping(WorldSpace world, Vector3 start, Vector3 ray, float near, float far)
        {
            RayHit h    = GetRayHit(world, start, ray, null);
            RayHit newH = new RayHit();

            for (int i = 0; i < h.intersects.Count; i++)
            {
                float perpDistance = h.distances[i];
                if (perspective)
                {
                    perpDistance *= Vector3.DotProduct(ray, direction);
                }
                if (perpDistance >= near - screenDistance && perpDistance <= far - screenDistance)
                {
                    newH.hit = true;
                    newH.intersects.Add(h.intersects[i]);
                    newH.triangles.Add(h.triangles[i]);
                    newH.distances.Add(h.distances[i]);
                }
            }
            return(newH);
        }
Example #3
0
        /*
         * Returns the colour that would be seen for a specific ray trace
         */
        public Colour RayTrace(WorldSpace world, Vector3 viewVector, Vector3 intersect, Triangle triangle, int reflectiveBounces)
        {
            RayHit  reflectHit;
            Colour  diffuse;
            Vector3 lightRay;
            float   lightCos;

            if (world.light.GetType() == typeof(DirectionalLight))
            {
                //Directional lighting
                DirectionalLight worldLight = (DirectionalLight)world.light;
                lightRay   = Vector3.Unit(Vector3.Multiply(worldLight.lightVec, -1));
                lightCos   = Math.Abs(Vector3.DotProduct(lightRay, triangle.normal));
                reflectHit = GetRayHit(world, intersect, lightRay, triangle);
                diffuse    = Colour.Combine(triangle.material.diffuse, world.light.colour, world.light.brightness * lightCos * triangle.material.diffuseVal);
            }
            else if (world.light.GetType() == typeof(SpotLight))
            {
                //Spot lighting
                SpotLight worldLight = (SpotLight)world.light;
                Vector3   spotVector = Vector3.Unit(Vector3.Multiply(worldLight.lightVec, -1));
                lightRay = Vector3.Subtract(world.light.origin, intersect);
                float lightDistance = lightRay.Magnitude();
                lightRay = Vector3.Unit(lightRay);
                lightCos = Math.Abs(Vector3.DotProduct(lightRay, triangle.normal));
                if (Vector3.DotProduct(spotVector, lightRay) >= Math.Cos(worldLight.spotAngle))
                {
                    reflectHit = GetRayHit(world, intersect, lightRay, triangle);
                    diffuse    = Colour.Combine(triangle.material.diffuse, world.light.colour, world.light.brightness * lightCos * triangle.material.diffuseVal / (lightDistance * lightDistance));
                }
                else
                {
                    reflectHit     = new RayHit();
                    reflectHit.hit = true;
                    diffuse        = new Colour(ColourList.BLACK);
                }
            }
            else
            {
                //Point lighting
                lightRay = Vector3.Subtract(world.light.origin, intersect);
                float lightDistance = lightRay.Magnitude();
                lightRay   = Vector3.Unit(lightRay);
                lightCos   = Math.Abs(Vector3.DotProduct(lightRay, triangle.normal));
                reflectHit = GetRayHit(world, intersect, lightRay, triangle);
                diffuse    = Colour.Combine(triangle.material.diffuse, world.light.colour, world.light.brightness * lightCos * triangle.material.diffuseVal / (lightDistance * lightDistance));
            }
            Colour ambient    = Colour.Combine(triangle.material.diffuse, background, world.ambientBrightness);
            Colour reflection = new Colour(ColourList.BLACK);
            Colour specular   = new Colour(ColourList.BLACK);

            if (reflectiveBounces > 0 && triangle.material.reflectivity > 0)
            {
                //Checks for recursive reflectivity
                Vector3 reverseVector    = Vector3.Unit(Vector3.Multiply(viewVector, -1));
                Vector3 reflectance      = Vector3.Subtract(Vector3.Multiply(triangle.normal, 2 * Vector3.DotProduct(triangle.normal, reverseVector)), reverseVector);
                Vector3 lightReflectance = Vector3.Subtract(Vector3.Multiply(triangle.normal, 2 * Vector3.DotProduct(triangle.normal, lightRay)), lightRay);
                float   specularDot      = Vector3.DotProduct(lightReflectance, reverseVector);
                if (specularDot < 0)
                {
                    specularDot = 0;
                }
                specular = Colour.Combine(triangle.material.specular, world.light.colour, triangle.material.reflectivity * (float)Math.Pow(specularDot, triangle.material.shininess));
                RayHit reflectionHit = GetRayHit(world, intersect, reflectance, triangle);
                if (reflectionHit.hit)
                {
                    float    smallestDistance    = reflectionHit.distances[0];
                    Vector3  reflectionIntersect = reflectionHit.intersects[0];
                    Triangle reflectionTriangle  = reflectionHit.triangles[0];
                    for (int k = 1; k < reflectionHit.intersects.Count; k++)
                    {
                        if (reflectionHit.distances[k] < smallestDistance)
                        {
                            smallestDistance    = reflectionHit.distances[k];
                            reflectionIntersect = reflectionHit.intersects[k];
                            reflectionTriangle  = reflectionHit.triangles[k];
                        }
                    }
                    reflection = Colour.Add(reflection, Colour.Multiply(RayTrace(world, reflectance, reflectionIntersect, reflectionTriangle, reflectiveBounces - 1), triangle.material.reflectivity));
                }
            }
            if (reflectHit.hit)
            {
                return(Colour.Add(ambient, reflection));
            }
            else
            {
                return(Colour.Add(ambient, diffuse, reflection, specular));
            }
        }
Example #4
0
        /*
         * Checks to see if the current ray is intersecting a triangle
         * This is where the most optimization is required
         */
        public RayHit GetRayHit(WorldSpace world, Vector3 start, Vector3 ray, Triangle exclusionTriangle)
        {
            RayHit h = new RayHit();

            for (int i = 0; i < world.objects.Count; i++)
            {
                //Checks to see if the ray is within an object's AABB
                Vector3 minAABB = world.objects[i].minAABB;
                Vector3 maxAABB = world.objects[i].maxAABB;
                float   tx1 = (minAABB.x - start.x) / ray.x;
                float   tx2 = (maxAABB.x - start.x) / ray.x;
                float   ty1 = (minAABB.y - start.y) / ray.y;
                float   ty2 = (maxAABB.y - start.y) / ray.y;
                float   tz1 = (minAABB.z - start.z) / ray.z;
                float   tz2 = (maxAABB.z - start.z) / ray.z;
                float   tmin, tmax;
                if (tx1 < tx2)
                {
                    tmin = tx1;
                    tmax = tx2;
                }
                else
                {
                    tmin = tx2;
                    tmax = tx1;
                }
                float tmpmin, tmpmax;
                if (ty1 < ty2)
                {
                    tmpmin = ty1;
                    tmpmax = ty2;
                }
                else
                {
                    tmpmin = ty2;
                    tmpmax = ty1;
                }
                if (tmax < tmpmin)
                {
                    tmpmin = tmax;
                }
                if (tmin > tmpmax)
                {
                    tmpmax = tmin;
                }
                if (tmin < tmpmin)
                {
                    tmin = tmpmin;
                }
                if (tmax > tmpmax)
                {
                    tmax = tmpmax;
                }
                if (tz1 < tz2)
                {
                    tmpmin = tz1;
                    tmpmax = tz2;
                }
                else
                {
                    tmpmin = tz2;
                    tmpmax = tz1;
                }
                if (tmax < tmpmin)
                {
                    tmpmin = tmax;
                }
                if (tmin > tmpmax)
                {
                    tmpmax = tmin;
                }
                if (tmin < tmpmin)
                {
                    tmin = tmpmin;
                }
                if (tmax > tmpmax)
                {
                    tmax = tmpmax;
                }
                if (tmax == tmin)
                {
                    continue;
                }
                //Checks each triangle for intersection with vectors
                for (int j = 0; j < world.objects[i].triangles.Length; j++)
                {
                    Triangle currentTriangle = world.objects[i].triangles[j];
                    if (currentTriangle == exclusionTriangle)
                    {
                        continue;
                    }
                    if (Vector3.DotProduct(currentTriangle.normal, ray) >= 0)
                    {
                        continue;
                    }
                    float npb = Vector3.DotProduct(currentTriangle.normal, Vector3.Subtract(start, currentTriangle.vertices[1]));
                    float nr  = Vector3.DotProduct(currentTriangle.normal, ray);
                    float t   = 0; // distance
                    if (nr != 0)
                    {
                        t = -npb / nr;
                    }
                    if (t <= 0)
                    {
                        continue;
                    }
                    Vector3 ab        = Vector3.Subtract(currentTriangle.vertices[0], currentTriangle.vertices[1]);
                    Vector3 cb        = Vector3.Subtract(currentTriangle.vertices[2], currentTriangle.vertices[1]);
                    Vector3 ac        = Vector3.Subtract(currentTriangle.vertices[0], currentTriangle.vertices[2]);
                    Vector3 intersect = Vector3.Add(start, Vector3.Multiply(ray, t));
                    Vector3 da        = Vector3.Subtract(intersect, currentTriangle.vertices[0]);
                    Vector3 db        = Vector3.Subtract(intersect, currentTriangle.vertices[1]);
                    Vector3 dc        = Vector3.Subtract(intersect, currentTriangle.vertices[2]);
                    //Checks to see if there is a point of intersection
                    if (Vector3.DotProduct(currentTriangle.normal, Vector3.CrossProduct(da, ab)) >= 0 && Vector3.DotProduct(currentTriangle.normal, Vector3.CrossProduct(cb, db)) >= 0 && Vector3.DotProduct(currentTriangle.normal, Vector3.CrossProduct(ac, dc)) >= 0)
                    {
                        h.hit = true;
                        h.triangles.Add(currentTriangle);
                        h.intersects.Add(intersect);
                        h.distances.Add(t);
                    }
                }
            }
            return(h);
        }
Example #5
0
        static void Main(string[] args)
        {
            int    width    = 1280;
            int    height   = 720;
            string filename = "image";

            Console.WriteLine("Importing models...\t 0% complete");
            Importer importer = new Importer();

            Console.WriteLine("Generating scene...\t25% complete");
            Camera      camera      = new Camera(new Vector3(0, 3, 0), new Vector3(0, 0, -15), 80.0f, 1.0f, 40.0f, (float)height / width, true, new Colour(155, 230, 255));
            WorldSpace  world       = new WorldSpace(0.15f);
            Material    orangeFlat  = new Material(new Colour(ColourList.ORANGE), new Colour(ColourList.WHITE), 1.0f, 0.0f, 0);
            Material    greenShiny  = new Material(new Colour(ColourList.YELLOW), new Colour(ColourList.WHITE), 1.0f, 0.5f, 5);
            Material    floorGrey   = new Material(new Colour(ColourList.GREY), new Colour(ColourList.WHITE), 1.0f, 0.5f, 20);
            Material    glossPurple = new Material(new Colour(ColourList.PURPLE), new Colour(ColourList.WHITE), 1.0f, 0.9f, 3);
            WorldObject pyramid     = new WorldObject(
                new Vector3(5, 1.5f, -1.5f),
                new Vector3[] {
                new Vector3(0, -1, 0),
                new Vector3(1, 1, -1),
                new Vector3(1, 1, 1),
                new Vector3(-1, 1, 0)
            },
                new int[, ] {
                { 0, 1, 2 },
                { 0, 3, 1 },
                { 0, 2, 3 },
                { 3, 2, 1 }
            },
                new Material[] {
                greenShiny,
                orangeFlat,
                greenShiny,
                orangeFlat
            }
                );
            WorldObject sphere = importer.ImportSTL(
                new Vector3(6, 1.5f, 0),
                glossPurple,
                "sphere.stl"
                );
            WorldObject floor = new WorldObject(
                new Vector3(0, 0, 0),
                new Vector3[] {
                new Vector3(0, 0, -20),
                new Vector3(0, 0, 20),
                new Vector3(40, 0, -20),
                new Vector3(40, 0, 20),
                new Vector3(0, -1, 0)
            },
                new int[, ] {
                { 0, 1, 2 },
                { 1, 3, 2 }
            },
                new Material[] {
                floorGrey,
                floorGrey
            }
                );

            pyramid.RotateZ(45);
            LightSource light = new PointLight(new Vector3(3.0f, 5.0f, 1.0f), 30.0f, new Colour(255, 247, 219));

            //LightSource light = new SpotLight(new Vector3(3.0f, 5.0f, 1.0f), new Vector3(1, -1, 0), 60.0f, new Colour(36, 36, 36), 30.0f);
            //LightSource light = new DirectionalLight(new Vector3(1, -1, -1), 0.7f, new Colour(255, 247, 219));
            world.AddObject(pyramid);
            world.AddObject(sphere);
            world.AddObject(floor);
            world.SetLight(light);
            Exporter exporter = new Exporter(width, height);

            Colour[,] image = new Colour[width, height];
            Console.WriteLine("Rendering image...\t50% complete");
            exporter.SetImage(camera.GetImage(world, width, height, 8));
            Console.WriteLine("Exporting...\t\t75% complete");
            exporter.CreateFile(filename);
            Console.WriteLine("All jobs finished\t100% complete\n");
            Console.WriteLine("Exported file " + filename + ".ppm");
            Console.WriteLine("Press any key to continue");
            Console.ReadLine();
        }