Compare commits

...

12 Commits

Author SHA1 Message Date
Samuele Lorefice
c65346aeec Added release build configs 2025-04-07 07:56:23 +02:00
Samuele Lorefice
a74ae1167e Updated gitignore 2025-04-07 07:51:39 +02:00
mm00
d7d2091d64 Merge remote-tracking branch 'origin/ILGpu' into ILGpu 2025-04-04 19:23:20 +02:00
mm00
ea28738280 added border to initial image used in final image calculation 2025-04-04 19:23:02 +02:00
Samuele Lorefice
2faab96a7d Merge remote-tracking branch 'origin/ILGpu' into ILGpu 2025-04-04 19:22:26 +02:00
Samuele Lorefice
8c5ca2ce21 Small kernel fixes 2025-04-04 19:22:05 +02:00
mm00
d0fbd31c1d fixed final image masking 2025-04-04 19:20:43 +02:00
mm00
5cf8612699 Fixed directional blur 2025-04-03 20:49:44 +02:00
mm00
dfa2cf3f31 added luma threshould 2025-04-03 19:28:26 +02:00
mm00
64b7eb9dcc added SDF normalization 2025-04-03 19:28:20 +02:00
Samuele Lorefice
d652c63586 Added editor config 2025-04-03 19:14:58 +02:00
Samuele Lorefice
9614283dc8 Cleanup and added formatting rules. Reformatted 2025-04-03 19:02:50 +02:00
12 changed files with 4403 additions and 294 deletions

4012
.editorconfig Normal file

File diff suppressed because it is too large Load Diff

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@ obj/
/packages/ /packages/
riderModule.iml riderModule.iml
/_ReSharper.Caches/ /_ReSharper.Caches/
publish/

View File

@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

View File

@@ -0,0 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Release Build Linux-x64" type="DotNetFolderPublish" factoryName="Publish to folder">
<riderPublish configuration="Release" delete_existing_files="true" include_native_libs_for_self_extract="true" platform="Any CPU" produce_single_file="true" runtime="linux-x64" target_folder="$PROJECT_DIR$/SDFMapCreator/publish/linux-x64" target_framework="net8.0" uuid_high="-7972981449231152312" uuid_low="-5206031561210231144" />
<method v="2" />
</configuration>
</component>

View File

@@ -0,0 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Release Build Win-x64" type="DotNetFolderPublish" factoryName="Publish to folder">
<riderPublish configuration="Release" delete_existing_files="true" include_native_libs_for_self_extract="true" platform="Any CPU" produce_single_file="true" runtime="win-x64" target_folder="$PROJECT_DIR$/SDFMapCreator/publish/win-x64" target_framework="net8.0" uuid_high="-7972981449231152312" uuid_low="-5206031561210231144" />
<method v="2" />
</configuration>
</component>

View File

