示例#1
0
        public BvhNode(IEnumerable <IHitable> hitables)
        {
            var axis   = (int)(3 * Utils.NextFloat());
            var sorted = hitables.OrderBy(h =>
            {
                var box = h.BoundingBox();
                return(box.IsOK ? box.Content.Min[axis] : float.NegativeInfinity);
            }).ToList();

            var count = sorted.Count;

            if (count > 0)
            {
                if (count == 1)
                {
                    Left = Right = sorted[0];
                }
                else
                {
                    Left  = new BvhNode(sorted.Take(count / 2));
                    Right = new BvhNode(sorted.Skip(count / 2));
                }
            }

            var leftBox = Left != null?Left.BoundingBox() : new Result <AABB>();

            var rightBox = Right != null?Right.BoundingBox() : new Result <AABB>();

            if (leftBox.IsOK && rightBox.IsOK)
            {
                Box = leftBox.Content + rightBox.Content;
            }
        }
示例#2
0
        private static void Render(SceneDefinition sceneDef, StringBuilder output)
        {
            /*var world = new HitableList()
             * {
             *  new Sphere(new Vec3(0.0f, 0.0f, -1.0f), 0.5f, new Lambertian(new Vec3(0.8f, 0.3f, 0.3f))),
             *  new Sphere(new Vec3(0.0f, -100.5f, -1.0f), 100.0f, new Lambertian(new Vec3(0.8f, 0.8f, 0.0f))),
             *  new Sphere(new Vec3(1.0f, 0.0f, -1.0f), 0.5f, new Metal(new Vec3(0.8f, 0.6f, 0.2f), 1.0f)),
             *
             *  // make bubble by having a smaller sphere with negative radius
             *  new Sphere(new Vec3(-1.0f, 0.0f, -1.0f), 0.5f, new Dielectric(1.5f)),
             *  new Sphere(new Vec3(-1.0f, 0.0f, -1.0f), -0.45f, new Dielectric(1.5f)),
             * };*/

            var world = new BvhNode(RandomScene());

            // var world = TwoPerlinSpheres();

            var lookFrom      = new Vec3(sceneDef.CameraLookFrom[0], sceneDef.CameraLookFrom[1], sceneDef.CameraLookFrom[2]);
            var lookAt        = new Vec3(sceneDef.CameraLookAt[0], sceneDef.CameraLookAt[1], sceneDef.CameraLookAt[2]);
            var focusDistance = sceneDef.CameraFocusDistance;
            var aperture      = sceneDef.CameraAperture;
            var cam           = new Camera(lookFrom, lookAt, new Vec3(0.0f, 1.0f, 0.0f), 20.0f, sceneDef.ImageWidth / (float)sceneDef.ImageHeight, aperture, focusDistance);

            var totalCount   = sceneDef.ImageWidth * sceneDef.ImageHeight;
            var currentCount = 0;

            var sw = new Stopwatch();

            sw.Start();

            output.AppendLine($"P3\n{sceneDef.ImageWidth} {sceneDef.ImageHeight}\n255");

            if (sceneDef.ChunkSize > 0)
            {
                var chunks   = Enumerable.Range(0, totalCount).Chunk(sceneDef.ChunkSize * sceneDef.ChunkSize).ToArray();
                var bag      = new ConcurrentBag <Tuple <int, StringBuilder> >();
                var progress = new Progress <int>(cnt => ReportProgress(cnt, totalCount, sw.Elapsed)) as IProgress <int>;
                Parallel.ForEach(chunks, chunk =>
                {
                    var chunkOutput = new StringBuilder();
                    foreach (var idx in chunk)
                    {
                        var i = idx % sceneDef.ImageWidth;
                        var j = sceneDef.ImageHeight - 1 - idx / sceneDef.ImageWidth;

                        RenderPart(i, j, sceneDef, cam, world, chunkOutput);

                        Interlocked.Increment(ref currentCount);
                        progress.Report(currentCount);
                    }
                    bag.Add(new Tuple <int, StringBuilder>(chunk.First(), chunkOutput));
                });

                foreach (var tuple in bag.OrderBy(x => x.Item1))
                {
                    output.Append(tuple.Item2);
                }
            }
            else
            {
                for (var j = sceneDef.ImageHeight - 1; j >= 0; j--)
                {
                    for (var i = 0; i < sceneDef.ImageWidth; i++)
                    {
                        RenderPart(i, j, sceneDef, cam, world, output);
                        ReportProgress(++currentCount, totalCount, sw.Elapsed);
                    }
                }
            }

            sw.Stop();
            Console.WriteLine($"\nElapsed: {sw.Elapsed.Hours:00}:{sw.Elapsed.Minutes:00}:{sw.Elapsed.Seconds:00}");
        }