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