diff --git a/SDFMapCreator.sln.DotSettings.user b/SDFMapCreator.sln.DotSettings.user index 0c42637..c9bd358 100644 --- a/SDFMapCreator.sln.DotSettings.user +++ b/SDFMapCreator.sln.DotSettings.user @@ -6,6 +6,7 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded <AssemblyExplorer> diff --git a/SDFMapCreator/Program.cs b/SDFMapCreator/Program.cs index 7000caf..143a26a 100644 --- a/SDFMapCreator/Program.cs +++ b/SDFMapCreator/Program.cs @@ -7,9 +7,7 @@ public class Program { private const float MAX = 1f; private const float MIN = 0f; private static readonly int MAX_THREADS = Environment.ProcessorCount - 2; - private const bool outputMasks = true; - private const bool outputSDFs = true; - private const bool outputGradients = true; + private static bool debug = true; static readonly ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = MAX_THREADS }; static List Images = new(); static List ImageMasks = new(); @@ -24,15 +22,18 @@ public class Program { public static void Main(string[] args) { Console.WriteLine("Reading images..."); - -/* + + if(debug) { + if (!Directory.Exists("Debug")) Directory.CreateDirectory("Debug"); + Console.WriteLine("Debug mode enabled."); + } + var imagesPath = "images"; for (int i = 0; i < 8; i++) { var pixels = ImageUtil.LoadImage($"./{imagesPath}{Path.DirectorySeparatorChar}{i + 1:00}.png"); Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1))); } -*/ - +/* var pixels = ImageUtil.LoadImage($"./sphereempty.png"); Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1))); pixels = ImageUtil.LoadImage($"./spherehalf.png"); @@ -41,59 +42,50 @@ public class Program { Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1))); pixels = ImageUtil.LoadImage($"./spherefull.png"); Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1))); - +*/ + //check if all the images in Images are the same resolution if (Images.Select(img => (img.Width, img.Height)).Distinct().Count() > 1) { Console.WriteLine("Error: Not all images have the same resolution."); Environment.Exit(1); } - - for (int i = 1; i < Images.Count; i++) { - for (int x = 0; x < Images[i].Width; x++) { - for (int y = 0; y < Images[i].Height; y++) { - Images[i].Pixels[x, y].X = MathF.Min(Images[i - 1].Pixels[x, y].X + Images[i].Pixels[x, y].X, MAX); - Images[i].Pixels[x, y].Y = MathF.Min(Images[i - 1].Pixels[x, y].Y + Images[i].Pixels[x, y].X, MAX); - Images[i].Pixels[x, y].Z = MathF.Min(Images[i - 1].Pixels[x, y].Z + Images[i].Pixels[x, y].X, MAX); - } - } - Images[i].Pixels.SaveImage($"./Sum{i}.png"); - } - - Console.WriteLine("Creating masks..."); - //for each image pair, create a mask + width = (uint)Images[0].Width; height = (uint)Images[0].Height; - for (int i = 0; i < Images.Count; i++) { - ImageMasks.Add(new(SelfMask(Images[i].Pixels, width, height), Images[i], new())); - if (i < Images.Count - 1) { - Console.WriteLine($"Creating mask {i}..."); - var mask = GetABMask(Images[i].Pixels, Images[i + 1].Pixels, width, height); - TransitionMasks.Add(new(mask, Images[i], Images[i + 1])); - } + + Console.WriteLine("Creating masks..."); + for (int i = 0; i < Images.Count; i++) { //for each image pair, create a mask + var selfMask = SelfMask(Images[i].Pixels); + ImageMasks.Add(new(selfMask, Images[i], new())); + if (debug) selfMask.SaveImage($"Debug/selfMask{i}.png"); + if (i >= Images.Count - 1) continue; + ConsoleUpdateLine($"Creating mask {i}..."); + var mask = GetABMask(Images[i].Pixels, Images[i + 1].Pixels); + TransitionMasks.Add(new(mask, Images[i], Images[i + 1])); + if (debug) mask.SaveImage($"Debug/mask{i}.png"); } - - Console.WriteLine("Edge detecting masks..."); + //EdgeDetect all masks - foreach (var t in ImageMasks) EdgeDetect(t); - - if (outputMasks) { - Console.WriteLine("Writing masks..."); - for (int i = 0; i < TransitionMasks.Count; i++) ImageMasks[i].Mask.SaveImage($"mask{i}.png"); + Console.WriteLine("\nEdge detecting masks..."); + foreach (var mask in ImageMasks) { + ConsoleUpdateLine($"Edge detecting mask {ImageMasks.IndexOf(mask)}..."); + EdgeDetect(mask); } + if (debug) for (int i = 0; i < TransitionMasks.Count; i++) ImageMasks[i].Mask.SaveImage($"Debug/mask{i}.png"); Console.WriteLine("Creating SDFs..."); for (var i = 0; i < ImageMasks.Count; i++) { var mask = ImageMasks[i]; SDFs.Add(SDF(mask)); - if (outputSDFs) SDFs[i].SDF.SaveImage($"sdf{i}.png"); + if (debug) SDFs[i].SDF.SaveImage($"Debug/sdf{i}.png"); } Console.WriteLine("Creating gradients..."); for (var i = 0; i < TransitionMasks.Count; i++) { - Console.WriteLine($"Generating gradient {i}..."); + ConsoleUpdateLine($"Generating gradient {i}..."); var gradientData = Gradient(TransitionMasks[i], SDFs[i], SDFs[i + 1]); Gradients.Add(gradientData); - if (outputGradients) gradientData.SaveImage($"gradient{i}.png"); + if (debug) gradientData.SaveImage($"Debug/gradient{i}.png"); } // generate final image @@ -136,8 +128,6 @@ public class Program { } private static void EdgeDetect(MaskData maskData) { - uint width = (uint)maskData.Image.Width; - uint height = (uint)maskData.Image.Height; var sw = new Stopwatch(); sw.Start(); Console.WriteLine("Running edge detection..."); @@ -155,8 +145,6 @@ public class Program { } static Vector3[,] Gradient(TransitionMaskData mask, SDFData sdfA, SDFData sdfB) { - uint width = (uint)mask.ImageA.Width; - uint height = (uint)mask.ImageA.Height; int iterCount = 0; var sw = new Stopwatch(); sw.Start(); @@ -191,43 +179,13 @@ public class Program { } static SDFData SDF(MaskData mask) { - var width = (uint)mask.Mask.GetLength(0); - var height = (uint)mask.Mask.GetLength(1); - float AbsMax = MIN; int iterCount = 0; var sw = new Stopwatch(); sw.Start(); - /*Parallel.For(0, width * height, parallelOptions, (i) => - { - //convert 1D index to 2D index - var x = (int)(i % width); - var y = (int)(i / width); - Vector2 p = new(x / (float)width, y / (float)height); //get the pixel position as a Vector2 - float minDist = MAX + 1; //initialize the minimum distance to the maximum possible value - - //loop through all the pixels in the mask - foreach (var edge in mask.Edges) { - Vector2 edgeNorm = new(edge.X / (float)width, edge.Y / (float)height); - float dist = Vector2.DistanceSquared(p, edgeNorm); - if (dist < minDist) minDist = dist; - } - - if (minDist > MAX) - minDist = MAX; - - temp[x, y] = new(minDist); - if (minDist > AbsMax) AbsMax = minDist; - iterCount++; - if (iterCount % (width * height / 100) == 0) { - ConsoleUpdateLine( - $"Progress: {iterCount / (float)(width * height):P}% | {iterCount / (sw.Elapsed.TotalSeconds):N0} pixels/s"); - } - });*/ kernels.Sdf(mask.Edges.ToArray(), (int)width, (int)height, out var temp); - Console.WriteLine( - $"\nSDF Generation Time: {sw.Elapsed.TotalSeconds:N4}s ({iterCount / sw.Elapsed.TotalSeconds:N0} pixels/s)"); + Console.WriteLine($"\nSDF Generation Time: {sw.Elapsed.TotalSeconds:N4}s ({iterCount / sw.Elapsed.TotalSeconds:N0} pixels/s)"); return new(temp); } @@ -252,12 +210,12 @@ public class Program { private static float EuclideanDistance(Vector2 a, Vector2 b) => MathF.Sqrt(MathF.Pow(a.X - b.X, 2) + MathF.Pow(a.Y - b.Y, 2)); - static Vector3[,] GetABMask(Vector3[,] A, Vector3[,] B, uint resX, uint resY) { + static Vector3[,] GetABMask(Vector3[,] A, Vector3[,] B) { kernels.ABMask(A, B, out var temp); return temp; } - static Vector3[,] SelfMask(Vector3[,] A, uint resX, uint resY) { + static Vector3[,] SelfMask(Vector3[,] A) { kernels.SelfMask(A, out var temp); return temp; } diff --git a/SDFMapCreator/SdfKernels.cs b/SDFMapCreator/SdfKernels.cs index 5cea7c4..02b0b6f 100644 --- a/SDFMapCreator/SdfKernels.cs +++ b/SDFMapCreator/SdfKernels.cs @@ -27,11 +27,13 @@ public partial class SdfKernels { using Accelerator accelerator = device.CreateAccelerator(gpuContext); Console.WriteLine($"{GetInfoString(accelerator)}"); } + Console.WriteLine("Reading available accelerators (OpenCL only)..."); foreach (var device in gpuContext.GetCLDevices()) { using Accelerator accelerator = device.CreateAccelerator(gpuContext); Console.WriteLine($"{GetInfoString(accelerator)}"); } + Console.WriteLine("Reading available accelerators (CPU only)..."); foreach (var device in gpuContext.GetCPUDevices()) { using Accelerator accelerator = device.CreateAccelerator(gpuContext); @@ -130,7 +132,7 @@ public partial class SdfKernels { sdf = buffer.GetAsArray2D(); } - public void Gradient(ref Vector3[,] mask, ref Vector3[,] sdfa, ref Vector3[,] sdfb, out Vector3[,] gradient) { + public void Gradient(Vector3[,] mask, Vector3[,] sdfa, Vector3[,] sdfb, out Vector3[,] gradient) { var dev = gpuContext.GetPreferredDevice(preferCPU:false); int width = mask.GetLength(0); int height = mask.GetLength(1);