Commands/Shaders/Get-OBSGaussianBlurShader.ps1

function Get-OBSGaussianBlurShader {

[Alias('Set-OBSGaussianBlurShader','Add-OBSGaussianBlurShader')]
param(
# Set the ViewProj of OBSGaussianBlurShader
[ComponentModel.DefaultBindingProperty('ViewProj')]
[Single[][]]
$ViewProj,
# Set the image of OBSGaussianBlurShader
[ComponentModel.DefaultBindingProperty('image')]
[String]
$Image,
# Set the imageSize of OBSGaussianBlurShader
[ComponentModel.DefaultBindingProperty('imageSize')]
[Single[]]
$ImageSize,
# Set the imageTexel of OBSGaussianBlurShader
[ComponentModel.DefaultBindingProperty('imageTexel')]
[Single[]]
$ImageTexel,
# Set the u_radius of OBSGaussianBlurShader
[Alias('u_radius')]
[ComponentModel.DefaultBindingProperty('u_radius')]
[Int32]
$URadius,
# Set the u_diameter of OBSGaussianBlurShader
[Alias('u_diameter')]
[ComponentModel.DefaultBindingProperty('u_diameter')]
[Int32]
$UDiameter,
# Set the u_texelDelta of OBSGaussianBlurShader
[Alias('u_texelDelta')]
[ComponentModel.DefaultBindingProperty('u_texelDelta')]
[Single[]]
$UTexelDelta,
# Set the elapsed_time of OBSGaussianBlurShader
[Alias('elapsed_time')]
[ComponentModel.DefaultBindingProperty('elapsed_time')]
[Single]
$ElapsedTime,
# Set the uv_offset of OBSGaussianBlurShader
[Alias('uv_offset')]
[ComponentModel.DefaultBindingProperty('uv_offset')]
[Single[]]
$UvOffset,
# Set the uv_scale of OBSGaussianBlurShader
[Alias('uv_scale')]
[ComponentModel.DefaultBindingProperty('uv_scale')]
[Single[]]
$UvScale,
# Set the uv_pixel_interval of OBSGaussianBlurShader
[Alias('uv_pixel_interval')]
[ComponentModel.DefaultBindingProperty('uv_pixel_interval')]
[Single[]]
$UvPixelInterval,
# Set the kernel of OBSGaussianBlurShader
[ComponentModel.DefaultBindingProperty('kernel')]
[String]
$Kernel,
# Set the kernelTexel of OBSGaussianBlurShader
[ComponentModel.DefaultBindingProperty('kernelTexel')]
[Single[]]
$KernelTexel,
# Set the pixel_size of OBSGaussianBlurShader
[Alias('pixel_size')]
[ComponentModel.DefaultBindingProperty('pixel_size')]
[Single]
$PixelSize,
# The name of the source. This must be provided when adding an item for the first time
[Parameter(ValueFromPipelineByPropertyName)]
[Alias('SceneItemName')]
[String]
$SourceName,
# The name of the filter. If this is not provided, this will default to the shader name.
[Parameter(ValueFromPipelineByPropertyName)]
[String]
$FilterName,
# The inline value of the shader. This will normally be provided as a default parameter, based off of the name.
[Alias('ShaderContent')]
[String]
$ShaderText,
# If set, will force the recreation of a shader that already exists
[Management.Automation.SwitchParameter]
$Force,
# If set, will pass thru the commands that would be sent to OBS (these can be sent at any time with Send-OBS)
[Management.Automation.SwitchParameter]
$PassThru,
# If set, will not wait for a response from OBS (this will be faster, but will not return anything)
[Management.Automation.SwitchParameter]
$NoResponse,
# If set, use the shader elapsed time, instead of the OBS system elapsed time
[ComponentModel.DefaultBindingProperty('use_shader_elapsed_time')]
[Management.Automation.SwitchParameter]
$UseShaderTime
)


process {
$shaderName = 'gaussian-blur'
$ShaderNoun = 'OBSGaussianBlurShader'
if (-not $psBoundParameters['ShaderText']) {    
    $psBoundParameters['ShaderText'] = $ShaderText = '
//Converted to OpenGL by Q-mii & Exeldro March 11, 2022
// OBS Default
uniform float4x4 ViewProj;

// Settings (Shared)
uniform texture2d image;
uniform float2 imageSize;
uniform float2 imageTexel;
uniform int u_radius;
uniform int u_diameter;
uniform float2 u_texelDelta;

uniform float elapsed_time;
uniform float2 uv_offset;
uniform float2 uv_scale;
uniform float2 uv_pixel_interval;

// Settings (Private)
//uniform float registerkernel[25];
uniform texture2d kernel;
uniform float2 kernelTexel;
uniform float pixel_size = 1.0;

sampler_state pointClampSampler {
    Filter = Point;
    AddressU = Clamp;
    AddressV = Clamp;
};

sampler_state bilinearClampSampler {
    Filter = Bilinear;
    AddressU = Clamp;
    AddressV = Clamp;
};

struct VertData {
    float4 pos : POSITION;
    float2 uv : TEXCOORD0;
};

float Gaussian(float x, float o)
{
    float pivalue = 3.1415926535897932384626433832795;
    return (1.0 / (o * sqrt(2.0 * pivalue))) * exp((-(x * x)) / (2.0 * (o * o)));
}

VertData VSDefault(VertData vert_in)
{
    VertData vert_out;
    vert_out.pos = mul(float4(vert_in.pos.xyz, 1.0), ViewProj);
    vert_out.uv = vert_in.uv;
    return vert_out;
}

float4 InternalGaussian(float2 p_uv, float2 p_uvStep, int p_radius,
  texture2d p_image, float2 p_imageTexel)
  {
    float l_gauss = Gaussian(0.0, 1.0);
    float4 l_value = image.Sample(pointClampSampler, p_uv) * l_gauss;
    float2 l_uvoffset = float2(0, 0);
    for (int k = 1; k <= p_radius; k++) {
        l_uvoffset += p_uvStep;
        float l_g = Gaussian(float(k), uv_pixel_interval.x + uv_pixel_interval.y);
        float4 l_p = image.Sample(pointClampSampler, p_uv + l_uvoffset) * l_g;
        float4 l_n = image.Sample(pointClampSampler, p_uv - l_uvoffset) * l_g;
        l_value += l_p + l_n;
        l_gauss += l_g;
    }
    l_value = l_value * (1.0 / l_gauss);
    return l_value;
}

float4 InternalGaussianPrecalculated(float2 p_uv, float2 p_uvStep, int p_radius,
  texture2d p_image, float2 p_imageTexel,
  texture2d p_kernel, float2 p_kernelTexel)
  {
    float4 l_value = image.Sample(pointClampSampler, p_uv)
        * kernel.Sample(pointClampSampler, float2(0, 0)).r;
    float2 l_uvoffset = float2(0, 0);
    for (int k = 1; k <= p_radius; k++) {
        l_uvoffset += p_uvStep;
        float l_g = kernel.Sample(pointClampSampler, p_kernelTexel * k).r;
        float4 l_p = image.Sample(pointClampSampler, p_uv + l_uvoffset) * l_g;
        float4 l_n = image.Sample(pointClampSampler, p_uv - l_uvoffset) * l_g;
        l_value += l_p + l_n;
    }
    return l_value;
}

/*float4 InternalGaussianPrecalculatedNVOptimized(float2 p_uv, int pixel_size,
  texture2d p_image, float2 p_imageTexel,
  texture2d p_kernel, float2 p_kernelTexel)
  {
    if (pixel_size % 2 == 0) {
        float4 l_value = image.Sample(pointClampSampler, p_uv)
            * kernel.Sample(pointClampSampler, float2(0, 0)).r;
        float2 l_uvoffset = p_texel;
        float2 l_koffset = p_kernelTexel;
        for (int k = 1; k <= pixel_size; k++) {
            float l_g = kernel.Sample(pointClampSampler, l_koffset).r;
            float4 l_p = image.Sample(pointClampSampler, p_uv + l_uvoffset) * l_g;
            float4 l_n = image.Sample(pointClampSampler, p_uv - l_uvoffset) * l_g;
            l_value += l_p + l_n;
            l_uvoffset += p_texel;
            l_koffset += p_kernelTexel;
        }
        return l_value;
    } else {
        return InternalGaussianPrecalculated(p_uv, p_image, p_texel, pixel_size, p_kernel, p_kerneltexel);)
    }
}*/

float4 PSGaussian(VertData vert_in) : TARGET
{
    
    float4 color = image.Sample(pointClampSampler, vert_in.uv);

    float intensity = color.r * 0.299 + color.g * 0.587 + color.b * 0.114;

    return InternalGaussian(vert_in.uv, uv_offset, int(sqrt((uv_pixel_interval.x * uv_pixel_interval.x) + (uv_pixel_interval.y * uv_pixel_interval.y))), image, uv_scale);

    /*
    return InternalGaussianPrecalculated(
        vert_in.uv, u_texelDelta, u_radius,
        image, imageTexel,
        kernel, kernelTexel);
    */

    /*
    return InternalGaussianPrecalculatedNVOptimize(
        vert_in.uv, u_texelDelta, u_radius,
        image, imageTexel,
        kernel, kernelTexel);
    */
}

technique Draw
{
    pass
    {
        vertex_shader = VSDefault(vert_in);
        pixel_shader = PSGaussian(vert_in);
    }
}

'

}
$MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2
if (-not $myNoun) {
    $myNoun = $myVerb
    $myVerb = 'Get'    
}
switch -regex ($myVerb) {
    Get {
        $FilterNamePattern = "(?>$(
            if ($FilterName) {
                [Regex]::Escape($FilterName)
            }
            else {
                [Regex]::Escape($ShaderNoun -replace '^OBS' -replace 'Shader$'),[Regex]::Escape($shaderName) -join '|'
            }
        ))"

        if ($SourceName) {
            Get-OBSInput | 
                Where-Object InputName -eq $SourceName |
                Get-OBSSourceFilterList |
                Where-Object FilterName -Match $FilterNamePattern
        } else {
            $obs.Inputs |
                Get-OBSSourceFilterList |
                Where-Object FilterName -Match $FilterNamePattern
        }        
    }
    'Remove' {
        if ($SourceName) {
            Get-OBSInput | 
                Where-Object InputName -eq $SourceName |
                Get-OBSSourceFilterList |
                Where-Object FilterName -Match $FilterNamePattern |
                Remove-OBSSourceFilter
        }
    }
    '(?>Add|Set)' {
        $ShaderSettings = [Ordered]@{}
        :nextParameter foreach ($parameterMetadata in $MyInvocation.MyCommand.Parameters[@($psBoundParameters.Keys)]) {
            foreach ($parameterAttribute in $parameterMetadata.Attributes) {
                if ($parameterAttribute -isnot [ComponentModel.DefaultBindingPropertyAttribute]) { continue }
                $ShaderSettings[$parameterAttribute.Name] = $PSBoundParameters[$parameterMetadata.Name]
                if ($ShaderSettings[$parameterAttribute.Name] -is [switch]) {
                    $ShaderSettings[$parameterAttribute.Name] = $ShaderSettings[$parameterAttribute.Name] -as [bool]
                }
                continue nextParameter
            }            
        }

        if (-not $PSBoundParameters['FilterName']) {
            $filterName = $PSBoundParameters['FilterName'] = $shaderName
        }

        $ShaderFilterSplat = [Ordered]@{
            ShaderSetting = $ShaderSettings
            FilterName = $FilterName
            SourceName = $SourceName
        }        

        foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") {
            if ($PSBoundParameters.ContainsKey($CarryOnParameter)) {
                $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter]
            }
        }

        if (-not $script:CachedShaderFilesFromCommand) {
            $script:CachedShaderFilesFromCommand = @{}
        }

        if ($Home -and -not $script:CachedShaderFilesFromCommand[$shaderName]) {
            $MyObsPowerShellPath = Join-Path $home ".obs-powershell"
            $ThisShaderPath = Join-Path $MyObsPowerShellPath "$shaderName.shader"
            $shaderText | Set-Content -LiteralPath $ThisShaderPath
            $script:CachedShaderFilesFromCommand[$shaderName] = Get-Item -LiteralPath $ThisShaderPath
        }
        if ($script:CachedShaderFilesFromCommand[$shaderName]) {
            $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName
        } else {
            $ShaderFilterSplat.ShaderText = $shaderText
        }        

        if ($myVerb -eq 'Add') {                        
            Add-OBSShaderFilter @ShaderFilterSplat
        } else {
            Set-OBSShaderFilter @ShaderFilterSplat
        }
    }
}

}


}