From f3fca336060ee0186cebc1bf658dcfbf5bed0ac0 Mon Sep 17 00:00:00 2001 From: mm00 Date: Fri, 28 Mar 2025 19:30:43 +0100 Subject: [PATCH] fixed gradient calculation --- SDFMapCreator.sln.DotSettings.user | 5 +- SDFMapCreator/Program.cs | 110 +++++++++++++---------------- 2 files changed, 52 insertions(+), 63 deletions(-) diff --git a/SDFMapCreator.sln.DotSettings.user b/SDFMapCreator.sln.DotSettings.user index 4b0a35a..085f3a7 100644 --- a/SDFMapCreator.sln.DotSettings.user +++ b/SDFMapCreator.sln.DotSettings.user @@ -1,2 +1,5 @@  - ForceIncluded \ No newline at end of file + ForceIncluded + <AssemblyExplorer> + <Assembly Path="/mnt/nvme2/Railgun/SDFMapCreator/SDFMapCreator/bin/Debug/net8.0/Magick.NET-Q16-HDRI-OpenMP-x64.dll" /> +</AssemblyExplorer> \ No newline at end of file diff --git a/SDFMapCreator/Program.cs b/SDFMapCreator/Program.cs index c79fda3..4492536 100644 --- a/SDFMapCreator/Program.cs +++ b/SDFMapCreator/Program.cs @@ -24,7 +24,8 @@ public struct float4(float r, float g, float b, float a) { }*/ public record ImageData(MagickImage Image, float3[,] Pixels, List Edges); -public record MaskData(float3[,] Mask, ImageData A, List Edges); +public record MaskData(float3[,] Mask, ImageData Image, List Edges); +public record TransitionMaskData(float3[,] Mask, ImageData ImageA, ImageData ImageB); public record SDFData(float3[,] SDF); @@ -61,7 +62,8 @@ public class Program { private const bool outputGradients = true; static readonly ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = MAX_THREADS }; static List Images = new(); - static List Masks = new(); + static List TransitionMasks = new(); + static List ImageMasks = new(); static List SDFs = new(); static List Gradients = new(); @@ -91,13 +93,13 @@ public class Program { var imagesPath = "images"; - /* + for (int i = 0; i < 8; i++) LoadImage($"./{imagesPath}{Path.DirectorySeparatorChar}{i+1:00}.png"); - */ - LoadImage("spherecut.png"); - LoadImage("spherefull.png"); + + //LoadImage("spherecut.png"); + //LoadImage("spherefull.png"); //LoadImage("1.png"); //LoadImage("2.png"); @@ -108,29 +110,36 @@ public class Program { } Console.WriteLine("Creating masks..."); - Masks.Add(new (SelfMask(Images[0].Pixels, Images[0].Image.Width, Images[0].Image.Height), Images[0], new())); //for each image pair, create a mask - for (int i = 1; i < Images.Count; i++) { - var mask = GetABMask(Images[i-1].Pixels, Images[i].Pixels, Images[i].Image.Width, Images[i].Image.Height); - Masks.Add(new(mask, Images[i], new())); + var width = Images[0].Image.Width; + var height = Images[0].Image.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("Edge detecting masks..."); //EdgeDetect all masks - foreach (var t in Masks) { EdgeDetect(t); } + foreach (var t in ImageMasks) { EdgeDetect(t); } if(outputMasks) { Console.WriteLine("Writing masks..."); - for (int i = 0; i < Masks.Count; i++) { - var mask = new MagickImage(MagickColors.Black, (uint)Masks[i].Mask.GetLength(0), (uint)Masks[i].Mask.GetLength(1)); - mask.GetPixels().SetPixels(Masks[i].Mask.ToFloatArray()); + for (int i = 0; i < TransitionMasks.Count; i++) { + var mask = new MagickImage(MagickColors.Black, (uint)TransitionMasks[i].Mask.GetLength(0), (uint)TransitionMasks[i].Mask.GetLength(1)); + mask.GetPixels().SetPixels(TransitionMasks[i].Mask.ToFloatArray()); mask.Write($"mask{i}.png", MagickFormat.Png24); } } Console.WriteLine("Creating SDFs..."); - for (var i = 0; i < Masks.Count; i++) { - var mask = Masks[i]; + for (var i = 0; i < ImageMasks.Count; i++) { + var mask = ImageMasks[i]; SDFs.Add(SDF(mask)); if(!outputSDFs) continue; var sdf = new MagickImage(MagickColors.Black, (uint)mask.Mask.GetLength(0), (uint)mask.Mask.GetLength(1)); @@ -139,65 +148,42 @@ public class Program { } Console.WriteLine("Creating gradients..."); - for (var i = 0; i < Masks.Count - 1; i++) { - var gradientData = Gradient(Masks[i+1], SDFs[i], SDFs[i + 1]); + for (var i = 0; i < TransitionMasks.Count; i++) { + Console.WriteLine($"Generating gradient {i}..."); + var gradientData = Gradient(TransitionMasks[i], SDFs[i], SDFs[i + 1]); Gradients.Add(gradientData); if(!outputGradients) continue; - var gradient = new MagickImage(MagickColors.Black, (uint)Masks[i+1].Mask.GetLength(0), (uint)Masks[i+1].Mask.GetLength(1)); + var gradient = new MagickImage(MagickColors.Black, (uint)TransitionMasks[i].Mask.GetLength(0), (uint)TransitionMasks[i].Mask.GetLength(1)); gradient.GetPixels().SetPixels(gradientData.ToFloatArray()); gradient.Write($"gradient{i}.png", MagickFormat.Png24); } - - return; - Console.WriteLine("Preparing transitions..."); - //for each gradient read the corresponding mask - //for each pixel in the mask, lerp the pixel value with the gradient value - //write the result to a new image - int width = Masks[0].Mask.GetLength(0); - int height = Masks[0].Mask.GetLength(1); + // generate final image + var finalImage = new float3[width, height]; + var currStep = 0f; + var stepIncrement = MAX / (Gradients.Count + 1); for (var i = 0; i < Gradients.Count; i++) { - var mask = Masks[i + 1]; + var mask = ImageMasks[i + 1]; var gradient = Gradients[i]; - var transition = new float3[width, height]; - var absMax = MIN; - var absMin = MAX; for (var x = 0; x < mask.Mask.GetLength(0); x++) { for (var y = 0; y < mask.Mask.GetLength(1); y++) { if (mask.Mask[x, y].X == 0 || mask.Mask[x, y].Y > 0) continue; - transition[x, y] = new(Lerp(Images[i].Pixels[x, y].X, MAX, gradient[x, y].X)); - if (transition[x, y].X > absMax) absMax = transition[x, y].X; - if (transition[x, y].X < absMin) absMin = transition[x, y].X; + finalImage[x, y] = new(Remap(gradient[x,y].X, MAX, MIN, currStep, currStep + stepIncrement)); } } - - absMax = MathF.Min(absMax, MAX); - absMin = MathF.Max(absMin, MIN); - - //normalize - Parallel.For(0, width * height, parallelOptions, (j) => { - var x = (int)(j % width); - var y = (int)(j / width); - //Console.WriteLine($"Transition {i} | Min: {absMin} | Max: {absMax}, {transition[x, y].X}"); - transition[x, y] = new(Remap(transition[x, y].X, absMin, absMax, MIN, MAX)); - }); - - Console.WriteLine($"Transition {i} | Min: {absMin} | Max: {absMax}"); - Console.WriteLine($"Transition {i} | Min: {transition.Cast().Min(x => x.X)} | Max: {transition.Cast().Max(x => x.X)}"); - - var transitionImage = new MagickImage(MagickColors.Black, (uint)mask.Mask.GetLength(0), (uint)mask.Mask.GetLength(1)); - transitionImage.GetPixels().SetPixels(transition.ToFloatArray()); - - - transitionImage.Write($"transition{i}.png", MagickFormat.Png24); + currStep += stepIncrement; } + var finalImageMagick = new MagickImage(MagickColors.Black, (uint)width, (uint)height); + finalImageMagick.GetPixels().SetPixels(finalImage.ToFloatArray()); + finalImageMagick.Write("final.png", MagickFormat.Png24); + Console.WriteLine("Done!"); } private static void EdgeDetect(MaskData maskData) { - uint width = maskData.A.Image.Width; - uint height = maskData.A.Image.Height; + uint width = maskData.Image.Image.Width; + uint height = maskData.Image.Image.Height; int iterCount = 0; var sw = new Stopwatch(); sw.Start(); @@ -213,16 +199,16 @@ public class Program { lock(maskData.Edges) maskData.Edges.Add(new(x, y)); iterCount++; if (iterCount % (width * height / 100) == 0) { - ConsoleUpdateLine($"Progress: {iterCount/(width*height):P}% | {iterCount/(sw.Elapsed.TotalSeconds):N0} pixels/s"); + ConsoleUpdateLine($"Progress: {iterCount/(float)(width*height):P} | {iterCount/(sw.Elapsed.TotalSeconds):N0} pixels/s"); } }); sw.Stop(); Console.WriteLine($"Edge pixels: {maskData.Edges.Count} | {maskData.Edges.Count/sw.ElapsedMilliseconds} pixels/s\n Time: {sw.Elapsed.TotalSeconds:F4}s"); } - static float3[,] Gradient(MaskData mask, SDFData sdfA, SDFData sdfB) { - uint width = mask.A.Image.Width; - uint height = mask.A.Image.Height; + static float3[,] Gradient(TransitionMaskData mask, SDFData sdfA, SDFData sdfB) { + uint width = mask.ImageA.Image.Width; + uint height = mask.ImageA.Image.Height; int iterCount = 0; var sw = new Stopwatch(); sw.Start(); @@ -272,10 +258,10 @@ public class Program { //loop through all the pixels in the mask foreach (var edge in mask.Edges) { float dist = float2.DistanceSquared(p, edge); - if (dist < minDist) minDist = dist; + if (dist < minDist) minDist = mask.Mask[x, y].X == 0 ? dist : dist; } - temp[x, y] = new(float.Abs(minDist)); + temp[x, y] = new(minDist); if (minDist > AbsMax) AbsMax = minDist; iterCount++; if (iterCount % (width * height / 100) == 0) {