@@ -0,0 +1,19 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForBuiltInTypes/@EntryValue">UseVar</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_LOCK/@EntryValue">NotRequired</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_REDUNDANT/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/DEFAULT_PRIVATE_MODIFIER/@EntryValue">Implicit</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/METHOD_OR_OPERATOR_BODY/@EntryValue">ExpressionBody</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/MODIFIERS_ORDER/@EntryValue">public private protected internal file new static abstract virtual override readonly sealed extern unsafe volatile async required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_EXPR_METHOD_ON_SINGLE_LINE/@EntryValue">IF_OWNER_IS_SINGLE_LINE</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALLOW_COMMENT_AFTER_LBRACE/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue">END_OF_LINE</s:String>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_SINGLE_LINE_INVOCABLE/@EntryValue">1</s:Int64>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_NESTED_FOR_STMT/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_BEFORE_ARROW_WITH_EXPRESSIONS/@EntryValue">True</s:Boolean>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LIMIT/@EntryValue">151</s:Int64>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_OBJECT_AND_COLLECTION_INITIALIZER_STYLE/@EntryValue">WRAP_IF_LONG</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -18,14 +18,14 @@ public static class ImageUtil {
static T[,] ProcessPixelsRgba64<T>(this Image<Rgba64> image) where T : struct, IEquatable<T> { static T[,] ProcessPixelsRgba64<T>(this Image<Rgba64> image) where T : struct, IEquatable<T> {
var max = 65535f; var max = 65535f;
int width = image.Width; var width = image.Width;
int height = image.Height; var height = image.Height;
var result = new T[image.Width, image.Height]; var result = new T[image.Width, image.Height];
image.ProcessPixelRows(accessor => { image.ProcessPixelRows(accessor => {
//we use Y as the row index and X as the column index //we use Y as the row index and X as the column index
for (int y = 0; y < height; y++) { for (var y = 0; y < height; y++) {
var span = accessor.GetRowSpan(y); var span = accessor.GetRowSpan(y);
for (int x = 0; x < width; x++) { for (var x = 0; x < width; x++) {
switch (result) { switch (result) {
case float[,] f: case float[,] f:
f[x, y] = span[x].R / max * (span[x].A / max); f[x, y] = span[x].R / max * (span[x].A / max);
@@ -37,7 +37,7 @@ public static class ImageUtil {
f[x, y] = new Vector3(span[x].R / max, span[x].G / max, span[x].B / max) * new Vector3(span[x].A / max); f[x, y] = new Vector3(span[x].R / max, span[x].G / max, span[x].B / max) * new Vector3(span[x].A / max);
break; break;
case Vector4[,] f: case Vector4[,] f:
f[x, y] = new Vector4(span[x].R / max, span[x].G / max, span[x].B / max, span[x].A / max); f[x, y] = new(span[x].R / max, span[x].G / max, span[x].B / max, span[x].A / max);
break; break;
} }
} }
@@ -48,14 +48,14 @@ public static class ImageUtil {
static T[,] ProcessPixelsRgb24<T>(this Image<Rgb24> image) where T : struct, IEquatable<T> { static T[,] ProcessPixelsRgb24<T>(this Image<Rgb24> image) where T : struct, IEquatable<T> {
var max = 255f; var max = 255f;
int width = image.Width; var width = image.Width;
int height = image.Height; var height = image.Height;
var result = new T[image.Width, image.Height]; var result = new T[image.Width, image.Height];
image.ProcessPixelRows(accessor => { image.ProcessPixelRows(accessor => {
//we use Y as the row index and X as the column index //we use Y as the row index and X as the column index
for (int y = 0; y < height; y++) { for (var y = 0; y < height; y++) {
var span = accessor.GetRowSpan(y); var span = accessor.GetRowSpan(y);
for (int x = 0; x < width; x++) { for (var x = 0; x < width; x++) {
switch (result) { switch (result) {
case float[,] f: case float[,] f:
f[x, y] = span[x].R / max; f[x, y] = span[x].R / max;
@@ -78,14 +78,14 @@ public static class ImageUtil {
static T[,] ProcessPixelsRgba32<T>(this Image<Rgba32> image) where T : struct, IEquatable<T> { static T[,] ProcessPixelsRgba32<T>(this Image<Rgba32> image) where T : struct, IEquatable<T> {
var max = 255f; var max = 255f;
int width = image.Width; var width = image.Width;
int height = image.Height; var height = image.Height;
var result = new T[image.Width, image.Height]; var result = new T[image.Width, image.Height];
image.ProcessPixelRows(accessor => { image.ProcessPixelRows(accessor => {
//we use Y as the row index and X as the column index //we use Y as the row index and X as the column index
for (int y = 0; y < height; y++) { for (var y = 0; y < height; y++) {
var span = accessor.GetRowSpan(y); var span = accessor.GetRowSpan(y);
for (int x = 0; x < width; x++) { for (var x = 0; x < width; x++) {
switch (result) { switch (result) {
case float[,] f: case float[,] f:
f[x, y] = span[x].R / max * (span[x].A / max); f[x, y] = span[x].R / max * (span[x].A / max);
@@ -97,7 +97,7 @@ public static class ImageUtil {
f[x, y] = new Vector3(span[x].R / max, span[x].G / max, span[x].B / max) * new Vector3(span[x].A / max); f[x, y] = new Vector3(span[x].R / max, span[x].G / max, span[x].B / max) * new Vector3(span[x].A / max);
break; break;
case Vector4[,] f: case Vector4[,] f:
f[x, y] = new Vector4(span[x].R / max, span[x].G / max, span[x].B / max, span[x].A / max); f[x, y] = new(span[x].R / max, span[x].G / max, span[x].B / max, span[x].A / max);
break; break;
} }
} }
@@ -108,14 +108,14 @@ public static class ImageUtil {
static T[,] ProcessPixelsRgb48<T>(this Image<Rgb48> image) where T : struct, IEquatable<T> { static T[,] ProcessPixelsRgb48<T>(this Image<Rgb48> image) where T : struct, IEquatable<T> {
var max = 65535f; var max = 65535f;
int width = image.Width; var width = image.Width;
int height = image.Height; var height = image.Height;
var result = new T[image.Width, image.Height]; var result = new T[image.Width, image.Height];
image.ProcessPixelRows(accessor => { image.ProcessPixelRows(accessor => {
//we use Y as the row index and X as the column index //we use Y as the row index and X as the column index
for (int y = 0; y < height; y++) { for (var y = 0; y < height; y++) {
var span = accessor.GetRowSpan(y); var span = accessor.GetRowSpan(y);
for (int x = 0; x < width; x++) { for (var x = 0; x < width; x++) {
switch (result) { switch (result) {
case float[,] f: case float[,] f:
f[x, y] = span[x].R / max; f[x, y] = span[x].R / max;
@@ -149,21 +149,21 @@ public static class ImageUtil {
Console.Write($"Writing image {path}..."); Console.Write($"Writing image {path}...");
using Image<Rgb48> image = new(width, height); using Image<Rgb48> image = new(width, height);
image.ProcessPixelRows(accessor => { image.ProcessPixelRows(accessor => {
for (int y = 0; y < height; y++) { for (var y = 0; y < height; y++) {
var span = accessor.GetRowSpan(y); var span = accessor.GetRowSpan(y);
for (int x = 0; x < width; x++) { for (var x = 0; x < width; x++) {
switch (array) { switch (array) {
case float[,] f: case float[,] f:
span[x] = new Rgb48((ushort)(f[x, y] * 65535), (ushort)(f[x, y] * 65535), (ushort)(f[x,y] * 65535)); span[x] = new((ushort)(f[x, y] * 65535), (ushort)(f[x, y] * 65535), (ushort)(f[x, y] * 65535));
break; break;
case Vector2[,] f: case Vector2[,] f:
span[x] = new Rgb48((ushort)(f[x,y].X * 65535), (ushort)(f[x,y].Y * 65535), 0); span[x] = new((ushort)(f[x, y].X * 65535), (ushort)(f[x, y].Y * 65535), 0);
break; break;
case Vector3[,] f: case Vector3[,] f:
span[x] = new Rgb48((ushort)(f[x,y].X * 65535), (ushort)(f[x,y].Y * 65535), (ushort)(f[x,y].Z * 65535)); span[x] = new((ushort)(f[x, y].X * 65535), (ushort)(f[x, y].Y * 65535), (ushort)(f[x, y].Z * 65535));
break; break;
case Vector4[,] f: case Vector4[,] f:
span[x] = new Rgb48((ushort)(f[x,y].X * 65535), (ushort)(f[x,y].Y * 65535), (ushort)(f[x,y].Z * 65535)); span[x] = new((ushort)(f[x, y].X * 65535), (ushort)(f[x, y].Y * 65535), (ushort)(f[x, y].Z * 65535));
break; break;
} }
} }
@@ -173,12 +173,12 @@ public static class ImageUtil {
image.Save(path); image.Save(path);
} }
private static void ImageData(SixLabors.ImageSharp.Image image1, string path) { static void ImageData(SixLabors.ImageSharp.Image image1, string path) {
Console.WriteLine( Console.WriteLine(
$""" $"""
Image file: {path} Image file: {path}
Resolution: {image1.Width}x{image1.Height} Resolution: {image1.Width}x{image1.Height}
Total Pixels: {image1.Width*image1.Height} |{"NaN"} channels, {image1.PixelType.BitsPerPixel/4} bits per channel Total Pixels: {image1.Width * image1.Height} |{"NaN"} channels, {image1.PixelType.BitsPerPixel / 4} bits per channel
"""); """);
} }

View File

@@ -1,13 +1,14 @@
using System.Diagnostics; using System.Diagnostics;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SDFMapCreator;
public class Program { namespace SDFMapCreator;
private const float MAX = 1f;
private const float MIN = 0f; public static class Program {
private static readonly int MAX_THREADS = Environment.ProcessorCount - 2; const float MAX = 1f;
private static bool debug = true; const float MIN = 0f;
static readonly int MAX_THREADS = Environment.ProcessorCount - 2;
static bool debug = true;
static readonly ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = MAX_THREADS }; static readonly ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = MAX_THREADS };
static List<Image> Images = new(); static List<Image> Images = new();
static List<MaskData> ImageMasks = new(); static List<MaskData> ImageMasks = new();
@@ -23,17 +24,19 @@ public class Program {
public static void Main(string[] args) { public static void Main(string[] args) {
Console.WriteLine("Reading images..."); Console.WriteLine("Reading images...");
if(debug) { if (debug) {
if (!Directory.Exists("Debug")) Directory.CreateDirectory("Debug"); if (!Directory.Exists("Debug")) Directory.CreateDirectory("Debug");
Console.WriteLine("Debug mode enabled."); Console.WriteLine("Debug mode enabled.");
} }
var imagesPath = "images"; var imagesPath = "images";
for (int i = 0; i < 8; i++) { for (var i = 0; i < 8; i++) {
var pixels = ImageUtil.LoadImage<Vector3>($"./{imagesPath}{Path.DirectorySeparatorChar}{i + 1:00}.png"); var pixels = ImageUtil.LoadImage<Vector3>($"./{imagesPath}{Path.DirectorySeparatorChar}{i + 1:00}.png");
Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1))); Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1)));
} }
/*
/*
var pixels = ImageUtil.LoadImage<Vector3>($"./sphereempty.png"); var pixels = ImageUtil.LoadImage<Vector3>($"./sphereempty.png");
Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1))); Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1)));
pixels = ImageUtil.LoadImage<Vector3>($"./spherehalf.png"); pixels = ImageUtil.LoadImage<Vector3>($"./spherehalf.png");
@@ -53,8 +56,24 @@ public class Program {
width = (uint)Images[0].Width; width = (uint)Images[0].Width;
height = (uint)Images[0].Height; height = (uint)Images[0].Height;
// sum all images together
if(debug) Images[0].Pixels.SaveImage("Debug/Sum0.png");
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);
}
}
if(debug)Images[i].Pixels.SaveImage($"Debug/Sum{i}.png");
}
Console.WriteLine("Creating masks..."); Console.WriteLine("Creating masks...");
for (int i = 0; i < Images.Count; i++) { //for each image pair, create a mask for (var i = 0; i < Images.Count; i++) { //for each image pair, create a mask
var selfMask = SelfMask(Images[i].Pixels); var selfMask = SelfMask(Images[i].Pixels);
ImageMasks.Add(new(selfMask, Images[i], new())); ImageMasks.Add(new(selfMask, Images[i], new()));
if (debug) selfMask.SaveImage($"Debug/selfMask{i}.png"); if (debug) selfMask.SaveImage($"Debug/selfMask{i}.png");
@@ -62,7 +81,6 @@ public class Program {
ConsoleUpdateLine($"Creating mask {i}..."); ConsoleUpdateLine($"Creating mask {i}...");
var mask = GetABMask(Images[i].Pixels, Images[i + 1].Pixels); var mask = GetABMask(Images[i].Pixels, Images[i + 1].Pixels);
TransitionMasks.Add(new(mask, Images[i], Images[i + 1])); TransitionMasks.Add(new(mask, Images[i], Images[i + 1]));
if (debug) mask.SaveImage($"Debug/mask{i}.png");
} }
//EdgeDetect all masks //EdgeDetect all masks
@@ -71,7 +89,9 @@ public class Program {
ConsoleUpdateLine($"Edge detecting mask {ImageMasks.IndexOf(mask)}..."); ConsoleUpdateLine($"Edge detecting mask {ImageMasks.IndexOf(mask)}...");
EdgeDetect(mask); EdgeDetect(mask);
} }
if (debug) for (int i = 0; i < TransitionMasks.Count; i++) ImageMasks[i].Mask.SaveImage($"Debug/mask{i}.png"); if (debug)
for (var i = 0; i < TransitionMasks.Count; i++)
ImageMasks[i].Mask.SaveImage($"Debug/mask{i}.png");
Console.WriteLine("Creating SDFs..."); Console.WriteLine("Creating SDFs...");
for (var i = 0; i < ImageMasks.Count; i++) { for (var i = 0; i < ImageMasks.Count; i++) {
@@ -91,11 +111,12 @@ public class Program {
// generate final image // generate final image
var finalImage = new Vector3[width, height]; var finalImage = new Vector3[width, height];
var currStep = 0f; var currStep = 0f;
var stepIncrement = MAX / (Gradients.Count); var stepIncrement = MAX / Gradients.Count;
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++) for (var x = 0; x < width; x++)
finalImage[x, y] = new Vector3(Images[0].Pixels[x, y].X); for (var y = 0; y < height; y++)
finalImage[x, y] = new(ImageMasks[0].Mask[x, y].X != 0 || ImageMasks[0].Mask[x, y].Y > 0 ? MAX : MIN);
for (var i = 0; i < Gradients.Count; i++) { for (var i = 0; i < Gradients.Count; i++) {
var mask = ImageMasks[i + 1]; var mask = ImageMasks[i + 1];
@@ -103,7 +124,7 @@ public class Program {
Console.WriteLine($"Applying gradient {i}..., {currStep} -> {currStep + stepIncrement}"); Console.WriteLine($"Applying gradient {i}..., {currStep} -> {currStep + stepIncrement}");
for (var x = 0; x < mask.Mask.GetLength(0); x++) { for (var x = 0; x < mask.Mask.GetLength(0); x++) {
for (var y = 0; y < mask.Mask.GetLength(1); y++) { for (var y = 0; y < mask.Mask.GetLength(1); y++) {
if (gradient[x, y].X == 0) continue; if (mask.Mask[x,y].X == 0) continue;
var pixel = new Vector3(Remap(gradient[x, y].X, MIN, MAX, 1.0f - currStep, var pixel = new Vector3(Remap(gradient[x, y].X, MIN, MAX, 1.0f - currStep,
1.0f - (currStep + stepIncrement))); 1.0f - (currStep + stepIncrement)));
if (pixel.X > finalImage[x, y].X) finalImage[x, y] = pixel; if (pixel.X > finalImage[x, y].X) finalImage[x, y] = pixel;
@@ -112,22 +133,25 @@ public class Program {
currStep += stepIncrement; currStep += stepIncrement;
} }
finalImage.SaveImage("Debug/Final.png");
// apply directional blur // apply directional blur
var iterations = 10; var iterations = 1;
var radius = 3f; var radius = 100f;
var step = .5f; var step = .5f;
var sigma = 1f; var sigma = 1f;
for (int i = 0; i < iterations; i++) var totalMask = SelfMask(Images[^1].Pixels);
{ totalMask.SaveImage("Debug/TotalMask.png");
for (var i = 0; i < iterations; i++) {
Console.WriteLine($"Applying directional blur {i + 1}/{iterations}..."); Console.WriteLine($"Applying directional blur {i + 1}/{iterations}...");
finalImage = DirectionalBlur(finalImage, ImageMasks[0].Mask, radius, step, sigma); finalImage = DirectionalBlur(finalImage, totalMask, radius, step, sigma);
} }
finalImage.SaveImage("final.png"); finalImage.SaveImage("finalBlur.png");
Console.WriteLine("Done!"); Console.WriteLine("Done!");
} }
private static void EdgeDetect(MaskData maskData) { static void EdgeDetect(MaskData maskData) {
var sw = new Stopwatch(); var sw = new Stopwatch();
sw.Start(); sw.Start();
Console.WriteLine("Running edge detection..."); Console.WriteLine("Running edge detection...");
@@ -141,11 +165,10 @@ public class Program {
sw.Stop(); sw.Stop();
Console.WriteLine( Console.WriteLine(
$"\nEdge pixels: {maskData.Edges.Count} | {width*height / (sw.ElapsedMilliseconds + 1)} pixels/s\n Time: {sw.Elapsed.TotalSeconds:F4}s"); $"\nEdge pixels: {maskData.Edges.Count} | {width * height / (sw.ElapsedMilliseconds + 1)} pixels/s\n Time: {sw.Elapsed.TotalSeconds:F4}s");
} }
static Vector3[,] Gradient(TransitionMaskData mask, SDFData sdfA, SDFData sdfB) { static Vector3[,] Gradient(TransitionMaskData mask, SDFData sdfA, SDFData sdfB) {
int iterCount = 0;
var sw = new Stopwatch(); var sw = new Stopwatch();
sw.Start(); sw.Start();
/*Vector3[,] temp = new Vector3[width, height]; /*Vector3[,] temp = new Vector3[width, height];
@@ -172,40 +195,47 @@ public class Program {
});*/ });*/
kernels.Gradient(mask.Mask, sdfA.SDF, sdfB.SDF, out var temp); kernels.Gradient(mask.Mask, sdfA.SDF, sdfB.SDF, out var temp);
Console.WriteLine($"Gradient Time: {sw.Elapsed.TotalSeconds:N4}s ({width*height / (float)sw.Elapsed.TotalSeconds:N0} pixels/s)"); Console.WriteLine($"Gradient Time: {sw.Elapsed.TotalSeconds:N4}s ({width * height / (float)sw.Elapsed.TotalSeconds:N0} pixels/s)");
return temp; return temp;
} }
static SDFData SDF(MaskData mask) { static SDFData SDF(MaskData mask) {
int iterCount = 0;
var sw = new Stopwatch(); var sw = new Stopwatch();
sw.Start(); sw.Start();
kernels.Sdf(mask.Edges.ToArray(), (int)width, (int)height, out var temp); kernels.Sdf(mask.Edges.ToArray(), (int)width, (int)height, out var temp);
Console.WriteLine($"\nSDF Generation Time: {sw.Elapsed.TotalSeconds:N4}s ({width * height / sw.Elapsed.TotalSeconds:N0} pixels/s)");
Console.WriteLine($"\nSDF Generation Time: {sw.Elapsed.TotalSeconds:N4}s ({width*height / sw.Elapsed.TotalSeconds:N0} pixels/s)"); sw.Restart();
var absMax = 0f;
foreach (var pixel in temp) {
if (pixel.X > absMax) absMax = pixel.X;
}
Parallel.For(0, width * height, parallelOptions, (i) => {
//convert 1D index to 2D index
var x = (int)(i % width);
var y = (int)(i / width);
temp[x, y] = new(Remap(temp[x, y].X, 0, absMax, MIN, MAX));
});
sw.Stop();
Console.WriteLine(
$"SDF Normalization Time: {sw.Elapsed.TotalSeconds:N4}s ({width * height / sw.Elapsed.TotalSeconds:N0} pixels/s)");
return new(temp); return new(temp);
} }
static Vector3[,] DirectionalBlur(Vector3[,] image, Vector3[,] mask, float radius = 3f, float step = .5f, float sigma = 1f) { static Vector3[,] DirectionalBlur(Vector3[,] image, Vector3[,] mask, float radius = 3f, float step = .5f, float sigma = 1f) {
var width = (uint)image.GetLength(0);
var height = (uint)image.GetLength(1);
var output = new Vector3[width, height];
var sw = new Stopwatch(); var sw = new Stopwatch();
sw.Start(); sw.Start();
kernels.DirectionalBlur(image, mask, out var temp, radius, step, sigma); kernels.DirectionalBlur(image, mask, out var temp, radius, step, sigma);
Console.WriteLine( Console.WriteLine(
$"Directional Blur Time: {sw.Elapsed.TotalSeconds:N4}s ({width * height / sw.Elapsed.TotalSeconds:N0} pixels/s)"); $"Directional Blur Time: {sw.Elapsed.TotalSeconds:N4}s ({width * height / sw.Elapsed.TotalSeconds:N0} pixels/s)");
return temp; return temp;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float EuclideanDistance(Vector2 a, Vector2 b) => static float EuclideanDistance(Vector2 a, Vector2 b) =>
MathF.Sqrt(MathF.Pow(a.X - b.X, 2) + MathF.Pow(a.Y - b.Y, 2)); MathF.Sqrt(MathF.Pow(a.X - b.X, 2) + MathF.Pow(a.Y - b.Y, 2));
static Vector3[,] GetABMask(Vector3[,] A, Vector3[,] B) { static Vector3[,] GetABMask(Vector3[,] A, Vector3[,] B) {
@@ -222,7 +252,7 @@ public class Program {
where T : INumber<T>, IMultiplyOperators<T, float, T>, IAdditionOperators<T, T, T> where T : INumber<T>, IMultiplyOperators<T, float, T>, IAdditionOperators<T, T, T>
=> a * (1 - t) + b * t; => a * (1 - t) + b * t;
public static T Remap<T>(T value, T min, T max, T newMin, T newMax) static T Remap<T>(T value, T min, T max, T newMin, T newMax)
where T : INumber<T>, ISubtractionOperators<T, T, T>, IMultiplyOperators<T, T, T>, IAdditionOperators<T, T, T> where T : INumber<T>, ISubtractionOperators<T, T, T>, IMultiplyOperators<T, T, T>, IAdditionOperators<T, T, T>
=> (value - min) / (max - min) * (newMax - newMin) + newMin; => (value - min) / (max - min) * (newMax - newMin) + newMin;
} }

View File

@@ -3,10 +3,12 @@ using System.Numerics;
namespace SDFMapCreator; namespace SDFMapCreator;
public record Image(Vector3[,] Pixels, int Width, int Height); public record Image(Vector3[,] Pixels, int Width, int Height);
public record MaskData(Vector3[,] Mask, Image Image, List<Vector2> Edges) { public record MaskData(Vector3[,] Mask, Image Image, List<Vector2> Edges) {
public Vector3[,] Mask { get; set; } = Mask; public Vector3[,] Mask { get; set; } = Mask;
public List<Vector2> Edges { get; set; } = Edges; public List<Vector2> Edges { get; set; } = Edges;
} }
public record SDFData(Vector3[,] SDF); public record SDFData(Vector3[,] SDF);
public record TransitionMaskData(Vector3[,] Mask, Image ImageA, Image ImageB); public record TransitionMaskData(Vector3[,] Mask, Image ImageA, Image ImageB);

View File

@@ -8,67 +8,67 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ILGPU" Version="1.5.2" /> <PackageReference Include="ILGPU" Version="1.5.2"/>
<PackageReference Include="ILGPU.Algorithms" Version="1.5.2" /> <PackageReference Include="ILGPU.Algorithms" Version="1.5.2"/>
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" /> <PackageReference Include="SixLabors.ImageSharp" Version="3.1.7"/>
<PackageReference Include="System.Numerics.Vectors" Version="4.6.1" /> <PackageReference Include="System.Numerics.Vectors" Version="4.6.1"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Update="1.png"> <None Update="1.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="2.png"> <None Update="2.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="TestPattern.png"> <None Update="TestPattern.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Update="images\01.png"> <None Update="images\01.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="images\02.png"> <None Update="images\02.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="images\03.png"> <None Update="images\03.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="images\04.png"> <None Update="images\04.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="images\05.png"> <None Update="images\05.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="images\06.png"> <None Update="images\06.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="images\07.png"> <None Update="images\07.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="images\08.png"> <None Update="images\08.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="spherecut.png"> <None Update="spherecut.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="spherefull.png"> <None Update="spherefull.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="spherehalf.png"> <None Update="spherehalf.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="spherehalf32.png"> <None Update="spherehalf32.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="spherefull32.png"> <None Update="spherefull32.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="spherecut32.png"> <None Update="spherecut32.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="sphereempty.png"> <None Update="sphereempty.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -5,63 +5,68 @@ using ILGPU.Runtime;
namespace SDFMapCreator; namespace SDFMapCreator;
public partial class SdfKernels { public partial class SdfKernels {
private static void SelfMaskKernel(Index2D index, ArrayView2D<Vector3, Stride2D.DenseX> input, ArrayView2D<Vector3, Stride2D.DenseX> mask) {
int x = index.X; private const float LUMA_THRESHOLD = 0.0f;
int y = index.Y; static void SelfMaskKernel(Index2D index, ArrayView2D<Vector3, Stride2D.DenseX> input, ArrayView2D<Vector3, Stride2D.DenseX> mask) {
Vector3 value = input[x, y]; var x = index.X;
float lumaA = (value.X + value.Y + value.Z)/3f; var y = index.Y;
float r = lumaA > 0.99f ? 1f : 0f; var value = input[x, y];
mask[x,y] = new (r, 0f, 0f); var lumaA = value.X;
var r = lumaA > LUMA_THRESHOLD ? 1f : 0f;
mask[x, y] = new(r, 0f, 0f);
} }
private static void ABMaskKernel(Index2D index, static void ABMaskKernel(Index2D index,
ArrayView2D<Vector3, Stride2D.DenseX> A, ArrayView2D<Vector3, Stride2D.DenseX> A,
ArrayView2D<Vector3, Stride2D.DenseX> B, ArrayView2D<Vector3, Stride2D.DenseX> B,
ArrayView2D<Vector3, Stride2D.DenseX> mask ArrayView2D<Vector3, Stride2D.DenseX> mask
) { ) {
int x = index.X; var x = index.X;
int y = index.Y; var y = index.Y;
Vector3 valueA = A[x, y]; var valueA = A[x, y];
Vector3 valueB = B[x, y]; var valueB = B[x, y];
float lumaA = (valueA.X + valueA.Y + valueA.Z) / 3f; var lumaA = valueA.X;
float lumaB = (valueB.X + valueB.Y + valueB.Z) / 3f; var lumaB = valueB.X;
float r = lumaA > 0.99f && lumaB > 0.99f ? 1f : 0f; var r = lumaB - lumaA > LUMA_THRESHOLD ? 1f : 0f;
mask[x, y] = new (r, 0f, 0f); mask[x, y] = new(r, 0f, 0f);
} }
private static void EdgeKernel(Index2D index, static void EdgeKernel(Index2D index,
ArrayView2D<Vector3, Stride2D.DenseX> mask, ArrayView2D<Vector3, Stride2D.DenseX> mask,
uint width, uint height uint width, uint height
) { // early exit if not on mask ) { // early exit if not on mask
if (mask[index].X == 0f) return; if (mask[index].X == 0f) return;
int x = index.X; var x = index.X;
int y = index.Y; var y = index.Y;
//if we are on the edge of the image, return false //if we are on the edge of the image, return false
if (x == 0 || y == 0 || x == width - 1 || y == height - 1) return; if (x == 0 || y == 0 || x == width - 1 || y == height - 1) {
mask[index].Y = 1f; //set the edge flag
return;
}
//check the 3x3 kernel //check the 3x3 kernel
for (int xi = x - 1; xi <= x + 1; xi++) { for (var xi = x - 1; xi <= x + 1; xi++) {
for (int yi = y - 1; yi <= y + 1; yi++) { for (var yi = y - 1; yi <= y + 1; yi++) {
if (xi < 0 || xi >= width || yi < 0 || yi >= height) if (xi < 0 || xi >= width || yi < 0 || yi >= height)
continue; //skip out of bounds pixels continue; //skip out of bounds pixels
if (mask[xi, yi].X == 0f) if (mask[xi, yi].X == 0f)
mask[index].Y = 1f; //if we find a black pixel, return true mask[index].Y = 1f; //if we find a black pixel, return true
} }
} }
} }
private static void SdfKernel(Index2D index, static void SdfKernel(Index2D index,
ArrayView2D<Vector3, Stride2D.DenseX> sdf, ArrayView2D<Vector3, Stride2D.DenseX> sdf,
ArrayView1D<Vector2, Stride1D.Dense> edges, ArrayView1D<Vector2, Stride1D.Dense> edges,
int width, int height int width, int height
) { ) {
Vector2 pos = new((float)index.X / width, (float)index.Y / height); Vector2 pos = new((float)index.X / width, (float)index.Y / height);
float minDist = 2f; var minDist = 2f;
int count = edges.IntExtent.Size; var count = edges.IntExtent.Size;
for (int i = 0; i < count; i++) { for (var i = 0; i < count; i++) {
Vector2 edgeNrm = new (edges[i].X/width, edges[i].Y/height); Vector2 edgeNrm = new(edges[i].X / width, edges[i].Y / height);
float dist = Vector2.Distance(pos, edgeNrm); var dist = Vector2.Distance(pos, edgeNrm);
if (dist < minDist) minDist = dist; if (dist < minDist) minDist = dist;
} }
@@ -70,47 +75,71 @@ public partial class SdfKernels {
sdf[index] = new(minDist); sdf[index] = new(minDist);
} }
private static void GradientKernel(Index2D index, static void GradientKernel(Index2D index,
ArrayView2D<Vector3, Stride2D.DenseX> mask, ArrayView2D<Vector3, Stride2D.DenseX> mask,
ArrayView2D<Vector3, Stride2D.DenseX> sdfa, ArrayView2D<Vector3, Stride2D.DenseX> sdfa,
ArrayView2D<Vector3, Stride2D.DenseX> sdfb, ArrayView2D<Vector3, Stride2D.DenseX> sdfb,
ArrayView2D<Vector3, Stride2D.DenseX> gradient ArrayView2D<Vector3, Stride2D.DenseX> gradient
) { //early exit if not on mask ) { //early exit if not on mask
if(mask[index].X == 0f || mask[index].Y == 0f) return; if (mask[index].X == 0f) return;
float a = sdfa[index].X; float b = sdfb[index].X; var a = sdfa[index].X;
gradient[index] = new (a / (a + b)); var b = sdfb[index].X;
gradient[index] = new(a / (a + b));
}
private static void DirectionalBlurKernel(Index2D index, static Vector3 SampleBilinear(ArrayView2D<Vector3, Stride2D.DenseX> image, float x, float y) {
int width = image.IntExtent.X;
int height = image.IntExtent.Y;
var x0 = (int)x;
var y0 = (int)y;
var x1 = x0 + 1;
var y1 = y0 + 1;
if (x0 < 0 || x1 >= width || y0 < 0 || y1 >= height) return Vector3.Zero;
var a = new Vector2(x - x0, y - y0);
var b = new Vector2(1f - a.X, 1f - a.Y);
return Vector3.Lerp(
Vector3.Lerp(image[x0, y0], image[x1, y0], a.X),
Vector3.Lerp(image[x0, y1], image[x1, y1], a.X),
a.Y
);
}
static void DirectionalBlurKernel(Index2D index,
ArrayView2D<Vector3, Stride2D.DenseX> image, ArrayView2D<Vector3, Stride2D.DenseX> image,
ArrayView2D<Vector3, Stride2D.DenseX> mask, ArrayView2D<Vector3, Stride2D.DenseX> mask,
ArrayView2D<Vector3, Stride2D.DenseX> output, ArrayView2D<Vector3, Stride2D.DenseX> output,
float radius, float step, float sigma, float radius, float step, float sigma,
int width, int height int width, int height
) ) {
{ var x = index.X;
int x = index.X; var y = index.Y;
int y = index.Y; var value = image[x, y];
Vector3 value = image[x, y]; var maskValue = mask[x, y];
Vector3 maskValue = mask[x, y]; if (maskValue.X == 0f) {
if (maskValue.X == 0f)
{
output[x, y] = value; output[x, y] = value;
return; return;
} }
var gradient = Vector2.Zero; var gradient = Vector2.Zero;
for (int dx = -1; dx <= 1; dx++) // calculate the gradient
{ for (int i = -1; i <= 1; i++) {
for (int dy = -1; dy <= 1; dy++) if (x + i < 0 || x + i >= width || y + i < 0 || y + i >= height) continue;
{ gradient.X += i * image[x + i, y].X;
if (x + dx < 0 || x + dx >= width || y + dy < 0 || y + dy >= height) continue; gradient.Y += i * image[x, y + i].X;
gradient += new Vector2(dx, dy) * image[x + dx, y + dy].X;
}
} }
if (gradient == Vector2.Zero) /*
{ output[x, y] = new Vector3(float.Abs((gradient.X * 0.5f) + 0.5f),
float.Abs((gradient.Y * 0.5f) + 0.5f), 0.5f);
return;
*/
if (gradient == Vector2.Zero) {
output[x, y] = value; output[x, y] = value;
return; return;
} }
@@ -119,21 +148,20 @@ public partial class SdfKernels {
float sum = 0; float sum = 0;
// now we follow the direction line and sample the image for length; // now we follow the direction line and sample the image for length;
for (float l = -radius; l <= radius; l += step) for (var l = -radius; l <= radius; l += step) {
{ var xOffset = (gradient.X * l);
int xOffset = (int)(gradient.X * l); var yOffset = (gradient.Y * l);
int yOffset = (int)(gradient.Y * l); var xSample = x + xOffset;
int xSample = x + xOffset; var ySample = y + yOffset;
int ySample = y + yOffset;
if (xSample < 0 || xSample >= width || ySample < 0 || ySample >= height) continue; if (xSample < 0 || xSample >= width || ySample < 0 || ySample >= height) continue;
Vector3 sampleValue = image[xSample, ySample]; var sampleValue = SampleBilinear(image, xSample, ySample);
float weight = MathF.Exp(-l * l / (2f * sigma * sigma)); var weight = MathF.Exp(-(l * l) / (2f * sigma * sigma));
output[x, y] += sampleValue * weight; output[x, y] += sampleValue * weight;
sum += weight; sum += weight;
} }
output[x, y] /= sum; output[x, y] = output[x, y] / sum;
} }
} }

View File

@@ -10,7 +10,7 @@ using ILGPU.Algorithms;
namespace SDFMapCreator; namespace SDFMapCreator;
public partial class SdfKernels { public partial class SdfKernels {
private Context gpuContext; Context gpuContext;
public SdfKernels() { public SdfKernels() {
// Initialize the GPU context // Initialize the GPU context
@@ -24,40 +24,39 @@ public partial class SdfKernels {
Console.WriteLine("Reading available accelerators (CUDA only)..."); Console.WriteLine("Reading available accelerators (CUDA only)...");
foreach (var device in gpuContext.GetCudaDevices()) { foreach (var device in gpuContext.GetCudaDevices()) {
using Accelerator accelerator = device.CreateAccelerator(gpuContext); using var accelerator = device.CreateAccelerator(gpuContext);
Console.WriteLine($"{GetInfoString(accelerator)}"); Console.WriteLine($"{GetInfoString(accelerator)}");
} }
Console.WriteLine("Reading available accelerators (OpenCL only)..."); Console.WriteLine("Reading available accelerators (OpenCL only)...");
foreach (var device in gpuContext.GetCLDevices()) { foreach (var device in gpuContext.GetCLDevices()) {
using Accelerator accelerator = device.CreateAccelerator(gpuContext); using var accelerator = device.CreateAccelerator(gpuContext);
Console.WriteLine($"{GetInfoString(accelerator)}"); Console.WriteLine($"{GetInfoString(accelerator)}");
} }
Console.WriteLine("Reading available accelerators (CPU only)..."); Console.WriteLine("Reading available accelerators (CPU only)...");
foreach (var device in gpuContext.GetCPUDevices()) { foreach (var device in gpuContext.GetCPUDevices()) {
using Accelerator accelerator = device.CreateAccelerator(gpuContext); using var accelerator = device.CreateAccelerator(gpuContext);
Console.WriteLine($"{GetInfoString(accelerator)}"); Console.WriteLine($"{GetInfoString(accelerator)}");
} }
} }
public void SelfMask(Vector3[,] input, out Vector3[,] mask) { public void SelfMask(Vector3[,] input, out Vector3[,] mask) {
var dev = gpuContext.GetPreferredDevice(preferCPU:false); var dev = gpuContext.GetPreferredDevice(false);
int width = input.GetLength(0); var width = input.GetLength(0);
int height = input.GetLength(1); var height = input.GetLength(1);
mask = new Vector3[width, height]; mask = new Vector3[width, height];
using Accelerator accelerator = dev.CreateAccelerator(gpuContext); using var accelerator = dev.CreateAccelerator(gpuContext);
using var buffer = accelerator.Allocate2DDenseX<Vector3>(new (width, height)); using var buffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
buffer.CopyFromCPU(input); buffer.CopyFromCPU(input);
using var maskBuffer = accelerator.Allocate2DDenseX<Vector3>(new (width, height)); using var maskBuffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
var selfMaskKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D, ArrayView2D<Vector3, Stride2D.DenseX>, var selfMaskKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D, ArrayView2D<Vector3, Stride2D.DenseX>,
ArrayView2D<Vector3, Stride2D.DenseX>>(SelfMaskKernel); ArrayView2D<Vector3, Stride2D.DenseX>>(SelfMaskKernel);
selfMaskKernel(new (width, height), buffer.View, maskBuffer.View); selfMaskKernel(new(width, height), buffer.View, maskBuffer.View);
accelerator.Synchronize(); accelerator.Synchronize();
@@ -65,26 +64,26 @@ public partial class SdfKernels {
} }
public void ABMask(Vector3[,] A, Vector3[,] B, out Vector3[,] mask) { public void ABMask(Vector3[,] A, Vector3[,] B, out Vector3[,] mask) {
var dev = gpuContext.GetPreferredDevice(preferCPU:false); var dev = gpuContext.GetPreferredDevice(false);
int width = A.GetLength(0); var width = A.GetLength(0);
int height = A.GetLength(1); var height = A.GetLength(1);
mask = new Vector3[width, height]; mask = new Vector3[width, height];
using Accelerator accelerator = dev.CreateAccelerator(gpuContext); using var accelerator = dev.CreateAccelerator(gpuContext);
using var bufferA = accelerator.Allocate2DDenseX<Vector3>(new (width, height)); using var bufferA = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
bufferA.CopyFromCPU(A); bufferA.CopyFromCPU(A);
using var bufferB = accelerator.Allocate2DDenseX<Vector3>(new (width, height)); using var bufferB = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
bufferB.CopyFromCPU(B); bufferB.CopyFromCPU(B);
using var maskBuffer = accelerator.Allocate2DDenseX<Vector3>(new (width, height)); using var maskBuffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
var abMaskKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D, var abMaskKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D,
ArrayView2D<Vector3, Stride2D.DenseX>, ArrayView2D<Vector3, Stride2D.DenseX>,
ArrayView2D<Vector3, Stride2D.DenseX>, ArrayView2D<Vector3, Stride2D.DenseX>,
ArrayView2D<Vector3, Stride2D.DenseX>>(ABMaskKernel); ArrayView2D<Vector3, Stride2D.DenseX>>(ABMaskKernel);
abMaskKernel(new (width, height), bufferA.View, bufferB.View, maskBuffer.View); abMaskKernel(new(width, height), bufferA.View, bufferB.View, maskBuffer.View);
accelerator.Synchronize(); accelerator.Synchronize();
@@ -92,19 +91,19 @@ public partial class SdfKernels {
} }
public void EdgeDetect(Vector3[,] mask, out Vector3[,] edge) { public void EdgeDetect(Vector3[,] mask, out Vector3[,] edge) {
var dev = gpuContext.GetPreferredDevice(preferCPU:false); var dev = gpuContext.GetPreferredDevice(false);
int width = mask.GetLength(0); var width = mask.GetLength(0);
int height = mask.GetLength(1); var height = mask.GetLength(1);
edge = new Vector3[width, height]; edge = new Vector3[width, height];
using Accelerator accelerator = dev.CreateAccelerator(gpuContext); using var accelerator = dev.CreateAccelerator(gpuContext);
using var buffer = accelerator.Allocate2DDenseX<Vector3>(new (width, height)); using var buffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
buffer.CopyFromCPU(mask); buffer.CopyFromCPU(mask);
var edgeKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D, var edgeKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D,
ArrayView2D<Vector3, Stride2D.DenseX>, uint, uint>(EdgeKernel); ArrayView2D<Vector3, Stride2D.DenseX>, uint, uint>(EdgeKernel);
edgeKernel(new (width, height), buffer.View, (uint)width, (uint)height); edgeKernel(new(width, height), buffer.View, (uint)width, (uint)height);
accelerator.Synchronize(); accelerator.Synchronize();
@@ -112,10 +111,10 @@ public partial class SdfKernels {
} }
public void Sdf(Vector2[] edges, int width, int height, out Vector3[,] sdf) { public void Sdf(Vector2[] edges, int width, int height, out Vector3[,] sdf) {
var dev = gpuContext.GetPreferredDevice(preferCPU:false); var dev = gpuContext.GetPreferredDevice(false);
using Accelerator accelerator = dev.CreateAccelerator(gpuContext); using var accelerator = dev.CreateAccelerator(gpuContext);
using var buffer = accelerator.Allocate2DDenseX<Vector3>(new (width, height)); using var buffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
using var edgeBuffer = accelerator.Allocate1D<Vector2>(edges.Length); using var edgeBuffer = accelerator.Allocate1D<Vector2>(edges.Length);
edgeBuffer.CopyFromCPU(edges); edgeBuffer.CopyFromCPU(edges);
@@ -125,7 +124,7 @@ public partial class SdfKernels {
ArrayView1D<Vector2, Stride1D.Dense>, ArrayView1D<Vector2, Stride1D.Dense>,
int, int>(SdfKernel); int, int>(SdfKernel);
sdfKernel(new (width, height), buffer.View, edgeBuffer.View, width, height); sdfKernel(new(width, height), buffer.View, edgeBuffer.View, width, height);
accelerator.Synchronize(); accelerator.Synchronize();
@@ -133,22 +132,22 @@ public partial class SdfKernels {
} }
public void Gradient(Vector3[,] mask, Vector3[,] sdfa, Vector3[,] sdfb, out Vector3[,] gradient) { public void Gradient(Vector3[,] mask, Vector3[,] sdfa, Vector3[,] sdfb, out Vector3[,] gradient) {
var dev = gpuContext.GetPreferredDevice(preferCPU:false); var dev = gpuContext.GetPreferredDevice(false);
int width = mask.GetLength(0); var width = mask.GetLength(0);
int height = mask.GetLength(1); var height = mask.GetLength(1);
gradient = new Vector3[width, height]; gradient = new Vector3[width, height];
using Accelerator accelerator = dev.CreateAccelerator(gpuContext); using var accelerator = dev.CreateAccelerator(gpuContext);
using var bufferMask = accelerator.Allocate2DDenseX<Vector3>(new (width, height)); using var bufferMask = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
bufferMask.CopyFromCPU(mask); bufferMask.CopyFromCPU(mask);
using var bufferSdfa = accelerator.Allocate2DDenseX<Vector3>(new (width, height)); using var bufferSdfa = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
bufferSdfa.CopyFromCPU(sdfa); bufferSdfa.CopyFromCPU(sdfa);
using var bufferSdfb = accelerator.Allocate2DDenseX<Vector3>(new (width, height)); using var bufferSdfb = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
bufferSdfb.CopyFromCPU(sdfb); bufferSdfb.CopyFromCPU(sdfb);
using var bufferGradient = accelerator.Allocate2DDenseX<Vector3>(new (width, height)); using var bufferGradient = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
var gradientKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D, var gradientKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D,
ArrayView2D<Vector3, Stride2D.DenseX>, ArrayView2D<Vector3, Stride2D.DenseX>,
@@ -156,26 +155,28 @@ public partial class SdfKernels {
ArrayView2D<Vector3, Stride2D.DenseX>, ArrayView2D<Vector3, Stride2D.DenseX>,
ArrayView2D<Vector3, Stride2D.DenseX>>(GradientKernel); ArrayView2D<Vector3, Stride2D.DenseX>>(GradientKernel);
gradientKernel(new (width, height), bufferMask.View, bufferSdfa.View, bufferSdfb.View, bufferGradient.View); gradientKernel(new(width, height), bufferMask.View, bufferSdfa.View, bufferSdfb.View, bufferGradient.View);
accelerator.Synchronize(); accelerator.Synchronize();
gradient = bufferGradient.GetAsArray2D(); gradient = bufferGradient.GetAsArray2D();
}
public void DirectionalBlur(Vector3[,] image, Vector3[,] mask, out Vector3[,] output, float radius = 3f, float step = .5f, float sigma = 1f) { public void DirectionalBlur(Vector3[,] image, Vector3[,] mask, out Vector3[,] output, float radius = 3f,
var dev = gpuContext.GetPreferredDevice(preferCPU:false); float step = .5f, float sigma = 1f) {
int width = image.GetLength(0); var dev = gpuContext.GetPreferredDevice(false);
int height = image.GetLength(1); var width = image.GetLength(0);
var height = image.GetLength(1);
output = new Vector3[width, height]; output = new Vector3[width, height];
using Accelerator accelerator = dev.CreateAccelerator(gpuContext); using var accelerator = dev.CreateAccelerator(gpuContext);
using var imageBuffer = accelerator.Allocate2DDenseX<Vector3>(new (width, height)); using var imageBuffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
imageBuffer.CopyFromCPU(image); imageBuffer.CopyFromCPU(image);
using var maskBuffer = accelerator.Allocate2DDenseX<Vector3>(new (width, height)); using var maskBuffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
maskBuffer.CopyFromCPU(mask); maskBuffer.CopyFromCPU(mask);
using var outputBuffer = accelerator.Allocate2DDenseX<Vector3>(new (width, height)); using var outputBuffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
var blurKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D, var blurKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D,
ArrayView2D<Vector3, Stride2D.DenseX>, ArrayView2D<Vector3, Stride2D.DenseX>,
@@ -183,7 +184,7 @@ public partial class SdfKernels {
ArrayView2D<Vector3, Stride2D.DenseX>, ArrayView2D<Vector3, Stride2D.DenseX>,
float, float, float, int, int>(DirectionalBlurKernel); float, float, float, int, int>(DirectionalBlurKernel);
blurKernel(new (width, height), imageBuffer.View, maskBuffer.View, outputBuffer.View, blurKernel(new(width, height), imageBuffer.View, maskBuffer.View, outputBuffer.View,
radius, step, sigma, width, height); radius, step, sigma, width, height);
accelerator.Synchronize(); accelerator.Synchronize();
@@ -191,9 +192,8 @@ public partial class SdfKernels {
output = outputBuffer.GetAsArray2D(); output = outputBuffer.GetAsArray2D();
} }
private static string GetInfoString(Accelerator a) static string GetInfoString(Accelerator a) {
{ var infoString = new StringWriter();
StringWriter infoString = new StringWriter();
a.PrintInformation(infoString); a.PrintInformation(infoString);
return infoString.ToString(); return infoString.ToString();
} }