public void A_ray_misses_a_CSG_object() { var csg = new CsgShape(CsgOperation.Union, new Sphere(), new Cube()); var ray = new Ray(new Point(0, 2, -5), new Vector(0, 0, 1)); var intersections = csg.LocalIntersect(ray); intersections.Should().BeEmpty(); }
public void A_ray_hits_a_CSG_object() { var left = new Sphere(); var right = new Sphere(transform: Matrix4x4.CreateTranslation(0, 0, 0.5)); var csg = new CsgShape(CsgOperation.Union, left, right); var ray = new Ray(new Point(0, 0, -5), new Vector(0, 0, 1)); var intersections = csg.LocalIntersect(ray); intersections.Should().HaveCount(2); intersections.Ts.Should().ContainInOrder(4, 6.5); intersections.Shapes.Should().ContainInOrder(left, right); }
public void A_CSG_shape_is_composed_of_an_operation_and_two_operand_shapes() { var sphere = new Sphere(); var cube = new Cube(); var csg = new CsgShape(CsgOperation.Union, sphere, cube); csg.Operation.Should().Be(CsgOperation.Union); csg.Left.Should().Be(sphere); csg.Right.Should().Be(cube); sphere.Parent.Should().Be(csg); cube.Parent.Should().Be(csg); }
public void A_CSG_difference_preserves_all_intersections_not_exclusively_inside_the_object_on_the_right( bool isLeftHit, bool isWithinLeft, bool isWithinRight, bool expectedResult) { CsgShape.IsIntersectionAllowed( CsgOperation.Difference, isLeftHit, isWithinLeft, isWithinRight) .Should() .Be(expectedResult); }
public void A_CSG_intersect_preserves_all_intersections_where_both_shapes_overlap( bool isLeftHit, bool isWithinLeft, bool isWithinRight, bool expectedResult) { CsgShape.IsIntersectionAllowed( CsgOperation.Intersection, isLeftHit, isWithinLeft, isWithinRight) .Should() .Be(expectedResult); }
public void A_CSG_union_preserves_all_intersections_on_the_exterior_of_both_shapes( bool isLeftHit, bool isWithinLeft, bool isWithinRight, bool expectedResult) { CsgShape.IsIntersectionAllowed( CsgOperation.Union, isLeftHit, isWithinLeft, isWithinRight) .Should() .Be(expectedResult); }
Given_a_set_of_intersections_produce_a_subset_of_only_those_intersections_that_conform_to_the_operation_of_the_current_CSG_object( CsgOperation operation, int intersectionIndex1, int intersectionIndex2) { var left = new Sphere(); var right = new Cube(); var csg = new CsgShape(operation, left, right); var intersections = new IntersectionList((1, left), (2, right), (3, left), (4, right)); var filtered = csg.FilterIntersections(intersections); filtered.Should() .HaveCount(2) .And.ContainInOrder(intersections[intersectionIndex1], intersections[intersectionIndex2]); }
protected override Canvas Render(CameraRenderOptions options) { // Shapes var floorCeiling = new Cube( "FloorCeiling", Matrix4x4.CreateTranslation(0, 1, 0).Scale(20, 7, 20), new Material( pattern: new CheckerPattern( Colors.Black, Colors.DarkGray, Matrix4x4.CreateScaling(0.07, 0.07, 0.07)), ambient: 0.25, diffuse: 0.7, specular: 0.9, shininess: 300, reflective: 0.1)); var walls = new Cube( "Walls", Matrix4x4.CreateScaling(10, 10, 10), new Material( pattern: new CheckerPattern( new Color(0.4863, 0.3765, 0.2941), new Color(0.3725, 0.2902, 0.2275), Matrix4x4.CreateScaling(0.05, 20, 0.05)), ambient: 0.1, diffuse: 0.7, specular: 0.9, shininess: 300, reflective: 0.1)); var csgUnion = new CsgShape( "Union", CsgOperation.Union, new Cube( "YellowCube", Matrix4x4.CreateTranslation(0, 1.5, 0), new Material(Colors.Yellow, diffuse: 0.7, specular: 0.3)), new Sphere( "RedSphere", Matrix4x4.CreateTranslation(0.6, 2, -0.6), new Material(Colors.Red, diffuse: 0.7, specular: 0.9)), transform: Matrix4x4.CreateRotationY(-Math.PI / 3).Translate(-4, 0, -2)); var csgIntersection = new CsgShape( "Intersection", CsgOperation.Intersection, new Cube( "YellowCube", Matrix4x4.CreateTranslation(0, 1.5, 0), new Material(Colors.Yellow, diffuse: 0.7, specular: 0.3)), new Sphere( "RedSphere", Matrix4x4.CreateTranslation(0.6, 2, -0.6), new Material(Colors.Red, diffuse: 0.7, specular: 0.9)), transform: Matrix4x4.CreateRotationY(-Math.PI / 2).Translate(0, 0, -2)); var csgDifference = new CsgShape( "Difference", CsgOperation.Difference, new Cube( "YellowCube", Matrix4x4.CreateTranslation(0, 1.5, 0), new Material(Colors.Yellow, diffuse: 0.7, specular: 0.3)), new Sphere( "RedSphere", Matrix4x4.CreateTranslation(0.6, 2, -0.6), new Material(Colors.Red, diffuse: 0.7, specular: 0)), transform: Matrix4x4.CreateRotationY(-Math.PI / 6).Translate(3, 0, 2)); // Lights, camera, action. var light = new PointLight(new Point(8, 8, -5), Colors.White); var world = new World(light, floorCeiling, walls, csgUnion, csgIntersection, csgDifference); var cameraTransform = Matrix4x4.CreateLookAt(new Point(8, 6, -8), new Point(0, 3, 0), Vector.UnitY); var camera = new Camera(CanvasWidth, CanvasHeight, fieldOfView: 0.785, cameraTransform); Canvas canvas = camera.Render(world, options); return(canvas); }