diff --git a/SDFMapCreator/Program.cs b/SDFMapCreator/Program.cs index 8efb7bf..8a43e28 100644 --- a/SDFMapCreator/Program.cs +++ b/SDFMapCreator/Program.cs @@ -120,11 +120,44 @@ public class Program { Console.WriteLine("Creating SDFs..."); for (var i = 0; i < Masks.Count; i++) { var mask = Masks[i]; - var sdf = new MagickImage(MagickColors.Black, (uint)mask.Mask.GetLength(0), (uint)mask.Mask.GetLength(1)); SDFs.Add(SDF(mask)); + if(!outputSDFs) continue; + var sdf = new MagickImage(MagickColors.Black, (uint)mask.Mask.GetLength(0), (uint)mask.Mask.GetLength(1)); sdf.GetPixels().SetPixels(SDFs[i].SDF.ToFloatArray()); sdf.Write($"sdf{i}.png", MagickFormat.Png48); } + + Console.WriteLine("Creating gradients..."); + for (var i = 0; i < Masks.Count - 1; i++) { + var gradientData = Gradient(Masks[i], SDFs[i], SDFs[i + 1]); + Gradients.Add(gradientData); + if(!outputGradients) continue; + var gradient = new MagickImage(MagickColors.Black, (uint)Masks[i].Mask.GetLength(0), (uint)Masks[i].Mask.GetLength(1)); + gradient.GetPixels().SetPixels(gradientData.ToFloatArray()); + gradient.Write($"gradient{i}.png", MagickFormat.Png24); + } + + 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); + for (var i = 0; i < Gradients.Count; i++) { + var mask = Masks[i + 1]; + var gradient = Gradients[i]; + var transition = new float3[width, height]; + 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].r == 0) continue; + transition[x, y] = new(Lerp(Images[i].Pixels[x,y].r, MAX, gradient[x,y].r)); + } + } + 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); + } + Console.WriteLine("Done!"); } @@ -152,6 +185,32 @@ public class Program { 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; + int iterCount = 0; + var sw = new Stopwatch(); + sw.Start(); + float3[,] temp = new float3[width, height]; + Console.WriteLine("Running edge detection..."); + Parallel.For(0, width * height, (i) => { + int x = (int)(i % width); + int y = (int)(i / width); + + var a = (sdfA.SDF[x,y].r + sdfB.SDF[x,y].g + sdfB.SDF[x,y].b )/ 3; + var b = (sdfB.SDF[x,y].r + sdfB.SDF[x,y].g + sdfB.SDF[x,y].b )/ 3; + + var gradient = a / (a + b); + temp[x, y] = new(Remap(gradient, 0, 1, MIN, MAX)); + }); + + Console.WriteLine($"Gradient Time: {sw.Elapsed.TotalSeconds:N4}s ({iterCount/sw.Elapsed.TotalSeconds:N0} pixels/s)"); + var min = temp.Cast().Min(x => x.r); + var max = temp.Cast().Max(x => x.r); + Console.WriteLine($"Min: {min} | Max: {max}"); + return temp; + } static SDFData SDF(MaskData mask) { var width = (uint)mask.Mask.GetLength(0); @@ -166,11 +225,6 @@ public class Program { var x = (int)(i % width); var y = (int)(i / width); float2 p = new(x, y); - //skip all pixels we don't care about - if(mask.Mask[x, y].r == 0) { - temp[x, y] = new(MIN); - return; - } float minDist = MAX; //initialize the minimum distance to the maximum possible value @@ -230,6 +284,19 @@ public class Program { }); return temp; } + + static float3[,] SelfMask(float3[,] A, uint resX, uint resY) { + var temp = new float3[resX, resY]; + Parallel.For(0, resX*resY, (i) => { + uint x = (uint)(i % resX); + uint y = (uint)(i / resX); + var pixelA = A[x, y]; + float lumaA = (pixelA.r+pixelA.g+pixelA.b)/3; + float resultPixel = lumaA > 0 ? MAX : MIN; + temp[x, y] = new(resultPixel, 0, 0); + }); + return temp; + } static bool EdgeKernel(float3[,] mask, int x, int y, uint width, uint height) { //if we are already empty, return false