obs-StreamFX/data/effects/sdf-generator.effect

120 lines
2.6 KiB
Plaintext

// OBS Default
uniform float4x4 ViewProj;
// Inputs
uniform texture2d _image;
uniform float2 _size;
uniform texture2d _sdf; // in, out - swap rendering
uniform float _threshold;
#define NEAR_INFINITE 18446744073709551616.0
#define RANGE 4
sampler_state sdfSampler {
Filter = Point;
AddressU = Clamp;
AddressV = Clamp;
};
sampler_state imageSampler {
Filter = Point;
AddressU = Clamp;
AddressV = Clamp;
};
struct VertDataIn {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
struct VertDataOut {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
VertDataOut VSDefault(VertDataIn v_in)
{
VertDataOut vert_out;
vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj);
vert_out.uv = v_in.uv;
return vert_out;
}
float4 PS_SDFGenerator_v1(VertDataOut v_in) : TARGET
{
float4 outval = float4(0.0, 0.0, v_in.uv.x, v_in.uv.y);
// utility values
float2 uv_step = 1.0 / _size;
float lowest = NEAR_INFINITE;
float2 lowest_source = float2(NEAR_INFINITE, NEAR_INFINITE);
float2 lowest_origin = float2(NEAR_INFINITE, NEAR_INFINITE);
// inputs
float imageA = _image.Sample(imageSampler, v_in.uv).a;
// sdf contains 4 values: R = Positive Distance, G = Negative Distance, BA = UV of nearest edge.
if (imageA > _threshold) {
// Inside
// TODO: Optimize to be O(n*n) instead of (2n*2n)
for (int x = -RANGE; x < RANGE; x++) {
for (int y = -RANGE; y < RANGE; y++) {
if ((x == 0) && (y == 0)) {
continue;
}
float2 dtr = float2(x, y);
float2 dt = uv_step * dtr;
float4 here = _sdf.Sample(sdfSampler, v_in.uv + dt);
float dst = abs(distance(float2(0., 0.), dtr));
if (lowest > (here.g + dst)) {
lowest = here.g + dst;
lowest_source = v_in.uv + dt;
lowest_origin = here.ba;
}
}
}
if (lowest < NEAR_INFINITE) {
outval.g = lowest;
outval.ba = lowest_origin;
}
} else {
// Outside
// TODO: Optimize to be O(n*n) instead of (2n*2n)
for (int x = -RANGE; x < RANGE; x++) {
for (int y = -RANGE; y < RANGE; y++) {
if ((x == 0) && (y == 0)) {
continue;
}
float2 dtr = float2(x, y);
float2 dt = uv_step * dtr;
float4 here = _sdf.Sample(sdfSampler, v_in.uv + dt);
float dst = abs(distance(float2(0., 0.), dtr));
if (lowest > (here.r + dst)) {
lowest = here.r + dst;
lowest_source = v_in.uv + dt;
lowest_origin = here.ba;
}
}
}
if (lowest < NEAR_INFINITE) {
outval.r = lowest;
outval.ba = lowest_origin;
}
}
return outval;
}
technique Draw
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PS_SDFGenerator_v1(v_in);
}
}