internal static Scene SphereScene (int level, Vector center, double radius) { Sphere sphere = new Sphere (center, radius); if (level == 1) { return sphere; } else { Group scene = new Group (new Sphere (center, 3.0 * radius)); scene.Add (sphere); double rn = 3.0 * radius / Math.Sqrt (12.0); for (int dz = -1; dz <= 1; dz += 2) { for (int dx = -1; dx <= 1; dx += 2) { Vector c2 = new Vector ( center.x - dx * rn , center.y + rn , center.z - dz * rn ); scene.Add (SphereScene (level - 1, c2, radius / 2.0)); } } return scene; } }
// Normally we'd use double.Epsilon public static void Main (String[] args, ILog ilog) { int n = 0; if (args.Length > 0) n = Int32.Parse (args [0]); Scene scene = Scene.SphereScene (levels, new Vector (0.0, -1.0, 0.0), 1.0); ilog.InfoFormat ("P5"); ilog.InfoFormat ("{0} {1}", n, n); ilog.InfoFormat ("255"); Stream stream = Stream.Null; byte[] temp = new byte[1]; for (int y = n - 1; y >= 0; --y) { for (int x = 0; x < n; ++x) { double greyscale = 0.0; for (int dx = 0; dx < ss; ++dx) { for (int dy = 0; dy < ss; ++dy) { Vector v = new Vector ( x + dx / (double)ss - n / 2.0 , y + dy / (double)ss - n / 2.0 , n); Ray ray = new Ray (new Vector (0.0, 0.0, -4.0), v.Normalized ()); greyscale += scene.TraceRay (ray, new Vector (-1.0, -3.0, 2.0).Normalized ()); } } temp [0] = (byte)(0.5 + 255.0 * greyscale / (ss * ss)); stream.Write (temp, 0, 1); } } }
internal double TraceRay (Ray ray, Vector light) { IntersectionPoint p = Intersect (ray, new IntersectionPoint ( double.PositiveInfinity, new Vector (0.0, 0.0, 0.0))); if (double.IsInfinity (p.distance)) return 0.0; double greyscale = -(p.normal * light); if (greyscale <= 0.0) return 0.0; Vector o = ray.origin + (p.distance * ray.direction) + (Epsilon * p.normal); Ray shadowRay = new Ray (o, new Vector (0.0, 0.0, 0.0) - light); IntersectionPoint shadowp = Intersect (shadowRay, new IntersectionPoint (double.PositiveInfinity, p.normal)); return double.IsInfinity (shadowp.distance) ? greyscale : 0.0; }
internal IntersectionPoint (double distance, Vector normal) { _distance = distance; _normal = normal; }
internal Ray (Vector origin, Vector direction) { _origin = origin; _direction = direction; }
internal Sphere (Vector center, double radius) { this.center = center; this.radius = radius; }