Example #1
0
        public void GivenExpectedAnswer_VerifyColor(float r, float g, float b)
        {
            var expectedAnswer = Color.FromScRgb(Material.DefaultColorA, r, g, b);

            var hit          = _world.CalculateHit(_rayInstance);
            var actualAnswer = Lighting.CalculateColorWithPhongReflection(hit, _world.LightSource);

            // Note: Addition of "shadow rendering" required a reduction of Color precision
            // for these tests. These tests effected by use of IntersectionDto.OverPosition,
            // which itself required a reduction in precision to eliminate "acne".
            //   That all said, still looks great to the naked eye!
            Assert.True(expectedAnswer.AreClose(actualAnswer, true, 4));
        }
Example #2
0
        public void GivenExpectedAnswer_CalculateT1Shadowed_VerifyResult(string in_shadow)
        {
            // For Ray from point (_t1), back to the light source:
            //  * Any collisions?
            //  * If so, is hit between the point position and the light? i.e. casts _t1 in shadow
            var v              = _world.LightSource.Position - _t1;
            var direction      = Vector4.Normalize(v);
            var lightingResult = Lighting.CalculateColorWithPhongReflection(
                _world, new Model.Ray(_t1, direction));

            var expectedAnswer = bool.Parse(in_shadow);
            var actualAnswer   = lightingResult.IsInShadow;

            Assert.Equal(expectedAnswer, actualAnswer);
        }
Example #3
0
        public static void DrawDefaultWorldLarger(string outputBitmapFilePath = null, System.Drawing.Bitmap canvas = null)
        {
            var world  = CreateDefaultWorldLarger();
            var camera = new Camera(110, 110, MathF.PI / 2);

            // Pull back out a bit more to allow for larger sphere size.
            // Result kind of cool when you don't - you're seeing the inner circle,
            // with the silhouette of the outer circle.
            var from = new Vector4(0F, 0F, -10F, 1F);
            var to   = new Vector4(0F, 0F, 0F, 1F);
            var up   = new Vector4(0F, 1F, 0F, 0F);

            camera.SetViewTransformation(from, to, up);

            bool shouldDispose = canvas == null;

            if (canvas == null)
            {
                canvas = new System.Drawing.Bitmap(camera.HorizontalSize, camera.VerticalSize);
            }

            for (int y = 0; y < camera.VerticalSize - 1; y++)
            {
                for (int x = 0; x < camera.HorizontalSize - 1; x++)
                {
                    var   ray   = camera.GetRay(x, y);
                    Color color = Lighting.CalculateColorWithPhongReflection(world, ray);

                    canvas.SetPixel(x, y, color.Simplify(255));
                }
            }

            if (outputBitmapFilePath != null)
            {
                canvas.Save(outputBitmapFilePath);
            }

            if (shouldDispose)
            {
                canvas.Dispose();
            }
        }
Example #4
0
        protected override Task Handle(RenderSceneCommand request, CancellationToken cancellationToken)
        {
            var shapes = new List <IBasicShape>();

            shapes.AddRange(request.Scene.Shapes.Select(ShapeFactory.MapApiToDomain));

            var world = new World(shapes, LightFactory.MapApiToDomain(request.Scene.LightSource));

            var camera = CameraFactory.MapApiToDomain(request.Scene.Camera);

            // Render image

            using var canvas = new System.Drawing.Bitmap(camera.HorizontalSize, camera.VerticalSize);

            for (int y = 0; y < camera.VerticalSize - 1; y++)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    break;
                }
                for (int x = 0; x < camera.HorizontalSize - 1; x++)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        break;
                    }
                    var   ray   = camera.GetRay(x, y);
                    Color color = Lighting.CalculateColorWithPhongReflection(world, ray);

                    canvas.SetPixel(x, y, color.Simplify(255));
                }
            }

            if (!cancellationToken.IsCancellationRequested)
            {
                canvas.Save(request.FilePath);
            }

            return(cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask);
        }
