Ejemplo n.º 1
0
        /// <summary>
        /// Renders the scene into a pixel buffer.
        /// </summary>
        public void Render(PixelBuffer pixbuf)
        {
            float dx = 1.0f / pixbuf.Width, dy = 1.0f / pixbuf.Height;
            camera.AspectRatio = (float)pixbuf.Width / pixbuf.Height;

            // Free parallelism, why not! Note a Parallel.For loop
            // over each row is slightly faster but less readable.
            Parallel.ForEach(pixbuf, (pixel) =>
            {
                var color = Vector.Zero;
                float u = pixel.X * dx;
                float v = pixel.Y * dy;

                var rays = new[]
                {
                    camera.Trace(2 * (u - 0.25f * dx) - 1, 2 * (v - 0.25f * dy) - 1),
                    camera.Trace(2 * (u + 0.25f * dx) - 1, 2 * (v - 0.25f * dy) - 1),
                    camera.Trace(2 * (u - 0.25f * dx) - 1, 2 * (v + 0.25f * dy) - 1),
                    camera.Trace(2 * (u + 0.25f * dx) - 1, 2 * (v + 0.25f * dy) - 1),
                };

                // Trace a packet of 4 coherent AA rays
                var packet = scene.Intersects4(rays);

                // Convert the packet to a set of usable ray-geometry intersections
                Intersection<Model>[] hits = packet.ToIntersection<Model>(scene);

                for (int t = 0; t < 4; ++t)
                {
                    if (hits[t].HasHit)
                    {
                        color += new Vector(0.1f, 0.1f, 0.1f);

						var ray = rays[t];
                        var model = hits[t].Instance;

                        // Parse the surface normal returned and then process it manually
                        var rawNormal = new Vector(hits[t].NX, hits[t].NY, hits[t].NZ);
                        var normal = model.CorrectNormal(rawNormal); // Important!

                        // Calculate the new ray towards the light source
                        var hitPoint = ray.PointAt(hits[t].Distance);
                        var toLight = lightPosition - hitPoint; // from A to B = B - A
                        var lightRay = new Ray(hitPoint + normal * Constants.Epsilon, toLight);

                        // Is the light source occluded? If so, no point calculating any lighting
                        if (!scene.Occludes(lightRay, 0, toLight.Length()))
                        {
                            // Compute the Lambertian cosine term (rendering equation)
                            float cosLight = Vector.Dot(normal, toLight.Normalize());

                            // Calculate the total light attenuation (inverse square law + cosine law)
                            var attenuation = lightIntensity * cosLight / Vector.Dot(toLight, toLight);

                            color += model.Material(hits[t].Mesh).BRDF(toLight.Normalize(), ray.Direction, normal) * attenuation;
                        }
                    }
                }

                // Average the 4 per-pixel samples
                pixbuf.SetColor(pixel, color / 4);
            });
        }
Ejemplo n.º 2
0
 /// <summary>
 /// Returns the point at a given distance along the ray.
 /// </summary>
 public static Point PointAt(Ray ray, float distance)
 {
     return ray.Origin + ray.Direction * distance;
 }
Ejemplo n.º 3
0
        /// <summary>
        /// Transforms a ray by a given matrix.
        /// </summary>
        public static Ray Transform(Ray ray, Matrix transform)
        {
            Point p1 = transform.Transform(ray.Origin);
            Point p2 = transform.Transform(ray.Origin + ray.Direction);

            return new Ray(p1, p2 - p1);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Renders the scene into a pixel buffer.
        /// </summary>
        public void Render(PixelBuffer pixbuf)
        {
            float dx = 1.0f / pixbuf.Width, dy = 1.0f / pixbuf.Height;

            camera.AspectRatio = (float)pixbuf.Width / pixbuf.Height;

            // Free parallelism, why not! Note a Parallel.For loop
            // over each row is slightly faster but less readable.
            Parallel.ForEach(pixbuf, (pixel) =>
            {
                var color = Vector.Zero;
                float u   = pixel.X * dx;
                float v   = pixel.Y * dy;

                var rays = new[]
                {
                    camera.Trace(2 * (u - 0.25f * dx) - 1, 2 * (v - 0.25f * dy) - 1),
                    camera.Trace(2 * (u + 0.25f * dx) - 1, 2 * (v - 0.25f * dy) - 1),
                    camera.Trace(2 * (u - 0.25f * dx) - 1, 2 * (v + 0.25f * dy) - 1),
                    camera.Trace(2 * (u + 0.25f * dx) - 1, 2 * (v + 0.25f * dy) - 1),
                };

                // Trace a packet of 4 coherent AA rays
                var packet = scene.Intersects4(rays);

                // Convert the packet to a set of usable ray-geometry intersections
                Intersection <Model>[] hits = packet.ToIntersection <Model>(scene);

                for (int t = 0; t < 4; ++t)
                {
                    if (hits[t].HasHit)
                    {
                        color += new Vector(0.1f, 0.1f, 0.1f);

                        var ray   = rays[t];
                        var model = hits[t].Instance;

                        // Parse the surface normal returned and then process it manually
                        var rawNormal = new Vector(hits[t].NX, hits[t].NY, hits[t].NZ);
                        var normal    = model.CorrectNormal(rawNormal); // Important!

                        // Calculate the new ray towards the light source
                        var hitPoint = ray.PointAt(hits[t].Distance);
                        var toLight  = lightPosition - hitPoint; // from A to B = B - A
                        var lightRay = new Ray(hitPoint + normal * Constants.Epsilon, toLight);

                        // Is the light source occluded? If so, no point calculating any lighting
                        if (!scene.Occludes(lightRay, 0, toLight.Length()))
                        {
                            // Compute the Lambertian cosine term (rendering equation)
                            float cosLight = Vector.Dot(normal, toLight.Normalize());

                            // Calculate the total light attenuation (inverse square law + cosine law)
                            var attenuation = lightIntensity * cosLight / Vector.Dot(toLight, toLight);

                            color += model.Material(hits[t].Mesh).BRDF(toLight.Normalize(), ray.Direction, normal) * attenuation;
                        }
                    }
                }

                // Average the 4 per-pixel samples
                pixbuf.SetColor(pixel, color / 4);
            });
        }