Ejemplo n.º 1
0
        public void RayTriangleTest()
        {
            Vector3 origin = new Vector3(0, 0, 0);
            Vector3 direction = new Vector3(1, 0, 0);
            Ray r = new Ray(origin, direction);
            Triangle t = new Triangle(
                new Vertex() { Position = new Vector3(2, 1, 0) },
                new Vertex() { Position = new Vector3(2, 0, -1) },
                new Vertex() { Position = new Vector3(2, 0, 1) });

            float time = -1f;
            bool collides = r.CollidesWith(t, ref time);

            Assert.True(collides);
            Assert.Equal(2f, time);

            Ray r2 = new Ray(origin, -direction);

            collides = r2.CollidesWith(t, ref time);
            Assert.False(collides);
            Assert.Equal(-2f, time);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Renders the scene
        /// </summary>
        /// <returns>The constructed bitmap</returns>
        public Bitmap Render()
        {
            Bitmap output = new Bitmap(config.OutputWidth, config.OutputHeight);

            Matrix view = Matrix.LookAt(config.ViewportData.Up, config.ViewportData.Position, config.ViewportData.Target);

            // calcualte the camera position using the view matrix
            cameraPosition = new Vector3(0, 0, 0);
            cameraPosition.Z = (config.OutputHeight / (2.0f * (float)Math.Tan((config.ViewportData.FieldOfView / 2.0f) * (float)Math.PI / 180.0f)));
            cameraPosition = view * cameraPosition;

            Vector3 right = new Vector3(1, 0, 0);
            Vector3 up = new Vector3(0, 1, 0);

            // Get the left and top side of the viewport in screen coordinates
            Vector3 viewportLeftWorldSpace = (-(config.ViewportData.Width / 2.0f) * right);
            Vector3 viewportTopWorldSpace = ((config.ViewportData.Height / 2.0f) * up);

            // Get the number of world units per pixel
            float horizontalUnitsPerPixel = config.ViewportData.Width / config.OutputWidth;
            float verticalUnitsPerPixel = config.ViewportData.Height / config.OutputHeight;

            // Keep track of all the tasks we start (one for each ray emitted by camera
            Task[] tasks = new Task[config.OutputWidth * config.OutputHeight];

            // Keep track of the final color of each pixel.  Bitmap doesnt allow concurrent access
            Vector4[,] colors = new Vector4[config.OutputWidth, config.OutputHeight];

            // Start casting the rays and tracing
            for (int h = 0; h < config.OutputHeight; h++)
            {
                for (int w = 0; w < config.OutputWidth; w++)
                {
                    // Store current loop state to pass to the task
                    TaskData d = new TaskData();
                    d.x = w;
                    d.y = h;

                    tasks[h * config.OutputWidth + w] = Task.Factory.StartNew((td) =>
                    {
                        TaskData data = (TaskData)td;

                        // Get the position of the ray target in the viewport 
                        Vector3 viewportPos =
                            right * data.x * horizontalUnitsPerPixel + viewportLeftWorldSpace
                            - up * data.y * verticalUnitsPerPixel + viewportTopWorldSpace;

                        // Calculate the viewport position using the view matrix
                        viewportPos = view * viewportPos;

                        // Calculate the direction of the ray
                        Vector3 direction = viewportPos - cameraPosition;

                        // Create the ray
                        Ray r = new Ray(cameraPosition, direction);

                        // Cast the ray into the scene and store the resultant color
                        colors[data.x, data.y] = CastRay(r);

                    }, (object)d);
                }
            }

            Task.WaitAll(tasks);

            for (int x = 0; x < config.OutputWidth; x++)
            {
                for (int y = 0; y < config.OutputHeight; y++)
                {
                    ScaleColor(ref colors[x, y]);
                    colors[x, y] *= 255;
                    output.SetPixel(x, y,
                        Color.FromArgb(
                            (int)colors[x, y].W,
                            (int)colors[x, y].X,
                            (int)colors[x, y].Y,
                            (int)colors[x, y].Z));
                }
            }

            // Do anti-aliasing and other post processing effects here

            return output;
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Determines if a point has direct line of sight to a light, or if it is shadowed by another object
        /// </summary>
        /// <param name="pos">The position being checked</param>
        /// <param name="light">The light source</param>
        /// <returns>Whether or not the point is lit by the light or in a shadow</returns>
        private bool InShadow(Vector3 pos, Light light)
        {
            // Get a vector from pos to light with some variation
            Vector3 lightVec = light.Location
                + new Vector3(
                    (float)rand.NextDouble() * 2.0f * light.Radius - light.Radius,
                    (float)rand.NextDouble() * 2.0f * light.Radius - light.Radius,
                    (float)rand.NextDouble() * 2.0f * light.Radius - light.Radius)
                - pos;

            float lightDist = lightVec.Magnitude;

            Ray shadowRay = new Ray(pos, lightVec);

            float time = -1;

            // Iterate over all the triangles in the scene to see if they block the light
            foreach(var t in scene.Triangles)
            {
                if(shadowRay.CollidesWith(t, ref time))
                {
                    if(time < lightDist && time > ProximityTolerance)
                    {
                        return true;
                    }
                }
            }

            return false;
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Casts a ray and gets the resultant color
        /// </summary>
        /// <param name="r">The ray to cast</param>
        /// <param name="depth">The current depth of the ray into the scene</param>
        /// <param name="sourceTriangle">The source of the ray if it was reflected/refracted</param>
        /// <returns>The resultant color of the ray</returns>
        public Vector4 CastRay(Ray r, int depth = 0, Triangle sourceTriangle = null)
        {
            float closestTime = float.MaxValue;
            Triangle closestTriangle = null;
            Vector3 closestPosition = Vector3.Zero;
            Vector4 returnColor = Vector4.Zero;

            foreach (var t in scene.Triangles)
            {
                float time = float.MaxValue;

                if (r.CollidesWith(t, ref time))
                {
                    if (time < closestTime && time > ProximityTolerance)
                    {
                        closestTime = time;
                        closestTriangle = t;
                        closestPosition = r.PointAtDistance(time);
                    }
                }
            }

            // If we can still cast rays deeper and we collided with an object, then cast more rays
            if (depth < config.MaxRayDepth && closestTriangle != null)
            {
                // TODO: Cast reflection rays

                // TODO: Cast refraction rays

                // TODO: Add the color combinations from reflection and refraction
                returnColor = GetColor(closestTriangle, closestPosition);
            }
            else if (closestTriangle != null)
            {
                returnColor = GetColor(closestTriangle, closestPosition);
            }

            return returnColor;
        }