Example #5
0
        public static void DrawDefaultWorld(string outputBitmapFilePath = null, System.Drawing.Bitmap canvas = null)
        {
            var world  = CreateDefaultWorld();
            var camera = new Camera(11, 11, MathF.PI / 2);

            var from = new Vector4(0F, 0F, -5F, 1F);
            var to   = new Vector4(0F, 0F, 0F, 1F);
            var up   = new Vector4(0F, 1F, 0F, 0F);

            camera.SetViewTransformation(from, to, up);

            bool shouldDispose = canvas == null;

            if (canvas == null)
            {
                canvas = new System.Drawing.Bitmap(camera.HorizontalSize, camera.VerticalSize);
            }

            for (int y = 0; y < camera.VerticalSize - 1; y++)
            {
                for (int x = 0; x < camera.HorizontalSize - 1; x++)
                {
                    var   ray   = camera.GetRay(x, y);
                    Color color = Lighting.CalculateColorWithPhongReflection(world, ray);

                    canvas.SetPixel(x, y, color.Simplify(255));
                }
            }

            if (outputBitmapFilePath != null)
            {
                canvas.Save(outputBitmapFilePath);
            }

            if (shouldDispose)
            {
                canvas.Dispose();
            }
        }
Example #6
0
 public void Calculate_Lighting_SetOnResultColor()
 {
     _resultantColor = Lighting.CalculateColorWithPhongReflection(
         _materialInstance, _lightInstance, _pointPosition, _eye, _surfaceNormal, _isInShadow
         );
 }
Example #7
0
        public static void RenderSphereCentral(string outputBitmapFilePath, bool useAcneEffect = false)
        {
            // Define world

            var floor = Sphere.CreateDefaultInstance();

            floor.Transformation = new MatrixTransformationBuilder()
                                   .Scale(new Vector3(10F, 0.01F, 10F));
            floor.UpdateColor(Color.FromScRgb(Material.DefaultColorA, 1F, 0.9F, 0.9F))
            .UpdateSpecular(0F);

            var left_wall = Sphere.CreateDefaultInstance();

            left_wall.Transformation = new MatrixTransformationBuilder()
                                       .Scale(new Vector3(10F, 0.01F, 10F))
                                       .RotateX(MathF.PI / 2)
                                       .RotateY(-MathF.PI / 4)
                                       .Translate(new Vector3(0F, 0F, 5F))
            ;
            left_wall.Material = floor.Material;

            var right_wall = Sphere.CreateDefaultInstance();

            right_wall.Transformation = new MatrixTransformationBuilder()
                                        .Scale(new Vector3(10F, 0.01F, 10F))
                                        .RotateX(MathF.PI / 2)
                                        .RotateY(MathF.PI / 4)
                                        .Translate(new Vector3(0F, 0F, 5F))
            ;
            right_wall.Material = floor.Material;

            var middle = Sphere.CreateDefaultInstance();

            middle.Transformation = new MatrixTransformationBuilder()
                                    .Translate(new Vector3(-0.5F, 1F, 0.5F));
            middle.UpdateColor(Color.FromScRgb(Material.DefaultColorA, 0.1F, 1F, 0.5F))
            .UpdateDiffuse(0.7F)
            .UpdateSpecular(0.3F);

            var right = Sphere.CreateDefaultInstance();

            right.Transformation = new MatrixTransformationBuilder()
                                   .Scale(new Vector3(0.5F, 0.5F, 0.5F))
                                   .Translate(new Vector3(1.5F, 0.5F, -0.5F))
            ;
            right.UpdateColor(Color.FromScRgb(Material.DefaultColorA, 0.5F, 1F, 0.1F))
            .UpdateDiffuse(0.7F)
            .UpdateSpecular(0.3F);

            var left = Sphere.CreateDefaultInstance();

            left.Transformation = new MatrixTransformationBuilder()
                                  .Scale(new Vector3(0.33F, 0.33F, 0.33F))
                                  .Translate(new Vector3(-1.5F, 0.33F, -0.75F))
            ;
            left.UpdateColor(Color.FromScRgb(Material.DefaultColorA, 1F, 0.8F, 0.1F))
            .UpdateDiffuse(0.7F)
            .UpdateSpecular(0.3F);

            var world = new World(new List <IBasicShape>
            {
                floor, left_wall, right_wall,
                left, middle, right
            },
                                  new Light
            {
                Position  = new Vector4(-10.0F, 10.0F, -10.0F, 1.0F),
                Intensity = Color.White
            });

            // Use low res until happy, then crank up. Takes a lot of clock cycles!
#pragma warning disable CS0219 // Variable is assigned but its value is never used
            int high   = 1000;
            int medium = 500;
            int low    = 250;
            int res    = medium;
#pragma warning restore CS0219 // Variable is assigned but its value is never used

            var camera = new Camera(res, res / 2, MathF.PI / 3);
            camera.SetViewTransformation(
                from: new Vector4(0F, 1.5F, -5F, 1F),
                to: new Vector4(0F, 1F, 0F, 1F),
                up: new Vector4(0F, 1F, 0F, 0F)
                );


            // Render image

            using var canvas = new System.Drawing.Bitmap(camera.HorizontalSize, camera.VerticalSize);

            for (int y = 0; y < camera.VerticalSize - 1; y++)
            {
                for (int x = 0; x < camera.HorizontalSize - 1; x++)
                {
                    var   ray   = camera.GetRay(x, y);
                    Color color = Lighting.CalculateColorWithPhongReflection(world, ray, useAcneEffect);

                    canvas.SetPixel(x, y, color.Simplify(255));
                }
            }

            canvas.Save(outputBitmapFilePath);
        }
