mirror of
https://github.com/Xaymar/obs-StreamFX
synced 2024-11-13 23:35:06 +00:00
filter-blur: Add Linear Box Blur and combine all effects
Linear Box Blur abuses the fact that with Linear Sampling we can sample up to four adjacent texels at the same time and get a correct result for Box Blur back. Using this the total number of sample for Box Blur is reduced by n, making the total either n+1 (Even Radius) or n (Odd Radius). Additionally all blur effect files have been merged into a single blur.effect file to reduce the time required to change a single parameter name. New blur effects should be added as a new technique instead of as a new effect file. See Also: #21 Blur Quality
This commit is contained in:
parent
0ad73bbf67
commit
93df9b50b8
9 changed files with 253 additions and 318 deletions
|
@ -184,7 +184,7 @@ ElseIf(${PropertyPrefix}OBS_DOWNLOAD)
|
||||||
)
|
)
|
||||||
INCLUDE("${libobs_SOURCE_DIR}/cmake/LibObs/LibObsConfig.cmake")
|
INCLUDE("${libobs_SOURCE_DIR}/cmake/LibObs/LibObsConfig.cmake")
|
||||||
Else()
|
Else()
|
||||||
Message(CRITICAL "Impossible case reached, very system stability.")
|
Message(CRITICAL "Impossible case reached, verify system stability.")
|
||||||
Return()
|
Return()
|
||||||
EndIf()
|
EndIf()
|
||||||
|
|
||||||
|
@ -195,15 +195,13 @@ SET(PROJECT_DATA_LOCALE
|
||||||
"${PROJECT_SOURCE_DIR}/data/locale/en-US.ini"
|
"${PROJECT_SOURCE_DIR}/data/locale/en-US.ini"
|
||||||
)
|
)
|
||||||
SET(PROJECT_DATA_EFFECTS
|
SET(PROJECT_DATA_EFFECTS
|
||||||
"${PROJECT_SOURCE_DIR}/data/effects/bilateral-blur.effect"
|
"${PROJECT_SOURCE_DIR}/data/effects/blur.effect"
|
||||||
"${PROJECT_SOURCE_DIR}/data/effects/box-blur.effect"
|
|
||||||
"${PROJECT_SOURCE_DIR}/data/effects/gaussian-blur.effect"
|
|
||||||
"${PROJECT_SOURCE_DIR}/data/effects/displace.effect"
|
|
||||||
"${PROJECT_SOURCE_DIR}/data/effects/color-conversion.effect"
|
"${PROJECT_SOURCE_DIR}/data/effects/color-conversion.effect"
|
||||||
|
"${PROJECT_SOURCE_DIR}/data/effects/displace.effect"
|
||||||
"${PROJECT_SOURCE_DIR}/data/effects/mask.effect"
|
"${PROJECT_SOURCE_DIR}/data/effects/mask.effect"
|
||||||
"${PROJECT_SOURCE_DIR}/data/effects/mip-mapper.effect"
|
|
||||||
"${PROJECT_SOURCE_DIR}/data/effects/mipgen.effect"
|
"${PROJECT_SOURCE_DIR}/data/effects/mipgen.effect"
|
||||||
"${PROJECT_SOURCE_DIR}/data/effects/sdf-generator.effect"
|
"${PROJECT_SOURCE_DIR}/data/effects/sdf-generator.effect"
|
||||||
|
"${PROJECT_SOURCE_DIR}/data/effects/sdf-shadow.effect"
|
||||||
)
|
)
|
||||||
SET(PROJECT_DATA_SHADERS
|
SET(PROJECT_DATA_SHADERS
|
||||||
# "${PROJECT_SOURCE_DIR}/data/shaders/name.effect"
|
# "${PROJECT_SOURCE_DIR}/data/shaders/name.effect"
|
||||||
|
|
|
@ -1,95 +0,0 @@
|
||||||
// OBS Default
|
|
||||||
uniform float4x4 ViewProj;
|
|
||||||
|
|
||||||
// Settings (Shared)
|
|
||||||
uniform texture2d u_image;
|
|
||||||
uniform float2 u_imageSize;
|
|
||||||
uniform float2 u_imageTexel;
|
|
||||||
uniform int u_radius;
|
|
||||||
uniform int u_diameter;
|
|
||||||
uniform float2 u_texelDelta;
|
|
||||||
|
|
||||||
// Settings (Private)
|
|
||||||
uniform float bilateralSmoothing;
|
|
||||||
uniform float bilateralSharpness;
|
|
||||||
|
|
||||||
sampler_state textureSampler {
|
|
||||||
Filter = Point;
|
|
||||||
AddressU = Clamp;
|
|
||||||
AddressV = Clamp;
|
|
||||||
MinLOD = 0;
|
|
||||||
MaxLOD = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bilateral Blur
|
|
||||||
float Bilateral(float x, float sigma) {
|
|
||||||
return 0.39894 * exp(-0.5 * (x*x) / (sigma*sigma)) / sigma;
|
|
||||||
}
|
|
||||||
|
|
||||||
float Bilateral3(float3 v, float sigma) {
|
|
||||||
// First part is Bilateral function (1.0 / (o * sqrt(2.0 * pivalue))) with o = 1
|
|
||||||
return 0.39894 * exp(-0.5 * dot(v,v) / (sigma*sigma)) / sigma;
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 BlurFunc(float2 uv, float4 rgba) {
|
|
||||||
float2 uvOffset = float2(0, 0);
|
|
||||||
|
|
||||||
float Z = 0.0;
|
|
||||||
float bZ = 1.0 / Bilateral(0.0, bilateralSharpness);
|
|
||||||
float3 color = float3(0, 0, 0);
|
|
||||||
for (int k = 1; k <= u_radius; k++) {
|
|
||||||
uvOffset += u_texelDelta;
|
|
||||||
|
|
||||||
// Bilateral Kernel
|
|
||||||
float bKernel = Bilateral(abs(k), bilateralSmoothing);
|
|
||||||
bKernel *= bKernel;
|
|
||||||
float bZKernel = bZ * bKernel;
|
|
||||||
|
|
||||||
// Sample Color
|
|
||||||
float3 l_p = u_image.SampleLevel(textureSampler, uv + uvOffset, 0).rgb;
|
|
||||||
float3 l_n = u_image.SampleLevel(textureSampler, uv - uvOffset, 0).rgb;
|
|
||||||
|
|
||||||
// Bilateral Stuff
|
|
||||||
float l_factor_p = Bilateral3(l_p - rgba.rgb, bilateralSharpness) * bZKernel;
|
|
||||||
float l_factor_n = Bilateral3(l_n - rgba.rgb, bilateralSharpness) * bZKernel;
|
|
||||||
Z = Z + l_factor_p + l_factor_n;
|
|
||||||
|
|
||||||
// Store Color
|
|
||||||
color += l_p * l_factor_p;
|
|
||||||
color += l_n * l_factor_n;
|
|
||||||
}
|
|
||||||
|
|
||||||
return float4(color.rgb / Z, rgba.a);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PSBilateral(VertDataOut v_in) : TARGET {
|
|
||||||
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
|
|
||||||
return BlurFunc(v_in.uv, rgba);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique Draw
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
vertex_shader = VSDefault(v_in);
|
|
||||||
pixel_shader = PSBilateral(v_in);
|
|
||||||
}
|
|
||||||
}
|
|
207
data/effects/blur.effect
Normal file
207
data/effects/blur.effect
Normal file
|
@ -0,0 +1,207 @@
|
||||||
|
// OBS Default
|
||||||
|
uniform float4x4 ViewProj;
|
||||||
|
|
||||||
|
// Settings (Shared)
|
||||||
|
uniform texture2d u_image;
|
||||||
|
uniform float2 u_imageSize;
|
||||||
|
uniform float2 u_imageTexel;
|
||||||
|
uniform int u_radius;
|
||||||
|
uniform int u_diameter;
|
||||||
|
uniform float2 u_texelDelta;
|
||||||
|
|
||||||
|
// Kernel Settings
|
||||||
|
//uniform float registerkernel[25];
|
||||||
|
uniform texture2d kernel;
|
||||||
|
uniform float2 kernelTexel;
|
||||||
|
|
||||||
|
// Bilateral Settings
|
||||||
|
uniform float bilateralSmoothing;
|
||||||
|
uniform float bilateralSharpness;
|
||||||
|
|
||||||
|
// Data
|
||||||
|
sampler_state pointSampler {
|
||||||
|
Filter = Point;
|
||||||
|
AddressU = Clamp;
|
||||||
|
AddressV = Clamp;
|
||||||
|
MinLOD = 0;
|
||||||
|
MaxLOD = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
sampler_state linearSampler {
|
||||||
|
Filter = Linear;
|
||||||
|
AddressU = Clamp;
|
||||||
|
AddressV = Clamp;
|
||||||
|
MinLOD = 0;
|
||||||
|
MaxLOD = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Blur: Box
|
||||||
|
float4 PSBoxBlur(VertDataOut vtx) : TARGET {
|
||||||
|
float4 origin = u_image.SampleLevel(pointSampler, vtx.uv, 0);
|
||||||
|
|
||||||
|
float4 final = origin;
|
||||||
|
for (int k = 1; k <= u_radius; k++) {
|
||||||
|
final += u_image.SampleLevel(pointSampler, vtx.uv + (u_texelDelta * k), 0);
|
||||||
|
final += u_image.SampleLevel(pointSampler, vtx.uv - (u_texelDelta * k), 0);
|
||||||
|
}
|
||||||
|
final /= u_diameter;
|
||||||
|
|
||||||
|
return final;
|
||||||
|
}
|
||||||
|
|
||||||
|
technique Box
|
||||||
|
{
|
||||||
|
pass
|
||||||
|
{
|
||||||
|
vertex_shader = VSDefault(vtx);
|
||||||
|
pixel_shader = PSBoxBlur(vtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Blur: Box (Linear Optimized)
|
||||||
|
// By abusing Linear sampling we can reduce the necessary samples, halving the total samples.
|
||||||
|
float4 PSBoxBlurLinear(VertDataOut vtx) : TARGET {
|
||||||
|
// Radius 4 (Even):
|
||||||
|
// [-4, -3, -2, -1, 0, +1, +2, +3, +4]
|
||||||
|
// ^-S-^ ^-S-^ S ^-S-^ ^-S-^
|
||||||
|
// Total Samples: 5 (n+1)
|
||||||
|
|
||||||
|
// Radius 3 (Odd):
|
||||||
|
// [-3, -2, -1, 0, +1, +2, +3]
|
||||||
|
// ^-S-^ ^-S-^ S ^-S-^
|
||||||
|
// Total Samples: 4 (n)
|
||||||
|
|
||||||
|
// Radius 2 (Even):
|
||||||
|
// [-2, -1, 0, +1, +2]
|
||||||
|
// ^-S-^ S ^-S-^
|
||||||
|
|
||||||
|
float4 final = float4(0, 0, 0, 0);
|
||||||
|
float2 halfTexelDelta = u_texelDelta / 2.0;
|
||||||
|
if (u_radius % 2 == 0) {
|
||||||
|
// Even Numbers require the origin sample in the middle.
|
||||||
|
float4 origin = u_image.SampleLevel(pointSampler, vtx.uv, 0);
|
||||||
|
final = origin;
|
||||||
|
for (int k = 1; k <= u_radius; k+=2) {
|
||||||
|
float2 offset = k * u_texelDelta + halfTexelDelta;
|
||||||
|
final += u_image.SampleLevel(linearSampler, vtx.uv + offset, 0) * 2;
|
||||||
|
final += u_image.SampleLevel(linearSampler, vtx.uv - offset, 0) * 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Odd Numbers put the origin sample in another location.
|
||||||
|
float4 origin = u_image.SampleLevel(pointSampler, vtx.uv + u_texelDelta, 0);
|
||||||
|
float4 group = u_image.SampleLevel(linearSampler, vtx.uv - halfTexelDelta, 0);
|
||||||
|
final = origin + group * 2;
|
||||||
|
|
||||||
|
for (int k = 2; k <= u_radius; k+=2) {
|
||||||
|
float2 offset = k * u_texelDelta + halfTexelDelta;
|
||||||
|
final += u_image.SampleLevel(linearSampler, vtx.uv + offset, 0) * 2;
|
||||||
|
final += u_image.SampleLevel(linearSampler, vtx.uv - offset, 0) * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final /= u_diameter;
|
||||||
|
|
||||||
|
return final;
|
||||||
|
}
|
||||||
|
|
||||||
|
technique BoxLinear
|
||||||
|
{
|
||||||
|
pass
|
||||||
|
{
|
||||||
|
vertex_shader = VSDefault(vtx);
|
||||||
|
pixel_shader = PSBoxBlurLinear(vtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Blur: Gaussian
|
||||||
|
// ToDo: Switch to array Kernel instead of Texture kernel.
|
||||||
|
float4 PSGaussianBlur(VertDataOut vtx) : TARGET {
|
||||||
|
float2 uvOffset = float2(0, 0);
|
||||||
|
float4 final = u_image.SampleLevel(pointSampler, vtx.uv, 0)
|
||||||
|
* kernel.SampleLevel(pointSampler, (float2(0, u_radius - 1) * kernelTexel), 0).r;
|
||||||
|
for (int k = 1; k <= u_radius; k++) {
|
||||||
|
uvOffset += u_texelDelta;
|
||||||
|
float l_g = kernel.SampleLevel(pointSampler, (float2(k, u_radius - 1) * kernelTexel), 0).r;
|
||||||
|
float4 l_p = u_image.SampleLevel(pointSampler, vtx.uv + uvOffset, 0);
|
||||||
|
float4 l_n = u_image.SampleLevel(pointSampler, vtx.uv - uvOffset, 0);
|
||||||
|
final += (l_p + l_n) * l_g;
|
||||||
|
}
|
||||||
|
return final;
|
||||||
|
}
|
||||||
|
|
||||||
|
technique Gaussian
|
||||||
|
{
|
||||||
|
pass
|
||||||
|
{
|
||||||
|
vertex_shader = VSDefault(vtx);
|
||||||
|
pixel_shader = PSGaussianBlur(vtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Blur: Bilateral
|
||||||
|
float Bilateral(float x, float sigma) {
|
||||||
|
return 0.39894 * exp(-0.5 * (x*x) / (sigma*sigma)) / sigma;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bilateral3(float3 v, float sigma) {
|
||||||
|
// First part is Bilateral function (1.0 / (o * sqrt(2.0 * pivalue))) with o = 1
|
||||||
|
return 0.39894 * exp(-0.5 * dot(v,v) / (sigma*sigma)) / sigma;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 PSBilateralBlur(VertDataOut vtx) : TARGET {
|
||||||
|
float4 origin = u_image.SampleLevel(pointSampler, vtx.uv, 0);
|
||||||
|
float2 uvOffset = float2(0, 0);
|
||||||
|
|
||||||
|
float Z = 0.0;
|
||||||
|
float bZ = 1.0 / Bilateral(0.0, bilateralSharpness);
|
||||||
|
float3 color = float3(0, 0, 0);
|
||||||
|
for (int k = 1; k <= u_radius; k++) {
|
||||||
|
uvOffset += u_texelDelta;
|
||||||
|
|
||||||
|
// Bilateral Kernel
|
||||||
|
float bKernel = Bilateral(abs(k), bilateralSmoothing);
|
||||||
|
bKernel *= bKernel;
|
||||||
|
float bZKernel = bZ * bKernel;
|
||||||
|
|
||||||
|
// Sample Color
|
||||||
|
float3 l_p = u_image.SampleLevel(pointSampler, vtx.uv + uvOffset, 0).rgb;
|
||||||
|
float3 l_n = u_image.SampleLevel(pointSampler, vtx.uv - uvOffset, 0).rgb;
|
||||||
|
|
||||||
|
// Bilateral Stuff
|
||||||
|
float l_factor_p = Bilateral3(l_p - origin.rgb, bilateralSharpness) * bZKernel;
|
||||||
|
float l_factor_n = Bilateral3(l_n - origin.rgb, bilateralSharpness) * bZKernel;
|
||||||
|
Z = Z + l_factor_p + l_factor_n;
|
||||||
|
|
||||||
|
// Store Color
|
||||||
|
color += l_p * l_factor_p;
|
||||||
|
color += l_n * l_factor_n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return float4(color.rgb / Z, origin.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
technique Bilateral
|
||||||
|
{
|
||||||
|
pass
|
||||||
|
{
|
||||||
|
vertex_shader = VSDefault(vtx);
|
||||||
|
pixel_shader = PSBilateralBlur(vtx);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,61 +0,0 @@
|
||||||
// Parameters
|
|
||||||
/// OBS
|
|
||||||
uniform float4x4 ViewProj;
|
|
||||||
/// Blur
|
|
||||||
uniform texture2d u_image;
|
|
||||||
uniform float2 u_imageSize;
|
|
||||||
uniform float2 u_imageTexel;
|
|
||||||
uniform int u_radius;
|
|
||||||
uniform int u_diameter;
|
|
||||||
uniform float2 u_texelDelta;
|
|
||||||
|
|
||||||
// Data
|
|
||||||
sampler_state pointSampler {
|
|
||||||
Filter = Point;
|
|
||||||
AddressU = Clamp;
|
|
||||||
AddressV = Clamp;
|
|
||||||
MinLOD = 0;
|
|
||||||
MaxLOD = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Box Blur
|
|
||||||
float4 BlurFunc(float2 uv, float4 rgba) {
|
|
||||||
float4 final = rgba;
|
|
||||||
for (int k = 1; k <= u_radius; k++) {
|
|
||||||
final += u_image.SampleLevel(pointSampler, uv + (u_texelDelta * k), 0);
|
|
||||||
final += u_image.SampleLevel(pointSampler, uv - (u_texelDelta * k), 0);
|
|
||||||
}
|
|
||||||
return final / u_diameter;
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PSBox(VertDataOut v_in) : TARGET {
|
|
||||||
float4 rgba = u_image.SampleLevel(pointSampler, v_in.uv, 0);
|
|
||||||
return BlurFunc(v_in.uv, rgba);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique Draw
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
vertex_shader = VSDefault(v_in);
|
|
||||||
pixel_shader = PSBox(v_in);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
// OBS Default
|
|
||||||
uniform float4x4 ViewProj;
|
|
||||||
|
|
||||||
// Settings (Shared)
|
|
||||||
uniform texture2d u_image;
|
|
||||||
uniform float2 u_imageSize;
|
|
||||||
uniform float2 u_imageTexel;
|
|
||||||
uniform int u_radius;
|
|
||||||
uniform int u_diameter;
|
|
||||||
uniform float2 u_texelDelta;
|
|
||||||
|
|
||||||
// Settings (Private)
|
|
||||||
//uniform float registerkernel[25];
|
|
||||||
uniform texture2d kernel;
|
|
||||||
uniform float2 kernelTexel;
|
|
||||||
|
|
||||||
sampler_state textureSampler {
|
|
||||||
Filter = Point;
|
|
||||||
AddressU = Clamp;
|
|
||||||
AddressV = Clamp;
|
|
||||||
MinLOD = 0;
|
|
||||||
MaxLOD = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
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 BlurFunc(float2 uv, float4 rgba) {
|
|
||||||
float2 uvOffset = float2(0, 0);
|
|
||||||
float4 final = rgba * kernel.SampleLevel(textureSampler, (float2(0, u_radius - 1) * kernelTexel), 0).r;
|
|
||||||
for (int k = 1; k <= u_radius; k++) {
|
|
||||||
uvOffset += u_texelDelta;
|
|
||||||
float l_g = kernel.SampleLevel(textureSampler, (float2(k, u_radius - 1) * kernelTexel), 0).r;
|
|
||||||
float4 l_p = u_image.SampleLevel(textureSampler, uv + uvOffset, 0);
|
|
||||||
float4 l_n = u_image.SampleLevel(textureSampler, uv - uvOffset, 0);
|
|
||||||
final += (l_p + l_n) * l_g;
|
|
||||||
}
|
|
||||||
return final;
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PSGaussian(VertDataOut v_in) : TARGET {
|
|
||||||
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
|
|
||||||
return BlurFunc(v_in.uv, rgba);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique Draw
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
vertex_shader = VSDefault(v_in);
|
|
||||||
pixel_shader = PSGaussian(v_in);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
uniform matrix4 ViewProj;
|
|
||||||
|
|
||||||
uniform texture2d image;
|
|
||||||
uniform float2 imageTexel;
|
|
||||||
uniform int layer;
|
|
||||||
|
|
||||||
sampler_state textureSampler {
|
|
||||||
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 PSAverage(VertDataOut v_in) : TARGET
|
|
||||||
{
|
|
||||||
float4 rgba = 0;
|
|
||||||
for (float x = -1; x <= 1; x++) {
|
|
||||||
for (float y = -1; y <= 1; y++) {
|
|
||||||
rgba += image.Sample(textureSampler, v_in.uv + vec2(x,y) * imageTexel + imageTexel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rgba / 9.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
technique Draw
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
vertex_shader = VSDefault(v_in);
|
|
||||||
pixel_shader = PSAverage(v_in);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -28,8 +28,9 @@ CustomShader.Texture.Type.Source="Source"
|
||||||
# Filter - Blur
|
# Filter - Blur
|
||||||
Filter.Blur="Blur"
|
Filter.Blur="Blur"
|
||||||
Filter.Blur.Type="Type"
|
Filter.Blur.Type="Type"
|
||||||
Filter.Blur.Type.Description="The type of blur to apply:\n- 'Box' smoothes pixels equally.\n- 'Gaussian' applies a gaussian curve to the smoothed pixels.\n- 'Bilateral' is an edge detection variant of 'Gaussian'."
|
Filter.Blur.Type.Description="The type of blur to apply:\n- 'Box' smoothes pixels equally.\n- 'Box Linear' uses linear sampling to reduce the GPU usage, sacrificing minimal quality.\n- 'Gaussian' applies a gaussian curve to the smoothed pixels.\n- 'Bilateral' is an edge detection variant of 'Gaussian'."
|
||||||
Filter.Blur.Type.Box="Box"
|
Filter.Blur.Type.Box="Box"
|
||||||
|
Filter.Blur.Type.BoxLinear="Box Linear"
|
||||||
Filter.Blur.Type.Gaussian="Gaussian"
|
Filter.Blur.Type.Gaussian="Gaussian"
|
||||||
Filter.Blur.Type.Bilateral="Bilateral"
|
Filter.Blur.Type.Bilateral="Bilateral"
|
||||||
Filter.Blur.Size="Size (Pixel)"
|
Filter.Blur.Size="Size (Pixel)"
|
||||||
|
|
|
@ -39,6 +39,7 @@ extern "C" {
|
||||||
|
|
||||||
#define P_TYPE "Filter.Blur.Type"
|
#define P_TYPE "Filter.Blur.Type"
|
||||||
#define P_TYPE_BOX "Filter.Blur.Type.Box"
|
#define P_TYPE_BOX "Filter.Blur.Type.Box"
|
||||||
|
#define P_TYPE_BOXLINEAR "Filter.Blur.Type.BoxLinear"
|
||||||
#define P_TYPE_GAUSSIAN "Filter.Blur.Type.Gaussian"
|
#define P_TYPE_GAUSSIAN "Filter.Blur.Type.Gaussian"
|
||||||
#define P_TYPE_BILATERAL "Filter.Blur.Type.Bilateral"
|
#define P_TYPE_BILATERAL "Filter.Blur.Type.Bilateral"
|
||||||
#define P_SIZE "Filter.Blur.Size"
|
#define P_SIZE "Filter.Blur.Size"
|
||||||
|
@ -137,8 +138,8 @@ bool filter::blur::blur_instance::apply_gaussian_param()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool filter::blur::blur_instance::apply_mask_parameters(std::shared_ptr<gs::effect> effect, gs_texture_t* original_texture,
|
bool filter::blur::blur_instance::apply_mask_parameters(std::shared_ptr<gs::effect> effect,
|
||||||
gs_texture_t* blurred_texture)
|
gs_texture_t* original_texture, gs_texture_t* blurred_texture)
|
||||||
{
|
{
|
||||||
if (effect->has_parameter("image_orig")) {
|
if (effect->has_parameter("image_orig")) {
|
||||||
effect->get_parameter("image_orig").set_texture(original_texture);
|
effect->get_parameter("image_orig").set_texture(original_texture);
|
||||||
|
@ -297,6 +298,7 @@ obs_properties_t* filter::blur::blur_instance::get_properties()
|
||||||
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_TYPE)));
|
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_TYPE)));
|
||||||
obs_property_set_modified_callback2(p, modified_properties, this);
|
obs_property_set_modified_callback2(p, modified_properties, this);
|
||||||
obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_BOX), filter::blur::type::Box);
|
obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_BOX), filter::blur::type::Box);
|
||||||
|
obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_BOXLINEAR), filter::blur::type::BoxLinear);
|
||||||
obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_GAUSSIAN), filter::blur::type::Gaussian);
|
obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_GAUSSIAN), filter::blur::type::Gaussian);
|
||||||
obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_BILATERAL), filter::blur::type::Bilateral);
|
obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_BILATERAL), filter::blur::type::Bilateral);
|
||||||
|
|
||||||
|
@ -396,6 +398,7 @@ void filter::blur::blur_instance::update(obs_data_t* settings)
|
||||||
{
|
{
|
||||||
type = (blur::type)obs_data_get_int(settings, P_TYPE);
|
type = (blur::type)obs_data_get_int(settings, P_TYPE);
|
||||||
blur_effect = blur_factory::get()->get_effect(type);
|
blur_effect = blur_factory::get()->get_effect(type);
|
||||||
|
blur_technique = blur_factory::get()->get_technique(type);
|
||||||
size = (uint64_t)obs_data_get_int(settings, P_SIZE);
|
size = (uint64_t)obs_data_get_int(settings, P_SIZE);
|
||||||
|
|
||||||
// bilateral blur
|
// bilateral blur
|
||||||
|
@ -620,8 +623,6 @@ void filter::blur::blur_instance::video_render(gs_effect_t* effect)
|
||||||
std::make_tuple("Vertical", vertical_rendertarget, 0.0f, 1.0f / baseH),
|
std::make_tuple("Vertical", vertical_rendertarget, 0.0f, 1.0f / baseH),
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string pass = "Draw";
|
|
||||||
|
|
||||||
for (auto v : kvs) {
|
for (auto v : kvs) {
|
||||||
const char* name = std::get<0>(v);
|
const char* name = std::get<0>(v);
|
||||||
gs_texrender_t* rt = std::get<1>(v);
|
gs_texrender_t* rt = std::get<1>(v);
|
||||||
|
@ -649,7 +650,7 @@ void filter::blur::blur_instance::video_render(gs_effect_t* effect)
|
||||||
gs_clear(GS_CLEAR_COLOR | GS_CLEAR_DEPTH, &black, 0, 0);
|
gs_clear(GS_CLEAR_COLOR | GS_CLEAR_DEPTH, &black, 0, 0);
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
while (gs_effect_loop(blur_effect->get_object(), pass.c_str())) {
|
while (gs_effect_loop(this->blur_effect->get_object(), this->blur_technique.c_str())) {
|
||||||
gs_draw_sprite(intermediate, 0, baseW, baseH);
|
gs_draw_sprite(intermediate, 0, baseW, baseH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -812,27 +813,9 @@ void filter::blur::blur_factory::on_list_fill()
|
||||||
obs_enter_graphics();
|
obs_enter_graphics();
|
||||||
|
|
||||||
{
|
{
|
||||||
char* file = obs_module_file("effects/box-blur.effect");
|
char* file = obs_module_file("effects/blur.effect");
|
||||||
try {
|
try {
|
||||||
effects.insert_or_assign(type::Box, std::make_shared<gs::effect>(file));
|
blur_effect = std::make_shared<gs::effect>(file);
|
||||||
} catch (std::runtime_error ex) {
|
|
||||||
P_LOG_ERROR("<filter-blur> Loading effect '%s' failed with error(s): %s", file, ex.what());
|
|
||||||
}
|
|
||||||
bfree(file);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char* file = obs_module_file("effects/gaussian-blur.effect");
|
|
||||||
try {
|
|
||||||
effects.insert_or_assign(type::Gaussian, std::make_shared<gs::effect>(file));
|
|
||||||
} catch (std::runtime_error ex) {
|
|
||||||
P_LOG_ERROR("<filter-blur> Loading effect '%s' failed with error(s): %s", file, ex.what());
|
|
||||||
}
|
|
||||||
bfree(file);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char* file = obs_module_file("effects/bilateral-blur.effect");
|
|
||||||
try {
|
|
||||||
effects.insert_or_assign(type::Bilateral, std::make_shared<gs::effect>(file));
|
|
||||||
} catch (std::runtime_error ex) {
|
} catch (std::runtime_error ex) {
|
||||||
P_LOG_ERROR("<filter-blur> Loading effect '%s' failed with error(s): %s", file, ex.what());
|
P_LOG_ERROR("<filter-blur> Loading effect '%s' failed with error(s): %s", file, ex.what());
|
||||||
}
|
}
|
||||||
|
@ -864,7 +847,7 @@ void filter::blur::blur_factory::on_list_fill()
|
||||||
void filter::blur::blur_factory::on_list_empty()
|
void filter::blur::blur_factory::on_list_empty()
|
||||||
{
|
{
|
||||||
obs_enter_graphics();
|
obs_enter_graphics();
|
||||||
effects.clear();
|
blur_effect.reset();
|
||||||
kernels.clear();
|
kernels.clear();
|
||||||
color_converter_effect.reset();
|
color_converter_effect.reset();
|
||||||
mask_effect.reset();
|
mask_effect.reset();
|
||||||
|
@ -1034,7 +1017,22 @@ void filter::blur::blur_factory::scene_destroy_handler(void* ptr, calldata_t* da
|
||||||
|
|
||||||
std::shared_ptr<gs::effect> filter::blur::blur_factory::get_effect(filter::blur::type type)
|
std::shared_ptr<gs::effect> filter::blur::blur_factory::get_effect(filter::blur::type type)
|
||||||
{
|
{
|
||||||
return effects.at(type);
|
return blur_effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string filter::blur::blur_factory::get_technique(filter::blur::type type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case type::Box:
|
||||||
|
return "Box";
|
||||||
|
case type::BoxLinear:
|
||||||
|
return "BoxLinear";
|
||||||
|
case type::Gaussian:
|
||||||
|
return "Gaussian";
|
||||||
|
case type::Bilateral:
|
||||||
|
return "Bilateral";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<gs::effect> filter::blur::blur_factory::get_color_converter_effect()
|
std::shared_ptr<gs::effect> filter::blur::blur_factory::get_color_converter_effect()
|
||||||
|
|
|
@ -42,6 +42,7 @@ namespace filter {
|
||||||
namespace blur {
|
namespace blur {
|
||||||
enum type : int64_t {
|
enum type : int64_t {
|
||||||
Box,
|
Box,
|
||||||
|
BoxLinear,
|
||||||
Gaussian,
|
Gaussian,
|
||||||
Bilateral,
|
Bilateral,
|
||||||
};
|
};
|
||||||
|
@ -61,6 +62,7 @@ namespace filter {
|
||||||
|
|
||||||
// blur
|
// blur
|
||||||
std::shared_ptr<gs::effect> blur_effect;
|
std::shared_ptr<gs::effect> blur_effect;
|
||||||
|
std::string blur_technique;
|
||||||
filter::blur::type type;
|
filter::blur::type type;
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
|
|
||||||
|
@ -138,7 +140,7 @@ namespace filter {
|
||||||
std::shared_ptr<gs::effect> color_converter_effect;
|
std::shared_ptr<gs::effect> color_converter_effect;
|
||||||
std::shared_ptr<gs::effect> mask_effect;
|
std::shared_ptr<gs::effect> mask_effect;
|
||||||
|
|
||||||
std::map<filter::blur::type, std::shared_ptr<gs::effect>> effects;
|
std::shared_ptr<gs::effect> blur_effect;
|
||||||
std::map<filter::blur::type, std::shared_ptr<gs::texture>> kernels;
|
std::map<filter::blur::type, std::shared_ptr<gs::texture>> kernels;
|
||||||
|
|
||||||
std::map<std::string, obs_scene_t*> scenes;
|
std::map<std::string, obs_scene_t*> scenes;
|
||||||
|
@ -177,6 +179,8 @@ namespace filter {
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<gs::effect> get_effect(filter::blur::type type);
|
std::shared_ptr<gs::effect> get_effect(filter::blur::type type);
|
||||||
|
|
||||||
|
std::string get_technique(filter::blur::type type);
|
||||||
|
|
||||||
std::shared_ptr<gs::effect> get_color_converter_effect();
|
std::shared_ptr<gs::effect> get_color_converter_effect();
|
||||||
|
|
||||||
std::shared_ptr<gs::effect> get_mask_effect();
|
std::shared_ptr<gs::effect> get_mask_effect();
|
||||||
|
|
Loading…
Reference in a new issue