public static IBasicShape MapApiToDomain(ShapeDto input) { IBasicShape output = null; switch (input.Type) { case ShapeDto.ShapeType.Sphere: // TODO: worth normalizing Shape instantiation e.g. new() output = Sphere.CreateDefaultInstance(); break; case ShapeDto.ShapeType.Plane: output = new Plane(); break; default: throw new ArgumentOutOfRangeException(nameof(input.Type), "Unrecognized shape type: " + input.Type); } if (input.Material != null) { output.Material = MaterialFactory.MapApiToDomain(input.Material); } if (input.Transformations != null && input.Transformations.Any()) { foreach (var transform in input.Transformations) { var domainTransformAction = TransformationFactory.MapApiTransformToDomainAction(transform); domainTransformAction(output.Transformation); } } return(output); }
private void InitializationValues_SetupDefaultWorld_Overload(float?fixedAmbient = null) { _outerSphere = Sphere.CreateDefaultInstance(); _innerSphere = Sphere.CreateDefaultInstance(); _outerSphere .UpdateColor(Color.FromScRgb(Material.DefaultColorA, 0.8F, 1.0F, 0.6F)) .UpdateDiffuse(0.7F) .UpdateSpecular(0.2F) .UpdateAmbient(fixedAmbient ?? _outerSphere.Material.Ambient); _innerSphere .UpdateAmbient(fixedAmbient ?? _innerSphere.Material.Ambient); // As feature file: concentric circles with inner sphere scaled down. _innerSphere.Transformation = new MatrixTransformationBuilder() .Scale(new Vector3(0.5F, 0.5F, 0.5F)); _world = new World( new List <IBasicShape> { _outerSphere, _innerSphere }, new Model.Light { Position = new Vector4(-10.0F, 10.0F, -10.0F, 1.0F), Intensity = Color.White } ); }
private static World CreateDefaultWorldLarger() { var outerSphere = Sphere.CreateDefaultInstance(); var innerSphere = Sphere.CreateDefaultInstance(); outerSphere .UpdateColor(Color.FromScRgb(Material.DefaultColorA, 0.8F, 1.0F, 0.6F)) .UpdateDiffuse(0.7F) .UpdateSpecular(0.2F); // As feature file: concentric circles with inner sphere scaled down. innerSphere.Transformation = new MatrixTransformationBuilder() .Scale(new Vector3(10.0F, 10.0F, 10.0F)); innerSphere.Transformation = new MatrixTransformationBuilder() .Scale(new Vector3(5.0F, 5.0F, 5.0F)); return(new World( new List <IBasicShape> { outerSphere, innerSphere }, new Domain.Model.Light { Position = new Vector4(-30.0F, 30.0F, -30.0F, 1.0F), Intensity = Color.White } )); }
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; IBasicShape shape = Sphere.CreateDefaultInstance(); shape.Transformation = transformation; #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; var color = Color.FromScRgb(1.0F, 0.0F, 0.0F, 1.0F).Simplify(); 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)); if (xs.CalculateHit(r).HasValue) { canvas.SetPixel(x, y, color); } } } canvas.Save(outputBitmapFilePath); }
public static SceneDto GetSphereCentralWithPlanesExample() { // Templates var defaultSphere = Sphere.CreateDefaultInstance(); var defaultMaterial = Material.CreateDefaultInstance(); var white = Color.White; // Copying ReRenderSphereCentralWithPlanes code using serializable DTOs. // Planes var floor = new ShapeDto { Type = ShapeDto.ShapeType.Plane, Material = new MaterialDto { Color = new ColorDto { A = Material.DefaultColorA, R = 1F, G = 0.9F, B = 0.9F }, Specular = 0F, Ambient = defaultMaterial.Ambient, Diffuse = defaultMaterial.Diffuse, Shininess = defaultMaterial.Shininess } }; var left_wall = new ShapeDto { Type = ShapeDto.ShapeType.Plane, Material = floor.Material, Transformations = new List <TransformDto> { new TransformDto { TransformType = TransformDto.TransformationType.RotateX, RotationRadians = MathF.PI / 2 }, new TransformDto { TransformType = TransformDto.TransformationType.RotateY, RotationRadians = -MathF.PI / 4 }, new TransformDto { TransformType = TransformDto.TransformationType.Translate, VectorTransformation = new VectorDto { X = 0F, Y = 0F, Z = 5F } } } }; var right_wall = new ShapeDto { Type = ShapeDto.ShapeType.Plane, Material = floor.Material, Transformations = new List <TransformDto> { new TransformDto { TransformType = TransformDto.TransformationType.RotateX, RotationRadians = MathF.PI / 2 }, new TransformDto { TransformType = TransformDto.TransformationType.RotateY, RotationRadians = MathF.PI / 4 }, new TransformDto { TransformType = TransformDto.TransformationType.Translate, VectorTransformation = new VectorDto { X = 0F, Y = 0F, Z = 5F } } } }; // Spheres var middle = new ShapeDto { Type = ShapeDto.ShapeType.Sphere, Material = new MaterialDto { Color = new ColorDto { A = Material.DefaultColorA, R = 0.1F, G = 1F, B = 0.5F }, Diffuse = 0.7F, Specular = 0.3F, Ambient = defaultMaterial.Ambient, Shininess = defaultMaterial.Shininess }, Transformations = new List <TransformDto> { new TransformDto { TransformType = TransformDto.TransformationType.Translate, VectorTransformation = new VectorDto { X = -0.5F, Y = 1F, Z = 0.5F } } } }; var right = new ShapeDto { Type = ShapeDto.ShapeType.Sphere, Material = new MaterialDto { Color = new ColorDto { A = Material.DefaultColorA, R = 0.5F, G = 1F, B = 0.1F }, Diffuse = 0.7F, Specular = 0.3F, Ambient = defaultMaterial.Ambient, Shininess = defaultMaterial.Shininess }, Transformations = new List <TransformDto> { new TransformDto { TransformType = TransformDto.TransformationType.Scale, VectorTransformation = new VectorDto { X = 0.5F, Y = 0.5F, Z = 0.5F } }, new TransformDto { TransformType = TransformDto.TransformationType.Translate, VectorTransformation = new VectorDto { X = 1.5F, Y = 0.5F, Z = -0.5F } } } }; var left = new ShapeDto { Type = ShapeDto.ShapeType.Sphere, Material = new MaterialDto { Color = new ColorDto { A = Material.DefaultColorA, R = 1F, G = 0.8F, B = 0.1F }, Diffuse = 0.7F, Specular = 0.3F, Ambient = defaultMaterial.Ambient, Shininess = defaultMaterial.Shininess }, Transformations = new List <TransformDto> { new TransformDto { TransformType = TransformDto.TransformationType.Scale, VectorTransformation = new VectorDto { X = 0.33F, Y = 0.33F, Z = 0.33F } }, new TransformDto { TransformType = TransformDto.TransformationType.Translate, VectorTransformation = new VectorDto { X = -1.5F, Y = 0.33F, Z = -0.75F } } } }; // Scene - pull together shapes into root serializable object // 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 scene = new SceneDto { Shapes = new List <ShapeDto> { floor, left_wall, right_wall, left, middle, right }, LightSource = new LightDto { Position = new VectorDto { X = -10F, Y = 10F, Z = -10F }, Intensity = new ColorDto { A = white.ScA, R = white.ScR, G = white.ScG, B = white.ScB } }, Camera = new CameraDto { HSize = res, VSize = res / 2, FieldOfView = MathF.PI / 3, From = new VectorDto { X = 0F, Y = 1.5F, Z = -5F }, To = new VectorDto { X = 0F, Y = 1F, Z = 0F }, Up = new VectorDto { X = 0F, Y = 1F, Z = 0F } } }; return(scene); }
public void InitializationValues_SetOnSphereInstance() { _sphereInstance = Sphere.CreateDefaultInstance(false); }
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); }