public static void CreateAnimation(Viewport from, Viewport to, ref ReadOnlyBuffer <float> coordinates, int imageWidth, int imageHeight) { // Creating/handling the frames folder. if (Directory.Exists("frames")) { foreach (var f in Directory.GetFiles("frames")) { File.Delete(f); } } else { Directory.CreateDirectory("frames"); } Thread.Sleep(500); var previousMaxDensity = -1f; /// This just determines how many frames to render. var timeToTake = 1; // seconds var frameRate = 1000; var progress = 0; var watch = new Stopwatch(); watch.Start(); for (var i = 0; i < frameRate * timeToTake; i++) { var t = i / (float)(frameRate * timeToTake); t = Smoothing(t); var image = new PSprite(imageWidth, imageHeight); image.Art.SetPixels(GalaxyRenderer.Render( Viewport.Lerp(from, to, t), 1000, 1000, GalaxyRenderer.DefaultColorMapping, i == 0 ? (float?)null : previousMaxDensity, out previousMaxDensity, ref coordinates)); if (!(image is null)) { image.Save(@"frames\" + i.ToString("000000") + ".png"); image.Dispose(); } progress++; #region Logging progress per frame Console.WriteLine(progress + " / " + (frameRate * timeToTake) + " - " + ((progress * 100) / (double)(frameRate * timeToTake)).ToString("0.00") + "%"); var secondsPerFrame = watch.Elapsed.TotalSeconds / progress; var framesRemaining = (frameRate * timeToTake) - progress; var timeRemaining = new TimeSpan((long)(10000000 * (framesRemaining * secondsPerFrame))); Console.WriteLine("Estimated time remaining: " + timeRemaining.Hours.ToString("00") + ":" + timeRemaining.Minutes.ToString("00") + ":" + timeRemaining.Seconds.ToString("00")); Console.WriteLine("Average time per frame: " + secondsPerFrame.ToString("0.00") + " seconds."); #endregion } Console.WriteLine("Frame rendering complete. Compiling video..."); var info = new ProcessStartInfo() { FileName = "ffmpeg", Arguments = string.Format(" -framerate {0} -i %06d.png -c:v libx264 -r {0} {1}.mp4", frameRate, "out"), WorkingDirectory = "frames", }; var p = Process.Start(info); p.WaitForExit(); Console.WriteLine("Finished. Saved video as out.mp4."); Console.Read(); }
public void Setup() { Console.Write("Enter video framerate: "); var framerate = Console.ReadLine(); Console.Write("Enter total frame count: "); var frames = int.Parse(Console.ReadLine()); Console.Write("Enter output video file name (no extension): "); var name = Console.ReadLine().Trim(); Console.Write("Enter resolution separated by a comma (480,480): "); var res = Console.ReadLine().Split(',').ToList().ConvertAll(resPart => int.Parse(resPart)).ToArray(); Console.Write("Enter mandelbrot power range (x in f(z)=z^x + c) separated by a comma (1,10): "); var range = Console.ReadLine().Split(',').ToList().ConvertAll(rangePart => int.Parse(rangePart)).ToArray(); var s = Stopwatch.StartNew(); Console.WriteLine("Generation is starting, please wait..."); var done = 0; var items = Enumerable.Range(0, frames).ToArray(); var chunks = items .Select((s2, i) => new { Value = s2, Index = i }) .GroupBy(x => x.Index / 10) .Select(grp => grp.Select(x => x.Value).ToArray()).ToList(); var threads = new List <Thread>(); for (var t = 0; t < Environment.ProcessorCount - 1; t++) { var t2 = t; var thread = new Thread(() => { start:; if (chunks.Count == 0) { goto exit; } var assignedChunk = chunks[0]; chunks.RemoveAt(0); foreach (var a in assignedChunk) { var pow = PMath.Map(a, 1, frames, range[0], range[1]); var Image = new PSprite(res[0], res[1]); var pixels = Image.Art.GetPixels(); for (var y = 0; y < Image.Height; y++) { for (var x = 0; x < Image.Width; x++) { var xTarget = 4f; var yTarget = (xTarget / Image.Width) * Image.Height; var x2 = (x / (Image.Width / (xTarget))) - (xTarget / 2); var y2 = (y / (Image.Height / (yTarget))) - (yTarget / 2); var c = new Complex(x2, y2); var z = Complex.Zero; var max = -1f; var maxWasHit = false; for (var i = 0; i < maxDepth; i++) { z = (Complex.Pow(z, pow)) + c; if ((z.Real * z.Real) + (z.Imaginary * z.Imaginary) > 16 && max == -1f) { max = i; maxWasHit = true; break; } } var color = PColor.Black; if (maxWasHit) { var floorMax = (int)Math.Floor(max); var c1 = pallet[floorMax % pallet.Length]; var c2 = pallet[(floorMax + 1) % pallet.Length]; color = PColor.Lerp(c1, c2, 0.5f); } var pos = ((y * Image.Width) + x) * 4; pixels[pos] = (byte)(color.R); pixels[pos + 1] = (byte)(color.G); pixels[pos + 2] = (byte)(color.B); pixels[pos + 3] = 255; } } Image.Art.SetPixels(pixels); Image.Save(folder + a.ToString("000000") + ".png"); var percent = (done / (float)frames); var remaining = (1f - percent) * 100; var secondsPerPercent = s.Elapsed.TotalSeconds / (percent * 100f); var minutesRemaining = ((secondsPerPercent * remaining) / 60f); var estimatedTime = DateTime.Now.AddMinutes(done == 0 ? 0 : minutesRemaining); Console.WriteLine("Progress: " + done + "/" + frames + " " + (percent * 100f).ToString("0.00") + "% Estimated completion time: " + estimatedTime); done++; } goto start; exit:; }) { Name = "Mandelbrot: Core " + (t + 1), Priority = ThreadPriority.AboveNormal, }; threads.Add(thread); thread.Start(); } ; var info = new ProcessStartInfo() { FileName = "ffmpeg", Arguments = string.Format(" -framerate {0} -i %06d.png -c:v libx264 -r {0} {1}.mp4", framerate, name), WorkingDirectory = folder, }; var activeThreads = 1; do { Console.Title = "Active thread count: " + activeThreads; activeThreads = threads.Where(t => t.IsAlive).Count(); Thread.Sleep(1000); Title(activeThreads); }while (activeThreads > 0); Console.Title = "Active thread count: 0"; var p = Process.Start(info); p.WaitForExit(); Console.WriteLine(@"Saved as " + folder + "out.mp4"); Console.ReadLine(); Close(); }