obs-StreamFX/data/effects/blur/gaussian.effect
Michael Fabian 'Xaymar' Dirks fedc8e075c gfx/blur/gaussian: Refactor Gaussian Blur
Gaussian Blur is another Blur that now supports the new system, increasing the maxium Blur size to 128 and adding support for Rotational and Zoom blur. Various optimizations were done to the actual shader code which further reduced the GPU usage.

Currently the Gaussian curve is recalculated when the blur is first created, which can lead to a short hitch due to it having to search for the correct kernels. This is currently unavoidable and expected behavior until a better solution is found.

Related: #45, #6
2019-04-02 03:50:01 +02:00

146 lines
3.3 KiB
Text

// Parameters:
/// OBS Default
uniform float4x4 ViewProj;
/// Texture
uniform texture2d pImage;
uniform float2 pImageTexel;
/// Blur
uniform float pSize;
uniform float pAngle;
uniform float2 pCenter;
uniform float2 pStepScale;
/// Gaussian
uniform float4 pKernel[32];
#define MAX_BLUR_SIZE 128
// Sampler
sampler_state linearSampler {
Filter = Linear;
AddressU = Clamp;
AddressV = Clamp;
MinLOD = 0;
MaxLOD = 0;
};
// Default Vertex Shader and Data
struct VertDataIn {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
struct VertDataOut {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
VertDataOut VSDefault(VertDataIn vtx) {
VertDataOut vert_out;
vert_out.pos = mul(float4(vtx.pos.xyz, 1.0), ViewProj);
vert_out.uv = vtx.uv;
return vert_out;
}
// Functions
float GetKernelAt(int i) {
return ((float[4])(pKernel[floor(i/4)]))[i%4];
}
// Blur 1 Dimensional
float4 PSBlur1D(VertDataOut vtx) : TARGET {
float4 final = pImage.Sample(linearSampler, vtx.uv)
* GetKernelAt(0);
// Loop unrolling is only possible with a fixed known maximum.
// Some compilers may unroll up to x iterations, but most will not.
for (int n = 1; n <= MAX_BLUR_SIZE; n++) {
float2 nstep = (pImageTexel * pStepScale) * n;
float kernel = GetKernelAt(n);
final += pImage.Sample(linearSampler, vtx.uv + nstep) * kernel;
final += pImage.Sample(linearSampler, vtx.uv - nstep) * kernel;
if (n >= pSize) {
break;
}
}
return final;
}
technique Draw {
pass {
vertex_shader = VSDefault(vtx);
pixel_shader = PSBlur1D(vtx);
}
}
// Blur Rotation
float2 rotate(float2 pt, float angle) {
float cp = cos(angle);
float sp = sin(angle);
float sn = -sp;
return float2((pt.x * cp) + (pt.y * sn), (pt.x * sp) + (pt.y * cp));
}
float2 rotateAround(float2 pt, float2 cpt, float angle) {
return rotate(pt - cpt, angle) + cpt;
}
float4 PSRotate(VertDataOut vtx) : TARGET {
float4 final = pImage.Sample(linearSampler, vtx.uv)
* GetKernelAt(0);
float angstep = pAngle * pStepScale.x;
// Loop unrolling is only possible with a fixed known maximum.
// Some compilers may unroll up to x iterations, but most will not.
for (int n = 1; n <= MAX_BLUR_SIZE; n++) {
float kernel = GetKernelAt(n);
final += pImage.Sample(linearSampler, rotateAround(vtx.uv, pCenter, angstep * n)) * kernel;
final += pImage.Sample(linearSampler, rotateAround(vtx.uv, pCenter, angstep * -n)) * kernel;
if (n >= pSize) {
break;
}
}
return final;
}
technique Rotate {
pass {
vertex_shader = VSDefault(vtx);
pixel_shader = PSRotate(vtx);
}
}
// Blur Zoom
float4 PSZoom(VertDataOut vtx) : TARGET {
float4 final = pImage.Sample(linearSampler, vtx.uv)
* GetKernelAt(0);
// step is calculated from the direction relative to the center
float2 dir = normalize(vtx.uv - pCenter) * pStepScale * pImageTexel;
float dist = distance(vtx.uv, pCenter);
// Loop unrolling is only possible with a fixed known maximum.
// Some compilers may unroll up to x iterations, but most will not.
for (int n = 1; n <= MAX_BLUR_SIZE; n++) {
float kernel = GetKernelAt(n);
final += pImage.Sample(linearSampler, vtx.uv + (dir * n) * dist) * kernel;
final += pImage.Sample(linearSampler, vtx.uv - (dir * n) * dist) * kernel;
if (n >= pSize) {
break;
}
}
return final;
}
technique Zoom {
pass {
vertex_shader = VSDefault(vtx);
pixel_shader = PSZoom(vtx);
}
}