mirror of
https://github.com/Xaymar/obs-StreamFX
synced 2024-11-11 06:15:05 +00:00
011bee032a
While the previous method worked, it matches no other implementation including a reference implementation. The new implementation almost perfectly matches the reference implementation and uses oversampling to achieve the goal. This has the downside of limiting the blur size to just 64, but it is necessary in order to achieve correct results. Fixes #573
124 lines
4 KiB
Text
124 lines
4 KiB
Text
#include "common.effect"
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Uniforms
|
|
//------------------------------------------------------------------------------
|
|
// This shader requires that pSize is the number of samples, not the size of the
|
|
// kernel. That way oversampling can be performed, which is much more accurate than
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Defines
|
|
//------------------------------------------------------------------------------
|
|
#define MAX_SAMPLES 128
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Technique: Directional / Area
|
|
//------------------------------------------------------------------------------
|
|
float4 PSBlur1D(VertexInformation vtx) : TARGET {
|
|
float2 uvstep = pImageTexel * pStepScale;
|
|
float weights = 0;
|
|
|
|
// Move to texel center.
|
|
vtx.uv.xy += pImageTexel.xy / 2.;
|
|
|
|
// Calculate the actual Gaussian Blur
|
|
// 1. Sample the center immediately.
|
|
float kernel = kernelAt(0);
|
|
weights += kernel;
|
|
float4 final = pImage.Sample(LinearClampSampler, vtx.uv) * kernel;
|
|
// 2. Then sample both + and - coordinates in one go to reduce code iterations.
|
|
for (uint step = 1; (step < pSize) && (step < MAX_SAMPLES); step++) {
|
|
float2 offset = uvstep * step;
|
|
kernel = kernelAt(step);
|
|
weights += kernel * 2;
|
|
|
|
final += pImage.Sample(LinearClampSampler, vtx.uv + offset) * kernel;
|
|
final += pImage.Sample(LinearClampSampler, vtx.uv - offset) * kernel;
|
|
}
|
|
// 3. Ensure we always have a total of 1.0, even if the kernel is bad.
|
|
final /= weights;
|
|
|
|
return final;
|
|
}
|
|
|
|
technique Draw {
|
|
pass {
|
|
vertex_shader = VSDefault(vtx);
|
|
pixel_shader = PSBlur1D(vtx);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Technique: Rotate
|
|
//------------------------------------------------------------------------------
|
|
float4 PSRotate(VertexInformation vtx) : TARGET {
|
|
float angstep = pAngle * pStepScale.x;
|
|
float weights = 0.;
|
|
|
|
// Move to texel center.
|
|
vtx.uv.xy += pImageTexel.xy / 2.;
|
|
|
|
// Calculate the actual Gaussian Blur
|
|
// 1. Sample the center immediately.
|
|
float kernel = kernelAt(0);
|
|
weights += kernel;
|
|
float4 final = pImage.Sample(LinearClampSampler, vtx.uv) * kernel;
|
|
// 2. Then sample both + and - coordinates in one go to reduce code iterations.
|
|
for (uint step = 1; (step < pSize) && (step < MAX_SAMPLES); step++) {
|
|
float offset = angstep * step;
|
|
kernel = kernelAt(step);
|
|
weights += kernel * 2;
|
|
|
|
final += pImage.Sample(LinearClampSampler, rotateAround(vtx.uv, pCenter, offset)) * kernel;
|
|
final += pImage.Sample(LinearClampSampler, rotateAround(vtx.uv, pCenter, -offset)) * kernel;
|
|
}
|
|
// 3. Ensure we always have a total of 1.0, even if the kernel is bad.
|
|
final /= weights;
|
|
|
|
return final;
|
|
}
|
|
|
|
technique Rotate {
|
|
pass {
|
|
vertex_shader = VSDefault(vtx);
|
|
pixel_shader = PSRotate(vtx);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Technique: Zoom
|
|
//------------------------------------------------------------------------------
|
|
float4 PSZoom(VertexInformation vtx) : TARGET {
|
|
float2 dir = normalize(vtx.uv - pCenter) * pStepScale * pImageTexel;
|
|
float dist = distance(vtx.uv, pCenter);
|
|
float weights = 0.;
|
|
|
|
// Move to texel center.
|
|
vtx.uv.xy += pImageTexel.xy / 2.;
|
|
|
|
// Calculate the actual Gaussian Blur
|
|
// 1. Sample the center immediately.
|
|
float kernel = kernelAt(0);
|
|
weights += kernel;
|
|
float4 final = pImage.Sample(LinearClampSampler, vtx.uv) * kernel;
|
|
// 2. Then sample both + and - coordinates in one go to reduce code iterations.
|
|
for (uint step = 1; (step < pSize) && (step < MAX_SAMPLES); step++) {
|
|
float2 offset = dir * step * dist;
|
|
kernel = kernelAt(step);
|
|
weights += kernel * 2;
|
|
|
|
final += pImage.Sample(LinearClampSampler, vtx.uv + offset) * kernel;
|
|
final += pImage.Sample(LinearClampSampler, vtx.uv - offset) * kernel;
|
|
}
|
|
// 3. Ensure we always have a total of 1.0, even if the kernel is bad.
|
|
final /= weights;
|
|
|
|
return final;
|
|
}
|
|
|
|
technique Zoom {
|
|
pass {
|
|
vertex_shader = VSDefault(vtx);
|
|
pixel_shader = PSZoom(vtx);
|
|
}
|
|
}
|