Example #8
0
        // NOTE: Using the 2D version as starting place. Couple of additions should turn it into a glorious 3D render!

        public static void DrawSphere(string outputBitmapFilePath, IMatrixTransformationBuilder transformation)
        {
            // Rough and ready. Fully following the pseudocode from the text.
            // Basically:
            //   For each pixel on the canvas, figure out the ray (direction) from there
            //   back to the origin of the emitting ray (light source).
            //   Then calculate the hit (first intersection), if any. If it's a hit then
            //   that pixel on the canvas gets drawn.
            //   The rest of the code is just pixel conversion e.g. determining what "1"
            //   represents in terms of numbers of pixels and also converting the half above /
            //   half below of the sphere to a non-negative set of pixels for drawing.

            // inputs: could encapsulate in class to cleanup the code.
            var ray_origin = new Vector4(0F, 0F, -5F, 1F);
            var wall_z     = 10F;
            var wall_size  = 7.0F;

            var sphere = Sphere.CreateDefaultInstance();

            sphere.UpdateColor(Color.FromScRgb(Material.DefaultColorA, 1.0F, 0.2F, 1.0F));
            IBasicShape shape = sphere;

            shape.Transformation = transformation;

            var light = new Light
            {
                Position  = new Vector3(-10F, 10F, -10F).AsPoint(),
                Intensity = Color.FromScRgb(Material.DefaultColorA, 1.0F, 1.0F, 1.0F)
            };

#pragma warning disable CS0618 // Type or member is obsolete
            var xs = new SceneIntersectionCalculator(new List <IBasicShape> {
                shape
            });
#pragma warning restore CS0618 // Type or member is obsolete
            var canvas_pixels = 100;
            var pixel_size    = wall_size / canvas_pixels;
            var half          = wall_size / 2;


            using var canvas = new System.Drawing.Bitmap(canvas_pixels, canvas_pixels);

            for (int y = 0; y < canvas_pixels; y++)
            {
                var world_y = half - pixel_size * y;

                for (int x = 0; x < canvas_pixels; x++)
                {
                    var world_x = -half + pixel_size * x;

                    var position = new Vector4(world_x, world_y, wall_z, 1F);

                    var r = new Domain.Model.Ray(
                        ray_origin,
                        Vector4.Normalize(position - ray_origin));

                    var hit = xs.CalculateHit(r);
                    if (hit.HasValue)
                    {
                        var color = Lighting.CalculateColorWithPhongReflection(hit, light);

                        // keep the alpha value static, otherwise you get strange results!
                        canvas.SetPixel(x, y, color.Simplify(255));
                    }
                }
            }


            canvas.Save(outputBitmapFilePath);
        }