public void Writing_pixels_to_a_canvas() { var canvas = new MutableCanvas(10, 20); canvas.SetPixel(2, 3, Colors.Red); canvas.GetPixel(2, 3).Should().Be(Colors.Red); }
//// =========================================================================================================== //// Methods //// =========================================================================================================== protected override Canvas Render(CameraRenderOptions options) { var start = new Point(0, 1, 0); var velocity = new Vector(1, 1.8, 0).Normalize() * 11.25; var cannonball = new Projectile(start, velocity); // gravity is -0.1 unit/tick and wind is -0.01 unit/tick var gravity = new Vector(0, -0.1, 0); var wind = new Vector(-0.01, 0, 0); var environment = new Environment(gravity, wind); var color = Colors.Magenta; const int pixelBorderSize = 2; var canvas = new MutableCanvas(CanvasWidth, CanvasHeight); while (cannonball.Position.Y > 0) { cannonball = Tick(environment, cannonball); int pointX = (int)Math.Round(cannonball.Position.X); int pointY = (int)Math.Round(canvas.Height - cannonball.Position.Y); canvas.FillRect( top: pointY - pixelBorderSize, left: pointX - pixelBorderSize, bottom: pointY + pixelBorderSize, right: pointX + pixelBorderSize, color); } return(canvas.ToImmutable()); }
protected override Canvas Render(CameraRenderOptions options) { var canvas = new MutableCanvas(CanvasWidth, CanvasHeight); int centerX = canvas.Width / 2; int centerY = canvas.Height / 2; double clockRadius = Math.Min(canvas.Width * (3d / 8), canvas.Height * (3d / 8)); var color = Colors.Cyan; const int pixelBorderSize = 4; // The clock is oriented along the y axis, which means when looking at it face-on you're looking // towards the negative y axis and the clock face sits on the x-z plane. var twelve = new Point(0, 0, 1); const double rotationAngle = (2 * Math.PI) / 12; for (int hour = 0; hour < 12; hour++) { // Rotate the twelve point around the y axis. // Scale by the clock radius. // Translate to the center of the canvas. var transform = Matrix4x4.CreateRotationY(hour * rotationAngle); Point hourPoint = transform * twelve; int x = centerX + (int)Math.Round(hourPoint.X * clockRadius); int y = centerY - (int)Math.Round(hourPoint.Z * clockRadius); canvas.FillRect( top: y - pixelBorderSize, left: x - pixelBorderSize, bottom: y + pixelBorderSize, right: x + pixelBorderSize, color); } return(canvas.ToImmutable()); }
protected override Canvas Render(CameraRenderOptions options) { var canvas = new MutableCanvas(CanvasWidth, CanvasHeight); var sphere = new Sphere(); var rayOrigin = new Point(0, 0, -5); const double wallZ = 10; const double wallSize = 7.0; double pixelSize = wallSize / canvas.Width; const double halfWallSize = wallSize / 2; double totalPixels = canvas.Width * canvas.Height; // For each row of pixels in the canvas... for (int y = 0; y < canvas.Height; y++) { // Compute the world y coordinate (top = +half, bottom = -half). double worldY = halfWallSize - (pixelSize * y); // For each pixel in the row... for (int x = 0; x < canvas.Width; x++) { // See if we should stop. if (options.CancellationToken.IsCancellationRequested) { return(canvas.ToImmutable()); } // Compute the world x coordinate (left = -half, right = +half). double worldX = -halfWallSize + (pixelSize * x); // Describe the point on the wall that the ray will target. var position = new Point(worldX, worldY, wallZ); // Cast the ray into the scene to see what it hits. var ray = new Ray(rayOrigin, (position - rayOrigin).Normalize()); var intersections = sphere.Intersect(ray); if (intersections.Hit != null) { canvas.SetPixel(x, y, Colors.Red); } } // Report the progress. double pixelsRendered = (y * CanvasWidth) + CanvasWidth; int percentComplete = (int)Math.Round((pixelsRendered / totalPixels) * 100.0); options.Progress?.Report(new RenderProgressStep(percentComplete, y, canvas.GetRow(y))); } return(canvas.ToImmutable()); }
public void Creating_a_canvas() { var canvas = new MutableCanvas(10, 20); canvas.Width.Should().Be(10); canvas.Height.Should().Be(20); for (int y = 0; y < 20; y++) { for (int x = 0; x < 10; x++) { canvas.GetPixel(x, y).Should().Be(Colors.Black); } } }
protected override Canvas Render(CameraRenderOptions options) { var canvas = new MutableCanvas(CanvasWidth, CanvasHeight); var sphere = new Sphere(material: new Material(new Color(1, 0.2, 1))); var lightPosition = new Point(-10, 10, -10); var lightColor = Colors.White; var light = new PointLight(lightPosition, lightColor); var rayOrigin = new Point(0, 0, -5); const int wallZ = 10; const double wallSize = 7.0; double pixelSize = wallSize / canvas.Width; const double halfWallSize = wallSize / 2; double totalPixels = canvas.Width * canvas.Height; // For each row of pixels in the canvas... for (int y = 0; y < canvas.Height; y++) { // Compute the world y coordinate (top = +half, bottom = -half). double worldY = halfWallSize - (pixelSize * y); // For each pixel in the row... for (int x = 0; x < canvas.Width; x++) { // See if we should stop. if (options.CancellationToken.IsCancellationRequested) { return(canvas.ToImmutable()); } // Compute the world x coordinate (left = -half, right = +half). double worldX = -halfWallSize + (pixelSize * x); // Describe the point on the wall that the ray will target. var position = new Point(worldX, worldY, wallZ); // Cast the ray into the scene to see what it hits. var ray = new Ray(rayOrigin, (position - rayOrigin).Normalize()); IntersectionList intersections = sphere.Intersect(ray); Intersection? hit = intersections.Hit; if (hit != null) { Point point = ray.PositionAt(hit.T); Vector normal = hit.Shape.NormalAt(point); Vector eye = ray.Direction.Negate(); Color color = hit.Shape.Material.CalculateLighting(hit.Shape, light, point, eye, normal, false); canvas.SetPixel(x, y, color); } } // Report the progress. double pixelsRendered = (y * CanvasWidth) + CanvasWidth; int percentComplete = (int)Math.Round((pixelsRendered / totalPixels) * 100.0); options.Progress?.Report(new RenderProgressStep(percentComplete, y, canvas.GetRow(y))); } return(canvas.ToImmutable()); }