diff --git a/CHANGELOG.md b/CHANGELOG.md index c6f75620..54f80ad4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,32 @@ > Like It? [Star It](https://github.com/StartAutomating/obs-powershell) > Love It? [Support It](https://github.com/sponsors/StartAutomating) +## obs-powershell 0.2.1: + +* New General Purpose Commands + * Start-OBS (#220) + * Stop-OBS (#226) +* New Shader Commands: + * Get-OBS3dPanelShader + * Get-OBSAudioShader + * Get-OBSCubeRotatingShader + * Get-OBSDisplacementMapAdvancedInvertShader + * Get-OBSDisplacementMapAdvancedShader + * Get-OBSDisplacementMapInvertShader + * Get-OBSDisplacementMapShader + * Get-OBSGlitchPeriodicShader + * Get-OBSHardBlinkShader + * Get-OBSMotionBlurShader + * Get-OBSNoiseShader + * Get-OBSNormalMapShader + * Get-OBSPerspectiveShader + * Get-OBSQuadrilateralCropShader + * Get-OBSRepeatGridCenterCropShader + * Get-OBSWalkingDeadPixelFixerShader + * Get-OBSZoomBlurTransitionShader + +--- + ## obs-powershell 0.2.0.1: * Fixing `Watch-OBS` (Fixes #216) diff --git a/Commands/Shaders/Get-OBS3dPanelShader.ps1 b/Commands/Shaders/Get-OBS3dPanelShader.ps1 new file mode 100644 index 00000000..bef20bdf --- /dev/null +++ b/Commands/Shaders/Get-OBS3dPanelShader.ps1 @@ -0,0 +1,450 @@ +function Get-OBS3dPanelShader { + +[Alias('Set-OBS3dPanelShader','Add-OBS3dPanelShader')] +param( +# Set the credits of OBS3dPanelShader +[ComponentModel.DefaultBindingProperty('credits')] +[String] +$Credits, +# Set the scale of OBS3dPanelShader +[ComponentModel.DefaultBindingProperty('scale')] +[Single] +$Scale, +# Set the tilt_x_deg of OBS3dPanelShader +[Alias('tilt_x_deg')] +[ComponentModel.DefaultBindingProperty('tilt_x_deg')] +[Single] +$TiltXDeg, +# Set the tilt_y_deg of OBS3dPanelShader +[Alias('tilt_y_deg')] +[ComponentModel.DefaultBindingProperty('tilt_y_deg')] +[Single] +$TiltYDeg, +# Set the tilt_z_deg of OBS3dPanelShader +[Alias('tilt_z_deg')] +[ComponentModel.DefaultBindingProperty('tilt_z_deg')] +[Single] +$TiltZDeg, +# Set the pos_x of OBS3dPanelShader +[Alias('pos_x')] +[ComponentModel.DefaultBindingProperty('pos_x')] +[Single] +$PosX, +# Set the pos_y of OBS3dPanelShader +[Alias('pos_y')] +[ComponentModel.DefaultBindingProperty('pos_y')] +[Single] +$PosY, +# Set the thickness of OBS3dPanelShader +[ComponentModel.DefaultBindingProperty('thickness')] +[Single] +$Thickness, +# Set the radius_fb of OBS3dPanelShader +[Alias('radius_fb')] +[ComponentModel.DefaultBindingProperty('radius_fb')] +[Single] +$RadiusFb, +# Set the brightness of OBS3dPanelShader +[ComponentModel.DefaultBindingProperty('brightness')] +[Single] +$Brightness, +# Set the light_position of OBS3dPanelShader +[Alias('light_position')] +[ComponentModel.DefaultBindingProperty('light_position')] +[Int32] +$LightPosition, +# Set the wiggle of OBS3dPanelShader +[ComponentModel.DefaultBindingProperty('wiggle')] +[Single] +$Wiggle, +# Set the wiggle_rot of OBS3dPanelShader +[Alias('wiggle_rot')] +[ComponentModel.DefaultBindingProperty('wiggle_rot')] +[Management.Automation.SwitchParameter] +$WiggleRot, +# 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 = '3d-panel' +$ShaderNoun = 'OBS3dPanelShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//based on https://x.com/HoraiChan/status/1986268258883010766 + +uniform string credits< + string widget_type = "info"; +> = "Based on effect by Horaiken"; + +uniform float scale< + string label = "大きさ / Scale"; + string widget_type = "slider"; + float minimum = 0.25; + float maximum = 3.00; + float step = 0.001; +> = 1.0; +uniform float tilt_x_deg< + string label = "縦方向の傾き(X) / Tilt (X)"; + string widget_type = "slider"; + float minimum = -360.0; + float maximum = 360.00; + float step = 0.1; +> = 20.0; +uniform float tilt_y_deg< + string label = "横方向の傾き(Y) / Tilt (Y)"; + string widget_type = "slider"; + float minimum = -360.0; + float maximum = 360.00; + float step = 0.1; +> = 35.0; +uniform float tilt_z_deg< + string label = "回転(Z) / Roll (Z)"; + string widget_type = "slider"; + float minimum = -360.0; + float maximum = 360.00; + float step = 0.1; +> = 0.0; +uniform float pos_x< + string label = "横位置 / Horizontal Position"; + string widget_type = "slider"; + float minimum = -1.00; + float maximum = 1.00; + float step = 0.0001; +> = 0.0; +uniform float pos_y< + string label = "縦位置 / Vertical Position"; + string widget_type = "slider"; + float minimum = -1.00; + float maximum = 1.00; + float step = 0.0001; +> = 0.0; +uniform float thickness< + string label = "厚み / Thickness"; + string widget_type = "slider"; + float minimum = 0.00; + float maximum = 0.1; + float step = 0.001; +> = 0.03; +uniform float radius_fb< + string label = "角丸 / Corner Radius"; + string widget_type = "slider"; + float minimum = 0.00; + float maximum = 1.00; + float step = 0.01; +> = 0.2; +uniform float brightness< + string label = "明るさ / Brightness"; + string widget_type = "slider"; + float minimum = 0.00; + float maximum = 2.00; + float step = 0.01; +> = 1.2; +uniform int light_position < + string label = "照明の位置 / Light Direction"; + string widget_type = "select"; + int option_0_value = 0; + string option_0_label = "左側に光 / Light From Left"; + int option_1_value = 1; + string option_1_label = "右側に光 / Light From Right"; +> = 0; +uniform float wiggle < + string label = "ゆらゆら / Wiggle"; + string widget_type = "slider"; + float minimum = 0.00; + float maximum = 2.50; + float step = 0.01; +> = 0.0; +uniform bool wiggle_rot < + string label = "角度もゆらゆら / Wiggle Rotation"; +>; + +float hash1(float n){ return frac(sin(n)*43758.5453123); } + +float noise1D(float x) { + float i = floor(x); + float f = frac(x); + float u = f*f*(3.0 - 2.0*f); + return lerp(hash1(i), hash1(i+1.0), u); // 0..1 +} + +float fbm1D(float x) { + float v = 0.0; + float a = 0.5; + float f = 1.0; + for(int k=0;k<4;k++){ + v += a * noise1D(x * f); + f *= 2.0; + a *= 0.5; + } + return v; +} + +float saturate(float x) { return clamp(x, 0.0, 1.0); } + +float3 rotateX(float3 p, float a){ float c=cos(a), s=sin(a); return float3(p.x, c*p.y - s*p.z, s*p.y + c*p.z); } +float3 rotateY(float3 p, float a){ float c=cos(a), s=sin(a); return float3( c*p.x + s*p.z, p.y, -s*p.x + c*p.z); } +float3 rotateZ(float3 p, float a){ float c=cos(a), s=sin(a); return float3(c*p.x - s*p.y, s*p.x + c*p.y, p.z); } + +// 2D 角丸長方形 SDF(中心、半径 bxy, 角丸 r) +float sdRoundRect2D(float2 p, float2 bxy, float r) { + float2 q = abs(p) - bxy + r; + return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - r; +} + +// 正面シルエット角丸 + Z方向に押し出し +float sdFrontViewRoundedPrism(float3 p, float3 b, float r_fb_norm) { + float r_fb = saturate(r_fb_norm) * (0.999 * min(b.x, b.y)); + float a = sdRoundRect2D(p.xy, b.xy, r_fb); + float dz = abs(p.z) - b.z; + return max(a, dz); +} + +// 法線 +float3 calcNormal(float3 p, float3 b, float rfb) { + const float e = 0.001; + float3 ex=float3(e,0,0), ey=float3(0,e,0), ez=float3(0,0,e); + float dx = sdFrontViewRoundedPrism(p+ex,b,rfb) - sdFrontViewRoundedPrism(p-ex,b,rfb); + float dy = sdFrontViewRoundedPrism(p+ey,b,rfb) - sdFrontViewRoundedPrism(p-ey,b,rfb); + float dz = sdFrontViewRoundedPrism(p+ez,b,rfb) - sdFrontViewRoundedPrism(p-ez,b,rfb); + return normalize(float3(dx,dy,dz)); +} + +// 照明 +float3 shade(float3 n, float3 v) { + float3 l; + if (light_position == 0) { // 左から光 + l = normalize(float3(-1.0, -0.1, 1.0)); + } + else { // 右から光 + l = normalize(float3( 1.0, -0.1, 1.0)); + } + float diff = saturate(dot(n,l)); + float rim = pow(1.0 - saturate(dot(n,v)), 2.0); + float li = 0.25 + 0.75*diff + 0.08*rim; + return float3(li, li, li); +} + +float4 mainImage(VertData v_in) : TARGET { + float2 uv = v_in.uv; + + // 画面座標(短辺基準) + float aspect = uv_size.x / uv_size.y; + float2 ndc = uv * 2.0 - 1.0; + ndc += float2(pos_x, pos_y) * -1.0 * (scale + 1.0); + float2 p2 = ndc; + p2.x *= aspect; + + // カメラ設定 + float3 ro = float3(0.0, 0.0, 3.2); + float3 rd = normalize(float3(p2, -4.0)); + + // 回転(Z→Y→X の順に逆回転) + float ax=radians(tilt_x_deg), ay=radians(tilt_y_deg), az=radians(tilt_z_deg); + ro = rotateX(rotateY(rotateZ(ro, -az), -ay), -ax); + rd = normalize(rotateX(rotateY(rotateZ(rd, -az), -ay), -ax)); + + // 画面フィット(短辺基準)+ 厚み + float2 baseXY; + if (aspect > 1.0) { + baseXY = float2(1.0, 1.0 / aspect); + } else { + const float portraitMargin = 0.6; + baseXY = float2(aspect * portraitMargin, 1.0 * portraitMargin); + } + float3 b = float3(baseXY, thickness) * max(scale, 0.0001); + + // Wiggle + float diag = length(2.0 * b); + float amp = 0.05 * wiggle * diag; + const float WSPD = 0.1; + + // 各軸に独立ノイズ + float wx = (fbm1D(elapsed_time*WSPD + 13.37) * 2.0 - 1.0) * amp; + float wy = (fbm1D(elapsed_time*WSPD + 47.11) * 2.0 - 1.0) * amp; + float wz = (fbm1D(elapsed_time*WSPD + 91.73) * 2.0 - 1.0) * amp * 0.35; + float3 woff = float3(wx, wy, wz); + + float rotAmp = radians(12.0) * wiggle; + + float wobX = (fbm1D(elapsed_time*WSPD + 128.31) * 2.0 - 1.0) * rotAmp; + float wobY = (fbm1D(elapsed_time*WSPD + 299.91) * 2.0 - 1.0) * rotAmp; + + float3 ro2 = ro; + float3 rd2 = rd; + + if (wiggle_rot) { + ro2 = rotateX(ro2, wobX); + ro2 = rotateY(ro2, wobY); + rd2 = rotateX(rd2, wobX); + rd2 = rotateY(rd2, wobY); + } + + float t = 0.0; + float d = 0.0; + bool hit = false; + for (int i=0; i<64; i++) { + float3 pos = ro2 + rd2 * t; + d = sdFrontViewRoundedPrism(pos - woff, b, radius_fb); + if (d < 0.001) { hit = true; break; } + t += d; + if (t > 8.0) break; + } + + // ヒットしなければ完全透明(元ソースは非表示) + if (!hit) return float4(0.0, 0.0, 0.0, 0.0); + + float3 pos = ro2 + rd2 * t; + float3 pObj = pos - woff; + float3 n = calcNormal(pObj, b, radius_fb); + float3 vdir = normalize(-rd2); + + // テクスチャ貼り付け + float frontMask = smoothstep(0.5, 0.8, dot(n, float3(0.0, 0.0, 1.0))); + float2 uvTex = (pObj.xy / b.xy) * 0.5 + 0.5; + + // サンプル(Address Clamp なので側面/背面は端ピクセルが“引き伸ばし”) + float4 texFront = image.Sample(textureSampler, uvTex); + float4 texEdge = image.Sample(textureSampler, uvTex); + float4 tex = lerp(texEdge, texFront, frontMask); + + // フロント面エッジ・ハイライト(細い線) + float r_fb = saturate(radius_fb) * (0.999 * min(b.x, b.y)); + float a_xy = sdRoundRect2D(pObj.xy, b.xy, r_fb); // XY角丸SDF + float edgeWidth = 0.02 * min(b.x, b.y); + float edgeIntensity = 0.6; + float edgeProx = 1.0 - saturate(abs(a_xy) / edgeWidth); + float edgeMask = frontMask * edgeProx; + tex.rgb *= (1.0 + edgeMask * edgeIntensity); + + // 照明 + float3 lightTerm = shade(n, vdir); + tex.rgb *= lightTerm; + + // 明るさスライダ + tex.rgb *= brightness; + + // 出力 + return float4(tex.rgb, 1.0); +} + +' +} +$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 + } + } +} + +} + + +} + diff --git a/Commands/Shaders/Get-OBSAsciiShader.ps1 b/Commands/Shaders/Get-OBSAsciiShader.ps1 index 867c0cbc..9b910a98 100644 --- a/Commands/Shaders/Get-OBSAsciiShader.ps1 +++ b/Commands/Shaders/Get-OBSAsciiShader.ps1 @@ -118,8 +118,8 @@ float2 mod(float2 x, float2 y) float4 mainImage( VertData v_in ) : TARGET { - float2 iResolution = uv_size*uv_scale; - float2 pix = v_in.pos.xy; + float2 iResolution = uv_size; + float2 pix = v_in.uv * iResolution; float4 c = image.Sample(textureSampler, floor(pix/float2(scale*8.0,scale*8.0))*float2(scale*8.0,scale*8.0)/iResolution.xy); float gray = 0.3 * c.r + 0.59 * c.g + 0.11 * c.b; diff --git a/Commands/Shaders/Get-OBSAudioShader.ps1 b/Commands/Shaders/Get-OBSAudioShader.ps1 new file mode 100644 index 00000000..fcfbb990 --- /dev/null +++ b/Commands/Shaders/Get-OBSAudioShader.ps1 @@ -0,0 +1,190 @@ +function Get-OBSAudioShader { + +[Alias('Set-OBSAudioShader','Add-OBSAudioShader')] +param( +# Set the audio_peak of OBSAudioShader +[Alias('audio_peak')] +[ComponentModel.DefaultBindingProperty('audio_peak')] +[Single] +$AudioPeak, +# Set the audio_magnitude of OBSAudioShader +[Alias('audio_magnitude')] +[ComponentModel.DefaultBindingProperty('audio_magnitude')] +[Single] +$AudioMagnitude, +# Set the intensity of OBSAudioShader +[ComponentModel.DefaultBindingProperty('intensity')] +[Single] +$Intensity, +# 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 = 'audio' +$ShaderNoun = 'OBSAudioShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Audio shader example showing the difference between audio_peak and audio_magnitude. +// Left half uses audio_peak (red), right half uses audio_magnitude (blue). +uniform float audio_peak; +uniform float audio_magnitude; + +uniform float intensity < + string label = "Audio intensity"; + string widget_type = "slider"; + float minimum = 0.1; + float maximum = 3.0; + float step = 0.1; +> = 1.0; + +float4 mainImage(VertData v_in) : TARGET { + float4 color = image.Sample(textureSampler, v_in.uv); + + // Split screen based on UV coordinate + if (v_in.uv.x < 0.5) { + // Left half: audio_peak (instantaneous spikes, more reactive) + // Tint with red to show peak activity. + float peak_strength = audio_peak * intensity; + float3 peak_color = color.rgb + float3(peak_strength, 0, 0); + return float4(peak_color, color.a); + } else { + // Right half: audio_magnitude (RMS/averaged levels, smoother) + // Tint with blue to show magnitude activity. + float mag_strength = audio_magnitude * intensity; + float3 mag_color = color.rgb + float3(0, 0, mag_strength); + return float4(mag_color, color.a); + } +} + +/* +EXPLANATION: +- audio_peak: Shows instantaneous maximum levels, very responsive to drums/percussion. +- audio_magnitude: Shows RMS (Root Mean Square) levels, smoother and represents sustained audio. + +TYPICAL BEHAVIOR: +- With music containing drums: Left side (peak) will flash more dramatically on beats. +- With sustained tones: Right side (magnitude) will show more consistent levels. +- Peak reacts faster to sudden sounds, magnitude is more stable for smooth effects. +*/ + +' +} +$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 + } + } +} + +} + + +} + diff --git a/Commands/Shaders/Get-OBSCubeRotatingShader.ps1 b/Commands/Shaders/Get-OBSCubeRotatingShader.ps1 new file mode 100644 index 00000000..b60a0522 --- /dev/null +++ b/Commands/Shaders/Get-OBSCubeRotatingShader.ps1 @@ -0,0 +1,234 @@ +function Get-OBSCubeRotatingShader { + +[Alias('Set-OBSCubeRotatingShader','Add-OBSCubeRotatingShader')] +param( +# Set the images of OBSCubeRotatingShader +[ComponentModel.DefaultBindingProperty('images')] +[Int32] +$Images, +# Set the speed of OBSCubeRotatingShader +[ComponentModel.DefaultBindingProperty('speed')] +[Single] +$Speed, +# Set the shadow of OBSCubeRotatingShader +[ComponentModel.DefaultBindingProperty('shadow')] +[Single] +$Shadow, +# Set the other_image1 of OBSCubeRotatingShader +[Alias('other_image1')] +[ComponentModel.DefaultBindingProperty('other_image1')] +[String] +$OtherImage1, +# Set the other_image2 of OBSCubeRotatingShader +[Alias('other_image2')] +[ComponentModel.DefaultBindingProperty('other_image2')] +[String] +$OtherImage2, +# Set the other_image3 of OBSCubeRotatingShader +[Alias('other_image3')] +[ComponentModel.DefaultBindingProperty('other_image3')] +[String] +$OtherImage3, +# 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 = 'cube_rotating' +$ShaderNoun = 'OBSCubeRotatingShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform int images< + string label = "Images"; + string widget_type = "select"; + int option_0_value = 1; + string option_0_label = "1"; + int option_1_value = 2; + string option_1_label = "2"; + int option_2_value = 4; + string option_2_label = "4"; +> = 1; + +uniform float speed< + string label = "Speed"; + string widget_type = "slider"; + float minimum = -5.0; + float maximum = 5.0; + float step = 0.001; +> = 0.5; + +uniform float shadow< + string label = "Shadow"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 2.5; + float step = 0.001; +> = 1.0; + +uniform texture2d other_image1; +uniform texture2d other_image2; +uniform texture2d other_image3; + +#define PI 3.14159265359 +float4 mainImage(VertData v_in) : TARGET +{ + float t = elapsed_time * speed; + float4 c = float4(0,0,0,0); + for(float side = 0.0; side<4.0; side += 1.0){ + float left = cos(t+((side*0.5-0.25)*PI))/2+0.5; + float right = cos(t+((side*0.5+0.25)*PI))/2+0.5; + if(left < right){ + float2 uv; + uv.x = (v_in.uv.x-left)/(right-left); + float left_size = 1.0 +sin(t+((side*0.5-0.25)*PI))/2+0.5; + float right_size = 1.0 + sin(t+((side*0.5+0.25)*PI))/2+0.5; + float size = (uv.x * right_size) + ((1.0-uv.x) * left_size); + uv.y = (v_in.uv.y-0.5)*size+0.5; + float4 sample = float4(0,0,0,0); + if(images <= 1 || side == 0.0){ + sample = image.Sample(textureSampler, uv); + }else if(images == 2){ + if(side == 1.0 || side == 3.0){ + sample = other_image1.Sample(textureSampler, uv); + }else{ + sample = image.Sample(textureSampler, uv); + } + }else if(images == 4){ + if(side == 1.0){ + sample = other_image1.Sample(textureSampler, uv); + }else if(side == 2.0){ + sample = other_image2.Sample(textureSampler, uv); + }else if(side == 3.0){ + sample = other_image3.Sample(textureSampler, uv); + }else{ + sample = image.Sample(textureSampler, uv); + } + } + if(sample.a > 0.0){ + c += float4(sample.rgb*(1.0-abs((left+right)/2.0-0.5)*shadow),sample.a); + } + } + } + return c; +} + +' +} +$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 + } + } +} + +} + + +} + diff --git a/Commands/Shaders/Get-OBSCutRectPerCornerShader.ps1 b/Commands/Shaders/Get-OBSCutRectPerCornerShader.ps1 index 6c8ac1a7..a0abaf03 100644 --- a/Commands/Shaders/Get-OBSCutRectPerCornerShader.ps1 +++ b/Commands/Shaders/Get-OBSCutRectPerCornerShader.ps1 @@ -88,35 +88,35 @@ uniform int corner_tl< int minimum = 0; int maximum = 100; int step = 1; ->; +> = 0; uniform int corner_tr< string label = "Corner top right"; string widget_type = "slider"; int minimum = 0; int maximum = 100; int step = 1; ->; +> = 0; uniform int corner_br< string label = "Corner bottom right"; string widget_type = "slider"; int minimum = 0; int maximum = 100; int step = 1; ->; +> = 0; uniform int corner_bl< string label = "Corner bottom left"; string widget_type = "slider"; int minimum = 0; int maximum = 100; int step = 1; ->; +> = 0; uniform int border_thickness< string label = "Border thickness"; string widget_type = "slider"; int minimum = 0; int maximum = 100; int step = 1; ->; +> = 0; uniform float4 border_color; uniform float border_alpha_start< string label = "Border aplha start"; diff --git a/Commands/Shaders/Get-OBSDisplacementMapAdvancedInvertShader.ps1 b/Commands/Shaders/Get-OBSDisplacementMapAdvancedInvertShader.ps1 new file mode 100644 index 00000000..de6b610a --- /dev/null +++ b/Commands/Shaders/Get-OBSDisplacementMapAdvancedInvertShader.ps1 @@ -0,0 +1,433 @@ +function Get-OBSDisplacementMapAdvancedInvertShader { + +[Alias('Set-OBSDisplacementMapAdvancedInvertShader','Add-OBSDisplacementMapAdvancedInvertShader')] +param( +# Set the displacement_info of OBSDisplacementMapAdvancedInvertShader +[Alias('displacement_info')] +[ComponentModel.DefaultBindingProperty('displacement_info')] +[String] +$DisplacementInfo, +# Set the displacement_x of OBSDisplacementMapAdvancedInvertShader +[Alias('displacement_x')] +[ComponentModel.DefaultBindingProperty('displacement_x')] +[Single] +$DisplacementX, +# Set the displacement_y of OBSDisplacementMapAdvancedInvertShader +[Alias('displacement_y')] +[ComponentModel.DefaultBindingProperty('displacement_y')] +[Single] +$DisplacementY, +# Set the displacement_curve of OBSDisplacementMapAdvancedInvertShader +[Alias('displacement_curve')] +[ComponentModel.DefaultBindingProperty('displacement_curve')] +[Int32] +$DisplacementCurve, +# Set the blur_info of OBSDisplacementMapAdvancedInvertShader +[Alias('blur_info')] +[ComponentModel.DefaultBindingProperty('blur_info')] +[String] +$BlurInfo, +# Set the blur_size of OBSDisplacementMapAdvancedInvertShader +[Alias('blur_size')] +[ComponentModel.DefaultBindingProperty('blur_size')] +[Single] +$BlurSize, +# Set the blur_quality of OBSDisplacementMapAdvancedInvertShader +[Alias('blur_quality')] +[ComponentModel.DefaultBindingProperty('blur_quality')] +[Single] +$BlurQuality, +# Set the blur_directions of OBSDisplacementMapAdvancedInvertShader +[Alias('blur_directions')] +[ComponentModel.DefaultBindingProperty('blur_directions')] +[Single] +$BlurDirections, +# Set the blur_angle of OBSDisplacementMapAdvancedInvertShader +[Alias('blur_angle')] +[ComponentModel.DefaultBindingProperty('blur_angle')] +[Single] +$BlurAngle, +# Set the chromatic_aberration_info of OBSDisplacementMapAdvancedInvertShader +[Alias('chromatic_aberration_info')] +[ComponentModel.DefaultBindingProperty('chromatic_aberration_info')] +[String] +$ChromaticAberrationInfo, +# Set the chromatic_aberration of OBSDisplacementMapAdvancedInvertShader +[Alias('chromatic_aberration')] +[ComponentModel.DefaultBindingProperty('chromatic_aberration')] +[Single] +$ChromaticAberration, +# Set the colorize_info of OBSDisplacementMapAdvancedInvertShader +[Alias('colorize_info')] +[ComponentModel.DefaultBindingProperty('colorize_info')] +[String] +$ColorizeInfo, +# Set the colorize_color of OBSDisplacementMapAdvancedInvertShader +[Alias('colorize_color')] +[ComponentModel.DefaultBindingProperty('colorize_color')] +[String] +$ColorizeColor, +# Set the flags_info of OBSDisplacementMapAdvancedInvertShader +[Alias('flags_info')] +[ComponentModel.DefaultBindingProperty('flags_info')] +[String] +$FlagsInfo, +# Set the blue_affects_strength of OBSDisplacementMapAdvancedInvertShader +[Alias('blue_affects_strength')] +[ComponentModel.DefaultBindingProperty('blue_affects_strength')] +[Management.Automation.SwitchParameter] +$BlueAffectsStrength, +# Set the blue_affects_colorize of OBSDisplacementMapAdvancedInvertShader +[Alias('blue_affects_colorize')] +[ComponentModel.DefaultBindingProperty('blue_affects_colorize')] +[Management.Automation.SwitchParameter] +$BlueAffectsColorize, +# Set the blue_affects_blur of OBSDisplacementMapAdvancedInvertShader +[Alias('blue_affects_blur')] +[ComponentModel.DefaultBindingProperty('blue_affects_blur')] +[Management.Automation.SwitchParameter] +$BlueAffectsBlur, +# Set the alpha_affects_strength of OBSDisplacementMapAdvancedInvertShader +[Alias('alpha_affects_strength')] +[ComponentModel.DefaultBindingProperty('alpha_affects_strength')] +[Management.Automation.SwitchParameter] +$AlphaAffectsStrength, +# Set the apply_alpha of OBSDisplacementMapAdvancedInvertShader +[Alias('apply_alpha')] +[ComponentModel.DefaultBindingProperty('apply_alpha')] +[Management.Automation.SwitchParameter] +$ApplyAlpha, +# Set the background_layer of OBSDisplacementMapAdvancedInvertShader +[Alias('background_layer')] +[ComponentModel.DefaultBindingProperty('background_layer')] +[String] +$BackgroundLayer, +# 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 = 'displacement_map_advanced_invert' +$ShaderNoun = 'OBSDisplacementMapAdvancedInvertShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform string displacement_info< + string label = "Displacement"; + string widget_type = "info"; +> = "Displaces the Background Layer with the current image. Red channel is affected to X (horizontal) displacement and Green channel to Y (vertical). rgb(.5, .5, .5) is no displacement. You can choose the curve mapping to map values between -1 to 1 differently."; + +uniform float displacement_x< + string label = "Displacement X (px)"; +> = 16.0; + +uniform float displacement_y< + string label = "Displacement Y (px)"; +> = 16.0; + +uniform int displacement_curve< + string label = "Displacement Curve"; + string widget_type = "select"; + int option_0_value = 1; + string option_0_label = "Linear"; + int option_1_value = 2; + string option_1_label = "Quadratic"; + int option_2_value = 3; + string option_2_label = "Cubic"; +> = 0; + +uniform string blur_info< + string label = "Blur"; + string widget_type = "info"; +> = "Imitates how light disperses through displacement. It can recreate refractions like effects. Blur size affects how much light disperses, quality is the number of samples, directions of those samples (around a circle). You can choose the starting angle (use directions 1 or 2 to have highly directional refractions)."; + +uniform float blur_size< + string label = "Blur Size (px)"; +> = 8.0; // BLUR SIZE (Radius) +uniform float blur_quality< + string label = "Blur Quality (4.0)"; + string widget_type = "slider"; + float minimum = 1.0; + float maximum = 16; + float step = 1.0; +> = 4.0; // BLUR QUALITY (Default 4.0 - More is better but slower) +uniform float blur_directions< + string label = "Blur Directions (16.0)"; + string widget_type = "slider"; + float minimum = 1.0; + float maximum = 24; + float step = 1.0; +> = 16.0; // BLUR DIRECTIONS (number of rays in sampling) +uniform float blur_angle< + string label = "Blur Angle (degrees)"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 360; + float step = 1.0; +> = 0; // BLUR Angle (starting angle of first sample) + +uniform string chromatic_aberration_info< + string label = "Chromatic Aberration"; + string widget_type = "info"; +> = "Imitates how colors diverge when light refracts. Value is between -1 and 1 as a multiplier of the displacement amount."; + +uniform float chromatic_aberration< + string label = "Chromatic Aberration (0.0)"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; + +uniform string colorize_info< + string label = "Color"; + string widget_type = "info"; +> = "Imitates how light change color (tinted glass for instance)"; + +uniform float4 colorize_color< + string label = "Colorize"; +> = {0.0, 0.0, 0.0, 0.0}; + +uniform string flags_info< + string label = "Additional Channels"; + string widget_type = "info"; +> = "You can affect Blue channel (Height / Z) to displacement strength, colorization or blur radius, and Alpha to displacement (can fix glitches on edges)."; + +uniform bool blue_affects_strength< + string label = "Blue channel affects displacement"; +> = false; +uniform bool blue_affects_colorize< + string label = "Blue channel affects colorize"; +> = false; +uniform bool blue_affects_blur< + string label = "Blue channel affects blur"; +> = false; +uniform bool alpha_affects_strength< + string label = "Alpha channel affects displacement"; +> = false; +uniform bool apply_alpha< + string label = "Apply alpha"; +> = false; + +uniform texture2d background_layer < + string label = "Background Layer"; +>; + +float4 mainImage(VertData v_in) : TARGET +{ + float Pi = 6.28318530718; // Pi*2 + float blurAngleRadians = (blur_angle / 360.) * Pi; + + float4 map_rgba = image.Sample(textureSampler, v_in.uv); + + float2 displace_strength = float2(displacement_x, displacement_y) / uv_size; + float4 displace = float4( + (map_rgba.r * 2) - 1, + (map_rgba.g * 2) - 1, + (map_rgba.b * 2) - 1, + map_rgba.a + ); + + float2 displace_uv = float2(displace.r, displace.g) * displace_strength; + + for(int p=1; p 0 && displace.a > 0) { + float4 oc = base_rgba; + float transparent = oc.a; + int count = 1; + float samples = oc.a; + + // Blur calculations + [loop] for( float d=blurAngleRadians; d < Pi + blurAngleRadians; d+=Pi/blur_directions) { + [loop] for(float i=1.0 / blur_quality; i <= 1.0; i += 1.0 / blur_quality) { + float size = blur_size; + float4 sc; + + if (blue_affects_blur) { + size *= displace.b; + } + + if (chromatic_aberration) { + float4 sc_r = background_layer.Sample(textureSampler, v_in.uv + displace_uv - chromatic_aberration*displace_uv + float2(cos(d),sin(d)) * size * i / uv_size); + float4 sc_g = background_layer.Sample(textureSampler, v_in.uv + displace_uv + float2(cos(d),sin(d)) * size * i / uv_size); + float4 sc_b = background_layer.Sample(textureSampler, v_in.uv + displace_uv + chromatic_aberration*displace_uv + float2(cos(d),sin(d)) * size * i / uv_size); + + sc = float4(sc_r.r, sc_g.g, sc_b.b, sc_g.a); + } else { + sc = background_layer.Sample(textureSampler, v_in.uv + displace_uv + float2(cos(d),sin(d)) * size * i / uv_size); + } + + transparent += sc.a; + count++; + base_rgba += sc * sc.a; + samples += sc.a; + } + } + + //Calculate averages + if (samples > 0.0) + base_rgba /= samples; + + base_rgba.a = transparent / count; + } + + if (blue_affects_colorize) { + base_rgba = lerp(base_rgba, float4(colorize_color.r, colorize_color.g, colorize_color.b, 1.0), colorize_color.a * displace.b); + } else { + base_rgba = lerp(base_rgba, float4(colorize_color.r, colorize_color.g, colorize_color.b, 1.0), colorize_color.a); + } + + if (apply_alpha) { + float4 background_rgba = background_layer.Sample(textureSampler, v_in.uv); + + return lerp( + float4(background_rgba.r, background_rgba.g, background_rgba.b, background_rgba.a), + float4(base_rgba.r, base_rgba.g, base_rgba.b, base_rgba.a * displace.a), + displace.a + ); + } + + return float4(base_rgba.r, base_rgba.g, base_rgba.b, base_rgba.a * displace.a); +} +' +} +$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 + } + } +} + +} + + +} + diff --git a/Commands/Shaders/Get-OBSDisplacementMapAdvancedShader.ps1 b/Commands/Shaders/Get-OBSDisplacementMapAdvancedShader.ps1 new file mode 100644 index 00000000..294110d0 --- /dev/null +++ b/Commands/Shaders/Get-OBSDisplacementMapAdvancedShader.ps1 @@ -0,0 +1,433 @@ +function Get-OBSDisplacementMapAdvancedShader { + +[Alias('Set-OBSDisplacementMapAdvancedShader','Add-OBSDisplacementMapAdvancedShader')] +param( +# Set the displacement_info of OBSDisplacementMapAdvancedShader +[Alias('displacement_info')] +[ComponentModel.DefaultBindingProperty('displacement_info')] +[String] +$DisplacementInfo, +# Set the displacement_x of OBSDisplacementMapAdvancedShader +[Alias('displacement_x')] +[ComponentModel.DefaultBindingProperty('displacement_x')] +[Single] +$DisplacementX, +# Set the displacement_y of OBSDisplacementMapAdvancedShader +[Alias('displacement_y')] +[ComponentModel.DefaultBindingProperty('displacement_y')] +[Single] +$DisplacementY, +# Set the displacement_curve of OBSDisplacementMapAdvancedShader +[Alias('displacement_curve')] +[ComponentModel.DefaultBindingProperty('displacement_curve')] +[Int32] +$DisplacementCurve, +# Set the blur_info of OBSDisplacementMapAdvancedShader +[Alias('blur_info')] +[ComponentModel.DefaultBindingProperty('blur_info')] +[String] +$BlurInfo, +# Set the blur_size of OBSDisplacementMapAdvancedShader +[Alias('blur_size')] +[ComponentModel.DefaultBindingProperty('blur_size')] +[Single] +$BlurSize, +# Set the blur_quality of OBSDisplacementMapAdvancedShader +[Alias('blur_quality')] +[ComponentModel.DefaultBindingProperty('blur_quality')] +[Single] +$BlurQuality, +# Set the blur_directions of OBSDisplacementMapAdvancedShader +[Alias('blur_directions')] +[ComponentModel.DefaultBindingProperty('blur_directions')] +[Single] +$BlurDirections, +# Set the blur_angle of OBSDisplacementMapAdvancedShader +[Alias('blur_angle')] +[ComponentModel.DefaultBindingProperty('blur_angle')] +[Single] +$BlurAngle, +# Set the chromatic_aberration_info of OBSDisplacementMapAdvancedShader +[Alias('chromatic_aberration_info')] +[ComponentModel.DefaultBindingProperty('chromatic_aberration_info')] +[String] +$ChromaticAberrationInfo, +# Set the chromatic_aberration of OBSDisplacementMapAdvancedShader +[Alias('chromatic_aberration')] +[ComponentModel.DefaultBindingProperty('chromatic_aberration')] +[Single] +$ChromaticAberration, +# Set the colorize_info of OBSDisplacementMapAdvancedShader +[Alias('colorize_info')] +[ComponentModel.DefaultBindingProperty('colorize_info')] +[String] +$ColorizeInfo, +# Set the colorize_color of OBSDisplacementMapAdvancedShader +[Alias('colorize_color')] +[ComponentModel.DefaultBindingProperty('colorize_color')] +[String] +$ColorizeColor, +# Set the flags_info of OBSDisplacementMapAdvancedShader +[Alias('flags_info')] +[ComponentModel.DefaultBindingProperty('flags_info')] +[String] +$FlagsInfo, +# Set the blue_affects_strength of OBSDisplacementMapAdvancedShader +[Alias('blue_affects_strength')] +[ComponentModel.DefaultBindingProperty('blue_affects_strength')] +[Management.Automation.SwitchParameter] +$BlueAffectsStrength, +# Set the blue_affects_colorize of OBSDisplacementMapAdvancedShader +[Alias('blue_affects_colorize')] +[ComponentModel.DefaultBindingProperty('blue_affects_colorize')] +[Management.Automation.SwitchParameter] +$BlueAffectsColorize, +# Set the blue_affects_blur of OBSDisplacementMapAdvancedShader +[Alias('blue_affects_blur')] +[ComponentModel.DefaultBindingProperty('blue_affects_blur')] +[Management.Automation.SwitchParameter] +$BlueAffectsBlur, +# Set the alpha_affects_strength of OBSDisplacementMapAdvancedShader +[Alias('alpha_affects_strength')] +[ComponentModel.DefaultBindingProperty('alpha_affects_strength')] +[Management.Automation.SwitchParameter] +$AlphaAffectsStrength, +# Set the apply_alpha of OBSDisplacementMapAdvancedShader +[Alias('apply_alpha')] +[ComponentModel.DefaultBindingProperty('apply_alpha')] +[Management.Automation.SwitchParameter] +$ApplyAlpha, +# Set the mask_layer of OBSDisplacementMapAdvancedShader +[Alias('mask_layer')] +[ComponentModel.DefaultBindingProperty('mask_layer')] +[String] +$MaskLayer, +# 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 = 'displacement_map_advanced' +$ShaderNoun = 'OBSDisplacementMapAdvancedShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform string displacement_info< + string label = "Displacement"; + string widget_type = "info"; +> = "Displaces the current image with the Mask Layer. Red channel is affected to X (horizontal) displacement and Green channel to Y (vertical). rgb(.5, .5, .5) is no displacement. You can choose the curve mapping to map values between -1 to 1 differently."; + +uniform float displacement_x< + string label = "Displacement X (px)"; +> = 16.0; + +uniform float displacement_y< + string label = "Displacement Y (px)"; +> = 16.0; + +uniform int displacement_curve< + string label = "Displacement Curve"; + string widget_type = "select"; + int option_0_value = 1; + string option_0_label = "Linear"; + int option_1_value = 2; + string option_1_label = "Quadratic"; + int option_2_value = 3; + string option_2_label = "Cubic"; +> = 0; + +uniform string blur_info< + string label = "Blur"; + string widget_type = "info"; +> = "Imitates how light disperses through displacement. It can recreate refractions like effects. Blur size affects how much light disperses, quality is the number of samples, directions of those samples (around a circle). You can choose the starting angle (use directions 1 or 2 to have highly directional refractions)."; + +uniform float blur_size< + string label = "Blur Size (px)"; +> = 8.0; // BLUR SIZE (Radius) +uniform float blur_quality< + string label = "Blur Quality (4.0)"; + string widget_type = "slider"; + float minimum = 1.0; + float maximum = 16; + float step = 1.0; +> = 4.0; // BLUR QUALITY (Default 4.0 - More is better but slower) +uniform float blur_directions< + string label = "Blur Directions (16.0)"; + string widget_type = "slider"; + float minimum = 1.0; + float maximum = 24; + float step = 1.0; +> = 16.0; // BLUR DIRECTIONS (number of rays in sampling) +uniform float blur_angle< + string label = "Blur Angle (degrees)"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 360; + float step = 1.0; +> = 0; // BLUR Angle (starting angle of first sample) + +uniform string chromatic_aberration_info< + string label = "Chromatic Aberration"; + string widget_type = "info"; +> = "Imitates how colors diverge when light refracts. Value is between -1 and 1 as a multiplier of the displacement amount."; + +uniform float chromatic_aberration< + string label = "Chromatic Aberration (0.0)"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; + +uniform string colorize_info< + string label = "Color"; + string widget_type = "info"; +> = "Imitates how light change color (tinted glass for instance)"; + +uniform float4 colorize_color< + string label = "Colorize"; +> = {0.0, 0.0, 0.0, 0.0}; + +uniform string flags_info< + string label = "Additional Channels"; + string widget_type = "info"; +> = "You can affect Blue channel (Height / Z) to displacement strength, colorization or blur radius, and Alpha to displacement (can fix glitches on edges)."; + +uniform bool blue_affects_strength< + string label = "Blue channel affects displacement"; +> = false; +uniform bool blue_affects_colorize< + string label = "Blue channel affects colorize"; +> = false; +uniform bool blue_affects_blur< + string label = "Blue channel affects blur"; +> = false; +uniform bool alpha_affects_strength< + string label = "Alpha channel affects displacement"; +> = false; +uniform bool apply_alpha< + string label = "Apply alpha"; +> = false; + +uniform texture2d mask_layer < + string label = "Mask Layer"; +>; + +float4 mainImage(VertData v_in) : TARGET +{ + float Pi = 6.28318530718; // Pi*2 + float blurAngleRadians = (blur_angle / 360.) * Pi; + + float4 map_rgba = mask_layer.Sample(textureSampler, v_in.uv); + + float2 displace_strength = float2(displacement_x, displacement_y) / uv_size; + float4 displace = float4( + (map_rgba.r * 2) - 1, + (map_rgba.g * 2) - 1, + (map_rgba.b * 2) - 1, + map_rgba.a + ); + + float2 displace_uv = float2(displace.r, displace.g) * displace_strength; + + for(int p=1; p 0 && displace.a > 0) { + float4 oc = base_rgba; + float transparent = oc.a; + int count = 1; + float samples = oc.a; + + // Blur calculations + [loop] for( float d=blurAngleRadians; d < Pi + blurAngleRadians; d+=Pi/blur_directions) { + [loop] for(float i=1.0 / blur_quality; i <= 1.0; i += 1.0 / blur_quality) { + float size = blur_size; + float4 sc; + + if (blue_affects_blur) { + size *= displace.b; + } + + if (chromatic_aberration) { + float4 sc_r = image.Sample(textureSampler, v_in.uv + displace_uv - chromatic_aberration*displace_uv + float2(cos(d),sin(d)) * size * i / uv_size); + float4 sc_g = image.Sample(textureSampler, v_in.uv + displace_uv + float2(cos(d),sin(d)) * size * i / uv_size); + float4 sc_b = image.Sample(textureSampler, v_in.uv + displace_uv + chromatic_aberration*displace_uv + float2(cos(d),sin(d)) * size * i / uv_size); + + sc = float4(sc_r.r, sc_g.g, sc_b.b, sc_g.a); + } else { + sc = image.Sample(textureSampler, v_in.uv + displace_uv + float2(cos(d),sin(d)) * size * i / uv_size); + } + + transparent += sc.a; + count++; + base_rgba += sc * sc.a; + samples += sc.a; + } + } + + //Calculate averages + if (samples > 0.0) + base_rgba /= samples; + + base_rgba.a = transparent / count; + } + + if (blue_affects_colorize) { + base_rgba = lerp(base_rgba, float4(colorize_color.r, colorize_color.g, colorize_color.b, 1.0), colorize_color.a * displace.b); + } else { + base_rgba = lerp(base_rgba, float4(colorize_color.r, colorize_color.g, colorize_color.b, 1.0), colorize_color.a); + } + + if (apply_alpha) { + float4 background_rgba = image.Sample(textureSampler, v_in.uv); + + return lerp( + float4(background_rgba.r, background_rgba.g, background_rgba.b, background_rgba.a), + float4(base_rgba.r, base_rgba.g, base_rgba.b, base_rgba.a * displace.a), + displace.a + ); + } + + return float4(base_rgba.r, base_rgba.g, base_rgba.b, base_rgba.a * displace.a); +} +' +} +$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 + } + } +} + +} + + +} + diff --git a/Commands/Shaders/Get-OBSDisplacementMapInvertShader.ps1 b/Commands/Shaders/Get-OBSDisplacementMapInvertShader.ps1 new file mode 100644 index 00000000..9408f708 --- /dev/null +++ b/Commands/Shaders/Get-OBSDisplacementMapInvertShader.ps1 @@ -0,0 +1,187 @@ +function Get-OBSDisplacementMapInvertShader { + +[Alias('Set-OBSDisplacementMapInvertShader','Add-OBSDisplacementMapInvertShader')] +param( +# Set the displacement_info of OBSDisplacementMapInvertShader +[Alias('displacement_info')] +[ComponentModel.DefaultBindingProperty('displacement_info')] +[String] +$DisplacementInfo, +# Set the displacement_x of OBSDisplacementMapInvertShader +[Alias('displacement_x')] +[ComponentModel.DefaultBindingProperty('displacement_x')] +[Single] +$DisplacementX, +# Set the displacement_y of OBSDisplacementMapInvertShader +[Alias('displacement_y')] +[ComponentModel.DefaultBindingProperty('displacement_y')] +[Single] +$DisplacementY, +# Set the background_layer of OBSDisplacementMapInvertShader +[Alias('background_layer')] +[ComponentModel.DefaultBindingProperty('background_layer')] +[String] +$BackgroundLayer, +# 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 = 'displacement_map_invert' +$ShaderNoun = 'OBSDisplacementMapInvertShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform string displacement_info< + string label = "Displacement"; + string widget_type = "info"; +> = "Displaces the Background Layer with the current image. Red channel is affected to X (horizontal) displacement and Green channel to Y (vertical). rgb(.5, .5, .5) is no displacement."; + +uniform float displacement_x< + string label = "Displacement X (px)"; +> = 16.0; + +uniform float displacement_y< + string label = "Displacement Y (px)"; +> = 16.0; + +uniform texture2d background_layer ; + +float4 mainImage(VertData v_in) : TARGET +{ + float4 map = image.Sample(textureSampler, v_in.uv); + float4 base = background_layer.Sample(textureSampler, v_in.uv); + + float2 displace_strength = float2(displacement_x, displacement_y) / uv_size; + float4 displace = float4( + (map.r * 2) - 1, + (map.g * 2) - 1, + (map.b * 2) - 1, + map.a + ); + + float2 displace_uv = float2(displace.r, displace.g) * displace_strength; + float4 displaced = background_layer.Sample(textureSampler, v_in.uv + displace_uv); + + return float4(displaced.r, displaced.g, displaced.b, displaced.a * displace.a); +} + +' +} +$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 + } + } +} + +} + + +} + diff --git a/Commands/Shaders/Get-OBSDisplacementMapShader.ps1 b/Commands/Shaders/Get-OBSDisplacementMapShader.ps1 new file mode 100644 index 00000000..b7e7f35b --- /dev/null +++ b/Commands/Shaders/Get-OBSDisplacementMapShader.ps1 @@ -0,0 +1,187 @@ +function Get-OBSDisplacementMapShader { + +[Alias('Set-OBSDisplacementMapShader','Add-OBSDisplacementMapShader')] +param( +# Set the displacement_info of OBSDisplacementMapShader +[Alias('displacement_info')] +[ComponentModel.DefaultBindingProperty('displacement_info')] +[String] +$DisplacementInfo, +# Set the displacement_x of OBSDisplacementMapShader +[Alias('displacement_x')] +[ComponentModel.DefaultBindingProperty('displacement_x')] +[Single] +$DisplacementX, +# Set the displacement_y of OBSDisplacementMapShader +[Alias('displacement_y')] +[ComponentModel.DefaultBindingProperty('displacement_y')] +[Single] +$DisplacementY, +# Set the mask_layer of OBSDisplacementMapShader +[Alias('mask_layer')] +[ComponentModel.DefaultBindingProperty('mask_layer')] +[String] +$MaskLayer, +# 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 = 'displacement_map' +$ShaderNoun = 'OBSDisplacementMapShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform string displacement_info< + string label = "Displacement"; + string widget_type = "info"; +> = "Displaces the current image with the Mask Layer. Red channel is affected to X (horizontal) displacement and Green channel to Y (vertical). rgb(.5, .5, .5) is no displacement."; + +uniform float displacement_x< + string label = "Displacement X (px)"; +> = 16.0; + +uniform float displacement_y< + string label = "Displacement Y (px)"; +> = 16.0; + +uniform texture2d mask_layer ; + +float4 mainImage(VertData v_in) : TARGET +{ + float4 map = mask_layer.Sample(textureSampler, v_in.uv); + float4 base = image.Sample(textureSampler, v_in.uv); + + float2 displace_strength = float2(displacement_x, displacement_y) / uv_size; + float4 displace = float4( + (map.r * 2) - 1, + (map.g * 2) - 1, + (map.b * 2) - 1, + map.a + ); + + float2 displace_uv = float2(displace.r, displace.g) * displace_strength; + float4 displaced = image.Sample(textureSampler, v_in.uv + displace_uv); + + return float4(displaced.r, displaced.g, displaced.b, displaced.a * displace.a); +} + +' +} +$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 + } + } +} + +} + + +} + diff --git a/Commands/Shaders/Get-OBSGlitchPeriodicShader.ps1 b/Commands/Shaders/Get-OBSGlitchPeriodicShader.ps1 new file mode 100644 index 00000000..5818c18a --- /dev/null +++ b/Commands/Shaders/Get-OBSGlitchPeriodicShader.ps1 @@ -0,0 +1,243 @@ +function Get-OBSGlitchPeriodicShader { + +[Alias('Set-OBSGlitchPeriodicShader','Add-OBSGlitchPeriodicShader')] +param( +# Set the PERI of OBSGlitchPeriodicShader +[ComponentModel.DefaultBindingProperty('PERI')] +[Single] +$PERI, +# Set the DURA of OBSGlitchPeriodicShader +[ComponentModel.DefaultBindingProperty('DURA')] +[Single] +$DURA, +# Set the AMPL of OBSGlitchPeriodicShader +[ComponentModel.DefaultBindingProperty('AMPL')] +[Single] +$AMPL, +# Set the SCRA of OBSGlitchPeriodicShader +[ComponentModel.DefaultBindingProperty('SCRA')] +[Single] +$SCRA, +# 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 = 'glitch-periodic' +$ShaderNoun = 'OBSGlitchPeriodicShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Created by Éric Nicolas (ccjmne) for use with obs-shaderfilter 12/2025 +// Port of: https://www.shadertoy.com/view/WfVfDh +// Originally forked from: https://www.shadertoy.com/view/MtXBDs + +#define PI 3.14159265359 + +/* For visual explanation of the paramters, see */ +/* https://www.desmos.com/calculator/vezu1wyqma */ +/* */ +/* Period How often a glitch occurs (in seconds) 0–? */ +/* Duration How long a glitch lasts (in seconds) 0–Period */ +/* Amplitude How intense a glitch is 0–1 */ +/* Scratchiness How jittery a glitch is 0–1 */ + +uniform float PERI< + string label = "Period"; + string widget_type = "slider"; + float minimum = 1.; + float maximum = 60.; + float step = 1.; +> = 6.; + +uniform float DURA< + string label = "Duration"; + string widget_type = "slider"; + float minimum = 0.; + float maximum = 60.; + float step = .01; +> = .5; + +uniform float AMPL< + string label = "Amplitude"; + string widget_type = "slider"; + float minimum = 0.; + float maximum = 1.; + float step = .01; +> = .15; + +uniform float SCRA< + string label = "Scratchiness"; + string widget_type = "slider"; + float minimum = 0.; + float maximum = 1.; + float step = .01; +> = .2; + +float random2d(float2 n) { + return frac(sin(dot(n, float2(12.9898, 4.1414))) * 43758.5453); +} + +float randomRange(in float2 seed, in float lo, in float hi) { + return lo + random2d(seed) * (hi - lo); +} + +float insideRange(float v, float bottom, float top) { + return step(bottom, v) - step(top, v); +} + +float4 mainImage(VertData v_in): TARGET { + float time = floor(elapsed_time * SCRA * 60.); + float2 uv = v_in.uv; + + // Periodic intermittence + float AMP = AMPL * (cos(2. * PI * max(0., (mod(-elapsed_time / PERI, 1.) - 1.) * PERI / DURA + 1.)) * -.5 + .5); + + float4 outCol = image.Sample(textureSampler, uv); + + // Randomly offset slices horizontally + float offsetMax = AMP / 2.; + for (float i = 0.; i < 10. * AMP; i += 1.) { + float sliceY = random2d( float2(time, 2345. + i)); + float sliceH = random2d( float2(time, 9035. + i)) * .25; + float offsetH = randomRange(float2(time, 9625. + i), -offsetMax, offsetMax); + float2 uvOff = uv; + uvOff.x += offsetH; + if (insideRange(uv.y, sliceY, frac(sliceY + sliceH)) == 1.) { + outCol = image.Sample(textureSampler, uvOff); + } + } + + // Slightly offset one entire channel + offsetMax = AMP / 6.; + float2 colOff = float2( + randomRange(float2(time, 9545.), -offsetMax, offsetMax), + randomRange(float2(time, 7205.), -offsetMax, offsetMax) + ); + float rnd = random2d(float2(time , 9545.)); + if (rnd < .33) outCol.r = image.Sample(textureSampler, uv + colOff).r; + else if (rnd < .66) outCol.g = image.Sample(textureSampler, uv + colOff).g; + else outCol.b = image.Sample(textureSampler, uv + colOff).b; + + return outCol; +} + +' +} +$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 + } + } +} + +} + + +} + diff --git a/Commands/Shaders/Get-OBSHardBlinkShader.ps1 b/Commands/Shaders/Get-OBSHardBlinkShader.ps1 new file mode 100644 index 00000000..606b50cd --- /dev/null +++ b/Commands/Shaders/Get-OBSHardBlinkShader.ps1 @@ -0,0 +1,173 @@ +function Get-OBSHardBlinkShader { + +[Alias('Set-OBSHardBlinkShader','Add-OBSHardBlinkShader')] +param( +# Set the timeon of OBSHardBlinkShader +[ComponentModel.DefaultBindingProperty('timeon')] +[Single] +$Timeon, +# Set the timeoff of OBSHardBlinkShader +[ComponentModel.DefaultBindingProperty('timeoff')] +[Single] +$Timeoff, +# 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 = 'hard_blink' +$ShaderNoun = 'OBSHardBlinkShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// hard_blink shader created by https://github.com/WhazzItToYa +// +// Periodically makes the source image 100% transparent, in configurable intervals. + +uniform float timeon< + string label = "Time On"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 0.5; + +uniform float timeoff< + string label = "Time Off"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 0.5; + +float4 mainImage(VertData v_in) : TARGET +{ + float4 color = image.Sample(textureSampler, v_in.uv); + float m = timeon + timeoff; + float t = elapsed_time % m; + if (t < timeon) { + return color; + } else { + return float4(color.r, color.g, color.b, 0.0); + } +} + +' +} +$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 + } + } +} + +} + + +} + diff --git a/Commands/Shaders/Get-OBSMotionBlurShader.ps1 b/Commands/Shaders/Get-OBSMotionBlurShader.ps1 new file mode 100644 index 00000000..19b1aa4a --- /dev/null +++ b/Commands/Shaders/Get-OBSMotionBlurShader.ps1 @@ -0,0 +1,155 @@ +function Get-OBSMotionBlurShader { + +[Alias('Set-OBSMotionBlurShader','Add-OBSMotionBlurShader')] +param( +# Set the previous_output of OBSMotionBlurShader +[Alias('previous_output')] +[ComponentModel.DefaultBindingProperty('previous_output')] +[String] +$PreviousOutput, +# Set the strength of OBSMotionBlurShader +[ComponentModel.DefaultBindingProperty('strength')] +[Single] +$Strength, +# 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 = 'motion_blur' +$ShaderNoun = 'OBSMotionBlurShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform texture2d previous_output; +uniform float strength< + string label = "strength"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; + +float4 mainImage(VertData v_in) : TARGET +{ + return lerp(image.Sample(textureSampler, v_in.uv), previous_output.Sample(textureSampler, v_in.uv), 1.0 - pow(2, -7 * strength)); +} +' +} +$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 + } + } +} + +} + + +} + diff --git a/Commands/Shaders/Get-OBSNoiseShader.ps1 b/Commands/Shaders/Get-OBSNoiseShader.ps1 new file mode 100644 index 00000000..3cfb0f07 --- /dev/null +++ b/Commands/Shaders/Get-OBSNoiseShader.ps1 @@ -0,0 +1,210 @@ +function Get-OBSNoiseShader { + +[Alias('Set-OBSNoiseShader','Add-OBSNoiseShader')] +param( +# Set the speed of OBSNoiseShader +[ComponentModel.DefaultBindingProperty('speed')] +[Single] +$Speed, +# Set the scale of OBSNoiseShader +[ComponentModel.DefaultBindingProperty('scale')] +[Single] +$Scale, +# Set the noiseLevel of OBSNoiseShader +[ComponentModel.DefaultBindingProperty('noiseLevel')] +[Single] +$NoiseLevel, +# Set the monochromatic of OBSNoiseShader +[ComponentModel.DefaultBindingProperty('monochromatic')] +[Management.Automation.SwitchParameter] +$Monochromatic, +# Set the use_rand of OBSNoiseShader +[Alias('use_rand')] +[ComponentModel.DefaultBindingProperty('use_rand')] +[Management.Automation.SwitchParameter] +$UseRand, +# 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 = 'noise' +$ShaderNoun = 'OBSNoiseShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform float speed< + string label = "Speed"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 100; + float step = 0.1; +> = 1; +uniform float scale< + string label = "Scale"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 10; + float step = 0.0001; +> = 6; +uniform float noiseLevel< + string label = "Noise Level"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 1; + float step = 0.001; +> = 1; +uniform bool monochromatic = false; +uniform bool use_rand = false; + +float rand(float2 st) +{ + return frac(sin(dot(st.xy, float2(12.9898, 78.233))) * 43758.5453123); +} + +float4 mainImage(VertData v_in) : TARGET +{ + float time = rand_activation_f + (speed / 60) * elapsed_time * 0.00001; + + if (use_rand) { + time = rand_f; + } + + float4 x; + + if (monochromatic) { + x = rand(float2(v_in.uv.x, v_in.uv.y) * scale + time + scale); + } else { + x = float4( + rand(float2(v_in.uv.x, v_in.uv.y) * scale + time + 1 * scale), + rand(float2(v_in.uv.x, v_in.uv.y) * scale + time + 2 * scale), + rand(float2(v_in.uv.x, v_in.uv.y) * scale + time + 3 * scale), + 1 + ); + } + + float4 rgba = image.Sample(textureSampler, v_in.uv); + + float3 output = lerp(rgba, x, noiseLevel); + + return float4(output.r, output.g, output.b, rgba.a); +} +' +} +$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 + } + } +} + +} + + +} + diff --git a/Commands/Shaders/Get-OBSNormalMapShader.ps1 b/Commands/Shaders/Get-OBSNormalMapShader.ps1 new file mode 100644 index 00000000..938d1454 --- /dev/null +++ b/Commands/Shaders/Get-OBSNormalMapShader.ps1 @@ -0,0 +1,254 @@ +function Get-OBSNormalMapShader { + +[Alias('Set-OBSNormalMapShader','Add-OBSNormalMapShader')] +param( +# Set the strength of OBSNormalMapShader +[ComponentModel.DefaultBindingProperty('strength')] +[Single] +$Strength, +# Set the offsetHeight of OBSNormalMapShader +[ComponentModel.DefaultBindingProperty('offsetHeight')] +[Management.Automation.SwitchParameter] +$OffsetHeight, +# Set the invertR of OBSNormalMapShader +[ComponentModel.DefaultBindingProperty('invertR')] +[Management.Automation.SwitchParameter] +$InvertR, +# Set the invertG of OBSNormalMapShader +[ComponentModel.DefaultBindingProperty('invertG')] +[Management.Automation.SwitchParameter] +$InvertG, +# Set the invertH of OBSNormalMapShader +[ComponentModel.DefaultBindingProperty('invertH')] +[Management.Automation.SwitchParameter] +$InvertH, +# Set the type of OBSNormalMapShader +[ComponentModel.DefaultBindingProperty('type')] +[Int32] +$Type, +# 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 = 'normal_map' +$ShaderNoun = 'OBSNormalMapShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Normal map shader based on cpetry''s NormalMap-Online website +// https://github.com/cpetry/NormalMap-Online/blob/gh-pages/javascripts/shader/NormalMapShader.js + +uniform float strength< + string label = "Strength"; + string widget_type = "slider"; + float minimum = 0.001; + float maximum = 10; + float step = 0.001; +> = 1; + +uniform bool offsetHeight = true; +uniform bool invertR = false; +uniform bool invertG = false; +uniform bool invertH = false; + +uniform int type< + string label = "Filter Type"; + string widget_type = "select"; + int option_0_value = 0; + string option_0_label = "Sobel"; + int option_1_value = 1; + string option_1_label = "Scharr"; +> = 0; + +float4 mainImage( VertData v_in ) : TARGET { + float2 step = float2(1.0, 1.0) / uv_size; + float2 vUv = v_in.uv; + + float dz = 1 / strength; + float dz2 = dz * dz; + + float2 tlv = float2(vUv.x - step.x, vUv.y + step.y); + float2 lv = float2(vUv.x - step.x, vUv.y ); + float2 blv = float2(vUv.x - step.x, vUv.y - step.y); + float2 tv = float2(vUv.x , vUv.y + step.y); + float2 bv = float2(vUv.x , vUv.y - step.y); + float2 trv = float2(vUv.x + step.x, vUv.y + step.y); + float2 rv = float2(vUv.x + step.x, vUv.y ); + float2 brv = float2(vUv.x + step.x, vUv.y - step.y); + + tlv = float2(tlv.x >= 0.0 ? tlv.x : (1.0 + tlv.x), tlv.y >= 0.0 ? tlv.y : (1.0 + tlv.y)); + tlv = float2(tlv.x < 1.0 ? tlv.x : (tlv.x - 1.0 ), tlv.y < 1.0 ? tlv.y : (tlv.y - 1.0 )); + lv = float2( lv.x >= 0.0 ? lv.x : (1.0 + lv.x), lv.y >= 0.0 ? lv.y : (1.0 + lv.y)); + lv = float2( lv.x < 1.0 ? lv.x : ( lv.x - 1.0 ), lv.y < 1.0 ? lv.y : ( lv.y - 1.0 )); + blv = float2(blv.x >= 0.0 ? blv.x : (1.0 + blv.x), blv.y >= 0.0 ? blv.y : (1.0 + blv.y)); + blv = float2(blv.x < 1.0 ? blv.x : (blv.x - 1.0 ), blv.y < 1.0 ? blv.y : (blv.y - 1.0 )); + tv = float2( tv.x >= 0.0 ? tv.x : (1.0 + tv.x), tv.y >= 0.0 ? tv.y : (1.0 + tv.y)); + tv = float2( tv.x < 1.0 ? tv.x : ( tv.x - 1.0 ), tv.y < 1.0 ? tv.y : ( tv.y - 1.0 )); + bv = float2( bv.x >= 0.0 ? bv.x : (1.0 + bv.x), bv.y >= 0.0 ? bv.y : (1.0 + bv.y)); + bv = float2( bv.x < 1.0 ? bv.x : ( bv.x - 1.0 ), bv.y < 1.0 ? bv.y : ( bv.y - 1.0 )); + trv = float2(trv.x >= 0.0 ? trv.x : (1.0 + trv.x), trv.y >= 0.0 ? trv.y : (1.0 + trv.y)); + trv = float2(trv.x < 1.0 ? trv.x : (trv.x - 1.0 ), trv.y < 1.0 ? trv.y : (trv.y - 1.0 )); + rv = float2( rv.x >= 0.0 ? rv.x : (1.0 + rv.x), rv.y >= 0.0 ? rv.y : (1.0 + rv.y)); + rv = float2( rv.x < 1.0 ? rv.x : ( rv.x - 1.0 ), rv.y < 1.0 ? rv.y : ( rv.y - 1.0 )); + brv = float2(brv.x >= 0.0 ? brv.x : (1.0 + brv.x), brv.y >= 0.0 ? brv.y : (1.0 + brv.y)); + brv = float2(brv.x < 1.0 ? brv.x : (brv.x - 1.0 ), brv.y < 1.0 ? brv.y : (brv.y - 1.0 )); + + float tl = image.Sample(textureSampler, tlv).r; + float l = image.Sample(textureSampler, lv ).r; + float bl = image.Sample(textureSampler, blv).r; + float t = image.Sample(textureSampler, tv ).r; + float b = image.Sample(textureSampler, bv ).r; + float tr = image.Sample(textureSampler, trv).r; + float r = image.Sample(textureSampler, rv ).r; + float br = image.Sample(textureSampler, brv).r; + + float dx = 0.0; + float dy = 0.0; + + if(type == 0) { // Sobel + dx = tl + l*2.0 + bl - tr - r*2.0 - br; + dy = tl + t*2.0 + tr - bl - b*2.0 - br; + } + else { // Scharr + dx = tl*3.0 + l*10.0 + bl*3.0 - tr*3.0 - r*10.0 - br*3.0; + dy = tl*3.0 + t*10.0 + tr*3.0 - bl*3.0 - b*10.0 - br*3.0; + } + + float invH = invertH ? -1. : 1.; + float invR = invertR ? -1. : 1.; + float invG = invertG ? -1. : 1.; + + float4 normal = float4( + float3(dx * invR * invH, dy * invG * invH, dz), + image.Sample(textureSampler, vUv).a + ); + + l = sqrt((dx * dx) + (dy * dy) + dz2); + + if (offsetHeight) { + return float4(normal.xy / l * 0.5 + 0.5, normal.zw); + } + + return float4(normal.xyz / l * 0.5 + 0.5, normal.w); +} + +' +} +$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 + } + } +} + +} + + +} + diff --git a/Commands/Shaders/Get-OBSPerspectiveShader.ps1 b/Commands/Shaders/Get-OBSPerspectiveShader.ps1 new file mode 100644 index 00000000..37be6166 --- /dev/null +++ b/Commands/Shaders/Get-OBSPerspectiveShader.ps1 @@ -0,0 +1,256 @@ +function Get-OBSPerspectiveShader { + +[Alias('Set-OBSPerspectiveShader','Add-OBSPerspectiveShader')] +param( +# Set the angle_x of OBSPerspectiveShader +[Alias('angle_x')] +[ComponentModel.DefaultBindingProperty('angle_x')] +[Single] +$AngleX, +# Set the angle_y of OBSPerspectiveShader +[Alias('angle_y')] +[ComponentModel.DefaultBindingProperty('angle_y')] +[Single] +$AngleY, +# Set the angle_z of OBSPerspectiveShader +[Alias('angle_z')] +[ComponentModel.DefaultBindingProperty('angle_z')] +[Single] +$AngleZ, +# Set the perspective of OBSPerspectiveShader +[ComponentModel.DefaultBindingProperty('perspective')] +[Single] +$Perspective, +# Set the border_color of OBSPerspectiveShader +[Alias('border_color')] +[ComponentModel.DefaultBindingProperty('border_color')] +[String] +$BorderColor, +# Set the show_border of OBSPerspectiveShader +[Alias('show_border')] +[ComponentModel.DefaultBindingProperty('show_border')] +[Management.Automation.SwitchParameter] +$ShowBorder, +# 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 = 'perspective' +$ShaderNoun = 'OBSPerspectiveShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Perspective Transform Shader for OBS +// Allows adjustable 3D perspective effects +// Usage: Add as filter in OBS via ShaderFilter plugin + +uniform float angle_x< + string label = "X Rotation"; + string widget_type = "slider"; + float minimum = -180.0; + float maximum = 180.0; + float step = 1.0; +> = 0.0; + +uniform float angle_y< + string label = "Y Rotation"; + string widget_type = "slider"; + float minimum = -180.0; + float maximum = 180.0; + float step = 1.0; +> = 0.0; + +uniform float angle_z< + string label = "Z Rotation"; + string widget_type = "slider"; + float minimum = -180.0; + float maximum = 180.0; + float step = 1.0; +> = 0.0; + +uniform float perspective< + string label = "Perspective Strength"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.5; + +uniform float4 border_color< + string label = "Border Color"; +> = {0.0, 0.0, 0.0, 1.0}; + +uniform bool show_border< + string label = "Show Border"; +> = true; + +float4x4 rotationMatrix(float3 angles) +{ + float radX = radians(angles.x); + float radY = radians(angles.y); + float radZ = radians(angles.z); + + float sinX = sin(radX); + float cosX = cos(radX); + float sinY = sin(radY); + float cosY = cos(radY); + float sinZ = sin(radZ); + float cosZ = cos(radZ); + + return float4x4( + cosY*cosZ, -cosY*sinZ, sinY, 0, + sinX*sinY*cosZ + cosX*sinZ, -sinX*sinY*sinZ + cosX*cosZ, -sinX*cosY, 0, + -cosX*sinY*cosZ + sinX*sinZ, cosX*sinY*sinZ + sinX*cosZ, cosX*cosY, 0, + 0, 0, 0, 1 + ); +} + +float4 mainImage(VertData v_in) : TARGET +{ + float2 uv = v_in.uv; + + // Center coordinates + float2 center = float2(0.5, 0.5); + uv -= center; + + // Apply perspective + float perspectiveFactor = 1.0 / (1.0 + perspective * length(uv)); + uv *= perspectiveFactor; + + // Create rotation matrix + float3 angles = float3(angle_x, angle_y, angle_z); + float4x4 rotMat = rotationMatrix(angles); + + // Apply transformation + float4 transformed = mul(rotMat, float4(uv.x, uv.y, 0, 1)); + + // Restore center position + uv = transformed.xy + center; + + // Sample texture with border handling + if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) { + return show_border ? border_color : float4(0, 0, 0, 0); + } + + return image.Sample(textureSampler, uv); +} +' +} +$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 + } + } +} + +} + + +} + diff --git a/Commands/Shaders/Get-OBSQuadrilateralCropShader.ps1 b/Commands/Shaders/Get-OBSQuadrilateralCropShader.ps1 new file mode 100644 index 00000000..ef666664 --- /dev/null +++ b/Commands/Shaders/Get-OBSQuadrilateralCropShader.ps1 @@ -0,0 +1,247 @@ +function Get-OBSQuadrilateralCropShader { + +[Alias('Set-OBSQuadrilateralCropShader','Add-OBSQuadrilateralCropShader')] +param( +# Set the Top_Left_X of OBSQuadrilateralCropShader +[Alias('Top_Left_X')] +[ComponentModel.DefaultBindingProperty('Top_Left_X')] +[Single] +$TopLeftX, +# Set the Top_Left_Y of OBSQuadrilateralCropShader +[Alias('Top_Left_Y')] +[ComponentModel.DefaultBindingProperty('Top_Left_Y')] +[Single] +$TopLeftY, +# Set the Top_Right_X of OBSQuadrilateralCropShader +[Alias('Top_Right_X')] +[ComponentModel.DefaultBindingProperty('Top_Right_X')] +[Single] +$TopRightX, +# Set the Top_Right_Y of OBSQuadrilateralCropShader +[Alias('Top_Right_Y')] +[ComponentModel.DefaultBindingProperty('Top_Right_Y')] +[Single] +$TopRightY, +# Set the Bottom_Left_X of OBSQuadrilateralCropShader +[Alias('Bottom_Left_X')] +[ComponentModel.DefaultBindingProperty('Bottom_Left_X')] +[Single] +$BottomLeftX, +# Set the Bottom_Left_Y of OBSQuadrilateralCropShader +[Alias('Bottom_Left_Y')] +[ComponentModel.DefaultBindingProperty('Bottom_Left_Y')] +[Single] +$BottomLeftY, +# Set the Bottom_Right_X of OBSQuadrilateralCropShader +[Alias('Bottom_Right_X')] +[ComponentModel.DefaultBindingProperty('Bottom_Right_X')] +[Single] +$BottomRightX, +# Set the Bottom_Right_Y of OBSQuadrilateralCropShader +[Alias('Bottom_Right_Y')] +[ComponentModel.DefaultBindingProperty('Bottom_Right_Y')] +[Single] +$BottomRightY, +# 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 = 'quadrilateral_crop' +$ShaderNoun = 'OBSQuadrilateralCropShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Quadrilateral Crop shader (inverse of a corner pin): transform a 4 points polygon to the corners of the source. +// Useful to revert perspective. + +uniform float Top_Left_X< + string label = "Top Left X"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 100.0; + float step = 0.01; +> = 0; +uniform float Top_Left_Y< + string label = "Top Left Y"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 100.0; + float step = 0.01; +> = 0; +uniform float Top_Right_X< + string label = "Top Right X"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 100.0; + float step = 0.01; +> = 100.; +uniform float Top_Right_Y< + string label = "Top Right Y"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 100.0; + float step = 0.01; +> = 0; +uniform float Bottom_Left_X< + string label = "Bottom Left X"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 100.0; + float step = 0.01; +> = 0; +uniform float Bottom_Left_Y< + string label = "Bottom Left Y"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 100.0; + float step = 0.01; +> = 100.; +uniform float Bottom_Right_X< + string label = "Bottom Right X"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 100.0; + float step = 0.01; +> = 100.; +uniform float Bottom_Right_Y< + string label = "Bottom Right Y"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 100.0; + float step = 0.01; +> = 100.; + +float4 mainImage( VertData v_in ) : TARGET { + + float2 tl = float2(Top_Left_X, Top_Left_Y) * .01; + float2 tr = float2(Top_Right_X, Top_Right_Y) * .01; + float2 bl = float2(Bottom_Left_X, Bottom_Left_Y) * .01; + float2 br = float2(Bottom_Right_X, Bottom_Right_Y) * .01; + + float2 t = lerp(tl, tr, v_in.uv[0]); + float2 b = lerp(bl, br, v_in.uv[0]); + float2 uv = lerp(t, b, v_in.uv[1]); + + return image.Sample(textureSampler, uv); +} + +' +} +$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 + } + } +} + +} + + +} + diff --git a/Commands/Shaders/Get-OBSRepeatGridCenterCropShader.ps1 b/Commands/Shaders/Get-OBSRepeatGridCenterCropShader.ps1 new file mode 100644 index 00000000..8a15a900 --- /dev/null +++ b/Commands/Shaders/Get-OBSRepeatGridCenterCropShader.ps1 @@ -0,0 +1,204 @@ +function Get-OBSRepeatGridCenterCropShader { + +[Alias('Set-OBSRepeatGridCenterCropShader','Add-OBSRepeatGridCenterCropShader')] +param( +# Set the ViewProj of OBSRepeatGridCenterCropShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the image of OBSRepeatGridCenterCropShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the alpha of OBSRepeatGridCenterCropShader +[ComponentModel.DefaultBindingProperty('alpha')] +[Single] +$Alpha, +# Set the columns of OBSRepeatGridCenterCropShader +[ComponentModel.DefaultBindingProperty('columns')] +[Single] +$Columns, +# Set the rows of OBSRepeatGridCenterCropShader +[ComponentModel.DefaultBindingProperty('rows')] +[Single] +$Rows, +# 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 = 'repeat_grid_center_crop' +$ShaderNoun = 'OBSRepeatGridCenterCropShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// repeat_grid_center_crop.effect + +uniform float4x4 ViewProj; +uniform texture2d image; +sampler_state def_sampler { + Filter = Linear; + AddressU = Clamp; + AddressV = Clamp; +}; + +uniform float alpha = 1.0; +uniform float columns = 3.0; +uniform float rows = 1.0; + +struct VertInOut { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; + +VertInOut VSDefault(VertInOut vert_in) { + VertInOut vert_out; + vert_out.pos = mul(float4(vert_in.pos.xyz, 1), ViewProj); + vert_out.uv = vert_in.uv * float2(columns, rows); + return vert_out; +} + +float4 PSMain(VertInOut vert_in) : TARGET { + // Calculate fractional UV within grid cell + float2 cell_uv = frac(vert_in.uv); + + // Calculate center crop parameters + float horizontalCropStart = 0.5 - 0.5/columns; + + // Map to centered portion of original image + float2 original_uv = float2( + cell_uv.x / columns + horizontalCropStart, + cell_uv.y / rows + ); + + // Sample the image + float4 col = image.Sample(def_sampler, original_uv); + col.a *= alpha; + return col; +} + +technique Draw { + pass { + vertex_shader = VSDefault(vert_in); + pixel_shader = PSMain(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 + } + } +} + +} + + +} + diff --git a/Commands/Shaders/Get-OBSRoundedRect2Shader.ps1 b/Commands/Shaders/Get-OBSRoundedRect2Shader.ps1 index 531f5ab9..f72f8dcc 100644 --- a/Commands/Shaders/Get-OBSRoundedRect2Shader.ps1 +++ b/Commands/Shaders/Get-OBSRoundedRect2Shader.ps1 @@ -77,14 +77,14 @@ uniform int corner_radius< int minimum = 0; int maximum = 100; int step = 1; ->; +> = 0; uniform int border_thickness< string label = "Border thickness"; string widget_type = "slider"; int minimum = 0; int maximum = 100; int step = 1; ->; +> = 0; uniform float4 border_color; uniform float border_alpha_start< string label = "Border alpha start"; diff --git a/Commands/Shaders/Get-OBSRoundedRectPerCornerShader.ps1 b/Commands/Shaders/Get-OBSRoundedRectPerCornerShader.ps1 index 5777d1b3..512d30d0 100644 --- a/Commands/Shaders/Get-OBSRoundedRectPerCornerShader.ps1 +++ b/Commands/Shaders/Get-OBSRoundedRectPerCornerShader.ps1 @@ -88,35 +88,35 @@ uniform int corner_radius_tl< int minimum = 0; int maximum = 200; int step = 1; ->; +> = 0; uniform int corner_radius_tr< string label = "Corner radius top right"; string widget_type = "slider"; int minimum = 0; int maximum = 200; int step = 1; ->; +> = 0; uniform int corner_radius_br< string label = "Corner radius bottom right"; string widget_type = "slider"; int minimum = 0; int maximum = 200; int step = 1; ->; +> = 0; uniform int corner_radius_bl< string label = "Corner radius bottom left"; string widget_type = "slider"; int minimum = 0; int maximum = 200; int step = 1; ->; +> = 0; uniform int border_thickness< string label = "Border thickness"; string widget_type = "slider"; int minimum = 0; int maximum = 100; int step = 1; ->; +> = 0; uniform float4 border_color; uniform float border_alpha_start< string label = "border alpha start"; diff --git a/Commands/Shaders/Get-OBSRoundedRectPerSideShader.ps1 b/Commands/Shaders/Get-OBSRoundedRectPerSideShader.ps1 index cfd42586..9a192fd0 100644 --- a/Commands/Shaders/Get-OBSRoundedRectPerSideShader.ps1 +++ b/Commands/Shaders/Get-OBSRoundedRectPerSideShader.ps1 @@ -87,35 +87,35 @@ uniform int corner_radius_bottom< int minimum = 0; int maximum = 200; int step = 1; ->; +> = 0; uniform int corner_radius_left< string label = "Corner radius left"; string widget_type = "slider"; int minimum = 0; int maximum = 200; int step = 1; ->; +> = 0; uniform int corner_radius_top< string label = "Corner radius top"; string widget_type = "slider"; int minimum = 0; int maximum = 200; int step = 1; ->; +> = 0; uniform int corner_radius_right< string label = "Corner radius right"; string widget_type = "slider"; int minimum = 0; int maximum = 200; int step = 1; ->; +> = 0; uniform int border_thickness< string label = "Border thickness"; string widget_type = "slider"; int minimum = 0; int maximum = 100; int step = 1; ->; +> = 0; uniform float4 border_color; uniform float border_alpha_start< string label = "border alpha start"; diff --git a/Commands/Shaders/Get-OBSRoundedRectShader.ps1 b/Commands/Shaders/Get-OBSRoundedRectShader.ps1 index 0e3cb8cf..f4eb5afa 100644 --- a/Commands/Shaders/Get-OBSRoundedRectShader.ps1 +++ b/Commands/Shaders/Get-OBSRoundedRectShader.ps1 @@ -58,14 +58,14 @@ uniform int corner_radius< int minimum = 0; int maximum = 200; int step = 1; ->; +> = 0; uniform int border_thickness< string label = "border thickness"; string widget_type = "slider"; int minimum = 0; int maximum = 100; int step = 1; ->; +> = 0; uniform float4 border_color; diff --git a/Commands/Shaders/Get-OBSRoundedStrokeGradientShader.ps1 b/Commands/Shaders/Get-OBSRoundedStrokeGradientShader.ps1 index 4d946858..2ce530b6 100644 --- a/Commands/Shaders/Get-OBSRoundedStrokeGradientShader.ps1 +++ b/Commands/Shaders/Get-OBSRoundedStrokeGradientShader.ps1 @@ -88,14 +88,14 @@ uniform int corner_radius< int minimum = 0; int maximum = 200; int step = 1; ->; +> = 0; uniform int border_thickness< string label = "Border thickness"; string widget_type = "slider"; int minimum = 0; int maximum = 100; int step = 1; ->; +> = 0; uniform int minimum_alpha_percent< string label = "Minimum alpha percent"; string widget_type = "slider"; @@ -109,7 +109,7 @@ uniform int rotation_speed< int minimum = 0; int maximum = 100; int step = 1; ->; +> = 0; uniform float4 border_colorL; uniform float4 border_colorR; //uniform float color_spread = 2.0; diff --git a/Commands/Shaders/Get-OBSRoundedStrokeShader.ps1 b/Commands/Shaders/Get-OBSRoundedStrokeShader.ps1 index 6b3fbdd2..17b51bf8 100644 --- a/Commands/Shaders/Get-OBSRoundedStrokeShader.ps1 +++ b/Commands/Shaders/Get-OBSRoundedStrokeShader.ps1 @@ -69,14 +69,14 @@ uniform int corner_radius< int minimum = 0; int maximum = 200; int step = 1; ->; +> = 0; uniform int border_thickness< string label = "border thickness"; string widget_type = "slider"; int minimum = 0; int maximum = 100; int step = 1; ->; +> = 0; uniform int minimum_alpha_percent< string label = "Minimum alpha percent"; string widget_type = "slider"; diff --git a/Commands/Shaders/Get-OBSWalkingDeadPixelFixerShader.ps1 b/Commands/Shaders/Get-OBSWalkingDeadPixelFixerShader.ps1 new file mode 100644 index 00000000..bb51914d --- /dev/null +++ b/Commands/Shaders/Get-OBSWalkingDeadPixelFixerShader.ps1 @@ -0,0 +1,379 @@ +function Get-OBSWalkingDeadPixelFixerShader { + +[Alias('Set-OBSWalkingDeadPixelFixerShader','Add-OBSWalkingDeadPixelFixerShader')] +param( +# Set the Scan_Width of OBSWalkingDeadPixelFixerShader +[Alias('Scan_Width')] +[ComponentModel.DefaultBindingProperty('Scan_Width')] +[Int32] +$ScanWidth, +# Set the Scan_Height of OBSWalkingDeadPixelFixerShader +[Alias('Scan_Height')] +[ComponentModel.DefaultBindingProperty('Scan_Height')] +[Int32] +$ScanHeight, +# Set the Scan_Offset_X of OBSWalkingDeadPixelFixerShader +[Alias('Scan_Offset_X')] +[ComponentModel.DefaultBindingProperty('Scan_Offset_X')] +[Int32] +$ScanOffsetX, +# Set the Scan_Offset_Y of OBSWalkingDeadPixelFixerShader +[Alias('Scan_Offset_Y')] +[ComponentModel.DefaultBindingProperty('Scan_Offset_Y')] +[Int32] +$ScanOffsetY, +# Set the Show_Border of OBSWalkingDeadPixelFixerShader +[Alias('Show_Border')] +[ComponentModel.DefaultBindingProperty('Show_Border')] +[Management.Automation.SwitchParameter] +$ShowBorder, +# Set the Contrast_Threshold of OBSWalkingDeadPixelFixerShader +[Alias('Contrast_Threshold')] +[ComponentModel.DefaultBindingProperty('Contrast_Threshold')] +[Single] +$ContrastThreshold, +# Set the Min_Cluster_Size of OBSWalkingDeadPixelFixerShader +[Alias('Min_Cluster_Size')] +[ComponentModel.DefaultBindingProperty('Min_Cluster_Size')] +[Int32] +$MinClusterSize, +# Set the Max_Cluster_Size of OBSWalkingDeadPixelFixerShader +[Alias('Max_Cluster_Size')] +[ComponentModel.DefaultBindingProperty('Max_Cluster_Size')] +[Int32] +$MaxClusterSize, +# Set the Show_Green of OBSWalkingDeadPixelFixerShader +[Alias('Show_Green')] +[ComponentModel.DefaultBindingProperty('Show_Green')] +[Management.Automation.SwitchParameter] +$ShowGreen, +# Set the Bypass of OBSWalkingDeadPixelFixerShader +[ComponentModel.DefaultBindingProperty('Bypass')] +[Management.Automation.SwitchParameter] +$Bypass, +# 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 = 'walking-dead-pixel-fixer' +$ShaderNoun = 'OBSWalkingDeadPixelFixerShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Walking Dead Pixel Fixer, Version 0.10, for OBS Shaderfilter +// by Eegee http://github.com/eegee/ +// Based on Dead Pixel Fixer, Version 0.01, for OBS Shaderfilter +// Copyright ©️ 2022 by SkeletonBow +// License: GNU General Public License, version 2 +// Contact info: +// Twitter: +// Twitch: +// +// Description: Intended for use with an input source that has a dead pixel on its sensor such as a webcam. +// The pixels located in the user configured scan area and passing the threshold settings will have its colors +// overridden by taking the average of the colors of the surrounding pixels, effectively hiding the dead pixels. +// +// Changelog: +// 0.01 - Initial release +// 0.10 - Added a pixel scan area and added contrast threshold settings to replace blur size setting. + +uniform int Scan_Width< + string label = "Scan area width"; + int minimum = 1; + int maximum = 2560; + int step = 1; +> = 75; + +uniform int Scan_Height< + string label = "Scan area height"; + int minimum = 1; + int maximum = 1440; + int step = 1; +> = 120; + +uniform int Scan_Offset_X< + string label = "Scan area offset X"; + int minimum = 0; + int maximum = 2560; + int step = 1; +> = 110; + +uniform int Scan_Offset_Y< + string label = "Scan area offset Y"; + int minimum = 0; + int maximum = 1440; + int step = 1; +> = 20; + +uniform bool Show_Border< + string label = "Show scan area border in red"; + string widget_type = "checkbox"; +> = true; + +uniform float Contrast_Threshold< + string label = "Contrast threshold"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.05; + +uniform int Min_Cluster_Size< + string label = "Min cluster size"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 600; + int step = 2; +> = 324; + +uniform int Max_Cluster_Size< + string label = "Max cluster size"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 600; + int step = 2; +> = 400; + +uniform bool Show_Green< + string label = "Show matches in green"; + string widget_type = "checkbox"; +> = true; + +uniform bool Bypass< + string label = "Bypass"; + string widget_type = "checkbox"; +> = false; + + +#define SAMPLE_RADIUS 9 + +float luminance(float3 color) +{ + return dot(color, float3(0.299, 0.587, 0.114)); +} + +void sample_average(float2 uv, float2 center_uv, out float3 avgColor, out float avgLuminance, out int contrastCount, float contrastThreshold) +{ + float3 sumColor = float3(0.0, 0.0, 0.0); + float weightSum = 0.0; + contrastCount = 0; + + float3 centerColor = image.Sample(textureSampler, uv).rgb; + float centerLum = luminance(centerColor); + + for (int y = -SAMPLE_RADIUS; y <= SAMPLE_RADIUS; ++y) + { + for (int x = -SAMPLE_RADIUS; x <= SAMPLE_RADIUS; ++x) + { + if (x == 0 && y == 0) continue; + + float2 offset = float2(x, y) / uv_size; + float2 sample_uv = clamp(uv + offset, float2(0.0, 0.0), float2(1.0, 1.0)); + + // skip central pixel + if (ceil(sample_uv.x * uv_size.x) == ceil(center_uv.x) && + ceil(sample_uv.y * uv_size.y) == ceil(center_uv.y)) + continue; + + float3 sampleColor = image.Sample(textureSampler, sample_uv).rgb; + float lum = luminance(sampleColor); + + float weight = 1.0; + sumColor += sampleColor * weight; + weightSum += weight; + + if (abs(lum - centerLum) >= contrastThreshold) + contrastCount++; + } + } + + if (weightSum > 0) + { + avgColor = sumColor / weightSum; + } + else + { + avgColor = centerColor; + } + avgLuminance = luminance(avgColor); +} + +float4 mainImage(VertData v_in) : TARGET +{ + float2 uv = v_in.uv; + float2 pos = v_in.pos.xy; + + float4 tex = image.Sample(textureSampler, uv); + float3 color = tex.rgb; + + if (!Bypass) + { + int pixX = (int)round(pos.x); + int pixY = (int)round(pos.y); + + int borderwidth = 2; + + bool insideScan = + (pixX >= Scan_Offset_X && pixX < Scan_Offset_X + Scan_Width) && + (pixY >= Scan_Offset_Y && pixY < Scan_Offset_Y + Scan_Height); + + bool borderingScan = + (pixX >= Scan_Offset_X - borderwidth && pixX < Scan_Offset_X + Scan_Width + borderwidth) && + (pixY >= Scan_Offset_Y - borderwidth && pixY < Scan_Offset_Y + Scan_Height + borderwidth); + + if (insideScan) + { + float3 avgColor; + float avgLum; + int contrastCount; + + sample_average(uv, pos, avgColor, avgLum, contrastCount, Contrast_Threshold); + + if (contrastCount < Max_Cluster_Size && contrastCount >= Min_Cluster_Size) + { + color = avgColor; + + if (Show_Green) + { + int left = pixX - borderwidth; + int right = pixX + borderwidth; + int top = pixY - borderwidth; + int bottom = pixY + borderwidth; + + bool onOutline = + abs(pos.x - left) < borderwidth || abs(pos.x - right) < borderwidth || + abs(pos.y - top) < borderwidth || abs(pos.y - bottom) < borderwidth; + + if (onOutline) + return float4(0.0, 1.0, 0.0, 1.0); + } + } + } + else if (Show_Border && borderingScan) + { + return float4(1.0, 0.0, 0.0, 0.5); + } + } + return float4(color, tex.a); +} + +' +} +$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 + } + } +} + +} + + +} + diff --git a/Commands/Shaders/Get-OBSZoomBlurTransitionShader.ps1 b/Commands/Shaders/Get-OBSZoomBlurTransitionShader.ps1 new file mode 100644 index 00000000..08dbcfc8 --- /dev/null +++ b/Commands/Shaders/Get-OBSZoomBlurTransitionShader.ps1 @@ -0,0 +1,229 @@ +function Get-OBSZoomBlurTransitionShader { + +[Alias('Set-OBSZoomBlurTransitionShader','Add-OBSZoomBlurTransitionShader')] +param( +# Set the image_a of OBSZoomBlurTransitionShader +[Alias('image_a')] +[ComponentModel.DefaultBindingProperty('image_a')] +[String] +$ImageA, +# Set the image_b of OBSZoomBlurTransitionShader +[Alias('image_b')] +[ComponentModel.DefaultBindingProperty('image_b')] +[String] +$ImageB, +# Set the transition_time of OBSZoomBlurTransitionShader +[Alias('transition_time')] +[ComponentModel.DefaultBindingProperty('transition_time')] +[Single] +$TransitionTime, +# Set the convert_linear of OBSZoomBlurTransitionShader +[Alias('convert_linear')] +[ComponentModel.DefaultBindingProperty('convert_linear')] +[Management.Automation.SwitchParameter] +$ConvertLinear, +# Set the strength of OBSZoomBlurTransitionShader +[ComponentModel.DefaultBindingProperty('strength')] +[Single] +$Strength, +# 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 = 'zoom_blur_transition' +$ShaderNoun = 'OBSZoomBlurTransitionShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//based on https://www.shadertoy.com/view/Ml3XR2 + +uniform texture2d image_a; +uniform texture2d image_b; +uniform float transition_time = 0.5; +uniform bool convert_linear = true; + +//modified zoom blur from http://transitions.glsl.io/transition/b86b90161503a0023231 +uniform float strength< + string label = "Strength (0.3)"; + string widget_type = "slider"; + float minimum = 0.00; + float maximum = 1.50; + float step = 0.01; +> = 0.3; +#define PI 3.141592653589793 + +float Linear_ease(in float begin, in float change, in float duration, in float time) { + return change * time / duration + begin; +} + +float Exponential_easeInOut(in float begin, in float change, in float duration, in float time) { + if (time == 0.0) + return begin; + else if (time == duration) + return begin + change; + time = time / (duration / 2.0); + if (time < 1.0) + return change / 2.0 * pow(2.0, 10.0 * (time - 1.0)) + begin; + return change / 2.0 * (-pow(2.0, -10.0 * (time - 1.0)) + 2.0) + begin; +} + +float Sinusoidal_easeInOut(in float begin, in float change, in float duration, in float time) { + return -change / 2.0 * (cos(PI * time / duration) - 1.0) + begin; +} + +float random(in float3 scale, in float seed) { + return frac(sin(dot(float3(seed, seed, seed), scale)) * 43758.5453 + seed); +} + +float3 crossFade(in float2 uv, in float dissolve) { + return lerp(image_a.Sample(textureSampler, uv).rgb, image_b.Sample(textureSampler, uv).rgb, dissolve); +} + +float4 mainImage(VertData v_in) : TARGET { + float2 texCoord = v_in.uv; + float progress = transition_time; + // Linear interpolate center across center half of the image + float2 center = float2(Linear_ease(0.5, 0.0, 1.0, progress),0.5); + float dissolve = Exponential_easeInOut(0.0, 1.0, 1.0, progress); + + // Mirrored sinusoidal loop. 0->strength then strength->0 + float strength2 = Sinusoidal_easeInOut(0.0, strength, 0.5, progress); + + float3 color = float3(0.0,0.0,0.0); + float total = 0.0; + float2 toCenter = center - texCoord; + + /* randomize the lookup values to hide the fixed float of samples */ + float offset = random(float3(12.9898, 78.233, 151.7182), 0.0)*0.5; + + for (float t = 0.0; t <= 20.0; t++) { + float percent = (t + offset) / 20.0; + float weight = 1.0 * (percent - percent * percent); + color += crossFade(texCoord + toCenter * percent * strength2, dissolve) * weight; + total += weight; + } + float4 rgba = float4(color / total, 1.0); + if (convert_linear) + rgba.rgb = srgb_nonlinear_to_linear(rgba.rgb); + return rgba; +} +' +} +$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 + } + } +} + +} + + +} + diff --git a/Commands/Shaders/Get-OBSZoomShader.ps1 b/Commands/Shaders/Get-OBSZoomShader.ps1 index fa9ba836..bee64743 100644 --- a/Commands/Shaders/Get-OBSZoomShader.ps1 +++ b/Commands/Shaders/Get-OBSZoomShader.ps1 @@ -70,7 +70,7 @@ uniform float power< float minimum = 0; float maximum = 20.0; float step = 0.001; -> = 1.75; +> = 1.0; float4 mainImage(VertData v_in) : TARGET { diff --git a/Commands/Start-OBS.ps1 b/Commands/Start-OBS.ps1 new file mode 100644 index 00000000..c3ff1296 --- /dev/null +++ b/Commands/Start-OBS.ps1 @@ -0,0 +1,156 @@ + +function Start-OBS { + <# + .SYNOPSIS + Start OBS + .DESCRIPTION + Starts OBS + + Without any parameters, will attempt to start the obs process. + + If OBS is already running, will output the current obs process. + + * If `-Recording` is passed, will start recording + * If `-Streaming` is passed, will start streaming + * If `-StudioMode` is passed, will start studio mode + * If `-VirtualCamera` is passed, will start the virtual camera + + If additional arguments are passed, will pass them thru to a new obs process. + .LINK + Stop-OBS + .LINK + Start-OBSRecord + .LINK + Start-OBSStream + .LINK + Start-OBSVirtualCam + #> + [CmdletBinding(PositionalBinding=$false,SupportsShouldProcess)] + param( + # A list of arguments. These will be passed to a new obs process. + [Parameter(ValueFromRemainingArguments)] + [Alias('Arguments','Argument','Args')] + [PSObject[]] + $ArgumentList, + + # Any input object. This will currently be ignored. + [Parameter(ValueFromPipeline)] + [PSObject[]] + $InputObject, + + # If set, will start recording. + [Alias('Record')] + [switch] + $Recording, + + # If set, will start streaming. + [Alias('Stream')] + [switch] + $Streaming, + + # If set, will start studio mode. + [switch] + $StudioMode, + + # If set, will start the virtual camera + [Alias('VirtualCam')] + [switch] + $VirtualCamera + ) + + + # Get the obs application + $obsApp = $ExecutionContext.SessionState.InvokeCommand.GetCommand('obs', 'Application') + # If it was not in the path, and we are on Windows + if (-not $obsApp -and -not ($IsMacOS -or $IsLinux)) { + # look in program files. + $obsApp = $ExecutionContext.SessionState.InvokeCommand.GetCommand( + ( + Join-Path $env:ProgramFiles "obs-studio" | + Join-Path -ChildPath 'bin' | + Join-Path -ChildPath '64bit' | + Join-Path -ChildPath 'obs64.exe' + ), + 'Application' + ) + } + + # If we could not find obs + if (-not $obsApp) { + # error out + Write-Error "OBS not found" + return + } + + # Determine if obs is already running + $obsRunning = Get-Process | + Where-Object Path -EQ $obsApp.Source + + # If it is running, we can start various obs features. + if ($obsRunning) { + # If we want to start recording, + if ($Recording -and ( + $WhatIfPreference -or + $PSCmdlet.ShouldProcess('Start Recording') + )) { + # `Start-OBSRecord`. + Start-OBSRecord -PassThru:$WhatIfPreference + } + + # If we want to start streaming, + if ($Streaming -and ( + $WhatIfPreference -or + $PSCmdlet.ShouldProcess('Start Streaming') + )) { + # `Start-OBSStream`. + Start-OBSStream -PassThru:$WhatIfPreference + } + + # If we want to start studio mode, + if ($StudioMode -and ( + $WhatIfPreference -or + $PSCmdlet.ShouldProcess('Start Studio Mode') + )) { + # `Set-OBSStudioModeEnabled`. + Set-OBSStudioModeEnabled -StudioModeEnabled:$true -PassThru:$WhatIfPreference + } + + # If we want to start the virtual camera, + if ($VirtualCamera -and ( + $WhatIfPreference -or + $PSCmdlet.ShouldProcess('Start Virtual Camera') + )) { + # `Start-OBSVirtualCam`. + Start-OBSVirtualCam -PassThru:$WhatIfPreference + } + + # If any of these options were run + # they will output + if ($Recording -or + $Streaming -or + $StudioMode -or + $VirtualCamera + ) { + # and we can return. + return + } + + # Otherwise, return the obs process. + return $obsRunning + } else { + # If the process was not running, start it. + Start-Process -FilePath $obsApp.Path -PassThru -ArgumentList $ArgumentList -WorkingDirectory ( + $obsApp.Path | Split-Path + ) + + # If we wanted to start recording, streaming, studio mode, or virtual camera + if ($Recording -or + $Streaming -or + $StudioMode -or + $VirtualCamera + ) { + # warn us that we need to wait a bit. + Write-Warning "OBS starting up, cannot start virtual camera, recording, or streaming" + } + } +} \ No newline at end of file diff --git a/Commands/Stop-OBS.ps1 b/Commands/Stop-OBS.ps1 new file mode 100644 index 00000000..b1711fa4 --- /dev/null +++ b/Commands/Stop-OBS.ps1 @@ -0,0 +1,149 @@ +function Stop-OBS { + <# + .SYNOPSIS + Stops OBS + .DESCRIPTION + Stops OBS. + + By default, stops recording and streaming. + + If -Process is provided, will stop all running OBS processes + + If -Recording is provided, will stop recording + If -Streaming if provided, will stop obs streaming + If -VirtualCamera is provided, will stop the virtual camera + .NOTES + This command Supports Should Process and has a ConfirmImpact of 'High' + + In an interactive session, this command prompt by default. + + If `-WhatIf` is passed, will output what happen if this ran + If `-Confirm:$false`, confirmation will be skipped. + .EXAMPLE + # Stop Streaming and Recording + Stop-OBS + .EXAMPLE + # Stops obs recording + Stop-OBS -Recording + .EXAMPLE + # Stop Streaming + Stop-OBS -Streaming + .EXAMPLE + # Stop OBS Virtual Camera + Stop-OBS -VirtualCamera + .EXAMPLE + # Stop OBS Virtual Camera without prompting + Stop-OBS -VirtualCamera -Confirm:$false + .EXAMPLE + Stop-OBS -StudioMode + .LINK + Stop-OBSRecord + .LINK + Stop-OBSStream + .LINK + Stop-OBSVirtualCam + .LINK + Set-OBSStudioModeEnabled + #> + [CmdletBinding( + ConfirmImpact='High', + PositionalBinding=$false, + SupportsShouldProcess + )] + param( + # If set, will stop recording. + [switch] + $Recording, + + # If set, will stop streaming + [switch] + $Streaming, + + # If set, will stop the virtual camera. + [switch] + $VirtualCamera, + + # If set, will stop the OBS process. + [switch] + $Process, + + # If set, will enable studio mode. + [switch] + $StudioMode + ) + + if ($Process) { + $obsApp = $ExecutionContext.SessionState.InvokeCommand.GetCommand('obs', 'Application') + if (-not $obsApp -and -not ($IsMacOS -or $IsLinux)) { + $obsApp = $ExecutionContext.SessionState.InvokeCommand.GetCommand( + ( + Join-Path $env:ProgramFiles "obs-studio" | + Join-Path -ChildPath 'bin' | + Join-Path -ChildPath '64bit' | + Join-Path -ChildPath 'obs64.exe' + ), + 'Application' + ) + } + + if (-not $obsApp) { + Write-Error "OBS not found" + return + } + + $obsRunning = Get-Process | + Where-Object Path -EQ $obsApp.Source + + if (-not $obsRunning) { + Write-Error "OBS not running" + return + } + + if ($WhatIfPreference) { return $obsRunning } + if ($PSCmdlet.ShouldProcess('Stop OBS')) { + $obsRunning | Stop-Process -PassThru + } + return + } + + # Without any parameters, we will stop + if (-not $PSBoundParameters.Count) { + # recording + $Recording = $true + # and streaming. + $Streaming = $true + } + + + + # If we want to stop recording, + if ($Recording -and $PSCmdlet.ShouldProcess('Stop Recording')) { + # `Stop-ObsRecord`. + Stop-OBSRecord -PassThru:$WhatIfPreference + } + + # If we want to stop the virtual camera, + if ($VirtualCamera -and $PSCmdlet.ShouldProcess('Stop Virtual Camera')) { + # `Stop-OBSVirtualCamera`. + Stop-OBSVirtualCam -PassThru:$WhatIfPreference + } + + # If we want to stop streaming, + if ($Streaming -and $PSCmdlet.ShouldProcess('Stop Streaming')) { + # `Stop-OBSStream`. + Stop-OBSStream -PassThru:$WhatIfPreference + } + + if ($StudioMode -and $PSCmdlet.ShouldProcess('Stop Studio Mode')) { + Set-OBSStudioModeEnabled -StudioModeEnabled:$false -PassThru:$WhatIfPreference + } + + # If we are shutting down any part of obs + if ($Recording -or + $Streaming -or + $StudioMode -or + $VirtualCamera) { + # we do not want to stop obs + return + } +} diff --git a/Shaders/README.md b/Shaders/README.md new file mode 100644 index 00000000..ad1a361b --- /dev/null +++ b/Shaders/README.md @@ -0,0 +1,2 @@ +This directory contains some additional Pixel Shaders that may not be included in +[obs-shader-filter](https://github.com/exeldro/obs-shaderfilter/) \ No newline at end of file diff --git a/allcommands.ps1 b/allcommands.ps1 index bf33fc72..c898f34a 100644 --- a/allcommands.ps1 +++ b/allcommands.ps1 @@ -836,6 +836,243 @@ function Show-OBS { } } } +function Start-OBS { + + [CmdletBinding(PositionalBinding=$false,SupportsShouldProcess)] + param( + # A list of arguments. These will be passed to a new obs process. + [Parameter(ValueFromRemainingArguments)] + [Alias('Arguments','Argument','Args')] + [PSObject[]] + $ArgumentList, + + # Any input object. This will currently be ignored. + [Parameter(ValueFromPipeline)] + [PSObject[]] + $InputObject, + + # If set, will start recording. + [Alias('Record')] + [switch] + $Recording, + + # If set, will start streaming. + [Alias('Stream')] + [switch] + $Streaming, + + # If set, will start studio mode. + [switch] + $StudioMode, + + # If set, will start the virtual camera + [Alias('VirtualCam')] + [switch] + $VirtualCamera + ) + + + # Get the obs application + $obsApp = $ExecutionContext.SessionState.InvokeCommand.GetCommand('obs', 'Application') + # If it was not in the path, and we are on Windows + if (-not $obsApp -and -not ($IsMacOS -or $IsLinux)) { + # look in program files. + $obsApp = $ExecutionContext.SessionState.InvokeCommand.GetCommand( + ( + Join-Path $env:ProgramFiles "obs-studio" | + Join-Path -ChildPath 'bin' | + Join-Path -ChildPath '64bit' | + Join-Path -ChildPath 'obs64.exe' + ), + 'Application' + ) + } + + # If we could not find obs + if (-not $obsApp) { + # error out + Write-Error "OBS not found" + return + } + + # Determine if obs is already running + $obsRunning = Get-Process | + Where-Object Path -EQ $obsApp.Source + + # If it is running, we can start various obs features. + if ($obsRunning) { + # If we want to start recording, + if ($Recording -and ( + $WhatIfPreference -or + $PSCmdlet.ShouldProcess('Start Recording') + )) { + # `Start-OBSRecord`. + Start-OBSRecord -PassThru:$WhatIfPreference + } + + # If we want to start streaming, + if ($Streaming -and ( + $WhatIfPreference -or + $PSCmdlet.ShouldProcess('Start Streaming') + )) { + # `Start-OBSStream`. + Start-OBSStream -PassThru:$WhatIfPreference + } + + # If we want to start studio mode, + if ($StudioMode -and ( + $WhatIfPreference -or + $PSCmdlet.ShouldProcess('Start Studio Mode') + )) { + # `Set-OBSStudioModeEnabled`. + Set-OBSStudioModeEnabled -StudioModeEnabled:$true -PassThru:$WhatIfPreference + } + + # If we want to start the virtual camera, + if ($VirtualCamera -and ( + $WhatIfPreference -or + $PSCmdlet.ShouldProcess('Start Virtual Camera') + )) { + # `Start-OBSVirtualCam`. + Start-OBSVirtualCam -PassThru:$WhatIfPreference + } + + # If any of these options were run + # they will output + if ($Recording -or + $Streaming -or + $StudioMode -or + $VirtualCamera + ) { + # and we can return. + return + } + + # Otherwise, return the obs process. + return $obsRunning + } else { + # If the process was not running, start it. + Start-Process -FilePath $obsApp.Path -PassThru -ArgumentList $ArgumentList -WorkingDirectory ( + $obsApp.Path | Split-Path + ) + + # If we wanted to start recording, streaming, studio mode, or virtual camera + if ($Recording -or + $Streaming -or + $StudioMode -or + $VirtualCamera + ) { + # warn us that we need to wait a bit. + Write-Warning "OBS starting up, cannot start virtual camera, recording, or streaming" + } + } +} +#.ExternalHelp obs-powershell-Help.xml +function Stop-OBS { + + [CmdletBinding( + ConfirmImpact='High', + PositionalBinding=$false, + SupportsShouldProcess + )] + param( + # If set, will stop recording. + [switch] + $Recording, + + # If set, will stop streaming + [switch] + $Streaming, + + # If set, will stop the virtual camera. + [switch] + $VirtualCamera, + + # If set, will stop the OBS process. + [switch] + $Process, + + # If set, will enable studio mode. + [switch] + $StudioMode + ) + + if ($Process) { + $obsApp = $ExecutionContext.SessionState.InvokeCommand.GetCommand('obs', 'Application') + if (-not $obsApp -and -not ($IsMacOS -or $IsLinux)) { + $obsApp = $ExecutionContext.SessionState.InvokeCommand.GetCommand( + ( + Join-Path $env:ProgramFiles "obs-studio" | + Join-Path -ChildPath 'bin' | + Join-Path -ChildPath '64bit' | + Join-Path -ChildPath 'obs64.exe' + ), + 'Application' + ) + } + + if (-not $obsApp) { + Write-Error "OBS not found" + return + } + + $obsRunning = Get-Process | + Where-Object Path -EQ $obsApp.Source + + if (-not $obsRunning) { + Write-Error "OBS not running" + return + } + + if ($WhatIfPreference) { return $obsRunning } + if ($PSCmdlet.ShouldProcess('Stop OBS')) { + $obsRunning | Stop-Process -PassThru + } + return + } + + # Without any parameters, we will stop + if (-not $PSBoundParameters.Count) { + # recording + $Recording = $true + # and streaming. + $Streaming = $true + } + + + + # If we want to stop recording, + if ($Recording -and $PSCmdlet.ShouldProcess('Stop Recording')) { + # `Stop-ObsRecord`. + Stop-OBSRecord -PassThru:$WhatIfPreference + } + + # If we want to stop the virtual camera, + if ($VirtualCamera -and $PSCmdlet.ShouldProcess('Stop Virtual Camera')) { + # `Stop-OBSVirtualCamera`. + Stop-OBSVirtualCam -PassThru:$WhatIfPreference + } + + # If we want to stop streaming, + if ($Streaming -and $PSCmdlet.ShouldProcess('Stop Streaming')) { + # `Stop-OBSStream`. + Stop-OBSStream -PassThru:$WhatIfPreference + } + + if ($StudioMode -and $PSCmdlet.ShouldProcess('Stop Studio Mode')) { + Set-OBSStudioModeEnabled -StudioModeEnabled:$false -PassThru:$WhatIfPreference + } + + # If we are shutting down any part of obs + if ($Recording -or + $Streaming -or + $StudioMode -or + $VirtualCamera) { + # we do not want to stop obs + return + } +} + #.ExternalHelp obs-powershell-Help.xml function Watch-OBS { @@ -1030,50 +1267,81 @@ $($ExecutionContext.SessionState.InvokeCommand.GetCommand('Send-OBS', 'Function' } #.ExternalHelp obs-powershell-Help.xml -function Set-OBSAudioOutputSource { +function Set-OBS3DFilter { - #> - [Alias('Add-OBSAudioOutputSource','Get-OBSAudioOutputSource')] + [Alias('Add-OBS3DFilter')] param( - # The name of the audio device. - # This name or device ID of the audio device that should be captured. - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('ItemValue','ItemName','DeviceID')] - [string] - $AudioDevice, + # The Field of View + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("fov")] + [double] + $FieldOfView, - # The name of the scene. - # If no scene name is provided, the current program scene will be used. - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('SceneName')] - [string] - $Scene, + # The Rotation along the X-axis + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("rot_x")] + [double] + $RotationX, - # The name of the input. - # If no name is provided, "AudioOutput$($AudioDevice)" will be the input source name. - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('InputName','SourceName')] - [string] - $Name, + # The Rotation along the Y-axis + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("rot_y")] + [double] + $RotationY, - # If set, will check if the source exists in the scene before creating it and removing any existing sources found. - # If not set, you will get an error if a source with the same name exists. - [Parameter(ValueFromPipelineByPropertyName)] + # The Rotation along the Z-axis + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("rot_z")] + [double] + $RotationZ, + + # The Position along the X-axis + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("pos_x")] + [double] + $PositionX, + + # The Position along the Y-axis + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("pos_y")] + [double] + $PositionY, + + # The Position along the Z-axis + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("pos_z")] + [double] + $PositionZ, + + # The scale of the source along the X-axis + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("scale_x")] + [double] + $ScaleX, + + # The scale of the source along the Y-axis + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("scale_y")] + [double] + $ScaleY, + + # If set, will remove a filter if one already exists. + # If this is not provided and the filter already exists, the settings of the filter will be changed. [switch] $Force ) dynamicParam { $baseCommand = - if (-not $script:AddOBSInput) { - $script:AddOBSInput = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') - $script:AddOBSInput + if (-not $script:AddOBSSourceFilter) { + $script:AddOBSSourceFilter = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSSourceFilter','Function') + $script:AddOBSSourceFilter } else { - $script:AddOBSInput + $script:AddOBSSourceFilter } $IncludeParameter = @() - $ExcludeParameter = 'inputKind','sceneName','inputName' + $ExcludeParameter = 'FilterKind','FilterSettings' $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() @@ -1099,82 +1367,14 @@ function Set-OBSAudioOutputSource { } $DynamicParameters - } - begin { - # Audio Output sources have an inputKind of 'wasapi_output_capture'. - $inputKind = "wasapi_output_capture" - } process { - # Copy the bound parameters $myParameters = [Ordered]@{} + $PSBoundParameters - # and determine the name of the invocation - $MyInvocationName = "$($MyInvocation.InvocationName)" - # Split it into verb and noun - $myVerb, $myNoun = $MyInvocationName -split '-' - # and get a copy of ourself that we can call with anonymous recursion. - $myScriptBlock = $MyInvocation.MyCommand.ScriptBlock - # Determine if the verb was get, - $IsGet = $myVerb -eq "Get" - # if no verb was used, - $NoVerb = $MyInvocationName -match '^[^\.\&][^-]+$' - # and if there were any other parameters then name - $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' - - # If it is a get or there was no verb - if ($IsGet -or $NoVerb) { - $inputsOfKind = # Get all inputs of this kind - Get-OBSInput -InputKind $InputKind | - Where-Object { - if ($Name) { # If -Name was provided, - $_.InputName -like $Name # filter by name (as a wildcard). - } else { - $_ # otherwise, return every input. - } - } - - # If there were parameters other than name, - # and we were not explicitly called Get-* - if ($NonNameParameters -and -not $IsGet) { - # remove the name parameter - if ($myParameters.Name) { $myParameters.Remove('Name') } - # and pipe results back to ourself. - $inputsOfKind | & $myScriptBlock @myParameters - } else { - # Otherwise, we're just getting the list of inputs - $inputsOfKind - } - # (either way, if we were called Get- or with no verb, we're done now). - return - } - - if (-not $myParameters["Scene"]) { - $myParameters["Scene"] = Get-OBSCurrentProgramScene | - Select-Object -ExpandProperty currentProgramSceneName - } - - if (-not $myParameters["AudioDevice"]) { - $myParameters["AudioDevice"] = "default" - } - - # Window capture is a bit of a tricky one. - # In order to get the WindowTitle to match that OBS needs, we need to look thru the input properties list. - # and for that, an input needs to exist. - if (-not $myParameters["Name"]) { - - - if ($myParameters["AudioDevice"]) { - $Name = $myParameters["Name"] = "AudioOutput-" + $myParameters["AudioDevice"] - } - else { - $Name = $myParameters["Name"] = "AudioOutput" - } + if (-not $myParameters["FilterName"]) { + $filterName = $myParameters["FilterName"] = "3Band3D" } - - - - + $myParameterData = [Ordered]@{} foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { @@ -1194,167 +1394,146 @@ function Set-OBSAudioOutputSource { $myParameterData[$bindToPropertyName] = $parameter.Name -as [bool] } } - } - - $addSplat = @{ - sceneName = $myParameters["Scene"] - inputName = $myParameters["Name"] - inputKind = $inputKind - inputSettings = $myParameterData - NoResponse = $myParameters["NoResponse"] - } - - # If -SceneItemEnabled was passed, - if ($myParameters.Contains('SceneItemEnabled')) { - # propagate it to Add-OBSInput. - $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] } - - # Add the input. - $outputAddedResult = Add-OBSInput @addSplat *>&1 - $possibleDevices = Get-OBSInputPropertiesListPropertyItems -InputName $addSplat.inputName -PropertyName device_id - foreach ($deviceInfo in $possibleDevices) { - if ( - ($deviceInfo.itemName -eq $AudioDevice) -or - ($deviceInfo.ItemValue -eq $AudioDevice) -or - ($deviceInfo.ItemName -replace '\[[^\[\]]+\]\:\s' -eq $AudioDevice) -or - ($deviceInfo.ItemValue -like "*$AudioDevice*") -or - ($deviceInfo.ItemName -like "*$AudioDevice*") - ) { - $myParameterData["device_id"] = $deviceInfo.itemValue - break - } + + $addSplat = @{ + filterName = $myParameters["FilterName"] + SourceName = $myParameters["SourceName"] + filterKind = "3d_effect_filter" + filterSettings = $myParameterData + NoResponse = $myParameters["NoResponse"] } - # If -PassThru was passed if ($MyParameters["PassThru"]) { - # pass it down to each command - # Otherwise, remove SceneItemEnabled, InputKind, and SceneName - $addSplat.PassThru = $true - $addSplat.Remove('SceneItemEnabled') - $addSplat.Remove('inputKind') - $addSplat.Remove('sceneName') - # and passthru Set-OBSInputSettings. - Set-OBSInputSettings @addSplat - - return + $addSplat.Passthru = $MyParameters["PassThru"] + if ($MyInvocation.InvocationName -like 'Add-*') { + Add-OBSSourceFilter @addSplat + } else { + $addSplat.Remove('FilterKind') + Set-OBSSourceFilterSettings @addSplat + } + return } - if ($Force) { # If we do, remove the input - Remove-OBSInput -InputName $addSplat.inputName - # and re-add our result. - $outputAddedResult = Add-OBSInput @addSplat *>&1 + # Add the input. + $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 + + + # If we got back an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # and that error was saying the source already exists, + if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { + # then check if we use the -Force. + if ($Force) { # If we do, remove the input + Remove-OBSSourceFilter -FilterName $addSplat.FilterName -SourceName $addSplat.SourceName + # and re-add our result. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + } else { + # Otherwise, get the existing filter. + $existingFilter = Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName + # then apply the settings + $existingFilter.Set($addSplat.filterSettings) + # and output them + $existingFilter + # (don't forget to null the result, so we don't show this error) + $outputAddedResult = $null + } + } + # If the output was still an error if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { # use $psCmdlet.WriteError so that it shows the error correctly. $psCmdlet.WriteError($outputAddedResult) } - # Otherwise, if we had a result - elseif ($outputAddedResult) { - # get the input from the scene. - Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $myParameters["Scene"] - } - } else { - # Otherwise, get the input from the scene, - $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $myParameters["Name"] - # update the input settings - $sceneItem.Input.Settings = $addSplat.inputSettings - $sceneItem # and return the scene item. + + } + # Otherwise, if we had a result + elseif ($outputAddedResult) { + # Otherwise, get the input from the filters. + Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName + } } } + #.ExternalHelp obs-powershell-Help.xml -function Set-OBSBrowserSource { +function Set-OBSColorFilter { - [Alias('Add-OBSBrowserSource','Get-OBSBrowserSource')] + [Alias('Add-OBSColorFilter','Add-OBSColorCorrectionFilter','Set-OBSColorCorrectionFilter')] param( - # The uri or file path to display. - # If the uri points to a local file, this will be preferred - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('Url', 'Href','Path','FilePath','FullName')] - [uri] - $Uri, - - # The width of the browser source. - # If none is provided, this will be the output width of the video settings. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("width")] - [int] - $Width, - - # The width of the browser source. - # If none is provided, this will be the output height of the video settings. + # The opacity, as a number between 0 and 1. [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("height")] - [int] - $Height, + [ValidateRange(0,1)] + [ComponentModel.DefaultBindingProperty("opacity")] + [double] + $Opacity, - # The css style used to render the browser page. + # The brightness, as a number between -1 and 1. [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("css")] - [string] - $CSS = "body { background-color: rgba(0, 0, 0, 0); margin: 0px auto; overflow: hidden; }", + [ValidateRange(-1,1)] + [ComponentModel.DefaultBindingProperty("brightness")] + [double] + $Brightness, - # If set, the browser source will shutdown when it is hidden + # The constrast, as a number between -4 and 4. [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("shutdown")] - [switch] - $ShutdownWhenHidden, + [ValidateRange(-4,4)] + [ComponentModel.DefaultBindingProperty("contrast")] + [double] + $Contrast, - # If set, the browser source will restart when it is activated. + # The gamma correction, as a number between -3 and 3. [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("restart_when_active")] - [switch] - $RestartWhenActived, + [ValidateRange(-3,3)] + [ComponentModel.DefaultBindingProperty("gamma")] + [double] + $Gamma, - # If set, audio from the browser source will be rerouted into OBS. + # The saturation, as a number between -1 and 5. [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("reroute_audio")] - [switch] - $RerouteAudio, + [ValidateRange(-1,5)] + [ComponentModel.DefaultBindingProperty("saturation")] + [double] + $Saturation, - # If provided, the browser source will render at a custom frame rate. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("fps")] - [Alias('FPS')] - [int] - $FramesPerSecond, + # The change in hue, as represented in degrees around a color cicrle + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("hue_shift")] + [Alias('Spin')] + [double] + $Hue, - # The name of the scene. - # If no scene name is provided, the current program scene will be used. + # Multiply this color by all pixels within the source. [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("color_multiply")] [string] - $Scene, + $MultiplyColor, - # The name of the input. - # If no name is provided, the last segment of the URI or file path will be the input name. + # Add all this color to all pixels within the source. [Parameter(ValueFromPipelineByPropertyName)] - [Alias('InputName','SourceName')] + [ComponentModel.DefaultBindingProperty("color_add")] [string] - $Name, + $AddColor, - # If set, will check if the source exists in the scene before creating it and removing any existing sources found. - # If not set, you will get an error if a source with the same name exists. - [Parameter(ValueFromPipelineByPropertyName)] + # If set, will remove a filter if one already exists. + # If this is not provided and the filter already exists, the settings of the filter will be changed. [switch] $Force ) dynamicParam { $baseCommand = - if (-not $script:AddOBSInput) { - $script:AddOBSInput = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') - $script:AddOBSInput + if (-not $script:AddOBSSourceFilter) { + $script:AddOBSSourceFilter = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSSourceFilter','Function') + $script:AddOBSSourceFilter } else { - $script:AddOBSInput + $script:AddOBSSourceFilter } $IncludeParameter = @() - $ExcludeParameter = 'inputKind','sceneName','inputName' + $ExcludeParameter = 'FilterKind','FilterSettings' $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() @@ -1382,73 +1561,36 @@ function Set-OBSBrowserSource { } begin { - # Browser Sources are built into OBS. Their input kind is browser_source. - $inputKind = "browser_source" + filter ToOBSColor { + + if ($_ -is [uint32]) { $_ } + elseif ($_ -is [string]) { + if ($_ -match '^\#[a-f0-9]{3,4}$') { + $_ = $_ -replace '[a-f0-9]','$0$0' + } + + if ($_ -match '^#[a-f0-9]{8}$') { + $_ -replace '#','0x' -as [UInt32] + } + elseif ($_ -match '^#[a-f0-9]{6}$') { + $_ -replace '#','0xff' -as [UInt32] + } + } + + } } process { $myParameters = [Ordered]@{} + $PSBoundParameters - # Copy the bound parameters - $myParameters = [Ordered]@{} + $PSBoundParameters - # and determine the name of the invocation - $MyInvocationName = "$($MyInvocation.InvocationName)" - # Split it into verb and noun - $myVerb, $myNoun = $MyInvocationName -split '-' - # and get a copy of ourself that we can call with anonymous recursion. - $myScriptBlock = $MyInvocation.MyCommand.ScriptBlock - # Determine if the verb was get, - $IsGet = $myVerb -eq "Get" - # if no verb was used, - $NoVerb = $MyInvocationName -match '^[^\.\&][^-]+$' - # and if there were any other parameters then name - $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' + if (-not $myParameters["FilterName"]) { + $FilterName = $myParameters["FilterName"] = "ColorCorrection" + } + + $myParameterData = [Ordered]@{} + foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { - # If it is a get or there was no verb - if ($IsGet -or $NoVerb) { - $inputsOfKind = # Get all inputs of this kind - Get-OBSInput -InputKind $InputKind | - Where-Object { - if ($Name) { # If -Name was provided, - $_.InputName -like $Name # filter by name (as a wildcard). - } else { - $_ # otherwise, return every input. - } - } - - # If there were parameters other than name, - # and we were not explicitly called Get-* - if ($NonNameParameters -and -not $IsGet) { - # remove the name parameter - if ($myParameters.Name) { $myParameters.Remove('Name') } - # and pipe results back to ourself. - $inputsOfKind | & $myScriptBlock @myParameters - } else { - # Otherwise, we're just getting the list of inputs - $inputsOfKind - } - # (either way, if we were called Get- or with no verb, we're done now). - return - } - - if ((-not $width) -or (-not $height)) { - if (-not $script:CachedOBSVideoSettings) { - $script:CachedOBSVideoSettings = Get-OBSVideoSettings - } - $videoSettings = $script:CachedOBSVideoSettings - $myParameters["Width"] = $width = $videoSettings.outputWidth - $myParameters["Height"] = $height = $videoSettings.outputHeight - } - - if (-not $myParameters["Scene"]) { - $myParameters["Scene"] = Get-OBSCurrentProgramScene | - Select-Object -ExpandProperty currentProgramSceneName - } - - $myParameterData = [Ordered]@{} - foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { - - $bindToPropertyName = $null + $bindToPropertyName = $null foreach ($attribute in $parameter.Attributes) { if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { @@ -1461,76 +1603,45 @@ function Set-OBSBrowserSource { if ($myParameters.Contains($parameter.Name)) { $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] if ($myParameters[$parameter.Name] -is [switch]) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] -as [bool] + $myParameterData[$bindToPropertyName] = $parameter.Name -as [bool] } } } - - if ($fps -and $fps -ne 30) { - $myParameterData["custom_fps"] = $true - } - if ($uri.Scheme -eq 'File') { - if (Test-Path $uri.AbsolutePath) { - $myParameterData["local_file"] = "$uri" -replace '[\\/]', '/' -replace '^file:///' - $myParameterData["is_local_file"] = $true - } - } - else - { - if (Test-Path $uri) { - $rp = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($uri) - $myParameterData["local_file"] = "$rp" -replace '[\\/]', '/' -replace '^file:///' - $myParameterData["is_local_file"] = $true - } else { - $myParameterData["url"] = "$uri" - } + + if ($myParameterData.color_add) { + $myParameterData.color_add = $myParameterData.color_add | ToOBSColor } - - if (-not $Name) { - $Name = $myParameters['Name'] = - if ($uri.Segments) { - $uri.Segments[-1] - } elseif ($uri -match '[\\/]') { - @($uri -split '[\\/]')[-1] - } else { - $uri - } - } + if ($myParameterData.color_multiply) { + $myParameterData.color_multiply = $myParameterData.color_multiply | ToOBSColor + } - $addSplat = [Ordered]@{ - sceneName = $myParameters["Scene"] - inputKind = $inputKind - inputSettings = $myParameterData - inputName = $Name + + $addSplat = @{ + filterName = $myParameters["FilterName"] + SourceName = $myParameters["SourceName"] + filterKind = "color_filter_v2" + filterSettings = $myParameterData NoResponse = $myParameters["NoResponse"] } - # If -SceneItemEnabled was passed, - if ($myParameters.Contains('SceneItemEnabled')) { - # propagate it to Add-OBSInput. - $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] - } - - # If -PassThru was passed + if ($MyParameters["PassThru"]) { - # pass it down to each command $addSplat.Passthru = $MyParameters["PassThru"] - # If we were called with Add- if ($MyInvocation.InvocationName -like 'Add-*') { - Add-OBSInput @addSplat # passthru Add-OBSInput + Add-OBSSourceFilter @addSplat } else { - # Otherwise, remove SceneItemEnabled, InputKind, and SceneName - $addSplat.Remove('SceneItemEnabled') - $addSplat.Remove('inputKind') - $addSplat.Remove('sceneName') - # and passthru Set-OBSInputSettings. - Set-OBSInputSettings @addSplat + $addSplat.Remove('FilterKind') + Set-OBSSourceFilterSettings @addSplat } - return - } - + return + } + # Add the input. - $outputAddedResult = Add-OBSInput @addSplat *>&1 + $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 + + if ($PassThru) { + return $outputAddedResult + } # If we got back an error if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { @@ -1538,16 +1649,17 @@ function Set-OBSBrowserSource { if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { # then check if we use the -Force. if ($Force) { # If we do, remove the input - Remove-OBSInput -InputName $addSplat.inputName + Remove-OBSSourceFilter -FilterName $addSplat.FilterName -SourceName $addSplat.SourceName # and re-add our result. - $outputAddedResult = Add-OBSInput @addSplat *>&1 + $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 } else { - # Otherwise, get the input from the scene, - $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $myParameters["Name"] - # update the input settings - $sceneItem.Input.Settings = $addSplat.inputSettings - $sceneItem # and return the scene item. + # Otherwise, get the existing filter. + $existingFilter = Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName + # then apply the settings + $existingFilter.Set($addSplat.filterSettings) + # and output them + $existingFilter + # (don't forget to null the result, so we don't show this error) $outputAddedResult = $null } } @@ -1556,61 +1668,62 @@ function Set-OBSBrowserSource { if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { # use $psCmdlet.WriteError so that it shows the error correctly. $psCmdlet.WriteError($outputAddedResult) - } + } + } # Otherwise, if we had a result - if ($outputAddedResult -and - $outputAddedResult -isnot [Management.Automation.ErrorRecord]) { - # get the input from the scene. - Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $myParameters["Name"] + elseif ($outputAddedResult) { + # Otherwise, get the input from the filters. + Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName } } } + #.ExternalHelp obs-powershell-Help.xml -function Set-OBSColorSource { +function Set-OBSEqualizerFilter { - [Alias('Add-OBSColorSource','Get-OBSColorSource')] + [Alias('Add-OBSEqualizierFilter','Add-OBS3BandEqualizerFilter','Set-OBS3BandEqualizerFilter')] param( - # The name of the scene. - # If no scene name is provided, the current program scene will be used. - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('SceneName')] - [string] - $Scene, + # The change in low frequencies. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("low")] + [ValidateRange(-20,20)] + [double] + $Low, - # The name of the input. - # If no name is provided, "Display $($Monitor + 1)" will be the input source name. - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('InputName')] - [string] - $Name, + # The change in mid frequencies. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("mid")] + [ValidateRange(-20,20)] + [double] + $Mid, - [ValidatePattern('\#(?>[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{4}|[0-9a-f]{3})')] - [Parameter(ValueFromPipelineByPropertyName)] - [string] - $Color, + # The change in high frequencies. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("high")] + [ValidateRange(-20,20)] + [double] + $High, - # If set, will check if the source exists in the scene before creating it and removing any existing sources found. - # If not set, you will get an error if a source with the same name exists. - [Parameter(ValueFromPipelineByPropertyName)] + # If set, will remove a filter if one already exists. + # If this is not provided and the filter already exists, the settings of the filter will be changed. [switch] $Force ) dynamicParam { $baseCommand = - if (-not $script:AddOBSInput) { - $script:AddOBSInput = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') - $script:AddOBSInput + if (-not $script:AddOBSSourceFilter) { + $script:AddOBSSourceFilter = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSSourceFilter','Function') + $script:AddOBSSourceFilter } else { - $script:AddOBSInput + $script:AddOBSSourceFilter } $IncludeParameter = @() - $ExcludeParameter = 'inputKind','sceneName','inputName' + $ExcludeParameter = 'FilterKind','FilterSettings' $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() @@ -1636,145 +1749,56 @@ function Set-OBSColorSource { } $DynamicParameters - } - begin { - $inputKind = "color_source_v3" - } process { - # Copy the bound parameters $myParameters = [Ordered]@{} + $PSBoundParameters - # and determine the name of the invocation - $MyInvocationName = "$($MyInvocation.InvocationName)" - # Split it into verb and noun - $myVerb, $myNoun = $MyInvocationName -split '-' - # and get a copy of ourself that we can call with anonymous recursion. - $myScriptBlock = $MyInvocation.MyCommand.ScriptBlock - # Determine if the verb was get, - $IsGet = $myVerb -eq "Get" - # if no verb was used, - $NoVerb = $MyInvocationName -match '^[^\.\&][^-]+$' - # and if there were any other parameters then name - $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' - - # If it is a get or there was no verb - if ($IsGet -or $NoVerb) { - $inputsOfKind = # Get all inputs of this kind - Get-OBSInput -InputKind $InputKind | - Where-Object { - if ($Name) { # If -Name was provided, - $_.InputName -like $Name # filter by name (as a wildcard). - } else { - $_ # otherwise, return every input. - } - } - - # If there were parameters other than name, - # and we were not explicitly called Get-* - if ($NonNameParameters -and -not $IsGet) { - # remove the name parameter - if ($myParameters.Name) { $myParameters.Remove('Name') } - # and pipe results back to ourself. - $inputsOfKind | & $myScriptBlock @myParameters - } else { - # Otherwise, we're just getting the list of inputs - $inputsOfKind - } - # (either way, if we were called Get- or with no verb, we're done now). - return - } - if (-not $myParameters["Scene"]) { - $myParameters["Scene"] = Get-OBSCurrentProgramScene | - Select-Object -ExpandProperty currentProgramSceneName + if (-not $myParameters["FilterName"]) { + $filterName = $myParameters["FilterName"] = "3BandEqualizer" } + + $myParameterData = [Ordered]@{} + foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { - $hexChar = [Regex]::new('[0-9a-f]') - $hexColors = @($hexChar.Matches($Color)) - - switch ($hexColors.Length) { - 8 { - #full rgba - $alpha = [byte]::Parse($hexColors[0..1] -join '', 'HexNumber') - $red = [byte]::Parse($hexColors[2..3] -join '', 'HexNumber') - $green = [byte]::Parse($hexColors[4..5] -join '', 'HexNumber') - $blue = [byte]::Parse($hexColors[6..7] -join '', 'HexNumber') - } - 6 { - #rgb only, assume ff for alpha - $alpha = 0xff - $red = [byte]::Parse($hexColors[0..1] -join '', 'HexNumber') - $green = [byte]::Parse($hexColors[2..3] -join '', 'HexNumber') - $blue = [byte]::Parse($hexColors[4..5] -join '', 'HexNumber') - } - 4 { - #short rgba - $alpha = [byte]::Parse(($hexColors[0],$hexColors[0] -join ''), 'HexNumber') - $red = [byte]::Parse(($hexColors[1],$hexColors[1] -join ''), 'HexNumber') - $green = [byte]::Parse(($hexColors[2],$hexColors[2] -join ''), 'HexNumber') - $blue = [byte]::Parse(($hexColors[3],$hexColors[3] -join ''), 'HexNumber') - } - 3 { - #short rgb, assume f for alpha - $alpha = 0xff - $red = [byte]::Parse(($hexColors[0],$hexColors[0] -join ''), 'HexNumber') - $green = [byte]::Parse(($hexColors[1],$hexColors[1] -join ''), 'HexNumber') - $blue = [byte]::Parse(($hexColors[2],$hexColors[2] -join ''), 'HexNumber') + $bindToPropertyName = $null + + foreach ($attribute in $parameter.Attributes) { + if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { + $bindToPropertyName = $attribute.Name + break + } } - 0 { - # No color provided, default to transparent black - $alpha = 0 - $red = 0 - $green = 0 - $blue = 0 + + if (-not $bindToPropertyName) { continue } + if ($myParameters.Contains($parameter.Name)) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] + if ($myParameters[$parameter.Name] -is [switch]) { + $myParameterData[$bindToPropertyName] = $parameter.Name -as [bool] + } } } - - $hexColor = ("{0:x2}{1:x2}{2:x2}{3:x2}" -f $alpha, $blue, $green, $red) - - $realColor = [uint32]::Parse($hexColor,'HexNumber') - - if (-not $myParameters["Name"]) { - $myParameters["Name"] = "#$hexColor" - } - - $myParameterData = [Ordered]@{color=$realColor} - - $addSplat = @{ - sceneName = $myParameters["Scene"] - inputName = $myParameters["Name"] - inputKind = "color_source_v3" - inputSettings = $myParameterData - NoResponse = $myParameters["NoResponse"] - } - - # If -SceneItemEnabled was passed, - if ($myParameters.Contains('SceneItemEnabled')) { - # propagate it to Add-OBSInput. - $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] + $addSplat = @{ + filterName = $myParameters["FilterName"] + SourceName = $myParameters["SourceName"] + filterKind = "basic_eq_filter" + filterSettings = $myParameterData } - # If -PassThru was passed if ($MyParameters["PassThru"]) { - # pass it down to each command $addSplat.Passthru = $MyParameters["PassThru"] - # If we were called with Add- if ($MyInvocation.InvocationName -like 'Add-*') { - Add-OBSInput @addSplat # passthru Add-OBSInput + Add-OBSSourceFilter @addSplat } else { - # Otherwise, remove SceneItemEnabled, InputKind, and SceneName - $addSplat.Remove('SceneItemEnabled') - $addSplat.Remove('inputKind') - $addSplat.Remove('sceneName') - # and passthru Set-OBSInputSettings. - Set-OBSInputSettings @addSplat + $addSplat.Remove('FilterKind') + Set-OBSSourceFilterSettings @addSplat } - return + return } # Add the input. - $outputAddedResult = Add-OBSInput @addSplat *>&1 + $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 + # If we got back an error if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { @@ -1782,16 +1806,17 @@ function Set-OBSColorSource { if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { # then check if we use the -Force. if ($Force) { # If we do, remove the input - Remove-OBSInput -InputName $addSplat.inputName + Remove-OBSSourceFilter -FilterName $addSplat.FilterName -SourceName $addSplat.SourceName # and re-add our result. $outputAddedResult = Add-OBSInput @addSplat *>&1 } else { - # Otherwise, get the input from the scene, - $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $myParameters["Name"] - # update the input settings - $sceneItem.Input.Settings = $addSplat.inputSettings - $sceneItem # and return the scene item. + # Otherwise, get the existing filter. + $existingFilter = Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName + # then apply the settings + $existingFilter.Set($addSplat.filterSettings) + # and output them + $existingFilter + # (don't forget to null the result, so we don't show this error) $outputAddedResult = $null } } @@ -1800,73 +1825,48 @@ function Set-OBSColorSource { if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { # use $psCmdlet.WriteError so that it shows the error correctly. $psCmdlet.WriteError($outputAddedResult) - } + } + } # Otherwise, if we had a result - if ($outputAddedResult -and - $outputAddedResult -isnot [Management.Automation.ErrorRecord]) { - # get the input from the scene. - Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $myParameters["Name"] - } + elseif ($outputAddedResult) { + # Otherwise, get the input from the filters. + Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName + + } } } #.ExternalHelp obs-powershell-Help.xml -function Set-OBSDisplaySource { +function Set-OBSGainFilter { - [Alias('Add-OBSMonitorSource','Set-OBSMonitorSource','Add-OBSDisplaySource')] + [Alias('Add-OBSGainFilter')] param( - # The monitor number. - # This the number of the monitor you would like to capture. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("monitor")] - [Alias('MonitorNumber','Display','DisplayNumber')] - [int] - $Monitor = 1, - - # If set, will capture the cursor. - # This will be set by default. - # If explicitly set to false, the cursor will not be captured. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("capture_cursor")] - [switch] - $CaptureCursor, - - # The name of the scene. - # If no scene name is provided, the current program scene will be used. - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('SceneName')] - [string] - $Scene, - - # The name of the input. - # If no name is provided, "Display $($Monitor + 1)" will be the input source name. - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('InputName')] - [string] - $Name, + # The Audio Gain, in decibels. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("db")] + [double] + $Gain, - # If set, will check if the source exists in the scene before creating it and removing any existing sources found. - # If not set, you will get an error if a source with the same name exists. - [Parameter(ValueFromPipelineByPropertyName)] + # If set, will remove a filter if one already exists. + # If this is not provided and the filter already exists, the settings of the filter will be changed. [switch] $Force ) dynamicParam { $baseCommand = - if (-not $script:AddOBSInput) { - $script:AddOBSInput = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') - $script:AddOBSInput + if (-not $script:AddOBSSourceFilter) { + $script:AddOBSSourceFilter = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSSourceFilter','Function') + $script:AddOBSSourceFilter } else { - $script:AddOBSInput + $script:AddOBSSourceFilter } $IncludeParameter = @() - $ExcludeParameter = 'inputKind','sceneName','inputName' + $ExcludeParameter = 'FilterKind','FilterSettings' $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() @@ -1896,73 +1896,31 @@ function Set-OBSDisplaySource { process { $myParameters = [Ordered]@{} + $PSBoundParameters - if (-not $myParameters["Scene"]) { - $myParameters["Scene"] = Get-OBSCurrentProgramScene | - Select-Object -ExpandProperty currentProgramSceneName - } - - $myParameterData = [Ordered]@{} - foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { - - $bindToPropertyName = $null - - foreach ($attribute in $parameter.Attributes) { - if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { - $bindToPropertyName = $attribute.Name - break - } - } - - if (-not $bindToPropertyName) { continue } - if ($myParameters.Contains($parameter.Name)) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] - if ($myParameters[$parameter.Name] -is [switch]) { - $myParameterData[$bindToPropertyName] = $parameter.Name -as [bool] - } - } - } - - # Users like 1 indexed, computers like zero-indexed. - $myParameterData["monitor"] = $Monitor - 1 - - if (-not $myParameters["Name"]) { - $myParameters["Name"] = "Display $($Monitor)" + if (-not $myParameters["FilterName"]) { + $filterName = $myParameters["FilterName"] = "Gain" } - - $addSplat = @{ - sceneName = $myParameters["Scene"] - inputName = $myParameters["Name"] - inputKind = "monitor_capture" - inputSettings = $myParameterData + + $addSplat = @{ + filterName = $myParameters["FilterName"] + SourceName = $myParameters["SourceName"] + filterKind = "gain_filter" + filterSettings = [Ordered]@{db=$Gain} NoResponse = $myParameters["NoResponse"] - } - - # If -SceneItemEnabled was passed, - if ($myParameters.Contains('SceneItemEnabled')) { - # propagate it to Add-OBSInput. - $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] } - - # If -PassThru was passed + if ($MyParameters["PassThru"]) { - # pass it down to each command $addSplat.Passthru = $MyParameters["PassThru"] - # If we were called with Add- if ($MyInvocation.InvocationName -like 'Add-*') { - Add-OBSInput @addSplat # passthru Add-OBSInput + Add-OBSSourceFilter @addSplat } else { - # Otherwise, remove SceneItemEnabled, InputKind, and SceneName - $addSplat.Remove('SceneItemEnabled') - $addSplat.Remove('inputKind') - $addSplat.Remove('sceneName') - # and passthru Set-OBSInputSettings. - Set-OBSInputSettings @addSplat + $addSplat.Remove('FilterKind') + Set-OBSSourceFilterSettings @addSplat } - return + return } # Add the input. - $outputAddedResult = Add-OBSInput @addSplat *>&1 + $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 # If we got back an error if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { @@ -1970,16 +1928,17 @@ function Set-OBSDisplaySource { if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { # then check if we use the -Force. if ($Force) { # If we do, remove the input - Remove-OBSInput -InputName $addSplat.inputName + Remove-OBSSourceFilter -FilterName $addSplat.FilterName -SourceName $addSplat.SourceName # and re-add our result. $outputAddedResult = Add-OBSInput @addSplat *>&1 } else { - # Otherwise, get the input from the scene, - $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $myParameters["Name"] - # update the input settings - $sceneItem.Input.Settings = $addSplat.inputSettings - $sceneItem # and return the scene item. + # Otherwise, get the existing filter. + $existingFilter = Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName + # then apply the settings + $existingFilter.Set($addSplat.filterSettings) + # and output them + $existingFilter + # (don't forget to null the result, so we don't show this error) $outputAddedResult = $null } } @@ -1988,79 +1947,48 @@ function Set-OBSDisplaySource { if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { # use $psCmdlet.WriteError so that it shows the error correctly. $psCmdlet.WriteError($outputAddedResult) - } - } + } + + } # Otherwise, if we had a result - if ($outputAddedResult -and - $outputAddedResult -isnot [Management.Automation.ErrorRecord]) { - # get the input from the scene. - Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $name + elseif ($outputAddedResult) { + # Otherwise, get the input from the filters. + Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName + } } } + + #.ExternalHelp obs-powershell-Help.xml -function Set-OBSMarkdownSource { +function Set-OBSRenderDelayFilter { - [Alias('Add-OBSMarkdownSource','Get-OBSMarkdownSource')] + [Alias('Add-OBSRenderDelayFilter')] param( - # The markdown text, or the path to a markdown file - [Parameter(ValueFromPipelineByPropertyName)] - [string] - $Markdown, - - # The width of the browser source. - # If none is provided, this will be the output width of the video settings. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("width")] - [int] - $Width, - - # The width of the browser source. - # If none is provided, this will be the output height of the video settings. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("height")] - [int] - $Height, - - # The css style used to render the markdown. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("css")] - [string] - $CSS = "body { background-color: rgba(0, 0, 0, 0); margin: 0px auto; overflow: hidden; }", - - # The name of the scene. - # If no scene name is provided, the current program scene will be used. - [Parameter(ValueFromPipelineByPropertyName)] - [string] - $Scene, - - # The name of the input. - # If no name is provided, the last segment of the URI or file path will be the input name. + # The RenderDelay. [Parameter(ValueFromPipelineByPropertyName)] - [string] - $Name, + [timespan] + $RenderDelay, - # If set, will check if the source exists in the scene before creating it and removing any existing sources found. - # If not set, you will get an error if a source with the same name exists. - [Parameter(ValueFromPipelineByPropertyName)] + # If set, will remove a filter if one already exists. + # If this is not provided and the filter already exists, the settings of the filter will be changed. [switch] $Force ) dynamicParam { $baseCommand = - if (-not $script:AddOBSInput) { - $script:AddOBSInput = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') - $script:AddOBSInput + if (-not $script:AddOBSSourceFilter) { + $script:AddOBSSourceFilter = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSSourceFilter','Function') + $script:AddOBSSourceFilter } else { - $script:AddOBSInput + $script:AddOBSSourceFilter } $IncludeParameter = @() - $ExcludeParameter = 'inputKind','sceneName','inputName' + $ExcludeParameter = 'FilterKind','FilterSettings' $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() @@ -2086,129 +2014,43 @@ function Set-OBSMarkdownSource { } $DynamicParameters - } - begin { - $inputKind = "markdown_source" - } process { $myParameters = [Ordered]@{} + $PSBoundParameters - - $IsGet = $MyInvocation.InvocationName -like "Get-*" - $NoVerb = $MyInvocation.InvocationName -match '^[^-]+$' - $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' - - if ( - $IsGet -or - ($NoVerb -and -not $NonNameParameters) - ) { - Get-OBSInput -InputKind $InputKind | - Where-Object { - if ($Name) { - $_.InputName -like $Name - } else { - $_ - } - } - return + + if (-not $myParameters["FilterName"]) { + $filterName = $myParameters["FilterName"] = "RenderDelay" } - if ((-not $width) -or (-not $height)) { - if (-not $script:CachedOBSVideoSettings) { - $script:CachedOBSVideoSettings = Get-OBSVideoSettings - } - $videoSettings = $script:CachedOBSVideoSettings - $myParameters["Width"] = $width = $videoSettings.outputWidth - $myParameters["Height"] = $height = $videoSettings.outputHeight - } - - if (-not $myParameters["Scene"]) { - $myParameters["Scene"] = Get-OBSCurrentProgramScene | - Select-Object -ExpandProperty currentProgramSceneName - } - $myParameterData = [Ordered]@{} - foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { - - $bindToPropertyName = $null - - foreach ($attribute in $parameter.Attributes) { - if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { - $bindToPropertyName = $attribute.Name - break - } - } - - if (-not $bindToPropertyName) { continue } - if ($myParameters.Contains($parameter.Name)) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] - if ($myParameters[$parameter.Name] -is [switch]) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] -as [bool] - } - } - } - - $markdownAsUri = $null - if ($Markdown -like '*.md') { - $markdownAsUri = $markdown -as [uri] - if ($markdownAsUri.Scheme -eq 'File') { - $myParameterData["markdown_path"] = "$markdownAsUri" -replace '[\\/]', '/' -replace '^file:///' - $myParameterData["markdown_source"] = 1 - } - else { - + $myParameterData = [Ordered]@{ + delay_ms = if ($RenderDelay.Ticks -lt 10kb) { + [int]$RenderDelay.Ticks + } else { + [int]$RenderDelay.TotalMilliseconds } - } else { - $myParameterData["text"] = $Markdown - $myParameterData["markdown_source"] = 0 } - - if (-not $Name) { - $Name = $myParameters['Name'] = - if ($markdownAsUri.Segments) { - $markdownAsUri.Segments[-1] - } elseif ($markdownAsUri -match '[\\/]') { - @($markdownAsUri -split '[\\/]')[-1] - } elseif ($markdownAsUri) { - $markdownAsUri - } else { - "Markdown" - } - } - - $addSplat = [Ordered]@{ - sceneName = $myParameters["Scene"] - inputKind = "markdown_source" - inputSettings = $myParameterData - inputName = $Name + $addSplat = @{ + filterName = $myParameters["FilterName"] + SourceName = $myParameters["SourceName"] + filterKind = "gpu_delay" + filterSettings = $myParameterData NoResponse = $myParameters["NoResponse"] } - # If -SceneItemEnabled was passed, - if ($myParameters.Contains('SceneItemEnabled')) { - # propagate it to Add-OBSInput. - $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] - } - - # If -PassThru was passed + if ($MyParameters["PassThru"]) { - # pass it down to each command $addSplat.Passthru = $MyParameters["PassThru"] - # If we were called with Add- if ($MyInvocation.InvocationName -like 'Add-*') { - Add-OBSInput @addSplat # passthru Add-OBSInput + Add-OBSSourceFilter @addSplat } else { - # Otherwise, remove SceneItemEnabled, InputKind, and SceneName - $addSplat.Remove('SceneItemEnabled') - $addSplat.Remove('inputKind') - $addSplat.Remove('sceneName') - # and passthru Set-OBSInputSettings. - Set-OBSInputSettings @addSplat + $addSplat.Remove('FilterKind') + Set-OBSSourceFilterSettings @addSplat } - return + return } - + # Add the input. - $outputAddedResult = Add-OBSInput @addSplat *>&1 + $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 # If we got back an error if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { @@ -2216,16 +2058,17 @@ function Set-OBSMarkdownSource { if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { # then check if we use the -Force. if ($Force) { # If we do, remove the input - Remove-OBSInput -InputName $addSplat.inputName + Remove-OBSSourceFilter -FilterName $addSplat.FilterName -SourceName $addSplat.SourceName # and re-add our result. $outputAddedResult = Add-OBSInput @addSplat *>&1 } else { - # Otherwise, get the input from the scene, - $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $myParameters["Name"] - # update the input settings - $sceneItem.Input.Settings = $addSplat.inputSettings - $sceneItem # and return the scene item. + # Otherwise, get the existing filter. + $existingFilter = Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName + # then apply the settings + $existingFilter.Set($addSplat.filterSettings) + # and output them + $existingFilter + # (don't forget to null the result, so we don't show this error) $outputAddedResult = $null } } @@ -2234,104 +2077,64 @@ function Set-OBSMarkdownSource { if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { # use $psCmdlet.WriteError so that it shows the error correctly. $psCmdlet.WriteError($outputAddedResult) - } + } + } # Otherwise, if we had a result - if ($outputAddedResult -and - $outputAddedResult -isnot [Management.Automation.ErrorRecord]) { - # get the input from the scene. - Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $myParameters["Name"] + elseif ($outputAddedResult) { + # Otherwise, get the input from the filters. + Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName + } } } + + #.ExternalHelp obs-powershell-Help.xml -function Set-OBSMediaSource { +function Set-OBSScaleFilter { - [Alias('Add-OBSFFMpegSource','Add-OBSMediaSource','Set-OBSFFMpegSource','Get-OBSFFMpegSource','Get-OBSMediaSource')] + [Alias('Add-OBSScaleFilter')] param( - # The path to the media file. + # The Resolution. Can either width x height (e.g. 1920x1080) or an aspect ratio (16:9). [Parameter(ValueFromPipelineByPropertyName)] - [Alias('FullName','LocalFile','local_file')] - [string] - $FilePath, - - # If set, the source will close when it is inactive. - # By default, this will be set to true. - # To explicitly set it to false, use -CloseWhenInactive:$false - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("close_when_inactive")] - [switch] - $CloseWhenInactive, - - # If set, the source will automatically restart. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("looping")] - [Alias('Looping')] - [switch] - $Loop, - - # If set, will use hardware decoding, if available. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("hw_decode")] - [Alias('HardwareDecoding','hw_decode')] - [switch] - $UseHardwareDecoding, - - # If set, will clear the output on the end of the media. - # If this is set to false, the media will freeze on the last frame. - # This is set to true by default. - # To explicitly set to false, use -ClearMediaEnd:$false - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("clear_on_media_end")] - [Alias('ClearOnEnd','NoFreezeFrameOnEnd')] - [switch] - $ClearOnMediaEnd, - - # Any FFMpeg demuxer options. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("ffmpeg_options")] - [Alias('FFMpegOptions', 'FFMpeg_Options')] - [string] - $FFMpegOption, - - # The name of the scene. - # If no scene name is provided, the current program scene will be used. - [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("resolution")] + [Alias('Scale')] [string] - $Scene, + $Resolution, - # The name of the input. - # If no name is provided, the last segment of the URI or file path will be the input name. + # The sampling method. It will default to "lanczos". [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("sampling")] [string] - $Name, + $Sampling = 'lanczos', - # If set, will check if the source exists in the scene before creating it and removing any existing sources found. - # If not set, you will get an error if a source with the same name exists. + # If set, will keep the aspect ratio when scaling. + # This is only valid if the sampling method is set to "lanczos". [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("undistort")] + [Alias('Undistort')] [switch] - $Force, + $KeepAspectRatio, - # If set, will fit the input to the screen. - [Parameter(ValueFromPipelineByPropertyName)] + # If set, will remove a filter if one already exists. + # If this is not provided and the filter already exists, the settings of the filter will be changed. [switch] - $FitToScreen + $Force ) dynamicParam { $baseCommand = - if (-not $script:AddOBSInput) { - $script:AddOBSInput = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') - $script:AddOBSInput + if (-not $script:AddOBSSourceFilter) { + $script:AddOBSSourceFilter = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSSourceFilter','Function') + $script:AddOBSSourceFilter } else { - $script:AddOBSInput + $script:AddOBSSourceFilter } $IncludeParameter = @() - $ExcludeParameter = 'inputKind','sceneName','inputName' + $ExcludeParameter = 'FilterKind','FilterSettings' $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() @@ -2357,155 +2160,35 @@ function Set-OBSMediaSource { } $DynamicParameters - } - begin { - filter OutputAndFitToScreen { - - if ($FitToScreen -and $_.FitToScreen) { - $_.FitToScreen() - } - $_ - - } - $InputKind = "ffmpeg_source" - } process { - # Copy the bound parameters $myParameters = [Ordered]@{} + $PSBoundParameters - # and determine the name of the invocation - $MyInvocationName = "$($MyInvocation.InvocationName)" - # Split it into verb and noun - $myVerb, $myNoun = $MyInvocationName -split '-' - # and get a copy of ourself that we can call with anonymous recursion. - $myScriptBlock = $MyInvocation.MyCommand.ScriptBlock - # Determine if the verb was get, - $IsGet = $myVerb -eq "Get" - # if no verb was used, - $NoVerb = $MyInvocationName -match '^[^\.\&][^-]+$' - # and if there were any other parameters then name - $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' - - # If it is a get or there was no verb - if ($IsGet -or $NoVerb) { - $inputsOfKind = # Get all inputs of this kind - Get-OBSInput -InputKind $InputKind | - Where-Object { - if ($Name) { # If -Name was provided, - $_.InputName -like $Name # filter by name (as a wildcard). - } else { - $_ # otherwise, return every input. - } - } - - # If there were parameters other than name, - # and we were not explicitly called Get-* - if ($NonNameParameters -and -not $IsGet) { - # remove the name parameter - if ($myParameters.Name) { $myParameters.Remove('Name') } - # and pipe results back to ourself. - $inputsOfKind | & $myScriptBlock @myParameters - } else { - # Otherwise, we're just getting the list of inputs - $inputsOfKind - } - # (either way, if we were called Get- or with no verb, we're done now). - return - } - if (-not $myParameters["Scene"]) { - $myParameters["Scene"] = Get-OBSCurrentProgramScene | - Select-Object -ExpandProperty currentProgramSceneName - } - - $myParameterData = [Ordered]@{} - foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { - - $bindToPropertyName = $null - - foreach ($attribute in $parameter.Attributes) { - if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { - $bindToPropertyName = $attribute.Name - break - } - } - - if (-not $bindToPropertyName) { continue } - if ($myParameters.Contains($parameter.Name)) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] - if ($myParameters[$parameter.Name] -is [switch]) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] -as [bool] - } - } - } - - if ((Test-Path $FilePath)) { - $FilePathItem = Get-Item -Path $FilePath - $myParameterData['local_file'] = $FilePathItem.FullName -replace '/', '\' + if (-not $myParameters["FilterName"]) { + $filterName = $myParameters["FilterName"] = "Scale" } - - - if ($myParameters['InputSettings']) { - $keys = - @(if ($myParameters['InputSettings'] -is [Collections.IDictionary]) { - $myParameters['InputSettings'].Keys - } else { - foreach ($prop in $myParameters['InputSettings'].PSObject.Properties) { - $prop.Name - } - }) - - foreach ($key in $keys) { - $myParameterData[$key] = $myParameters['InputSettings'].$key - } - - $myParameterData.remove('inputSettings') - } - - if (-not $Name) { - - $Name = $myParameters["Name"] = - if ($FilePathItem.Name) { - $FilePathItem.Name - } else { - "Media" - } - - } - - $addSplat = [Ordered]@{ - sceneName = $myParameters["Scene"] - inputKind = $InputKind - inputSettings = $myParameterData - inputName = $Name + $addSplat = @{ + filterName = $myParameters["FilterName"] + SourceName = $myParameters["SourceName"] + filterKind = "scale_filter" + filterSettings = [Ordered]@{resolution=$Resolution;sampling=$Sampling;undistort=$KeepAspectRatio -as [bool]} NoResponse = $myParameters["NoResponse"] } - - if ($myParameters.Contains('SceneItemEnabled')) { - $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] - } - - # If -PassThru was passed + if ($MyParameters["PassThru"]) { - # pass it down to each command $addSplat.Passthru = $MyParameters["PassThru"] - # If we were called with Add- if ($MyInvocation.InvocationName -like 'Add-*') { - Add-OBSInput @addSplat # passthru Add-OBSInput + Add-OBSSourceFilter @addSplat } else { - # Otherwise, remove SceneItemEnabled, InputKind, and SceneName - $addSplat.Remove('SceneItemEnabled') - $addSplat.Remove('inputKind') - $addSplat.Remove('sceneName') - # and passthru Set-OBSInputSettings. - Set-OBSInputSettings @addSplat + $addSplat.Remove('FilterKind') + Set-OBSSourceFilterSettings @addSplat } - return + return } # Add the input. - $outputAddedResult = Add-OBSInput @addSplat *>&1 + $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 # If we got back an error if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { @@ -2513,16 +2196,17 @@ function Set-OBSMediaSource { if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { # then check if we use the -Force. if ($Force) { # If we do, remove the input - Remove-OBSInput -InputName $addSplat.inputName + Remove-OBSSourceFilter -FilterName $addSplat.FilterName -SourceName $addSplat.SourceName # and re-add our result. $outputAddedResult = Add-OBSInput @addSplat *>&1 } else { - # Otherwise, get the input from the scene, - $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $myParameters["Name"] - # update the input settings - $sceneItem.Input.Settings = $addSplat.inputSettings - $sceneItem # and return the scene item. + # Otherwise, get the existing filter. + $existingFilter = Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName + # then apply the settings + $existingFilter.Set($addSplat.filterSettings) + # and output them + $existingFilter + # (don't forget to null the result, so we don't show this error) $outputAddedResult = $null } } @@ -2532,152 +2216,77 @@ function Set-OBSMediaSource { # use $psCmdlet.WriteError so that it shows the error correctly. $psCmdlet.WriteError($outputAddedResult) } + } - # Otherwise, if we had a result - if ($outputAddedResult -isnot [Management.Automation.ErrorRecord]) { - # get the input from the scene and optionally fit it to the screen. - Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $name | - OutputAndFitToScreen + elseif ($outputAddedResult) { + # Otherwise, get the input from the filters. + Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName + } } } + + #.ExternalHelp obs-powershell-Help.xml -function Set-OBSSoundCloudSource { +function Set-OBSScrollFilter { - - [Alias('Add-OBSSoundCloudSource','Get-OBSSoundCloudSource')] + param( - # The uri to display. This must point to a SoundCloud URL. + # The horizontal scroll speed. [Parameter(ValueFromPipelineByPropertyName)] - [Alias('Url','SoundCloudUri','SoundCloudUrl')] - [uri] - $Uri, - - # If set, will not autoplay. - [Parameter(ValueFromPipelineByPropertyName)] - [switch] - $NoAutoPlay, + [ComponentModel.DefaultBindingProperty("speed_x")] + [Alias('SpeedX', 'Speed_X','HSpeed')] + [double] + $HorizontalSpeed, - # If set, will not display album artwork. - [Parameter(ValueFromPipelineByPropertyName)] - [switch] - $NoArtwork, - - # If set, will not display play count. - [Parameter(ValueFromPipelineByPropertyName)] - [switch] - $NoPlayCount, - - # If set, will not display uploader info. - [Parameter(ValueFromPipelineByPropertyName)] - [switch] - $NoUploaderInfo, - - # If provided, will start playing at a given track number. - [Parameter(ValueFromPipelineByPropertyName)] - [int] - $TrackNumber, - - # If set, will show a share link. - [Parameter(ValueFromPipelineByPropertyName)] - [switch] - $ShowShare, - - # If set, will show a download link. - [Parameter(ValueFromPipelineByPropertyName)] - [switch] - $ShowDownload, - - # If set, will show a buy link. - [Parameter(ValueFromPipelineByPropertyName)] - [switch] - $ShowBuy, - - # The color used for the SoundCloud audio bars and buttons. - [Parameter(ValueFromPipelineByPropertyName)] - [string] - $Color, - - # The width of the browser source. - # If none is provided, this will be the output width of the video settings. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("width")] - [int] - $Width, - - # The width of the browser source. - # If none is provided, this will be the output height of the video settings. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("height")] - [int] - $Height, - - # The css style used to render the browser page. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("css")] - [string] - $CSS = "body { background-color: rgba(0, 0, 0, 0); margin: 0px auto; overflow: hidden; }", - - # If set, the browser source will shutdown when it is hidden - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("shutdown")] - [switch] - $ShutdownWhenHidden, - - # If set, the browser source will restart when it is activated. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("restart_when_active")] - [switch] - $RestartWhenActived, + # The vertical scroll speed. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("speed_y")] + [Alias('SpeedY', 'Speed_Y','VSpeed')] + [double] + $VerticalSpeed, - # If set, audio from the browser source will be rerouted into OBS. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("reroute_audio")] + # If set, will not loop + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("loop")] [switch] - $RerouteAudio, - - # If provided, the browser source will render at a custom frame rate. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("fps")] - [Alias('FPS')] - [int] - $FramesPerSecond, + $NoLoop, - # The name of the scene. - # If no scene name is provided, the current program scene will be used. + # If provided, will limit the width. [Parameter(ValueFromPipelineByPropertyName)] - [Alias('SceneName')] - [string] - $Scene, + [ValidateRange(-500, 500)] + [ComponentModel.DefaultBindingProperty("cx")] + [Alias('LimitX', 'Limit_CX','WidthLimit')] + [double] + $LimitWidth, - # The name of the input. - # If no name is provided, then "SoundCloud" will be used. + # If provided, will limit the height. [Parameter(ValueFromPipelineByPropertyName)] - [Alias('InputName','SourceName')] - [string] - $Name, + [ValidateRange(-500, 500)] + [ComponentModel.DefaultBindingProperty("cy")] + [Alias('LimitY', 'Limit_CY','HeightLimit')] + [double] + $LimitHeight, - # If set, will check if the source exists in the scene before creating it and removing any existing sources found. - # If not set, you will get an error if a source with the same name exists. - [Parameter(ValueFromPipelineByPropertyName)] + # If set, will remove a filter if one already exists. + # If this is not provided and the filter already exists, the settings of the filter will be changed. [switch] $Force ) dynamicParam { $baseCommand = - if (-not $script:AddOBSInput) { - $script:AddOBSInput = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') - $script:AddOBSInput + if (-not $script:AddOBSSourceFilter) { + $script:AddOBSSourceFilter = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSSourceFilter','Function') + $script:AddOBSSourceFilter } else { - $script:AddOBSInput + $script:AddOBSSourceFilter } $IncludeParameter = @() - $ExcludeParameter = 'inputKind','sceneName','inputName' + $ExcludeParameter = 'FilterKind','FilterSettings' $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() @@ -2704,87 +2313,17 @@ function Set-OBSSoundCloudSource { $DynamicParameters } - begin { - # Browser Sources are built into OBS. Their input kind is browser_source. - # Sound Cloud Sources are really Browser Sources. - $inputKind = "browser_source" - - } - process { - # Copy the bound parameters + process { $myParameters = [Ordered]@{} + $PSBoundParameters - # and determine the name of the invocation - $MyInvocationName = "$($MyInvocation.InvocationName)" - # Split it into verb and noun - $myVerb, $myNoun = $MyInvocationName -split '-' - # and get a copy of ourself that we can call with anonymous recursion. - $myScriptBlock = $MyInvocation.MyCommand.ScriptBlock - # Determine if the verb was get, - $IsGet = $myVerb -eq "Get" - # if no verb was used, - $NoVerb = $MyInvocationName -match '^[^\.\&][^-]+$' - # and if there were any other parameters then name - $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' - - - if (-not $uri.DnsSafeHost -or $uri.DnsSafeHost -notmatch 'SoundCloud\.com$') { - Write-Error "URI must be from SoundCloud.com" - return - } - - if ($uri.Query) { - $uri = "https://$($uri.DnsSafeHost)" + $($uri.Segments -join '') - } - - # If it is a get or there was no verb - if ($IsGet -or $NoVerb) { - $inputsOfKind = # Get all inputs of this kind - Get-OBSInput -InputKind $InputKind | - Where-Object { - if ($Name) { # If -Name was provided, - $_.InputName -like $Name # filter by name (as a wildcard). - } else { - $_ # otherwise, return every input. - } - } | - Where-Object { - $_.Settings['LocalFile'] -like '*.SoundCloud.*' - } - - # If there were parameters other than name, - # and we were not explicitly called Get-* - if ($NonNameParameters -and -not $IsGet) { - # remove the name parameter - if ($myParameters.Name) { $myParameters.Remove('Name') } - # and pipe results back to ourself. - $inputsOfKind | & $myScriptBlock @myParameters - } else { - # Otherwise, we're just getting the list of inputs - $inputsOfKind - } - # (either way, if we were called Get- or with no verb, we're done now). - return - } - - if ((-not $width) -or (-not $height)) { - if (-not $script:CachedOBSVideoSettings) { - $script:CachedOBSVideoSettings = Get-OBSVideoSettings - } - $videoSettings = $script:CachedOBSVideoSettings - - $myParameters["Width"] = $width = $videoSettings.outputWidth - $myParameters["Height"] = $height = $videoSettings.outputHeight - } - - if (-not $myParameters["Scene"]) { - $myParameters["Scene"] = Get-OBSCurrentProgramScene | - Select-Object -ExpandProperty currentProgramSceneName + + if (-not $myParameters["FilterName"]) { + $filterName = $myParameters["FilterName"] = "Scroll" } $myParameterData = [Ordered]@{} foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { - $bindToPropertyName = $null + $bindToPropertyName = $null foreach ($attribute in $parameter.Attributes) { if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { @@ -2797,97 +2336,42 @@ function Set-OBSSoundCloudSource { if ($myParameters.Contains($parameter.Name)) { $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] if ($myParameters[$parameter.Name] -is [switch]) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] -as [bool] + $myParameterData[$bindToPropertyName] = $parameter.Name -as [bool] } } } - if ($fps -and $fps -ne 30) { - $myParameterData["custom_fps"] = $true + if ($myParameterData["loop"]) { + $myParameterData["loop"] = -not $myParameterData["loop"] } - - $MyObsPowerShellPath = if ($home) { - Join-Path $home ".obs-powershell" + if ($myParameterData["cx"]) { + $myParameterData["limit_cx"] = $true + } + if ($myParameterData["cy"]) { + $myParameterData["limit_cy"] = $true } - - $ThisSoundCloudSourceFileName = - if ($name) { - "${name}.SoundCloudSource.html" - } else { - "SoundCloudSource.html" - } - - $ThisSoundCloudSourceFilePath = Join-Path $MyObsPowerShellPath $ThisSoundCloudSourceFileName - - - $soundCloudSrc = @( - "https://w.soundcloud.com/player/?url=" - $Uri - "&" - @( - if ($PSBoundParameters["TrackNumber"]) {"start_track=$trackNumber"} - if ($color) { "color=$color" -replace "\#",'%23'} - if ($NoAutoPlay) { "auto_play=false" } else { "auto_play=true"} - if ($NoArtwork) { "show_artwork=false" } else {"show_artwork=true" } - if ($NoUploaderInfo) { "show_user=false" } else {"show_user=true"} - if ($NoPlayCount) { "show_playcount=false" } else {"show_playcount=true" } - if ($ShowDownload) { "download=true"} else { "download=false" } - if ($ShowBuy) { "buying=true"} else { "buying=false" } - if ($ShowShare) { "sharing=true"} else { "sharing=false" } - ) -join '&' - ) -join '' - - $soundCloudWidget = @( - "" - "" - "" - "" - "" - ) -join ' ' - - $newHtmlFile = New-Item -Value $soundCloudWidget -ItemType File -Path $ThisSoundCloudSourceFilePath -Force - $myParameterData["local_file"] = ([uri]$newHtmlFile.FullName) -replace '[\\/]', '/' -replace '^file:///' - $myParameterData["is_local_file"] = $true - - if (-not $Name) { - $Name = $myParameters['Name'] = 'SoundCloud' - } - - $addSplat = [Ordered]@{ - sceneName = $myParameters["Scene"] - inputKind = $inputKind - inputSettings = $myParameterData - inputName = $Name + $addSplat = @{ + filterName = $myParameters["FilterName"] + SourceName = $myParameters["SourceName"] + filterKind = "scroll_filter" + filterSettings = $myParameterData NoResponse = $myParameters["NoResponse"] - } - # If -SceneItemEnabled was passed, - if ($myParameters.Contains('SceneItemEnabled')) { - # propagate it to Add-OBSInput. - $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] - } + } - # If -PassThru was passed if ($MyParameters["PassThru"]) { - # pass it down to each command $addSplat.Passthru = $MyParameters["PassThru"] - # If we were called with Add- if ($MyInvocation.InvocationName -like 'Add-*') { - Add-OBSInput @addSplat # passthru Add-OBSInput + Add-OBSSourceFilter @addSplat } else { - # Otherwise, remove SceneItemEnabled, InputKind, and SceneName - $addSplat.Remove('SceneItemEnabled') - $addSplat.Remove('inputKind') - $addSplat.Remove('sceneName') - # and passthru Set-OBSInputSettings. - Set-OBSInputSettings @addSplat + $addSplat.Remove('FilterKind') + Set-OBSSourceFilterSettings @addSplat } - return + return } - + # Add the input. - $outputAddedResult = Add-OBSInput @addSplat *>&1 + $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 # If we got back an error if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { @@ -2895,16 +2379,17 @@ function Set-OBSSoundCloudSource { if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { # then check if we use the -Force. if ($Force) { # If we do, remove the input - Remove-OBSInput -InputName $addSplat.inputName + Remove-OBSSourceFilter -FilterName $addSplat.FilterName -SourceName $addSplat.SourceName # and re-add our result. $outputAddedResult = Add-OBSInput @addSplat *>&1 } else { - # Otherwise, get the input from the scene, - $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $myParameters["Name"] - # update the input settings - $sceneItem.Input.Settings = $addSplat.inputSettings - $sceneItem # and return the scene item. + # Otherwise, get the existing filter. + $existingFilter = Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName + # then apply the settings + $existingFilter.Set($addSplat.filterSettings) + # and output them + $existingFilter + # (don't forget to null the result, so we don't show this error) $outputAddedResult = $null } } @@ -2913,226 +2398,230 @@ function Set-OBSSoundCloudSource { if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { # use $psCmdlet.WriteError so that it shows the error correctly. $psCmdlet.WriteError($outputAddedResult) - } + } + } # Otherwise, if we had a result - if ($outputAddedResult -and - $outputAddedResult -isnot [Management.Automation.ErrorRecord]) { - # get the input from the scene. - Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $myParameters["Name"] + elseif ($outputAddedResult) { + # Otherwise, get the input from the filters. + Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName + } } } + #.ExternalHelp obs-powershell-Help.xml -function Set-OBSSwitchSource { +function Set-OBSShaderFilter { - [Alias('Add-OBSSwitchSource','Get-OBSSwitchSource')] + [Alias('Add-OBSShaderFilter')] param( - # The path to the media file. - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('Sources')] - [string[]] - $SourceList, - - # What to select in the playlist. - # If a number is provided, this will select an index. - # If a string is provided, this will select the whole name or last part of a name, accepting wildcards. - [Parameter(ValueFromPipelineByPropertyName)] - [ValidateScript({ - $validTypeList = [System.Int32],[System.String] - - $thisType = $_.GetType() - $IsTypeOk = - $(@( foreach ($validType in $validTypeList) { - if ($_ -as $validType) { - $true;break - } - })) - - if (-not $isTypeOk) { - throw "Unexpected type '$(@($thisType)[0])'. Must be 'int','string'." - } - return $true - })] - - [Alias('SelectIndex','SelectName')] - $Select, - - # If set, the list of sources will loop. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("loop")] - [Alias('Looping')] - [switch] - $Loop, - - # If set, will switch between sources. - # Sources will be displayed for a -Duration. - # No source wil be displayed for an -Interval. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("time_switch")] - [switch] - $TimeSwitch, - - # The interval between sources - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("time_switch_between")] - [timespan] - $Interval, - - # The duration between sources that are switching at a time. + # The text of the shader [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("time_switch_duration")] - [timespan] - $Duration, + [string]$ShaderText, - # The item that will be switched in a TimeSwitch, after -Duration and -Interval. + # The file path to the shader, or the short file name of the shader. [Parameter(ValueFromPipelineByPropertyName)] - [ValidateSet("None","Next","Previous","First","Last","Random")] + [Alias('ShaderName')] [string] - $TimeSwitchTo = "Next", - - # If set, will switch on the underlying source's media state events. - # Sources will be displayed for a -Duration. - # No source wil be displayed for an -Interval. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("media_state_switch")] - [switch] - $MediaStateSwitch, - - # The change in media state that should trigger a switch - [Parameter(ValueFromPipelineByPropertyName)] - [ValidateSet("Playing","Opening","Buffering","Paused","Stopped","Ended", "Error","Playing","NotOpening","NotBuffering","NotPaused","NotStopped","NotEnded", "NotError")] - $MediaStateChange, + $ShaderFile, - # When the source switcher is trigger by media end, this determines the next source that will be switched to. + # Any other settings for the shader. + # To see what the name of a shader setting is, change it in the user interface and then get the input's filters. [Parameter(ValueFromPipelineByPropertyName)] - [ValidateSet("None","Next","Previous","First","Last","Random")] - [string] - $MediaSwitchTo = "Next", + [Alias('ShaderSettings')] + [PSObject] + $ShaderSetting, - # The name of the transition between sources. - [ArgumentCompleter({ - param ( $commandName, - $parameterName, - $wordToComplete, - $commandAst, - $fakeBoundParameters ) - if (-not $script:OBSTransitionKinds) { - $script:OBSTransitionKinds = @(Get-OBSTransitionKind) -replace '_transition$' - } - - if ($wordToComplete) { - $toComplete = $wordToComplete -replace "^'" -replace "'$" - return @($script:OBSTransitionKinds -like "$toComplete*" -replace '^', "'" -replace '$',"'") + # If set, will remove a filter if one already exists. + # If this is not provided and the filter already exists, the settings of the filter will be changed. + [switch] + $Force + ) + dynamicParam { + $baseCommand = + if (-not $script:AddOBSSourceFilter) { + $script:AddOBSSourceFilter = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSSourceFilter','Function') + $script:AddOBSSourceFilter } else { - return @($script:OBSTransitionKinds -replace '^', "'" -replace '$',"'") + $script:AddOBSSourceFilter } - })] - [Parameter(ValueFromPipelineByPropertyName)] - [string] - $TransitionName, + $IncludeParameter = @() + $ExcludeParameter = 'FilterKind','FilterSettings' - # The properties sent to the transition. - # Notice: this current requires confirmation in the UI. - [Parameter(ValueFromPipelineByPropertyName)] - [PSObject] - $TransitionProperty, - # The name of the transition used to show a source. - [ArgumentCompleter({ - param ( $commandName, - $parameterName, - $wordToComplete, - $commandAst, - $fakeBoundParameters ) - if (-not $script:OBSTransitionKinds) { - $script:OBSTransitionKinds = @(Get-OBSTransitionKind) -replace '_transition$' + $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() + :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { + if ($ExcludeParameter) { + foreach ($exclude in $ExcludeParameter) { + if ($paramName -like $exclude) { continue nextInputParameter} + } } - - if ($wordToComplete) { - $toComplete = $wordToComplete -replace "^'" -replace "'$" - return @($script:OBSTransitionKinds -like "$toComplete*" -replace '^', "'" -replace '$',"'") - } else { - return @($script:OBSTransitionKinds -replace '^', "'" -replace '$',"'") + if ($IncludeParameter) { + $shouldInclude = + foreach ($include in $IncludeParameter) { + if ($paramName -like $include) { $true;break} + } + if (-not $shouldInclude) { continue nextInputParameter } } - })] - [Parameter(ValueFromPipelineByPropertyName)] - [string] - $ShowTransition, + + $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( + $baseCommand.Parameters[$paramName].Name, + $baseCommand.Parameters[$paramName].ParameterType, + $baseCommand.Parameters[$paramName].Attributes + )) + } + $DynamicParameters - # The properties sent to the show transition. - # Notice: this current requires confirmation in the UI. - [Parameter(ValueFromPipelineByPropertyName)] - [PSObject] - $ShowTransitionProperty, + } + process { + $myParameters = [Ordered]@{} + $PSBoundParameters + + if (-not $myParameters["FilterName"]) { + $filterName = $myParameters["FilterName"] = "Shader" + } - # The transition used to hide a source. - [ArgumentCompleter({ - param ( $commandName, - $parameterName, - $wordToComplete, - $commandAst, - $fakeBoundParameters ) - if (-not $script:OBSTransitionKinds) { - $script:OBSTransitionKinds = @(Get-OBSTransitionKind) -replace '_transition$' + $shaderSettings = [Ordered]@{} + if ($ShaderText) { + $shaderSettings.shader_text = $ShaderText + } + elseif ($ShaderFile) { + if ($ShaderFile -match '[\\/]') { + $shaderSettings.shader_file_name = "$($ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($ShaderFile))" -replace "\\", "/" + } else { + if (-not $script:CachedOBSShaderFilters) { + $script:CachedOBSShaderFilters = + Get-OBS | # Get the OBS object + Select-Object -ExpandProperty Process | # which has a process + Split-Path | Split-Path | Split-Path | # from it's parent path, we go up three levels. + Join-Path -ChildPath data | Join-Path -ChildPath obs-plugins | # then down into plugin data. + Get-ChildItem -Filter obs-shaderfilter | + Get-ChildItem -Filter examples | + Get-ChildItem -File # get all of the files in this directory + + } + + $foundShaderFile = $script:CachedOBSShaderFilters | + Where-Object Name -Like "$shaderFile*" | + Select-Object -First 1 + + if ($foundShaderFile) { + $shaderSettings.shader_file_name = $foundShaderFile.FullName -replace "\\", "/" + } + } + } + + if ($shaderSetting) { + if ($shaderSetting -is [Collections.IDictionary]) { + foreach ($kv in $shaderSetting.GetEnumerator()) { + $shaderSettings[$kv.Key] = $kv.Value + } + } elseif ($shaderSetting -is [psobject]) { + foreach ($prop in $shaderSetting.psobject.properties) { + $shaderSettings[$prop.Name] = $prop.Value + } + } + } + + if ($shaderSettings.shader_file_name) { + $shaderSettings.from_file = $true } + - if ($wordToComplete) { - $toComplete = $wordToComplete -replace "^'" -replace "'$" - return @($script:OBSTransitionKinds -like "$toComplete*" -replace '^', "'" -replace '$',"'") - } else { - return @($script:OBSTransitionKinds -replace '^', "'" -replace '$',"'") + $addSplat = @{ + filterName = $myParameters["FilterName"] + SourceName = $myParameters["SourceName"] + filterKind = "shader_filter" + filterSettings = $shaderSettings + NoResponse = $myParameters["NoResponse"] + } + + if ($MyParameters["PassThru"]) { + $addSplat.Passthru = $MyParameters["PassThru"] + if ($MyInvocation.InvocationName -like 'Add-*') { + Add-OBSSourceFilter @addSplat + } else { + $addSplat.Remove('FilterKind') + Set-OBSSourceFilterSettings @addSplat + } + return } - })] - [Parameter(ValueFromPipelineByPropertyName)] - [string] - $HideTransition, - # The properties sent to the hide transition. - # Notice: this current requires confirmation in the UI. - [Parameter(ValueFromPipelineByPropertyName)] - [PSObject] - $HideTransitionProperty, + # Add the filter. + $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 - # The name of the scene. - # If no scene name is provided, the current program scene will be used. - [Parameter(ValueFromPipelineByPropertyName)] - [string] - $Scene, + # If we got back an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # and that error was saying the source already exists, + if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { + # then check if we use the -Force. + if ($Force) { # If we do, remove the input + Remove-OBSSourceFilter -FilterName $addSplat.FilterName -SourceName $addSplat.SourceName + # and re-add our result. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + } else { + # Otherwise, get the existing filter. + $existingFilter = Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName + # then apply the settings + $existingFilter.Set($addSplat.filterSettings) + # and output them + $existingFilter + # (don't forget to null the result, so we don't show this error) + $outputAddedResult = $null + } + } - # The name of the input. - # If no name is provided, the last segment of the URI or file path will be the input name. - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('InputName','SourceName')] - [string] - $Name, + # If the output was still an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # use $psCmdlet.WriteError so that it shows the error correctly. + $psCmdlet.WriteError($outputAddedResult) + } + + } + # Otherwise, if we had a result + elseif ($outputAddedResult) { + # Otherwise, get the input from the filters. + Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName + + } + + } +} - # If set, will check if the source exists in the scene before creating it and removing any existing sources found. - # If not set, you will get an error if a source with the same name exists. - [Parameter(ValueFromPipelineByPropertyName)] - [switch] - $Force, - # If set, will fit the input to the screen. - [Parameter(ValueFromPipelineByPropertyName)] + +#.ExternalHelp obs-powershell-Help.xml +function Set-OBSSharpnessFilter { + + + [Alias('Add-OBSSharpnessFilter')] + param( + # The Sharpness. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("sharpness")] + [ValidateRange(0,1)] + [double] + $Sharpness, + + # If set, will remove a filter if one already exists. + # If this is not provided and the filter already exists, the settings of the filter will be changed. [switch] - $FitToScreen + $Force ) dynamicParam { $baseCommand = - if (-not $script:AddOBSInput) { - $script:AddOBSInput = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') - $script:AddOBSInput + if (-not $script:AddOBSSourceFilter) { + $script:AddOBSSourceFilter = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSSourceFilter','Function') + $script:AddOBSSourceFilter } else { - $script:AddOBSInput + $script:AddOBSSourceFilter } $IncludeParameter = @() - $ExcludeParameter = 'inputKind','sceneName','inputName' + $ExcludeParameter = 'FilterKind','FilterSettings' $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() @@ -3158,65 +2647,12 @@ function Set-OBSSwitchSource { } $DynamicParameters - } - begin { - filter OutputAndFitToScreen { - - if ($FitToScreen -and $_.FitToScreen) { - $_.FitToScreen() - } - $_ - - } - $InputKind = "source_switcher" - } process { - # Copy the bound parameters $myParameters = [Ordered]@{} + $PSBoundParameters - # and determine the name of the invocation - $MyInvocationName = "$($MyInvocation.InvocationName)" - # Split it into verb and noun - $myVerb, $myNoun = $MyInvocationName -split '-' - # and get a copy of ourself that we can call with anonymous recursion. - $myScriptBlock = $MyInvocation.MyCommand.ScriptBlock - # Determine if the verb was get, - $IsGet = $myVerb -eq "Get" - # if no verb was used, - $NoVerb = $MyInvocationName -match '^[^\.\&][^-]+$' - # and if there were any other parameters then name - $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' - - # If it is a get or there was no verb - if ($IsGet -or $NoVerb) { - $inputsOfKind = # Get all inputs of this kind - Get-OBSInput -InputKind $InputKind | - Where-Object { - if ($Name) { # If -Name was provided, - $_.InputName -like $Name # filter by name (as a wildcard). - } else { - $_ # otherwise, return every input. - } - } - - # If there were parameters other than name, - # and we were not explicitly called Get-* - if ($NonNameParameters -and -not $IsGet) { - # remove the name parameter - if ($myParameters.Name) { $myParameters.Remove('Name') } - # and pipe results back to ourself. - $inputsOfKind | & $myScriptBlock @myParameters - } else { - # Otherwise, we're just getting the list of inputs - $inputsOfKind - } - # (either way, if we were called Get- or with no verb, we're done now). - return - } - if (-not $myParameters["Scene"]) { - $myParameters["Scene"] = Get-OBSCurrentProgramScene | - Select-Object -ExpandProperty currentProgramSceneName + if (-not $myParameters["FilterName"]) { + $filterName = $myParameters["FilterName"] = "Sharpness" } $myParameterData = [Ordered]@{} @@ -3235,146 +2671,32 @@ function Set-OBSSwitchSource { if ($myParameters.Contains($parameter.Name)) { $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] if ($myParameters[$parameter.Name] -is [switch]) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] -as [bool] - } - if ($myParameters[$parameter.Name] -is [timespan]) { - $myParameterData[$bindToPropertyName] = [int]$myParameters[$parameter.Name].TotalMilliseconds - } - } - } - - - $selectedIndex = -1 - $sourcesObject = @( - $currentIndex = -1 - foreach ($sourceName in $SourceList) { - $currentIndex++ - $selected = ($null -ne $Select) -and ( - ($select -is [int] -and $currentIndex -eq $select) -or - ($select -is [string] -and - ($sourceName -like $select -or ($sourceName | Split-Path -Leaf -ErrorAction Ignore) -like $Select) - ) - ) - if ($selected) { - $selectedIndex = $currentIndex - } - [PSCustomObject][Ordered]@{hidden=$false;selected=$selected;value=$sourceName} - } - ) - - if ($sourcesObject) { - $myParameterData['sources'] = $sourcesObject - if ($selectedIndex -gt 0) { - $myParameterData["current_index"] = $selectedIndex - } - } - elseif ($Select -is [int]) { - $myParameterData['current_index'] = $Select - } - - - - if ($TransitionName) { - if ($TransitionName -notlike '*_transition') { - $TransitionName = "${TransitionName}_transition" - } - $myParameterData["transition"] = $TransitionName - } - - if ($TransitionProperty) { - $myParameterData["transition_properties"] = $TransitionProperty - } - - if ($ShowTransition) { - if ($ShowTransition -notlike '*_transition') { - $ShowTransition = "${ShowTransition}_transition" - } - $myParameterData["show_transition"] = $ShowTransition - } - - if ($ShowTransitionProperty) { - $myParameterData["show_transition_properties"] = $ShowTransitionProperty - } - - if ($HideTransition) { - if ($HideTransition -notlike '*_transition') { - $HideTransition = "${HideTransition}_transition" - } - $myParameterData["hide_transition"] = $ShowTransition - } - - if ($HideTransitionProperty) { - $myParameterData["hide_transition_properties"] = $HideTransitionProperty - } - - if ($TimeSwitchTo) { - $validValues = $MyInvocation.MyCommand.Parameters["TimeSwitchTo"].Attributes.ValidValues - for ($vvi = 0; $vvi -lt $validValues.Length;$vvi++) { - if ($TimeSwitchTo -eq $validValues[$vvi]) { - $myParameterData["time_switch_to"] = $vvi - break - } - } - } - - if ($MediaSwitchTo) { - $validValues = $MyInvocation.MyCommand.Parameters["MediaSwitchTo"].Attributes.ValidValues - for ($vvi = 0; $vvi -lt $validValues.Length;$vvi++) { - if ($TimeSwitchTo -eq $validValues[$vvi]) { - $myParameterData["media_state_switch_to"] = $vvi - break - } - } - } - - if ($MediaStateChange) { - $validValues = $MyInvocation.MyCommand.Parameters["MediaStateChange"].Attributes.ValidValues - for ($vvi = 0; $vvi -lt $validValues.Length;$vvi++) { - if ($TimeSwitchTo -eq $validValues[$vvi]) { - $myParameterData["media_switch_state"] = $vvi - break + $myParameterData[$bindToPropertyName] = $parameter.Name -as [bool] } } - } - - if (-not $Name) { - $Name = $myParameters["Name"] = "Source Switcher" - } - + } - - $addSplat = [Ordered]@{ - sceneName = $myParameters["Scene"] - inputKind = $InputKind - inputSettings = $myParameterData - inputName = $Name + $addSplat = @{ + filterName = $myParameters["FilterName"] + SourceName = $myParameters["SourceName"] + filterKind = "Sharpness_filter" + filterSettings = $myParameterData NoResponse = $myParameters["NoResponse"] - } - - if ($myParameters.Contains('SceneItemEnabled')) { - $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] - } + } - # If -PassThru was passed if ($MyParameters["PassThru"]) { - # pass it down to each command $addSplat.Passthru = $MyParameters["PassThru"] - # If we were called with Add- if ($MyInvocation.InvocationName -like 'Add-*') { - Add-OBSInput @addSplat # passthru Add-OBSInput + Add-OBSSourceFilter @addSplat } else { - # Otherwise, remove SceneItemEnabled, InputKind, and SceneName - $addSplat.Remove('SceneItemEnabled') - $addSplat.Remove('inputKind') - $addSplat.Remove('sceneName') - # and passthru Set-OBSInputSettings. - Set-OBSInputSettings @addSplat + $addSplat.Remove('FilterKind') + Set-OBSSourceFilterSettings @addSplat } - return + return } # Add the input. - $outputAddedResult = Add-OBSInput @addSplat *>&1 + $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 # If we got back an error if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { @@ -3382,19 +2704,18 @@ function Set-OBSSwitchSource { if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { # then check if we use the -Force. if ($Force) { # If we do, remove the input - Remove-OBSInput -InputName $addSplat.inputName + Remove-OBSSourceFilter -FilterName $addSplat.FilterName -SourceName $addSplat.SourceName # and re-add our result. $outputAddedResult = Add-OBSInput @addSplat *>&1 } else { - # Otherwise, get the input from the scene, - $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $myParameters["Name"] - # update the input settings - if ($sceneItem) { - $sceneItem.Input.Settings = $addSplat.inputSettings - $sceneItem # and return the scene item. - $outputAddedResult = $null - } + # Otherwise, get the existing filter. + $existingFilter = Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName + # then apply the settings + $existingFilter.Set($addSplat.filterSettings) + # and output them + $existingFilter + # (don't forget to null the result, so we don't show this error) + $outputAddedResult = $null } } @@ -3403,39 +2724,66 @@ function Set-OBSSwitchSource { # use $psCmdlet.WriteError so that it shows the error correctly. $psCmdlet.WriteError($outputAddedResult) } + } - # Otherwise, if we had a result - if ($outputAddedResult -and - $outputAddedResult -isnot [Management.Automation.ErrorRecord]) { - # get the input from the scene and optionally fit it to the screen. - Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $name | - OutputAndFitToScreen + elseif ($outputAddedResult) { + # Otherwise, get the input from the filters. + Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName + } } } + + #.ExternalHelp obs-powershell-Help.xml -function Set-OBSVLCSource { +function Get-OBSEffect +{ - - [Alias('Add-OBSVLCSource','Set-OBSPlaylistSource','Add-OBSPlaylistSource','Get-OBSVLCSource','Get-OBSPlaylistSource')] param( - # The path to the media file. - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('FullName','LocalFile','local_file','Playlist')] - [string[]] - $FilePath, - - # What to select in the playlist. - # If a number is provided, this will select an index. - # If a string is provided, this will select the whole name or last part of a name, accepting wildcards. - # If an `[IO.FileInfo]` is provided, this will be the exact file. + # The name of the effect. [Parameter(ValueFromPipelineByPropertyName)] + [Alias('EffectName')] + [string] + $Name + ) + + begin { + if (-not $script:OBSFX) { + $script:OBSFX = [Ordered]@{} + } + } + + process { + + if (-not $Name) { + $script:OBSFX.Values + } elseif ($script:OBSFX[$name]) { + $script:OBSFX[$name] + } + } +} +#.ExternalHelp obs-powershell-Help.xml +function Import-OBSEffect { + + + param( + # The source location of the effect. + # This can be a string, file, directory, command, or module. + [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)] + [Alias( + 'FromPath', + 'FromModule', + 'FromScript', + 'FromFunction', + 'FullName', + 'Path', + 'Source' + )] [ValidateScript({ - $validTypeList = [System.Int32],[System.String],[System.IO.FileInfo] + $validTypeList = [System.String],[System.IO.FileInfo],[System.IO.DirectoryInfo],[System.Management.Automation.CommandInfo],[System.Management.Automation.PSModuleInfo] $thisType = $_.GetType() $IsTypeOk = @@ -3446,1267 +2794,911 @@ function Set-OBSVLCSource { })) if (-not $isTypeOk) { - throw "Unexpected type '$(@($thisType)[0])'. Must be 'int','string','System.IO.FileInfo'." + throw "Unexpected type '$(@($thisType)[0])'. Must be 'string','System.IO.FileInfo','System.IO.DirectoryInfo','System.Management.Automation.CommandInfo','psmoduleinfo'." } return $true })] - [Alias('SelectIndex','SelectName')] - $Select, - - # If set, will shuffle the playlist - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("shuffle")] - [switch] - $Shuffle, - - # If set, the playlist will loop. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("loop")] - [Alias('Looping')] - [switch] - $Loop, + $From + ) - # If set, will show subtitles, if available. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("subtitle_enable")] - [Alias('ShowSubtitles','Subtitles')] - [switch] - $Subtitle, + begin { + if (-not $script:OBSFX) { + $script:OBSFX = [Ordered]@{} + } - # The selected audio track number. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("track")] - [int] - $AudioTrack, + $newEffects = @() + $obsEffectsPattern = [Regex]::new(' + (?> + ^OBS.(?>fx|effects?)\p{P} + | + [\p{P}-[-]]OBS\.(?>fx|effects?)$ + | + \p{P}OBS.(?>fx|effects?)\.(?>ps1|json)$ + ) + ','IgnoreCase,IgnorePatternWhitespace') + } - # The selected subtitle track number. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("subtitle")] - [int] - $SubtitleTrack, + process { + # Since -From can be many things, but a metric has to be a command, + # the purpose of this function is to essentially resolve many things to a command, + # and then cache that command. - # The name of the scene. - # If no scene name is provided, the current program scene will be used. - [Parameter(ValueFromPipelineByPropertyName)] - [string] - $Scene, - - # The name of the input. - # If no name is provided, the last segment of the URI or file path will be the input name. - [Parameter(ValueFromPipelineByPropertyName)] - [string] - $Name, - - # If set, will check if the source exists in the scene before creating it and removing any existing sources found. - # If not set, you will get an error if a source with the same name exists. - [Parameter(ValueFromPipelineByPropertyName)] - [switch] - $Force, - - # If set, will fit the input to the screen. - [Parameter(ValueFromPipelineByPropertyName)] - [switch] - $FitToScreen - ) - dynamicParam { - $baseCommand = - if (-not $script:AddOBSInput) { - $script:AddOBSInput = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') - $script:AddOBSInput - } else { - $script:AddOBSInput + # If -From was a string + if ($From -is [string]) { + # It could be a module, so check those first. + :ResolveFromString do { + foreach ($loadedModule in @(Get-Module)) { + # If we find the module, don't try to resolve -From as a path + if ($loadedModule.Name -eq $from) { + # (just set -From again and let the function continue) + $from = $fromModule = $loadedModule;break ResolveFromString + } + + } + # If we think from was a path + $resolvedPath = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($from) + # attempt to resolve it + if ($resolvedPath) { + $from = Get-Item -LiteralPath $resolvedPath + } + } while ($false) } - $IncludeParameter = @() - $ExcludeParameter = 'inputKind','sceneName','inputName' - - $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() - :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { - if ($ExcludeParameter) { - foreach ($exclude in $ExcludeParameter) { - if ($paramName -like $exclude) { continue nextInputParameter} + # If -From is a module + if ($from -is [Management.Automation.PSModuleInfo]) { + # recursively call ourselves with all matching commands + @($from.ExportedCommands.Values) -match $obsEffectsPattern | + Import-OBSEffect + # then, make -From a directory + if ($from.Path) { + $from = Get-Item ($from.Path | Split-Path) -ErrorAction SilentlyContinue } } - if ($IncludeParameter) { - $shouldInclude = - foreach ($include in $IncludeParameter) { - if ($paramName -like $include) { $true;break} - } - if (-not $shouldInclude) { continue nextInputParameter } - } - - $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( - $baseCommand.Parameters[$paramName].Name, - $baseCommand.Parameters[$paramName].ParameterType, - $baseCommand.Parameters[$paramName].Attributes - )) - } - $DynamicParameters - - } - begin { - filter OutputAndFitToScreen { - if ($FitToScreen -and $_.FitToScreen) { - $_.FitToScreen() - } - $_ - - } - $InputKind = "vlc_source" - - } - process { - # Copy the bound parameters - $myParameters = [Ordered]@{} + $PSBoundParameters - # and determine the name of the invocation - $MyInvocationName = "$($MyInvocation.InvocationName)" - # Split it into verb and noun - $myVerb, $myNoun = $MyInvocationName -split '-' - # and get a copy of ourself that we can call with anonymous recursion. - $myScriptBlock = $MyInvocation.MyCommand.ScriptBlock - # Determine if the verb was get, - $IsGet = $myVerb -eq "Get" - # if no verb was used, - $NoVerb = $MyInvocationName -match '^[^\.\&][^-]+$' - # and if there were any other parameters then name - $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' - - # If it is a get or there was no verb - if ($IsGet -or $NoVerb) { - $inputsOfKind = # Get all inputs of this kind - Get-OBSInput -InputKind $InputKind | - Where-Object { - if ($Name) { # If -Name was provided, - $_.InputName -like $Name # filter by name (as a wildcard). - } else { - $_ # otherwise, return every input. - } - } - - # If there were parameters other than name, - # and we were not explicitly called Get-* - if ($NonNameParameters -and -not $IsGet) { - # remove the name parameter - if ($myParameters.Name) { $myParameters.Remove('Name') } - # and pipe results back to ourself. - $inputsOfKind | & $myScriptBlock @myParameters - } else { - # Otherwise, we're just getting the list of inputs - $inputsOfKind - } - # (either way, if we were called Get- or with no verb, we're done now). + # If -From is a directory + if ($from -is [IO.DirectoryInfo]) { + $FromDirectory = $from + # recursively call ourselves with all matching scripts + Get-ChildItem -LiteralPath $from.FullName -Recurse -File | + Where-Object Name -match '\.obs\.(?>fx|effects?).(?>ps1|json)$' | + Import-OBSEffect return } - - if (-not $myParameters["Scene"]) { - $myParameters["Scene"] = Get-OBSCurrentProgramScene | - Select-Object -ExpandProperty currentProgramSceneName + + # If -From is a file + if ($from -is [IO.FileInfo]) { + # and it matches the naming convention + if ($from.Name -notmatch '\.obs\.(?>fx|effects?).(?>ps1|json)$') { return } + # make -From a command. + $from = $ExecutionContext.SessionState.InvokeCommand.GetCommand($from.FullName, 'ExternalScript,Application') } - - $myParameterData = [Ordered]@{} - foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { - $bindToPropertyName = $null - - foreach ($attribute in $parameter.Attributes) { - if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { - $bindToPropertyName = $attribute.Name - break - } + # If -From is a command + if ($from -is [Management.Automation.CommandInfo]) { + # decorate the command + if ($from.pstypenames -notcontains 'OBS.PowerShell.Effect') { + $from.pstypenames.insert(0,'OBS.PowerShell.Effect') } - if (-not $bindToPropertyName) { continue } - if ($myParameters.Contains($parameter.Name)) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] - if ($myParameters[$parameter.Name] -is [switch]) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] -as [bool] + if ($from -is [Management.Automation.ApplicationInfo]) { + $effectName = $from.Name -replace '\.obs\.(?>fx|effects?).(?>ps1|json)$' + $newEffect = [PSCustomObject][Ordered]@{ + PSTypeName = 'OBS.PowerShell.Effect' + Messages = Get-Content -Raw -Path $From.Source | ConvertFrom-Json + EffectName = $effectName + TypeName = $TypeName } - } - } - - $allPaths = @(foreach ($path in $FilePath) { - foreach ($_ in $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($path)) { - $_.Path - } - }) - $playlistObject = @( - $currentIndex = 0 - foreach ($path in $allPaths) { - $currentIndex++ - $selected = $Select -and ( - ($select -is [int] -and $currentIndex -eq $select) -or - ($select -is [IO.FileInfo] -and $path -eq $select.FullName) -or - ($select -is [string] -and - ($path -like $select -or ($path | Split-Path -Leaf) -like $Select) - ) - ) - [PSCustomObject][Ordered]@{hidden=$false;selected=$selected;value=$path} - } - ) - $myParameterData['playlist'] = $playlistObject - - if (-not $Name) { - $Name = $myParameters["Name"] = $FilePathItem.Name - } - - $addSplat = [Ordered]@{ - sceneName = $myParameters["Scene"] - inputKind = $InputKind - inputSettings = $myParameterData - inputName = $Name - NoResponse = $myParameters["NoResponse"] - } + $script:OBSFX[$effectName] = $newEffect + $newEffects += $newEffect + $newEffect + } else { + if ($from.pstypenames -notcontains 'OBS.PowerShell.Effect.Command') { + $from.pstypenames.insert(0,'OBS.PowerShell.Effect.Command') + } + # and add it to our list of new metrics + $newEffects+= $from + $script:OBSFX[$from.EffectName] = $from + $from + } + } + } - if ($myParameters.Contains('SceneItemEnabled')) { - $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] - } - # If -PassThru was passed - if ($MyParameters["PassThru"]) { - # pass it down to each command - $addSplat.Passthru = $MyParameters["PassThru"] - # If we were called with Add- - if ($MyInvocation.InvocationName -like 'Add-*') { - Add-OBSInput @addSplat # passthru Add-OBSInput - } else { - # Otherwise, remove SceneItemEnabled, InputKind, and SceneName - $addSplat.Remove('SceneItemEnabled') - $addSplat.Remove('inputKind') - $addSplat.Remove('sceneName') - # and passthru Set-OBSInputSettings. - Set-OBSInputSettings @addSplat - } - return - } - # Add the input. - $outputAddedResult = Add-OBSInput @addSplat *>&1 +} - # If we got back an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # and that error was saying the source already exists, - if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { - # then check if we use the -Force. - if ($Force) { # If we do, remove the input - Remove-OBSInput -InputName $addSplat.inputName - # and re-add our result. - $outputAddedResult = Add-OBSInput @addSplat *>&1 - } else { - # Otherwise, get the input from the scene, - $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $myParameters["Name"] - # update the input settings - $sceneItem.Input.Settings = $addSplat.inputSettings - $sceneItem # and return the scene item. - $outputAddedResult = $null - } - } + +#.ExternalHelp obs-powershell-Help.xml +function Remove-OBSEffect +{ + + param( + # The name of the effect. + [Parameter(Mandatory,ValueFromPipelineByPropertyName)] + [Alias('Name')] + [string] + $EffectName + ) - # If the output was still an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # use $psCmdlet.WriteError so that it shows the error correctly. - $psCmdlet.WriteError($outputAddedResult) - } + begin { + if (-not $script:OBSFX) { + $script:OBSFX = [Ordered]@{} } - - # Otherwise, if we had a result - if ($outputAddedResult -and - $outputAddedResult -isnot [Management.Automation.ErrorRecord]) { - # get the input from the scene and optionally fit it to the screen. - Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $name | - OutputAndFitToScreen + } + + process { + if ($script:OBSFX[$name]) { + $script:OBSFX.Stop() + $script:OBSFX.Remove($name) } - } } #.ExternalHelp obs-powershell-Help.xml -function Set-OBSWaveformSource { +function Start-OBSEffect +{ - - [Alias('Add-OBSWaveformSource','Get-OBSWaveformSource')] + [CmdletBinding(PositionalBinding=$false)] param( - # The width of the browser source. - # If none is provided, this will be the output width of the video settings. + # The name of the effect. + [ArgumentCompleter({ + param ( $commandName, + $parameterName, + $wordToComplete, + $commandAst, + $fakeBoundParameters ) + $effectNames = @(Get-OBSEffect| + Select-Object -Unique -ExpandProperty EffectName) + if ($wordToComplete) { + $toComplete = $wordToComplete -replace "^'" -replace "'$" + return @($effectNames -like "$toComplete*" -replace '^', "'" -replace '$',"'") + } else { + return @($effectNames -replace '^', "'" -replace '$',"'") + } + })] + [Parameter(Mandatory)] + [string[]] + $EffectName, + + # The duration of the effect. + # If provided, all effects should use this duration. + # If not provided, each effect should use it's own duration. + [Timespan] + $Duration, + + # The parameters passed to the effect. [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("width")] - [int] - $Width, + [Alias('EffectParameters')] + [Collections.IDictionary] + $EffectParameter = @{}, - # The width of the browser source. - # If none is provided, this will be the output height of the video settings. + # The arguments passed to the effect. + [Parameter(ValueFromRemainingArguments)] + [Alias('EffectArguments')] + [PSObject[]] + $EffectArgument = @(), + + # If provided, will step thru running [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("height")] + [Alias('ticks')] [int] - $Height, + $Step, - # The audio source for the waveform. + # The SceneItemID. If this is provided, the effect will be given a target. [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("audio_source")] - [string] - $AudioSource, + [int] + $SceneItemID, - # The display mode for the waveform. + # The SceneName. If this is provided with a -SceneItemID or -SourceName, the effect will be given a target. [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("display_mode")] - [ValidateSet("curve","bars","stepped_bars","level_meter","stepped_level_meter")] [string] - $DisplayMode, + $SceneName, - # The render mode for the waveform. + # The Filter Name. If this is provided with a -SourceName, the effect will be given a target. [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("render_mode")] - [ValidateSet("line","solid","gradient")] [string] - $RenderMode, + $FilterName, - # The windowing mode for the waveform. - # This is the mathematical function used to determine the current "window" of audio data. + # The Source Name. If this is provided with a -FitlerName -or -SceneName, the effect will be given a target. [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("render_mode")] - [ValidateSet("hann","hamming","blackman","blackman_harris","none")] [string] - $WindowMode, - - # The color used for the waveform. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("color_base")] - [PSObject] - $Color, - - # The crest color used for the waveform. - # This will be ignored if the render mode is not "gradient". - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("color_crest")] - [PSObject] - $CrestColor, + $SourceName, - # The channel mode for the waveform. - # This can be either mono or stereo. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("channel_mode")] - [ValidateSet("mono","stereo")] - [string] - $ChannelMode, + # If set, will loop the effect. + [switch] + $Loop, - # The number of pixels between each channel in stereo mode - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("channel_spacing")] + # If provided, will loop the effect a number of times. [int] - $ChannelSpacing, + $LoopCount, - # If set, will use a radial layout for the waveform - # Radial layouts will ignore the desired height of the source and instead create a square. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("radial_layout")] + # If set, will bounce the effect (flip it / reverse it) [switch] - $RadialLayout, + $Bounce, - # If set, will invert the direction for a radial waveform. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("invert_direction")] + # If set, will reverse an effect. [switch] - $InvertRadialDirection, + $Reverse + ) - # If set, will normalize the volume displayed in the waveform. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("normalize_volume")] - [switch] - $NoramlizeVolume, + process { + foreach ($NameOfEffect in $EffectName) { + $obsEffect = Get-OBSEffect -EffectName $NameOfEffect - # If set, will automatically declare an FFTSize - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("auto_fft_size")] - [switch] - $AutoFftSize, + if (-not $obsEffect) { + Write-Warning "No Effect named '$NameOfEffect'" + continue + } - # If set, will attempt to make audio peaks render faster. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("fast_peaks")] - [switch] - $FastPeak, + if ($LoopCount) { + $obsEffect | Add-Member -MemberType NoteProperty LoopCount $LoopCount -Force + } + + if ($loop -or $Bounce) { + $obsEffect | Add-Member -MemberType NoteProperty Mode "$(if ($Bounce) {"Bounce"})$(if ($loop) {"Loop"})" -Force + if (-not $LoopCount) { + $obsEffect | Add-Member -MemberType NoteProperty LoopCount -1 -Force + } + } else { + $obsEffect | Add-Member -MemberType NoteProperty Mode "Once" -Force + } - # The width of the waveform bar. - # This is only valid when -DisplayMode is 'bars' or 'stepped_bars' - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("bar_width")] - [int] - $BarWidth, + if ($Reverse) { + $obsEffect.Reversed = $true + } + + if ($obsEffect -isnot [Management.Automation.CommandInfo]) { + if ($step -and $obsEffect.Messages) { + $obsEffect.Step($step) + continue + } + + $obsEffect.Start() + + } else { + if ($step -and $obsEffect.Messages) { + $obsEffect.Step($step) + continue + } + + if (-not $this) { + if ($_.pstypenames -like '*.GetSourceFilter*') { + $this = $_ + } elseif ($FilterName -and $SourceName) { + $this = Get-OBSSourceFilter -SourceName $SourceName -FilterName $FilterName + } + + if ($_.pstypenames -like '*.GetSceneItem*') { + $this = $_ + } elseif ($SceneName -and ($SceneItemID -or $SourceName)) { + $this = + foreach ($sceneItem in Get-OBSSceneItem -SceneName $SceneName) { + if ($SceneItemID -and $sceneItem.SceneItemID -eq $SceneItemID) { + $sceneItem;break + } + elseif ($SceneName -and $sceneItem.SceneName -eq $SceneName) { + $sceneItem;break + } + } + } + } - # The gap between waveform bars. - # This is only valid when -DisplayMode is 'bars' or 'stepped_bars' - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("bar_gap")] - [int] - $BarGap, + if ($Duration -and $obsEffect.Parameters.Duration) { + $EffectParameter.Duration = $Duration + } - # The width of waveform bar step. - # This is only valid when -DisplayMode is 'stepped_bars' - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("step_width")] - [int] - $StepWidth, + $obsEffectOutput = . $obsEffect @EffectParameter @EffectArgument + if ($obsEffectOutput) { + $obsEffect | Add-Member NoteProperty Messages $obsEffectOutput -Force + if ($step) { + $obsEffect.Step($step) + } else { + $obsEffect.Start() + } + } + } + $obsEffect + } + + + } +} +#.ExternalHelp obs-powershell-Help.xml +function Stop-OBSEffect +{ + + param( + # The name of the effect. + [Parameter(Mandatory,ValueFromPipelineByPropertyName)] + [string] + $EffectName) - # The gap between waveform bar steps. - # This is only valid when -DisplayMode is 'stepped_bars' - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("step_gap")] - [int] - $StepGap, + process { + $obsEffect = Get-OBSEffect -EffectName $EffectName - # The low-frequency cutoff of the waveform. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("cutoff_low")] - [int] - $LowCutoff, + if (-not $obsEffect) { return } - # The high-frequency cutoff of the waveform. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("cutoff_high")] - [int] - $HighCutoff, + $obsEffect | Add-Member -MemberType NoteProperty Mode 'Stopped' -Force + } +} +#.ExternalHelp obs-powershell-Help.xml +function Add-OBSInput { - # The floor of the waveform. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("floor")] - [int] - $Floor, - # The ceiling of the waveform. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("ceiling")] - [int] - $Ceiling, +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'CreateInput')] +[Alias('obs.powershell.websocket.CreateInput')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("slope")] - [double] - $Slope, +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("rolloff_q")] - [Alias('RollOffOctaves')] - [double] - $RollOffOctave, +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("rolloff_rate")] - [double] - $RollOffRate, +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("grad_ratio")] - [double] - $GradientRatio, +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputKind')] +[string] +$InputKind, - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("deadzone")] - [double] - $Deadzone, +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputSettings')] +[PSObject] +$InputSettings, - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("temporal_smoothing")] - [ValidateSet("none","exp_moving_avg")] - [string] - $TemporalSmoothing, +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemEnabled')] +[switch] +$SceneItemEnabled, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - # The name of the scene. - # If no scene name is provided, the current program scene will be used. - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('SceneName')] - [string] - $Scene, - # The name of the input. - # If no name is provided, the last segment of the URI or file path will be the input name. - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('InputName')] - [string] - $Name, +process { - # If set, will check if the source exists in the scene before creating it and removing any existing sources found. - # If not set, you will get an error if a source with the same name exists. - [Parameter(ValueFromPipelineByPropertyName)] - [switch] - $Force - ) - dynamicParam { - $baseCommand = - if (-not $script:AddOBSInput) { - $script:AddOBSInput = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') - $script:AddOBSInput - } else { - $script:AddOBSInput - } - $IncludeParameter = @() - $ExcludeParameter = 'inputKind','sceneName','inputName' + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() - :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { - if ($ExcludeParameter) { - foreach ($exclude in $ExcludeParameter) { - if ($paramName -like $exclude) { continue nextInputParameter} - } + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if ($IncludeParameter) { - $shouldInclude = - foreach ($include in $IncludeParameter) { - if ($paramName -like $include) { $true;break} + + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, } - if (-not $shouldInclude) { continue nextInputParameter } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - - $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( - $baseCommand.Parameters[$paramName].Name, - $baseCommand.Parameters[$paramName].ParameterType, - $baseCommand.Parameters[$paramName].Attributes - )) - } - $DynamicParameters - } - begin { - $inputKind = "phandasm_waveform_source" - filter ToOBSColor { - - if ($_ -is [uint32]) { $_ } - elseif ($_ -is [string]) { - if ($_ -match '^\#[a-f0-9]{3,4}$') { - $_ = $_ -replace '[a-f0-9]','$0$0' - } - - if ($_ -match '^#[a-f0-9]{8}$') { - ( - '0x' + - (($_ -replace '#').ToCharArray()[0,1,-1,-2,-3,-4,-5,-6] -join '') - ) -as [UInt32] - } - elseif ($_ -match '^#[a-f0-9]{6}$') { - - ( - '0xff' + - (($_ -replace '#').ToCharArray()[-1..-6] -join '') - ) -as [UInt32] - } + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] } - - } - - } - process { - $myParameters = [Ordered]@{} + $PSBoundParameters - - $MyInvocationName = "$($MyInvocation.InvocationName)" - $myVerb, $myNoun = $MyInvocationName -split '-' - $myScriptBlock = $MyInvocation.MyCommand.ScriptBlock - $IsGet = $myVerb -eq "Get" - $NoVerb = $MyInvocationName -match '^[^\.\&][^-]+$' - $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' - - if ( - $IsGet -or - $NoVerb - ) { - $inputsOfKind = - Get-OBSInput -InputKind $InputKind | - Where-Object { - if ($Name) { - $_.InputName -like $Name - } else { - $_ - } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" } - if ($NonNameParameters -and -not $IsGet) { - $paramCopy = [Ordered]@{} + $PSBoundParameters - if ($paramCopy.Name) { $paramCopy.Remove('Name') } - $inputsOfKind | & $myScriptBlock @paramCopy - } else { - $inputsOfKind + continue nextParam + } } - return - } + } - if ((-not $width) -or (-not $height)) { - if (-not $script:CachedOBSVideoSettings) { - $script:CachedOBSVideoSettings = Get-OBSVideoSettings - } - $videoSettings = $script:CachedOBSVideoSettings - $myParameters["Width"] = $width = $videoSettings.outputWidth - $myParameters["Height"] = $height = $videoSettings.outputHeight + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if (-not $myParameters["Scene"]) { - $myParameters["Scene"] = Get-OBSCurrentProgramScene | - Select-Object -ExpandProperty currentProgramSceneName + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - - $myParameterData = [Ordered]@{} - foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { - $bindToPropertyName = $null - - foreach ($attribute in $parameter.Attributes) { - if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { - $bindToPropertyName = $attribute.Name - break - } - } +} - if (-not $bindToPropertyName) { continue } - if ($myParameters.Contains($parameter.Name)) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] - if ($myParameters[$parameter.Name] -is [switch]) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] -as [bool] - } - } - } +} - - if (-not $Name) { - $Name = $myParameters['Name'] = - if ($AudioSource) { - "$($AudioSource)-Waveform" - } else { - "Waveform" - } - } - - if ($myParameterData.color_base) { - $myParameterData.color_base = $myParameterData.color_base | ToOBSColor - } + +#.ExternalHelp obs-powershell-Help.xml +function Add-OBSProfile { - if ($myParameterData.color_crest) { - $myParameterData.color_crest = $myParameterData.color_crest | ToOBSColor - } - $addSplat = [Ordered]@{ - sceneName = $myParameters["Scene"] - inputKind = $inputKind - inputSettings = $myParameterData - inputName = $Name - NoResponse = $myParameters["NoResponse"] - } - # If -SceneItemEnabled was passed, - if ($myParameters.Contains('SceneItemEnabled')) { - # propagate it to Add-OBSInput. - $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'CreateProfile')] +[Alias('obs.powershell.websocket.CreateProfile')] +param( + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('profileName')] +[string] +$ProfileName, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) + + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - # If -PassThru was passed - if ($MyParameters["PassThru"]) { - # pass it down to each command - $addSplat.Passthru = $MyParameters["PassThru"] - # If we were called with Add- - if ($MyInvocation.InvocationName -like 'Add-*') { - Add-OBSInput @addSplat # passthru Add-OBSInput - } else { - # Otherwise, remove SceneItemEnabled, InputKind, and SceneName - $addSplat.Remove('SceneItemEnabled') - $addSplat.Remove('inputKind') - $addSplat.Remove('sceneName') - # and passthru Set-OBSInputSettings. - Set-OBSInputSettings @addSplat + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } - return } - - # Add the input. - $outputAddedResult = Add-OBSInput @addSplat *>&1 - # If we got back an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # and that error was saying the source already exists, - if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { - # then check if we use the -Force. - if ($Force) { # If we do, remove the input - Remove-OBSInput -InputName $addSplat.inputName - # and re-add our result. - $outputAddedResult = Add-OBSInput @addSplat *>&1 - } else { - # Otherwise, get the input from the scene, - $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $myParameters["Name"] - # update the input settings - $sceneItem.Input.Settings = $addSplat.inputSettings - $sceneItem # and return the scene item. - $outputAddedResult = $null + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam } } - - # If the output was still an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # use $psCmdlet.WriteError so that it shows the error correctly. - $psCmdlet.WriteError($outputAddedResult) - } - } - # Otherwise, if we had a result - if ($outputAddedResult -and - $outputAddedResult -isnot [Management.Automation.ErrorRecord]) { - # get the input from the scene. - Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $myParameters["Name"] } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" - } + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } + + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } + } + + +} + #.ExternalHelp obs-powershell-Help.xml -function Set-OBSWindowSource { - - - [Alias('Add-OBSWindowSource','Set-OBSWindowCaptureSource','Add-OBSWindowCaptureSource','Get-OBSWindowSource','Get-OBSWindowCaptureSource')] - param( - # The monitor number. - # This the number of the monitor you would like to capture. - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('ItemValue','ItemName','WindowName','MainWindowTitle')] - [string] - $WindowTitle, +function Add-OBSScene { - # The number of the capture method. By default, automatic (0). - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("method")] - [int] - $CaptureMethod, - # The capture priority. - [Parameter(ValueFromPipelineByPropertyName)] - [ValidateSet('ExactMatch','SameType','SameExecutable')] - [string] - $CapturePriority, +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'CreateScene')] +[Alias('obs.powershell.websocket.CreateScene')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( - # If set, will capture the cursor. - # This will be set by default. - # If explicitly set to false, the cursor will not be captured. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("cursor")] - [switch] - $CaptureCursor, +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - # If set, will capture the client area. - # This will be set by default. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("client_area")] - [switch] - $ClientArea, - # If set, will force SDR. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("force_sdr")] - [switch] - $ForceSDR, +process { - # The name of the scene. - # If no scene name is provided, the current program scene will be used. - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('SceneName')] - [string] - $Scene, - # The name of the input. - # If no name is provided, "Display $($Monitor + 1)" will be the input source name. - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('InputName')] - [string] - $Name, + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - # If set, will check if the source exists in the scene before creating it and removing any existing sources found. - # If not set, you will get an error if a source with the same name exists. - [Parameter(ValueFromPipelineByPropertyName)] - [switch] - $Force - ) - dynamicParam { - $baseCommand = - if (-not $script:AddOBSInput) { - $script:AddOBSInput = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') - $script:AddOBSInput - } else { - $script:AddOBSInput + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $IncludeParameter = @() - $ExcludeParameter = 'inputKind','sceneName','inputName' - - $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() - :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { - if ($ExcludeParameter) { - foreach ($exclude in $ExcludeParameter) { - if ($paramName -like $exclude) { continue nextInputParameter} - } - } - if ($IncludeParameter) { - $shouldInclude = - foreach ($include in $IncludeParameter) { - if ($paramName -like $include) { $true;break} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, } - if (-not $shouldInclude) { continue nextInputParameter } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - - $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( - $baseCommand.Parameters[$paramName].Name, - $baseCommand.Parameters[$paramName].ParameterType, - $baseCommand.Parameters[$paramName].Attributes - )) - } - $DynamicParameters - - } - begin { - $InputKind = "window_capture" - - } - process { - # Copy the bound parameters - $myParameters = [Ordered]@{} + $PSBoundParameters - # and determine the name of the invocation - $MyInvocationName = "$($MyInvocation.InvocationName)" - # Split it into verb and noun - $myVerb, $myNoun = $MyInvocationName -split '-' - # and get a copy of ourself that we can call with anonymous recursion. - $myScriptBlock = $MyInvocation.MyCommand.ScriptBlock - # Determine if the verb was get, - $IsGet = $myVerb -eq "Get" - # if no verb was used, - $NoVerb = $MyInvocationName -match '^[^\.\&][^-]+$' - # and if there were any other parameters then name - $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' - # If it is a get or there was no verb - if ($IsGet -or $NoVerb) { - $inputsOfKind = # Get all inputs of this kind - Get-OBSInput -InputKind $InputKind | - Where-Object { - if ($Name) { # If -Name was provided, - $_.InputName -like $Name # filter by name (as a wildcard). - } else { - $_ # otherwise, return every input. - } + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] } - - # If there were parameters other than name, - # and we were not explicitly called Get-* - if ($NonNameParameters -and -not $IsGet) { - # remove the name parameter - if ($myParameters.Name) { $myParameters.Remove('Name') } - # and pipe results back to ourself. - $inputsOfKind | & $myScriptBlock @myParameters - } else { - # Otherwise, we're just getting the list of inputs - $inputsOfKind + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } } - # (either way, if we were called Get- or with no verb, we're done now). - return } - if (-not $myParameters["Scene"]) { - $myParameters["Scene"] = Get-OBSCurrentProgramScene | - Select-Object -ExpandProperty currentProgramSceneName + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - - if (-not $myParameters["WindowTitle"]) { - while ($_ -is [Diagnostics.Process] -and -not $_.MainWindowTitle) { - $_ = $_.Parent - } - if ($_.MainWindowTitle) { - $WindowTitle = $myParameters["WindowTitle"] = "$($_.MainWindowTitle)" - } + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - # Window capture is a bit of a tricky one. - # In order to get the WindowTitle to match that OBS needs, we need to look thru the input properties list. - # and for that, an input needs to exist. - if (-not $myParameters["Name"]) { - if ($myParameters["WindowTitle"]) { - $Name = $myParameters["Name"] = "WindowCapture-" + $myParameters["WindowTitle"] - } - else { - $Name = "WindowCapture" - } - } +} - - - $myParameterData = [Ordered]@{} - foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { +} - $bindToPropertyName = $null - - foreach ($attribute in $parameter.Attributes) { - if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { - $bindToPropertyName = $attribute.Name - break - } - } + +#.ExternalHelp obs-powershell-Help.xml +function Add-OBSSceneCollection { - if (-not $bindToPropertyName) { continue } - if ($myParameters.Contains($parameter.Name)) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] - if ($myParameters[$parameter.Name] -is [switch]) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] -as [bool] - } - } - } - if ($null -ne $CaptureMethod) { - $myParameterData["method"] = $CaptureMethod - } - if ($CapturePriority -eq 'ExactMatch') { - $myParameterData["priority"] = 1 - } - elseif ($CapturePriority -eq 'SameType') { - $myParameterData["priority"] = 0 - } - elseif ($CapturePriority -eq 'SameExecutable') { - $myParameterData["priority"] = 2 - } +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'CreateSceneCollection')] +[Alias('obs.powershell.websocket.CreateSceneCollection')] +param( - $addSplat = @{ - sceneName = $myParameters["Scene"] - inputName = $myParameters["Name"] - inputKind = "window_capture" - inputSettings = $myParameterData - NoResponse = $myParameters["NoResponse"] - } +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneCollectionName')] +[string] +$SceneCollectionName, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - # If -SceneItemEnabled was passed, - if ($myParameters.Contains('SceneItemEnabled')) { - # propagate it to Add-OBSInput. - $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - # Add the input. - $outputAddedResult = Add-OBSInput @addSplat *>&1 - $possibleWindows = Get-OBSInputPropertiesListPropertyItems -InputName $addSplat.inputName -PropertyName window - foreach ($windowInfo in $possibleWindows) { - if (-not $WindowTitle) { continue } - if ( - ($windowInfo.itemName -eq $WindowTitle) -or - ($windowInfo.ItemValue -eq $WindowTitle) -or - ($windowInfo.ItemName -replace '\[[^\[\]]+\]\:\s' -eq $WindowTitle) -or - ($windowInfo.ItemValue -like "*$WindowTitle*") -or - ($windowInfo.ItemName -like "*$WindowTitle*") - ) { - $myParameterData["window"] = $windowInfo.itemValue - break + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - # If -PassThru was passed - if ($MyParameters["PassThru"]) { - # pass it down to each command - # Otherwise, remove SceneItemEnabled, InputKind, and SceneName - $addSplat.PassThru = $true - $addSplat.Remove('SceneItemEnabled') - $addSplat.Remove('inputKind') - $addSplat.Remove('sceneName') - # and passthru Set-OBSInputSettings. - Set-OBSInputSettings @addSplat - - return + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($Force) { # If we do, remove the input - Remove-OBSInput -InputName $addSplat.inputName - # and re-add our result. - $outputAddedResult = Add-OBSInput @addSplat *>&1 - # If the output was still an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # use $psCmdlet.WriteError so that it shows the error correctly. - $psCmdlet.WriteError($outputAddedResult) - } - # Otherwise, if we had a result - elseif ($outputAddedResult) { - # get the input from the scene. - Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $name - } + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - # Otherwise, get the input from the scene, - $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | - Where-Object SourceName -eq $myParameters["Name"] - # update the input settings - $sceneItem.Input.Settings = $addSplat.inputSettings - $sceneItem # and return the scene item. + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - - } + } + + +} + #.ExternalHelp obs-powershell-Help.xml -function Get-OBS3dSwapTransitionShader { +function Add-OBSSceneItem { -[Alias('Set-OBS3dSwapTransitionShader','Add-OBS3dSwapTransitionShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'CreateSceneItem')] +[Alias('obs.powershell.websocket.CreateSceneItem')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Add-OBSSceneSource')] param( -# Set the image_a of OBS3dSwapTransitionShader -[Alias('image_a')] -[ComponentModel.DefaultBindingProperty('image_a')] -[String] -$ImageA, -# Set the image_b of OBS3dSwapTransitionShader -[Alias('image_b')] -[ComponentModel.DefaultBindingProperty('image_b')] -[String] -$ImageB, -# Set the transition_time of OBS3dSwapTransitionShader -[Alias('transition_time')] -[ComponentModel.DefaultBindingProperty('transition_time')] -[Single] -$TransitionTime, -# Set the convert_linear of OBS3dSwapTransitionShader -[Alias('convert_linear')] -[ComponentModel.DefaultBindingProperty('convert_linear')] -[Management.Automation.SwitchParameter] -$ConvertLinear, -# Set the reflection of OBS3dSwapTransitionShader -[ComponentModel.DefaultBindingProperty('reflection')] -[Single] -$Reflection, -# Set the perspective of OBS3dSwapTransitionShader -[ComponentModel.DefaultBindingProperty('perspective')] -[Single] -$Perspective, -# Set the depth of OBS3dSwapTransitionShader -[ComponentModel.DefaultBindingProperty('depth')] -[Single] -$Depth, -# Set the background_color of OBS3dSwapTransitionShader -[Alias('background_color')] -[ComponentModel.DefaultBindingProperty('background_color')] -[String] -$BackgroundColor, -# The name of the source. This must be provided when adding an item for the first time + [Parameter(ValueFromPipelineByPropertyName)] -[Alias('SceneItemName')] -[String] +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sourceName')] +[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] +[ComponentModel.DefaultBindingProperty('sourceUuid')] +[string] +$SourceUuid, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemEnabled')] +[switch] +$SceneItemEnabled, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = '3d_swap_transition' -$ShaderNoun = 'OBS3dSwapTransitionShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//based on https://www.shadertoy.com/view/MlXGzf - -uniform texture2d image_a; -uniform texture2d image_b; -uniform float transition_time = 0.5; -uniform bool convert_linear = true; - -uniform float reflection< - string label = "Reflection (0.4)"; - string widget_type = "slider"; - float minimum = 0.00; - float maximum = 1.00; - float step = 0.01; -> = 0.4; -uniform float perspective< - string label = "Perspective (0.2)"; - string widget_type = "slider"; - float minimum = 0.00; - float maximum = 1.00; - float step = 0.01; -> = .2; -uniform float depth< - string label = "Depth (3.0)"; - string widget_type = "slider"; - float minimum = 1.00; - float maximum = 10.00; - float step = 0.1; -> = 3.; - -#ifndef OPENGL -#define lessThan(a,b) (a < b) -#endif -uniform float4 background_color = {0.0, 0.0, 0.0, 1.0}; - -bool inBounds (float2 p) { - return all(lessThan(float2(0.0,0.0), p)) && all(lessThan(p, float2(1.0,1.0))); -} - -float2 project (float2 p) { - return p * float2(1.0, -1.2) + float2(0.0, 2.22); -} - -float4 bgColor (float2 p, float2 pfr, float2 pto) { - float4 c = background_color; - pfr = project(pfr); - if (inBounds(pfr)) { - c += lerp(background_color, image_a.Sample(textureSampler, pfr), reflection * lerp(0.0, 1.0, pfr.y)); - } - pto = project(pto); - if (inBounds(pto)) { - c += lerp(background_color, image_b.Sample(textureSampler, pto), reflection * lerp(0.0, 1.0, pto.y)); - } - return c; -} - -float4 mainImage(VertData v_in) : TARGET { - float2 p = v_in.uv; - float2 pfr = float2(-1.,-1.); - float2 pto = float2(-1.,-1.); - - float progress = transition_time; - float size = lerp(1.0, depth, progress); - float persp = perspective * progress; - pfr = (p + float2(-0.0, -0.5)) * float2(size/(1.0-perspective*progress), size/(1.0-size*persp*p.x)) + float2(0.0, 0.5); - - size = lerp(1.0, depth, 1.-progress); - persp = perspective * (1.-progress); - pto = (p + float2(-1.0, -0.5)) * float2(size/(1.0-perspective*(1.0-progress)), size/(1.0-size*persp*(0.5-p.x))) + float2(1.0, 0.5); - - bool fromOver = progress < 0.5; - float4 rgba = background_color; - if (fromOver) { - if (inBounds(pfr)) { - rgba = image_a.Sample(textureSampler, pfr); - } - else if (inBounds(pto)) { - rgba = image_b.Sample(textureSampler, pto); - } - else { - rgba = bgColor(p, pfr, pto); - } - } - else { - if (inBounds(pto)) { - rgba = image_b.Sample(textureSampler, pto); - } - else if (inBounds(pfr)) { - rgba = image_a.Sample(textureSampler, pfr); - } - else { - rgba = bgColor(p, pfr, pto); - } - } - if (convert_linear) - rgba.rgb = srgb_nonlinear_to_linear(rgba.rgb); - return rgba; -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -4715,147 +3707,125 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSAddShader { +function Add-OBSSourceFilter { -[Alias('Set-OBSAddShader','Add-OBSAddShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'CreateSourceFilter')] +[Alias('obs.powershell.websocket.CreateSourceFilter')] param( -# Set the other_image of OBSAddShader -[Alias('other_image')] -[ComponentModel.DefaultBindingProperty('other_image')] -[String] -$OtherImage, -# The name of the source. This must be provided when adding an item for the first time + [Parameter(ValueFromPipelineByPropertyName)] -[Alias('SceneItemName')] -[String] +[ComponentModel.DefaultBindingProperty('sourceName')] +[string] $SourceName, -# The name of the filter. If this is not provided, this will default to the shader name. + [Parameter(ValueFromPipelineByPropertyName)] -[String] +[ComponentModel.DefaultBindingProperty('sourceUuid')] +[string] +$SourceUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('filterName')] +[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] + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('filterKind')] +[string] +$FilterKind, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('filterSettings')] +[PSObject] +$FilterSettings, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'Add' -$ShaderNoun = 'OBSAddShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform texture2d other_image; -float4 mainImage(VertData v_in) : TARGET -{ - float4 other = other_image.Sample(textureSampler, v_in.uv); - float4 base = image.Sample(textureSampler, v_in.uv); - return clamp(base + other, 0.0, 1.0); -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -4864,182 +3834,127 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSAlphaBorderShader { +function Copy-OBSSceneItem { -[Alias('Set-OBSAlphaBorderShader','Add-OBSAlphaBorderShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'DuplicateSceneItem')] +[Alias('obs.powershell.websocket.DuplicateSceneItem')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the border_color of OBSAlphaBorderShader -[Alias('border_color')] -[ComponentModel.DefaultBindingProperty('border_color')] -[String] -$BorderColor, -# Set the border_thickness of OBSAlphaBorderShader -[Alias('border_thickness')] -[ComponentModel.DefaultBindingProperty('border_thickness')] -[Int32] -$BorderThickness, -# Set the alpha_cut_off of OBSAlphaBorderShader -[Alias('alpha_cut_off')] -[ComponentModel.DefaultBindingProperty('alpha_cut_off')] -[Single] -$AlphaCutOff, -# 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. +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, + [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 -) +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemId')] +[ValidateRange(0,[int]::MaxValue)] +[double] +$SceneItemId, -process { -$shaderName = 'alpha_border' -$ShaderNoun = 'OBSAlphaBorderShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform float4 border_color< - string label = "Border color"; -> = {0.0,0.0,0.0,1.0}; -uniform int border_thickness< - string label = "Border thickness"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 0; -uniform float alpha_cut_off< - string label = "Alpha cut off"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.5; +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('destinationSceneName')] +[string] +$DestinationSceneName, -float4 mainImage(VertData v_in) : TARGET -{ - float4 pix = image.Sample(textureSampler, v_in.uv); - if (pix.a > alpha_cut_off) - return pix; - [loop] for(int x = -border_thickness;x alpha_cut_off) - return border_color; - } - } - } - return pix; -} -' -} -$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 - } - } +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('destinationSceneUuid')] +[string] +$DestinationSceneUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName - } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } +process { - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -5048,300 +3963,101 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSAlphaGamingBentCameraShader { +function Get-OBSCurrentPreviewScene { -[Alias('Set-OBSAlphaGamingBentCameraShader','Add-OBSAlphaGamingBentCameraShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetCurrentPreviewScene')] +[Alias('obs.powershell.websocket.GetCurrentPreviewScene')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the left_side_width of OBSAlphaGamingBentCameraShader -[Alias('left_side_width')] -[ComponentModel.DefaultBindingProperty('left_side_width')] -[Single] -$LeftSideWidth, -# Set the left_side_size of OBSAlphaGamingBentCameraShader -[Alias('left_side_size')] -[ComponentModel.DefaultBindingProperty('left_side_size')] -[Single] -$LeftSideSize, -# Set the left_side_shadow of OBSAlphaGamingBentCameraShader -[Alias('left_side_shadow')] -[ComponentModel.DefaultBindingProperty('left_side_shadow')] -[Single] -$LeftSideShadow, -# Set the left_flip_width of OBSAlphaGamingBentCameraShader -[Alias('left_flip_width')] -[ComponentModel.DefaultBindingProperty('left_flip_width')] -[Single] -$LeftFlipWidth, -# Set the left_flip_shadow of OBSAlphaGamingBentCameraShader -[Alias('left_flip_shadow')] -[ComponentModel.DefaultBindingProperty('left_flip_shadow')] -[Single] -$LeftFlipShadow, -# Set the right_side_width of OBSAlphaGamingBentCameraShader -[Alias('right_side_width')] -[ComponentModel.DefaultBindingProperty('right_side_width')] -[Single] -$RightSideWidth, -# Set the right_side_size of OBSAlphaGamingBentCameraShader -[Alias('right_side_size')] -[ComponentModel.DefaultBindingProperty('right_side_size')] -[Single] -$RightSideSize, -# Set the right_side_shadow of OBSAlphaGamingBentCameraShader -[Alias('right_side_shadow')] -[ComponentModel.DefaultBindingProperty('right_side_shadow')] -[Single] -$RightSideShadow, -# Set the right_flip_width of OBSAlphaGamingBentCameraShader -[Alias('right_flip_width')] -[ComponentModel.DefaultBindingProperty('right_flip_width')] -[Single] -$RightFlipWidth, -# Set the right_flip_shadow of OBSAlphaGamingBentCameraShader -[Alias('right_flip_shadow')] -[ComponentModel.DefaultBindingProperty('right_flip_shadow')] -[Single] -$RightFlipShadow, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'alpha-gaming-bent-camera' -$ShaderNoun = 'OBSAlphaGamingBentCameraShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform float left_side_width< - string label = "Left side width"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.1; -uniform float left_side_size< - string label = "Left side size"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.9; -uniform float left_side_shadow< - string label = "Left side shadow"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.8; -uniform float left_flip_width< - string label = "Left flip width"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.05; -uniform float left_flip_shadow< - string label = "Left flip shadow"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.6; - -uniform float right_side_width< - string label = "Right side width"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.1; -uniform float right_side_size< - string label = "Right side size"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.9; -uniform float right_side_shadow< - string label = "Right side shadow"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.8; -uniform float right_flip_width< - string label = "Right flip width"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.05; -uniform float right_flip_shadow< - string label = "Right flip shadow"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.6; -float4 mainImage(VertData v_in) : TARGET -{ - float2 pos=v_in.uv; - float shadow = 1.0; - if(pos.x < left_side_width){ - pos.y -= 0.5; - pos.y /= left_side_size; - pos.y += 0.5; - pos.x -= left_side_width + left_flip_width; - pos.x /= left_side_size; - pos.x += left_side_width + left_flip_width; - shadow = left_side_shadow; - }else if(pos.x < left_side_width + left_flip_width){ - float factor = 1.0 - ((left_side_width + left_flip_width)-pos.x)/left_flip_width*(1.0 - left_side_size); - pos.y -= 0.5; - pos.y /= factor; - pos.y += 0.5; - pos.x -= left_side_width + left_flip_width; - pos.x /= factor; - pos.x += left_side_width + left_flip_width; - shadow = left_flip_shadow; - } - if(1.0 - pos.x < right_side_width){ - pos.y -= 0.5; - pos.y /= right_side_size; - pos.y += 0.5; - pos.x -= 1.0 - (right_side_width + right_flip_width); - pos.x /= right_side_size; - pos.x += 1.0 - (right_side_width + right_flip_width); - shadow = right_side_shadow; - }else if(1.0 - pos.x < right_side_width + right_flip_width){ - float factor = 1.0 - ((right_side_width + right_flip_width) - (1.0 - pos.x))/right_flip_width*(1.0 - right_side_size); - pos.y -= 0.5; - pos.y /= factor; - pos.y += 0.5; - pos.x -= 1.0 - (right_side_width + right_flip_width); - pos.x /= factor; - pos.x += 1.0 -(right_side_width + right_flip_width); - shadow = right_flip_shadow; - } - float4 p_color = image.Sample(textureSampler, pos); - p_color.rgb *= shadow; - return p_color; -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -5350,270 +4066,204 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSAnimatedPathShader { +function Get-OBSCurrentProgramScene { -[Alias('Set-OBSAnimatedPathShader','Add-OBSAnimatedPathShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetCurrentProgramScene')] +[Alias('obs.powershell.websocket.GetCurrentProgramScene')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the ViewProj of OBSAnimatedPathShader -[ComponentModel.DefaultBindingProperty('ViewProj')] -[Single[][]] -$ViewProj, -# Set the image of OBSAnimatedPathShader -[ComponentModel.DefaultBindingProperty('image')] -[String] -$Image, -# Set the elapsed_time of OBSAnimatedPathShader -[Alias('elapsed_time')] -[ComponentModel.DefaultBindingProperty('elapsed_time')] -[Single] -$ElapsedTime, -# Set the uv_offset of OBSAnimatedPathShader -[Alias('uv_offset')] -[ComponentModel.DefaultBindingProperty('uv_offset')] -[Single[]] -$UvOffset, -# Set the uv_scale of OBSAnimatedPathShader -[Alias('uv_scale')] -[ComponentModel.DefaultBindingProperty('uv_scale')] -[Single[]] -$UvScale, -# Set the uv_pixel_interval of OBSAnimatedPathShader -[Alias('uv_pixel_interval')] -[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] -[Single[]] -$UvPixelInterval, -# Set the rand_f of OBSAnimatedPathShader -[Alias('rand_f')] -[ComponentModel.DefaultBindingProperty('rand_f')] -[Single] -$RandF, -# Set the speed_percent of OBSAnimatedPathShader -[Alias('speed_percent')] -[ComponentModel.DefaultBindingProperty('speed_percent')] -[Int32] -$SpeedPercent, -# Set the path_map of OBSAnimatedPathShader -[Alias('path_map')] -[ComponentModel.DefaultBindingProperty('path_map')] -[String] -$PathMap, -# Set the reverse of OBSAnimatedPathShader -[ComponentModel.DefaultBindingProperty('reverse')] -[Management.Automation.SwitchParameter] -$Reverse, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'animated_path' -$ShaderNoun = 'OBSAnimatedPathShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Path effect By Charles Fettinger (https://github.com/Oncorporation) 3/2019 -//Converted to OpenGL by Q-mii & Exeldro February 24, 2022 -uniform float4x4 ViewProj; -uniform texture2d image; -uniform float elapsed_time; -uniform float2 uv_offset; -uniform float2 uv_scale; -uniform float2 uv_pixel_interval; -uniform float rand_f; -uniform int speed_percent = 100; -uniform texture2d path_map; -uniform bool reverse = false; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -sampler_state textureSampler { - Filter = Linear; - AddressU = Border; - AddressV = Border; - BorderColor = 00000000; -}; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -struct VertData { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } + + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -float4 convert_pmalpha(float4 c) -{ - float4 ret = c; - if (c.a >= 0.001) - ret.xyz /= c.a; - else - ret = float4(0.0, 0.0, 0.0, 0.0); - return ret; } -VertData mainTransform(VertData v_in) -{ - VertData vert_out; - float3 pos = v_in.pos.xyz; - float3 current_pos; - float speed = speed_percent * 0.01; - //vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); - float t = 1.0 + sin(elapsed_time * speed) ; - // combine luma texture and user defined shine color - float luma = path_map.Sample(textureSampler, v_in.uv).x; - if (reverse) - { - luma = 1.0 - luma; - } - float time = lerp(0.0f, 1.0f , t - 1.0); +} - // set current position in time - current_pos.x = 0; - current_pos.y = 0; + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSCurrentSceneTransition { - float2 offset = uv_offset; - if (speed == 0.0f) - { - offset.x = 0.0f; - offset.y = 0.0f; - } - else - { - offset.x = uv_offset.x + time * luma; - offset.y = uv_offset.y + time * luma; - } +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetCurrentSceneTransition')] +[Alias('obs.powershell.websocket.GetCurrentSceneTransition')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - vert_out.pos = mul(float4(current_pos, 1), ViewProj); - vert_out.uv = v_in.uv * uv_scale + offset; - return vert_out; -} -float4 mainImage(VertData v_in) : TARGET -{ - return image.Sample(textureSampler, v_in.uv); -} +process { -technique Draw -{ - pass - { - vertex_shader = mainTransform(v_in); - pixel_shader = mainImage(v_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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -5622,403 +4272,204 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSAnimatedTextureShader { +function Get-OBSCurrentSceneTransitionCursor { -[Alias('Set-OBSAnimatedTextureShader','Add-OBSAnimatedTextureShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetCurrentSceneTransitionCursor')] +[Alias('obs.powershell.websocket.GetCurrentSceneTransitionCursor')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the ViewProj of OBSAnimatedTextureShader -[ComponentModel.DefaultBindingProperty('ViewProj')] -[Single[][]] -$ViewProj, -# Set the image of OBSAnimatedTextureShader -[ComponentModel.DefaultBindingProperty('image')] -[String] -$Image, -# Set the elapsed_time of OBSAnimatedTextureShader -[Alias('elapsed_time')] -[ComponentModel.DefaultBindingProperty('elapsed_time')] -[Single] -$ElapsedTime, -# Set the uv_offset of OBSAnimatedTextureShader -[Alias('uv_offset')] -[ComponentModel.DefaultBindingProperty('uv_offset')] -[Single[]] -$UvOffset, -# Set the uv_scale of OBSAnimatedTextureShader -[Alias('uv_scale')] -[ComponentModel.DefaultBindingProperty('uv_scale')] -[Single[]] -$UvScale, -# Set the uv_pixel_interval of OBSAnimatedTextureShader -[Alias('uv_pixel_interval')] -[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] -[Single[]] -$UvPixelInterval, -# Set the rand_f of OBSAnimatedTextureShader -[Alias('rand_f')] -[ComponentModel.DefaultBindingProperty('rand_f')] -[Single] -$RandF, -# Set the uv_size of OBSAnimatedTextureShader -[Alias('uv_size')] -[ComponentModel.DefaultBindingProperty('uv_size')] -[Single[]] -$UvSize, -# Set the notes of OBSAnimatedTextureShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# Set the Animation_Image of OBSAnimatedTextureShader -[Alias('Animation_Image')] -[ComponentModel.DefaultBindingProperty('Animation_Image')] -[String] -$AnimationImage, -# Set the Colorization_Image of OBSAnimatedTextureShader -[Alias('Colorization_Image')] -[ComponentModel.DefaultBindingProperty('Colorization_Image')] -[String] -$ColorizationImage, -# Set the reverse of OBSAnimatedTextureShader -[ComponentModel.DefaultBindingProperty('reverse')] -[Management.Automation.SwitchParameter] -$Reverse, -# Set the bounce of OBSAnimatedTextureShader -[ComponentModel.DefaultBindingProperty('bounce')] -[Management.Automation.SwitchParameter] -$Bounce, -# Set the center_animation of OBSAnimatedTextureShader -[Alias('center_animation')] -[ComponentModel.DefaultBindingProperty('center_animation')] -[Management.Automation.SwitchParameter] -$CenterAnimation, -# Set the polar_animation of OBSAnimatedTextureShader -[Alias('polar_animation')] -[ComponentModel.DefaultBindingProperty('polar_animation')] -[Management.Automation.SwitchParameter] -$PolarAnimation, -# Set the polar_angle of OBSAnimatedTextureShader -[Alias('polar_angle')] -[ComponentModel.DefaultBindingProperty('polar_angle')] -[Single] -$PolarAngle, -# Set the polar_height of OBSAnimatedTextureShader -[Alias('polar_height')] -[ComponentModel.DefaultBindingProperty('polar_height')] -[Single] -$PolarHeight, -# Set the speed_horizontal_percent of OBSAnimatedTextureShader -[Alias('speed_horizontal_percent')] -[ComponentModel.DefaultBindingProperty('speed_horizontal_percent')] -[Single] -$SpeedHorizontalPercent, -# Set the speed_vertical_percent of OBSAnimatedTextureShader -[Alias('speed_vertical_percent')] -[ComponentModel.DefaultBindingProperty('speed_vertical_percent')] -[Single] -$SpeedVerticalPercent, -# Set the tint_speed_horizontal_percent of OBSAnimatedTextureShader -[Alias('tint_speed_horizontal_percent')] -[ComponentModel.DefaultBindingProperty('tint_speed_horizontal_percent')] -[Single] -$TintSpeedHorizontalPercent, -# Set the tint_speed_vertical_percent of OBSAnimatedTextureShader -[Alias('tint_speed_vertical_percent')] -[ComponentModel.DefaultBindingProperty('tint_speed_vertical_percent')] -[Single] -$TintSpeedVerticalPercent, -# Set the Alpha of OBSAnimatedTextureShader -[ComponentModel.DefaultBindingProperty('Alpha')] -[Single] -$Alpha, -# Set the Use_Animation_Image_Color of OBSAnimatedTextureShader -[Alias('Use_Animation_Image_Color')] -[ComponentModel.DefaultBindingProperty('Use_Animation_Image_Color')] -[Management.Automation.SwitchParameter] -$UseAnimationImageColor, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'animated_texture' -$ShaderNoun = 'OBSAnimatedTextureShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Animated Texture By Charles Fettinger (https://github.com/Oncorporation) 3/2020 -// Animates a texture with polar sizing and color options -// for use with obs-shaderfilter 1.0 -//Converted to OpenGL by Q-mii & Exeldro February 24, 2022 -uniform float4x4 ViewProj; -uniform texture2d image; - -uniform float elapsed_time; -uniform float2 uv_offset; -uniform float2 uv_scale; -uniform float2 uv_pixel_interval; -uniform float rand_f; -uniform float2 uv_size; -uniform string notes; - -uniform texture2d Animation_Image; -uniform texture2d Colorization_Image; -uniform bool reverse = false; -uniform bool bounce = false; -uniform bool center_animation = true; -uniform bool polar_animation = true; -uniform float polar_angle = 90.0; -uniform float polar_height = 1.0; -uniform float speed_horizontal_percent = 50; -uniform float speed_vertical_percent = 5; -uniform float tint_speed_horizontal_percent = 50; -uniform float tint_speed_vertical_percent = 5; -uniform float Alpha = 1.0; -uniform bool Use_Animation_Image_Color = true; - -sampler_state textureSampler { - Filter = Linear; - AddressU = Border; - AddressV = Border; - BorderColor = 00000000; -}; - -struct VertData { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; - -float4 convert_pmalpha(float4 color) -{ - float4 ret = color; - if (color.a >= 0.001) - ret.xyz /= color.a; - else - ret = float4(0.0, 0.0, 0.0, 0.0); - return ret; -} - -float2 time(float2 speed_dir) -{ - float PI = 3.1415926535897932384626433832795; //acos(-1); - float2 t = (elapsed_time * speed_dir) ; - if (bounce) - { - // coordinates moved from -1.0 to 1.0 to 0.0 to 2.0 then modified to fit screen - t.x = sin(elapsed_time * speed_dir.x * PI * 0.6667) + 1.0; - t.y = cos(elapsed_time * speed_dir.y * PI) + 1.0; - t *= -0.5; - } - if (reverse) - t = t * -1; - return t; -} + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -VertData mainTransform(VertData v_in) -{ - float2 speed_dir = float2(speed_horizontal_percent * 0.01, speed_vertical_percent * 0.01); + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } - VertData vert_out; - //float2 direction = abs(sin((elapsed_time - 0.001) * speed_dir)); + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } - float2 offset = uv_offset; + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } - if (center_animation) - { - vert_out.uv = v_in.uv - 0.5f; - } - else - { - offset += time(speed_dir); - vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); - vert_out.uv = v_in.uv * uv_scale + offset; - } + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } - return vert_out; } -float4 mainImage(VertData v_in) : TARGET -{ - float PI = 3.1415926535897932384626433832795; //acos(-1); - float PI180th = 0.0174532925; //PI divided by 180 - - float2 speed_dir = float2(speed_horizontal_percent * 0.01, speed_vertical_percent * 0.01); - float2 tint_speed_dir = float2(tint_speed_horizontal_percent * 0.01, tint_speed_vertical_percent * 0.01); - - //compensate for background vertex shader values - float2 background_offset = float2(-.5,-.5); - if (!center_animation) - background_offset = time(speed_dir); - float4 rgba = image.Sample(textureSampler, v_in.uv - background_offset); //float4(0.0,0.0,0.0,0.01); - - // Convert our texture coordinates to polar form: - if (polar_animation) { - - float2 polar = float2( - atan2(v_in.uv.y, v_in.uv.x) / (polar_angle * PI180th * 4), // angle - log(dot(v_in.uv, v_in.uv)) * -1 * (polar_height * PI180th * PI) // log-radius - ); - - // Check how much our texture sampling point changes between - // neighbouring pixels to the sides (ddx) and above/below (ddy) - ///float4 gradient = float4(ddx(polar), ddy(polar)); +} - // If our angle wraps around between adjacent samples, - // discard one full rotation from its value and keep the fraction. - ///gradient.xz = frac(gradient.xz + 1.5f) - 0.5f; + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSGroup { - float2 tintUVs = polar * 4; - tintUVs += time(tint_speed_dir); - // Apply texture scale - polar *= 4; - // Scroll the texture over time. - polar += time(speed_dir); - float4 animation = Animation_Image.Sample(textureSampler, frac(polar)); - +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetGroupList')] +[Alias('obs.powershell.websocket.GetGroupList')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - float keyAmount = distance(animation.rgb,float3(0.0,0.0,0.0)); - float intensity = dot(animation.rgb ,float3(0.299,0.587,0.114)); - //animation.a = clamp((intensity),0.0,1.0); - if (Use_Animation_Image_Color) - { - animation.rgb *= Colorization_Image.Sample(textureSampler, frac(tintUVs)).rgb; - } - else - { - animation.rgb = Colorization_Image.Sample(textureSampler, frac(tintUVs)).rgb; - } - //if (keyAmount > 0.5f) - rgba = lerp(rgba, animation, animation.a * Alpha); - } - return rgba; -} +process { -technique Draw -{ - pass - { - vertex_shader = mainTransform(v_in); - pixel_shader = mainImage(v_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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -6027,256 +4478,111 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSAsciiShader { +function Get-OBSGroupSceneItem { -[Alias('Set-OBSAsciiShader','Add-OBSAsciiShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetGroupSceneItemList')] +[Alias('obs.powershell.websocket.GetGroupSceneItemList')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the scale of OBSAsciiShader -[ComponentModel.DefaultBindingProperty('scale')] -[Int32] -$Scale, -# Set the base_color of OBSAsciiShader -[Alias('base_color')] -[ComponentModel.DefaultBindingProperty('base_color')] -[String] -$BaseColor, -# Set the monochrome of OBSAsciiShader -[ComponentModel.DefaultBindingProperty('monochrome')] -[Management.Automation.SwitchParameter] -$Monochrome, -# Set the character_set of OBSAsciiShader -[Alias('character_set')] -[ComponentModel.DefaultBindingProperty('character_set')] -[Int32] -$CharacterSet, -# Set the note of OBSAsciiShader -[ComponentModel.DefaultBindingProperty('note')] -[String] -$Note, -# 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. +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, + [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] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'ascii' -$ShaderNoun = 'OBSAsciiShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// ASCII shader for use with obs-shaderfilter 7/2020 v1.0 -// https://github.com/Oncorporation/obs-shaderfilter -// Based on the following shaders: -// https://www.shadertoy.com/view/3dtXD8 - Created by DSWebber in 2019-10-24 -// https://www.shadertoy.com/view/lssGDj - Created by movAX13h in 2013-09-22 - -// Modifications of original shaders include: -// - Porting from GLSL to HLSL -// - Combining characters sets from both source shaders -// - Adding support for parameters from OBS for monochrome rendering, scaling and dynamic character set -// -// Add Additional Characters with this tool: http://thrill-project.com/archiv/coding/bitmap/ -// converts a bitmap into int then decodes it to look like text - -uniform int scale< - string label = "Scale"; - string widget_type = "slider"; - int minimum = 1; - int maximum = 20; - int step = 1; -> = 1; // Size of characters -uniform float4 base_color< - string label = "Base color"; -> = {0.0,1.0,0.0,1.0}; // Monochrome base color -uniform bool monochrome< - string label = "Monochrome"; -> = false; -uniform int character_set< - string label = "Character set"; - string widget_type = "select"; - int option_0_value = 0; - string option_0_label = "Large set of non-letters"; - int option_1_value = 1; - string option_1_label = "Small set of capital letters"; -> = 0; -uniform string note< - string widget_type = "info"; -> = "Base color is used as monochrome base color."; - -float character(int n, float2 p) -{ - p = floor(p*float2(4.0, 4.0) + 2.5); - if (clamp(p.x, 0.0, 4.0) == p.x) - { - if (clamp(p.y, 0.0, 4.0) == p.y) - { - int a = int(round(p.x) + 5.0 * round(p.y)); - if (((n >> a) & 1) == 1) return 1.0; - } - } - return 0.0; -} - -float2 mod(float2 x, float2 y) -{ - return x - y * floor(x/y); -} - -float4 mainImage( VertData v_in ) : TARGET -{ - float2 iResolution = uv_size*uv_scale; - float2 pix = v_in.pos.xy; - float4 c = image.Sample(textureSampler, floor(pix/float2(scale*8.0,scale*8.0))*float2(scale*8.0,scale*8.0)/iResolution.xy); - - float gray = 0.3 * c.r + 0.59 * c.g + 0.11 * c.b; - - int n; - int charset = clamp(character_set, 0, 1); - - if (charset==0) - { - if (gray <= 0.2) n = 4096; // . - if (gray > 0.2) n = 65600; // : - if (gray > 0.3) n = 332772; // * - if (gray > 0.4) n = 15255086; // o - if (gray > 0.5) n = 23385164; // & - if (gray > 0.6) n = 15252014; // 8 - if (gray > 0.7) n = 13199452; // @ - if (gray > 0.8) n = 11512810; // # - } - else if (charset==1) - { - if (gray <= 0.1) n = 0; - if (gray > 0.1) n = 9616687; // R - if (gray > 0.3) n = 32012382; // S - if (gray > 0.5) n = 16303663; // D - if (gray > 0.7) n = 15255086; // O - if (gray > 0.8) n = 16301615; // B - } - float2 p = mod(pix/float2(scale*4.0,scale*4.0),float2(2.0,2.0)) - float2(1.0,1.0); - - if (monochrome) - { - c.rgb = base_color.rgb; - } - c = c*character(n, p); - - return c; -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -6285,272 +4591,209 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSAspectRatioShader { +function Get-OBSHotkey { -[Alias('Set-OBSAspectRatioShader','Add-OBSAspectRatioShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetHotkeyList')] +[Alias('obs.powershell.websocket.GetHotkeyList')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the ViewProj of OBSAspectRatioShader -[ComponentModel.DefaultBindingProperty('ViewProj')] -[Single[][]] -$ViewProj, -# Set the image of OBSAspectRatioShader -[ComponentModel.DefaultBindingProperty('image')] -[String] -$Image, -# Set the elapsed_time of OBSAspectRatioShader -[Alias('elapsed_time')] -[ComponentModel.DefaultBindingProperty('elapsed_time')] -[Single] -$ElapsedTime, -# Set the uv_offset of OBSAspectRatioShader -[Alias('uv_offset')] -[ComponentModel.DefaultBindingProperty('uv_offset')] -[Single[]] -$UvOffset, -# Set the uv_scale of OBSAspectRatioShader -[Alias('uv_scale')] -[ComponentModel.DefaultBindingProperty('uv_scale')] -[Single[]] -$UvScale, -# Set the uv_pixel_interval of OBSAspectRatioShader -[Alias('uv_pixel_interval')] -[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] -[Single[]] -$UvPixelInterval, -# Set the rand_f of OBSAspectRatioShader -[Alias('rand_f')] -[ComponentModel.DefaultBindingProperty('rand_f')] -[Single] -$RandF, -# Set the uv_size of OBSAspectRatioShader -[Alias('uv_size')] -[ComponentModel.DefaultBindingProperty('uv_size')] -[Single[]] -$UvSize, -# Set the borderColor of OBSAspectRatioShader -[ComponentModel.DefaultBindingProperty('borderColor')] -[String] -$BorderColor, -# Set the notes of OBSAspectRatioShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'aspect_ratio' -$ShaderNoun = 'OBSAspectRatioShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//Converted to OpenGL by Q-mii & Exeldro March 8, 2022 - DO NOT USE THIS IT WAS NEVER COMPLETED -uniform float4x4 ViewProj; -uniform texture2d image; -uniform float elapsed_time; -uniform float2 uv_offset; -uniform float2 uv_scale; -uniform float2 uv_pixel_interval; -uniform float rand_f; -uniform float2 uv_size; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -// variables -uniform float4 borderColor = {0,0,0,0}; -float targetaspect = 1.7777777777777777777777f; //16.0f / 9.0f; -uniform string notes; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -sampler_state textureSampler { - Filter = Linear; - AddressU = Border; - AddressV = Border; - BorderColor = 00000000; -}; + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -struct VertData { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -VertData mainTransform(VertData v_in) -{ - VertData vert_out; - - vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); - vert_out.uv = v_in.uv * uv_scale + uv_offset; + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } - float2 hw = uv_scale; - // determine the game window''s current aspect ratio - float windowaspect = hw.x / hw.y; +} - // current viewport height should be scaled by this amount - float scaleheight = windowaspect / targetaspect; +} - // if scaled height is less than current height, add letterbox - if (scaleheight < 1.0f) - { - Rect rect = camera.rect; + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSInput { - rect.width = 1.0f; - rect.height = scaleheight; - rect.x = 0; - rect.y = (1.0f - scaleheight) / 2.0f; - camera.rect = rect; - } - else // add pillarbox - { - float scalewidth = 1.0f / scaleheight; +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputList')] +[Alias('obs.powershell.websocket.GetInputList')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( - Rect rect = camera.rect; +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputKind')] +[string] +$InputKind, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - rect.width = scalewidth; - rect.height = 1.0f; - rect.x = (1.0f - scalewidth) / 2.0f; - rect.y = 0; - camera.rect = rect; - } - return vert_out; -} +process { -float4 mainImage(VertData v_in) : TARGET -{ - if (v_in.uv.x < 0 || v_in.uv.x > 1 || v_in.uv.y < 0 || v_in.uv.y > 1) - { - return borderColor; - } - else - { - return image.Sample(textureSampler, v_in.uv); - } -} -technique Draw -{ - pass - { - vertex_shader = mainTransform(v_in); - pixel_shader = mainImage(v_in); - } -} + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -' -} -$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 + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -6559,315 +4802,224 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSBackgroundRemovalShader { +function Get-OBSInputAudioBalance { -[Alias('Set-OBSBackgroundRemovalShader','Add-OBSBackgroundRemovalShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputAudioBalance')] +[Alias('obs.powershell.websocket.GetInputAudioBalance')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the ViewProj of OBSBackgroundRemovalShader -[ComponentModel.DefaultBindingProperty('ViewProj')] -[Single[][]] -$ViewProj, -# Set the image of OBSBackgroundRemovalShader -[ComponentModel.DefaultBindingProperty('image')] -[String] -$Image, -# Set the elapsed_time of OBSBackgroundRemovalShader -[Alias('elapsed_time')] -[ComponentModel.DefaultBindingProperty('elapsed_time')] -[Single] -$ElapsedTime, -# Set the uv_offset of OBSBackgroundRemovalShader -[Alias('uv_offset')] -[ComponentModel.DefaultBindingProperty('uv_offset')] -[Single[]] -$UvOffset, -# Set the uv_scale of OBSBackgroundRemovalShader -[Alias('uv_scale')] -[ComponentModel.DefaultBindingProperty('uv_scale')] -[Single[]] -$UvScale, -# Set the uv_pixel_interval of OBSBackgroundRemovalShader -[Alias('uv_pixel_interval')] -[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] -[Single[]] -$UvPixelInterval, -# Set the rand_f of OBSBackgroundRemovalShader -[Alias('rand_f')] -[ComponentModel.DefaultBindingProperty('rand_f')] -[Single] -$RandF, -# Set the uv_size of OBSBackgroundRemovalShader -[Alias('uv_size')] -[ComponentModel.DefaultBindingProperty('uv_size')] -[Single[]] -$UvSize, -# Set the notes of OBSBackgroundRemovalShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# Set the target of OBSBackgroundRemovalShader -[ComponentModel.DefaultBindingProperty('target')] -[String] -$Target, -# Set the color of OBSBackgroundRemovalShader -[ComponentModel.DefaultBindingProperty('color')] -[String] -$Color, -# Set the opacity of OBSBackgroundRemovalShader -[ComponentModel.DefaultBindingProperty('opacity')] -[Single] -$Opacity, -# Set the invert of OBSBackgroundRemovalShader -[ComponentModel.DefaultBindingProperty('invert')] -[Management.Automation.SwitchParameter] -$Invert, -# Set the Convert_709to601 of OBSBackgroundRemovalShader -[Alias('Convert_709to601')] -[ComponentModel.DefaultBindingProperty('Convert_709to601')] -[Management.Automation.SwitchParameter] -$Convert709to601, -# Set the Convert_601to709 of OBSBackgroundRemovalShader -[Alias('Convert_601to709')] -[ComponentModel.DefaultBindingProperty('Convert_601to709')] -[Management.Automation.SwitchParameter] -$Convert601to709, -# 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. +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + [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] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'background_removal' -$ShaderNoun = 'OBSBackgroundRemovalShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// background removal effect By Charles Fettinger (https://github.com/Oncorporation) 4/2019 -//Converted to OpenGL by Exeldro February 19, 2022 -uniform float4x4 ViewProj; -uniform texture2d image; -uniform float elapsed_time; -uniform float2 uv_offset; -uniform float2 uv_scale; -uniform float2 uv_pixel_interval; -uniform float rand_f; -uniform float2 uv_size; -uniform string notes = "Opacity between 10 and 20 works. Adjust `Color` from white to fix environmental changes.\r\r\nUsage:\r\n1) Disable `Auto` settings like focus, white balance, etc.\r\n2) Take a video of just the background. \r\n3) Take a frame and use it as the background image. Windows Snipping Tool (%windir%\\system32\\SnippingTool.exe). \r\r\nThis eliminates differences based upon camera/video settings."; -uniform texture2d target; -uniform float4 color; -uniform float opacity = 15.0; -uniform bool invert; -uniform bool Convert_709to601; -uniform bool Convert_601to709; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -sampler_state textureSampler { - Filter = Linear; - AddressU = Clamp; - AddressV = Clamp; -}; + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -struct VertDataIn { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -struct VertDataOut { - float4 pos : POSITION; - float2 uv : TEXCOORD0; - float2 uv2 : TEXCOORD1; -}; + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -float dot(float3 a,float3 b){ - return a.x*b.x+a.y*b.y+a.z*b.z; } -//BT.601 to BT.709 -// Correct video colorspace BT.601 [SD] to BT.709 [HD] for HD video input -// Use this shader only if BT.709 [HD] encoded video is incorrectly matrixed to full range RGB with the BT.601 [SD] colorspace. -float4 Convert601to709(float4 rgba) -{ - float3 s1 = rgba.rgb; - s1 = s1.rrr * float3(0.299, -0.1495 / 0.886, 0.5) + s1.ggg * float3(0.587, -0.2935 / 0.886, -0.2935 / 0.701) + s1.bbb * float3(0.114, 0.5, -0.057 / 0.701); // RGB to Y''CbCr, BT.601 [SD] colorspace - return (s1.rrr + float3(0, -0.1674679 / 0.894, 1.8556) * s1.ggg + float3(1.5748, -0.4185031 / 0.894, 0) * s1.bbb).rgbb; // Y''CbCr to RGB output, BT.709 [HD] colorspace -} -//BT.709 to BT.601 -float4 Convert709to601(float4 rgba) -{ - float3 s1 = rgba.rgb; - s1 = float3(dot(float3(.2126, .7152, .0722), s1), dot(float3(-.1063 / .9278, -.3576 / .9278, .5), s1), dot(float3(.5, -.3576 / .7874, -.0361 / .7874), s1)); - return float3(s1.x + 1.402*s1.z, dot(s1, float3(1, -.202008 / .587, -.419198 / .587)), s1.x + 1.772*s1.y).rgbb; -} +} -VertDataOut VSDefault(VertDataIn v_in) -{ - VertDataOut vert_out; - vert_out.pos = mul(float4(v_in.pos.x, v_in.pos.y, v_in.pos.z, 1.0), ViewProj); - vert_out.uv = v_in.uv; - vert_out.uv2 = v_in.uv * uv_scale + uv_offset; - return vert_out; -} + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSInputAudioMonitorType { -float4 PSColorMaskRGBA(VertDataOut v_in) : TARGET -{ - float Tolerance = opacity * 0.01; - float4 rgba = image.Sample(textureSampler, v_in.uv); - float4 targetRGB = target.Sample(textureSampler, v_in.uv2) * color; - if (invert){ - targetRGB.rgb = 1.0 - targetRGB.rgb; - } - if (Convert_709to601) - { - rgba.rgb = Convert709to601(rgba).rgb; - targetRGB.rgb = Convert709to601(targetRGB).rgb; - } +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputAudioMonitorType')] +[Alias('obs.powershell.websocket.GetInputAudioMonitorType')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( - if (Convert_601to709) - { - rgba.rgb = Convert601to709(rgba).rgb; - targetRGB.rbg = Convert601to709(targetRGB).rgb; - } +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, - float4 shadowRGB = targetRGB * targetRGB; +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - if ((abs(targetRGB.r - rgba.r) <= Tolerance && - abs(targetRGB.g - rgba.g) <= Tolerance && - abs(targetRGB.b - rgba.b) <= Tolerance) - || (abs(shadowRGB.r - rgba.r) <= Tolerance && - abs(shadowRGB.g - rgba.g) <= Tolerance && - abs(shadowRGB.b - rgba.b) <= Tolerance)) - { - rgba.rgba = float4(0,0,0,0); - } - return rgba; -} -technique Draw -{ - pass - { - vertex_shader = VSDefault(v_in); - pixel_shader = PSColorMaskRGBA(v_in); - } -} +process { -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -6876,255 +5028,224 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSBlendOpacityShader { +function Get-OBSInputAudioSyncOffset { -[Alias('Set-OBSBlendOpacityShader','Add-OBSBlendOpacityShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputAudioSyncOffset')] +[Alias('obs.powershell.websocket.GetInputAudioSyncOffset')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the Vertical of OBSBlendOpacityShader -[ComponentModel.DefaultBindingProperty('Vertical')] -[Management.Automation.SwitchParameter] -$Vertical, -# Set the Rotational of OBSBlendOpacityShader -[ComponentModel.DefaultBindingProperty('Rotational')] -[Management.Automation.SwitchParameter] -$Rotational, -# Set the Rotation_Offset of OBSBlendOpacityShader -[Alias('Rotation_Offset')] -[ComponentModel.DefaultBindingProperty('Rotation_Offset')] -[Single] -$RotationOffset, -# Set the Opacity_Start_Percent of OBSBlendOpacityShader -[Alias('Opacity_Start_Percent')] -[ComponentModel.DefaultBindingProperty('Opacity_Start_Percent')] -[Single] -$OpacityStartPercent, -# Set the Opacity_End_Percent of OBSBlendOpacityShader -[Alias('Opacity_End_Percent')] -[ComponentModel.DefaultBindingProperty('Opacity_End_Percent')] -[Single] -$OpacityEndPercent, -# Set the Spread of OBSBlendOpacityShader -[ComponentModel.DefaultBindingProperty('Spread')] -[Single] -$Spread, -# Set the Speed of OBSBlendOpacityShader -[ComponentModel.DefaultBindingProperty('Speed')] -[Single] -$Speed, -# Set the Apply_To_Alpha_Layer of OBSBlendOpacityShader -[Alias('Apply_To_Alpha_Layer')] -[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] -[Management.Automation.SwitchParameter] -$ApplyToAlphaLayer, -# Set the Notes of OBSBlendOpacityShader -[ComponentModel.DefaultBindingProperty('Notes')] -[String] -$Notes, -# 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. +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + [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] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'blend_opacity' -$ShaderNoun = 'OBSBlendOpacityShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// opacity blend shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 -//https://github.com/Oncorporation/obs-shaderfilter -//Converted to OpenGL by Exeldro February 14, 2022 -uniform bool Vertical; -uniform bool Rotational; -uniform float Rotation_Offset< - string label = "Rotation Offset"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 6.28318531; - float step = 0.01; -> = 0.0; -uniform float Opacity_Start_Percent< - string label = "Opacity Start Percent"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 1.0; -> = 0.0; -uniform float Opacity_End_Percent< - string label = "Opacity End Percent"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 1.0; -> = 100.0; -uniform float Spread< - string label = "Spread"; - string widget_type = "slider"; - float minimum = 0.25; - float maximum = 10.0; - float step = 0.01; -> = 0.5; -uniform float Speed< - string label = "Speed"; - string widget_type = "slider"; - float minimum = -10.0; - float maximum = 10.0; - float step = 0.01; -> = 0.0; -uniform bool Apply_To_Alpha_Layer = true; -uniform string Notes< - string widget_type = "info"; -> = "Spread is wideness of opacity blend and is limited between .25 and 10. Edit at your own risk. Invert Start and End to Reverse effect."; -float4 mainImage(VertData v_in) : TARGET -{ - float4 point_color = image.Sample(textureSampler, v_in.uv); - float luminance = 0.299*point_color.r+0.587*point_color.g+0.114*point_color.b; - float4 gray = float4(luminance,luminance,luminance, 1); - float2 lPos = (v_in.uv * uv_scale + uv_offset) / clamp(Spread, 0.25, 10.0); - float time = (elapsed_time * clamp(Speed, -5.0, 5.0)) / clamp(Spread, 0.25, 10.0); - float dist = distance(v_in.uv , (float2(0.99, 0.99) * uv_scale + uv_offset)); + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (point_color.a > 0.0 || Apply_To_Alpha_Layer == false) - { - //set opacity and direction - float opacity = (-1 * lPos.x) * 0.5; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } - if (Rotational && (Vertical == false)) - { - float timeWithOffset = time + Rotation_Offset; - float sine = sin(timeWithOffset); - float cosine = cos(timeWithOffset); - opacity = (lPos.x * cosine + lPos.y * sine) * 0.5; - } + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } - if (Vertical && (Rotational == false)) - { - opacity = (-1 * lPos.y) * 0.5; - } + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } + + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } - opacity += time; - opacity = frac(opacity); - point_color.a = lerp(Opacity_Start_Percent * 0.01, Opacity_End_Percent * 0.01, clamp(opacity, 0.0, 1.0)); - } - return point_color; } +} -' -} -$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 - } - } + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSInputAudioTracks { - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName - } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputAudioTracks')] +[Alias('obs.powershell.websocket.GetInputAudioTracks')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) + + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -7133,152 +5254,106 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSBlinkShader { +function Get-OBSInputDefaultSettings { -[Alias('Set-OBSBlinkShader','Add-OBSBlinkShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputDefaultSettings')] +[Alias('obs.powershell.websocket.GetInputDefaultSettings')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the speed of OBSBlinkShader -[ComponentModel.DefaultBindingProperty('speed')] -[Single] -$Speed, -# 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(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputKind')] +[string] +$InputKind, +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'blink' -$ShaderNoun = 'OBSBlinkShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform float speed< - string label = "Speed"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 0.5; -float4 mainImage(VertData v_in) : TARGET -{ - float4 color = image.Sample(textureSampler, v_in.uv); - float t = elapsed_time * speed; - return float4(color.r, color.g, color.b, color.a * (1 + sin(t)) / 2); -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -7287,218 +5362,106 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSBloomShader { +function Get-OBSInputKind { -[Alias('Set-OBSBloomShader','Add-OBSBloomShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputKindList')] +[Alias('obs.powershell.websocket.GetInputKindList')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the Angle_Steps of OBSBloomShader -[Alias('Angle_Steps')] -[ComponentModel.DefaultBindingProperty('Angle_Steps')] -[Int32] -$AngleSteps, -# Set the Radius_Steps of OBSBloomShader -[Alias('Radius_Steps')] -[ComponentModel.DefaultBindingProperty('Radius_Steps')] -[Int32] -$RadiusSteps, -# Set the ampFactor of OBSBloomShader -[ComponentModel.DefaultBindingProperty('ampFactor')] -[Single] -$AmpFactor, -# Set the notes of OBSBloomShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# 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. +[ComponentModel.DefaultBindingProperty('unversioned')] +[switch] +$Unversioned, +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'bloom' -$ShaderNoun = 'OBSBloomShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Bloom shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 -//https://github.com/Oncorporation/obs-shaderfilter -//Converted to OpenGL by Exeldro February 15, 2022 -uniform int Angle_Steps< - string label = "Angle Steps"; - string widget_type = "slider"; - int minimum = 1; - int maximum = 20; - int step = 1; -> = 5; // -uniform int Radius_Steps< - string label = "Radius Steps"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 20; - int step = 1; -> = 9; // -uniform float ampFactor< - string label = "amp Factor"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.01; -> = 2.0; -uniform string notes< - string widget_type = "info"; -> = "Steps limited in range from 0 to 20. Edit bloom.shader to remove limits at your own risk."; - -float4 mainImage(VertData v_in) : TARGET -{ - int radiusSteps = clamp(Radius_Steps, 0, 20); - int angleSteps = clamp(Angle_Steps, 1, 20); - float PI = 3.1415926535897932384626433832795;//acos(-1); - float minRadius = (0.0 * uv_pixel_interval.y); - float maxRadius = (10.0 * uv_pixel_interval.y); - - float4 c0 = image.Sample(textureSampler, v_in.uv); - float4 outputPixel = c0; - float4 accumulatedColor = float4(0,0,0,0); - int totalSteps = radiusSteps * angleSteps; - float angleDelta = (2.0 * PI) / float(angleSteps); - float radiusDelta = (maxRadius - minRadius) / float(radiusSteps); - - for (int radiusStep = 0; radiusStep < radiusSteps; radiusStep++) { - float radius = minRadius + float(radiusStep) * radiusDelta; - - for (float angle=0.0; angle <(2.0*PI); angle += angleDelta) { - float2 currentCoord; - - float xDiff = radius * cos(angle); - float yDiff = radius * sin(angle); - - currentCoord = v_in.uv + float2(xDiff, yDiff); - float4 currentColor =image.Sample(textureSampler, currentCoord); - float currentFraction = float(radiusSteps+1 - radiusStep) / float(radiusSteps + 1); - accumulatedColor += currentFraction * currentColor / float(totalSteps); - - } - } - - outputPixel += accumulatedColor * ampFactor; - - return outputPixel; -} - -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -7507,151 +5470,111 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSBorderShader { +function Get-OBSInputMute { -[Alias('Set-OBSBorderShader','Add-OBSBorderShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputMute')] +[Alias('obs.powershell.websocket.GetInputMute')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the borderColor of OBSBorderShader -[ComponentModel.DefaultBindingProperty('borderColor')] -[String] -$BorderColor, -# 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. +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + [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] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'border' -$ShaderNoun = 'OBSBorderShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform float4 borderColor; -float4 mainImage(VertData v_in) : TARGET -{ - if (v_in.uv.x < 0 || v_in.uv.x > 1 || v_in.uv.y < 0 || v_in.uv.y > 1) - { - return borderColor; - } - else - { - return image.Sample(textureSampler, v_in.uv); - } -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -7660,237 +5583,116 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSBoxBlurShader { +function Get-OBSInputPropertiesListPropertyItems { -[Alias('Set-OBSBoxBlurShader','Add-OBSBoxBlurShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputPropertiesListPropertyItems')] +[Alias('obs.powershell.websocket.GetInputPropertiesListPropertyItems')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the Strength of OBSBoxBlurShader -[ComponentModel.DefaultBindingProperty('Strength')] -[Int32] -$Strength, -# Set the Mask_Left of OBSBoxBlurShader -[Alias('Mask_Left')] -[ComponentModel.DefaultBindingProperty('Mask_Left')] -[Single] -$MaskLeft, -# Set the Mask_Right of OBSBoxBlurShader -[Alias('Mask_Right')] -[ComponentModel.DefaultBindingProperty('Mask_Right')] -[Single] -$MaskRight, -# Set the Mask_Top of OBSBoxBlurShader -[Alias('Mask_Top')] -[ComponentModel.DefaultBindingProperty('Mask_Top')] -[Single] -$MaskTop, -# Set the Mask_Bottom of OBSBoxBlurShader -[Alias('Mask_Bottom')] -[ComponentModel.DefaultBindingProperty('Mask_Bottom')] -[Single] -$MaskBottom, -# 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. +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + [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] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('propertyName')] +[string] +$PropertyName, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'box-blur' -$ShaderNoun = 'OBSBoxBlurShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform int Strength< - string label = "Strength (1)"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 25; - int step = 1; -> = 1; -uniform float Mask_Left< - string label = "Mask left (1.0)"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 1.0; -uniform float Mask_Right< - string label = "Mask right (1.0)"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 1.0; -uniform float Mask_Top< - string label = "Mask top (1.0)"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 1.0; -uniform float Mask_Bottom< - string label = "Mask bottom (1.0)"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 1.0; -float4 mainImage(VertData v_in) : TARGET -{ - if(Strength <= 0) - return image.Sample(textureSampler, v_in.uv); - - if(Mask_Left + Mask_Right > 1.0){ - if(v_in.uv.x > Mask_Left || 1.0 - v_in.uv.x > Mask_Right ){ - return image.Sample(textureSampler, v_in.uv); - } - }else{ - if((v_in.uv.x > Mask_Left) && (1.0-v_in.uv.x > Mask_Right)){ - return image.Sample(textureSampler, v_in.uv); - } - } - if(Mask_Top + Mask_Bottom > 1.0){ - if(v_in.uv.y > Mask_Top || 1.0 - v_in.uv.y > Mask_Bottom){ - return image.Sample(textureSampler, v_in.uv); - } - }else { - if((v_in.uv.y > Mask_Top) && (1.0-v_in.uv.y > Mask_Bottom)){ - return image.Sample(textureSampler, v_in.uv); - } - } - float transparent = 0.0; - int count = 1; - float samples = 0.0; - float4 c = float4(0.0, 0.0, 0.0, 0.0); - float Steps = float(Strength); - - [loop] for (int i = -Strength; i <= Strength; i++) { - [loop] for (int k = -Strength; k <= Strength; k++) { - float4 sc = image.Sample(textureSampler, v_in.uv+float2(float(i), float(k))/uv_size*Steps); - transparent += sc.a; - count++; - c += sc * sc.a; - samples += sc.a; - } - } - if(samples > 0.0) - c /= samples; - c.a = transparent / float(count); - return c; -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -7899,227 +5701,327 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSBulgePinchShader { +function Get-OBSInputSettings { -[Alias('Set-OBSBulgePinchShader','Add-OBSBulgePinchShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputSettings')] +[Alias('obs.powershell.websocket.GetInputSettings')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the radius of OBSBulgePinchShader -[ComponentModel.DefaultBindingProperty('radius')] -[Single] -$Radius, -# Set the magnitude of OBSBulgePinchShader -[ComponentModel.DefaultBindingProperty('magnitude')] -[Single] -$Magnitude, -# Set the center_x of OBSBulgePinchShader -[Alias('center_x')] -[ComponentModel.DefaultBindingProperty('center_x')] -[Single] -$CenterX, -# Set the center_y of OBSBulgePinchShader -[Alias('center_y')] -[ComponentModel.DefaultBindingProperty('center_y')] -[Single] -$CenterY, -# Set the animate of OBSBulgePinchShader -[ComponentModel.DefaultBindingProperty('animate')] -[Management.Automation.SwitchParameter] -$Animate, -# Set the notes of OBSBulgePinchShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# 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. +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + [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] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'BulgePinch' -$ShaderNoun = 'OBSBulgePinchShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//Created by Radegast Stravinsky for obs-shaderfilter 9/2020 -uniform float radius< - string label = "Radius"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2.0; - float step = 0.01; -> = 0.0; -uniform float magnitude< - string label = "Magnitude"; - string widget_type = "slider"; - float minimum = -1.3333; - float maximum = 1.3333; - float step = 0.01; -> = 0.0; -uniform float center_x< - string label = "Center x"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 0.5; - float step = 0.01; -> = 0.25; -uniform float center_y< - string label = "Center y"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 0.5; - float step = 0.01; -> = 0.25; -uniform bool animate = false; -uniform string notes< - string widget_type = "info"; -> = "Distorts the screen, expanding or drawing in pixels around a point." + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -float4 mainImage(VertData v_in) : TARGET -{ - float2 center = float2(center_x, center_y); - VertData v_out; - v_out.pos = v_in.pos; - float2 hw = uv_size; - float ar = 1. * hw.y/hw.x; - v_out.uv = 1. * v_in.uv - center; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } - center.x /= ar; - v_out.uv.x /= ar; + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } - float dist = distance(v_out.uv, center); - if (dist < radius) - { - float anim_mag = (animate ? magnitude * sin(radians(elapsed_time * 20)) : magnitude); - float percent = dist/radius; - if(anim_mag > 0) - v_out.uv = (v_out.uv - center) * lerp(1.0, smoothstep(0.0, radius/dist, percent), anim_mag * 0.75); - else - v_out.uv = (v_out.uv-center) * lerp(1.0, pow(percent, 1.0 + anim_mag * 0.75) * radius/dist, 1.0 - percent); + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } - v_out.uv += (2 * center); - v_out.uv.x *= ar; + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } - return image.Sample(textureSampler, v_out.uv); - } - else - { - return image.Sample(textureSampler, v_in.uv); - } } -' -} -$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 '|' + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSInputVolume { + + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputVolume')] +[Alias('obs.powershell.websocket.GetInputVolume')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) + + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } + + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } - ))" - 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] + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam } - continue nextParameter - } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } +} - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSLastReplayBufferReplay { + + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetLastReplayBufferReplay')] +[Alias('obs.powershell.websocket.GetLastReplayBufferReplay')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) + + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -8128,343 +6030,214 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSBurnShader { +function Get-OBSMediaInputStatus { -[Alias('Set-OBSBurnShader','Add-OBSBurnShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetMediaInputStatus')] +[Alias('obs.powershell.websocket.GetMediaInputStatus')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the Burn_Gradient of OBSBurnShader -[Alias('Burn_Gradient')] -[ComponentModel.DefaultBindingProperty('Burn_Gradient')] -[String] -$BurnGradient, -# Set the Speed of OBSBurnShader -[ComponentModel.DefaultBindingProperty('Speed')] -[Single] -$Speed, -# Set the Gradient_Adjust of OBSBurnShader -[Alias('Gradient_Adjust')] -[ComponentModel.DefaultBindingProperty('Gradient_Adjust')] -[Single] -$GradientAdjust, -# Set the Dissolve_Value of OBSBurnShader -[Alias('Dissolve_Value')] -[ComponentModel.DefaultBindingProperty('Dissolve_Value')] -[Single] -$DissolveValue, -# Set the Animated of OBSBurnShader -[ComponentModel.DefaultBindingProperty('Animated')] -[Management.Automation.SwitchParameter] -$Animated, -# Set the Apply_to_Channel of OBSBurnShader -[Alias('Apply_to_Channel')] -[ComponentModel.DefaultBindingProperty('Apply_to_Channel')] -[Management.Automation.SwitchParameter] -$ApplyToChannel, -# Set the Apply_Smoke of OBSBurnShader -[Alias('Apply_Smoke')] -[ComponentModel.DefaultBindingProperty('Apply_Smoke')] -[Management.Automation.SwitchParameter] -$ApplySmoke, -# Set the Smoke_Horizonal_Speed of OBSBurnShader -[Alias('Smoke_Horizonal_Speed')] -[ComponentModel.DefaultBindingProperty('Smoke_Horizonal_Speed')] -[Single] -$SmokeHorizonalSpeed, -# Set the Smoke_Vertical_Speed of OBSBurnShader -[Alias('Smoke_Vertical_Speed')] -[ComponentModel.DefaultBindingProperty('Smoke_Vertical_Speed')] -[Single] -$SmokeVerticalSpeed, -# Set the Iterations of OBSBurnShader -[ComponentModel.DefaultBindingProperty('Iterations')] -[Int32] -$Iterations, -# Set the Notes of OBSBurnShader -[ComponentModel.DefaultBindingProperty('Notes')] -[String] -$Notes, -# 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. +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + [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] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'burn' -$ShaderNoun = 'OBSBurnShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//Burn shader by Charles Fettinger (https://github.com/Oncorporation) 4/2019 -//for use with obs-shaderfilter 1.0 -//Converted to OpenGL by Exeldro February 17, 2022 -float4 mod(float4 x, float4 y) -{ - return x - y * floor(x / y); -} -float4 mod289(float4 x) -{ - return x - floor(x / 289.0) * 289.0; -} -float4 permute(float4 x) -{ - return mod289(((x * 34.0) + 1.0) * x); -} -float4 taylorInvSqrt(float4 r) -{ - return 1.79284291400159 - r * 0.85373472095314; -} -float2 fade(float2 t) { - return t * t* t* (t * (t * 6.0 - 15.0) + 10.0); -} -float dot(float2 a,float2 b){ - return a.x*b.x+a.y*b.y; -} -// Classic Perlin noise -float cnoise(float2 P) -{ - float4 Pi = floor(P.xyxy) + float4(0.0, 0.0, 1.0, 1.0); - float4 Pf = frac(P.xyxy) - float4(0.0, 0.0, 1.0, 1.0); - Pi = mod289(Pi); // To avoid truncation effects in permutation - float4 ix = Pi.xzxz; - float4 iy = Pi.yyww; - float4 fx = Pf.xzxz; - float4 fy = Pf.yyww; - float4 i = permute(permute(ix) + iy); - float4 gx = frac(i / 41.0) * 2.0 - 1.0; - float4 gy = abs(gx) - 0.5; - float4 tx = floor(gx + 0.5); - gx = gx - tx; - float2 g00 = float2(gx.x, gy.x); - float2 g10 = float2(gx.y, gy.y); - float2 g01 = float2(gx.z, gy.z); - float2 g11 = float2(gx.w, gy.w); - float4 norm = taylorInvSqrt(float4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); - g00 *= norm.x; - g01 *= norm.y; - g10 *= norm.z; - g11 *= norm.w; - float n00 = dot(g00, float2(fx.x, fy.x)); - float n10 = dot(g10, float2(fx.y, fy.y)); - float n01 = dot(g01, float2(fx.z, fy.z)); - float n11 = dot(g11, float2(fx.w, fy.w)); - float2 fade_xy = fade(Pf.xy); - float2 n_x = lerp(float2(n00, n01), float2(n10, n11), fade_xy.x); - float n_xy = lerp(n_x.x, n_x.y, fade_xy.y); - return 2.3 * n_xy; -} -// Classic Perlin noise, periodic variant -float pnoise(float2 P, float2 rep) -{ - float4 Pi = floor(P.xyxy) + float4(0.0, 0.0, 1.0, 1.0); - float4 Pf = frac(P.xyxy) - float4(0.0, 0.0, 1.0, 1.0); - Pi = mod(Pi, rep.xyxy); // To create noise with explicit period - Pi = mod289(Pi); // To avoid truncation effects in permutation - float4 ix = Pi.xzxz; - float4 iy = Pi.yyww; - float4 fx = Pf.xzxz; - float4 fy = Pf.yyww; - float4 i = permute(permute(ix) + iy); - float4 gx = frac(i / 41.0) * 2.0 - 1.0; - float4 gy = abs(gx) - 0.5; - float4 tx = floor(gx + 0.5); - gx = gx - tx; - float2 g00 = float2(gx.x, gy.x); - float2 g10 = float2(gx.y, gy.y); - float2 g01 = float2(gx.z, gy.z); - float2 g11 = float2(gx.w, gy.w); - float4 norm = taylorInvSqrt(float4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); - g00 *= norm.x; - g01 *= norm.y; - g10 *= norm.z; - g11 *= norm.w; - float n00 = dot(g00, float2(fx.x, fy.x)); - float n10 = dot(g10, float2(fx.y, fy.y)); - float n01 = dot(g01, float2(fx.z, fy.z)); - float n11 = dot(g11, float2(fx.w, fy.w)); - float2 fade_xy = fade(Pf.xy); - float2 n_x = lerp(float2(n00, n01), float2(n10, n11), fade_xy.x); - float n_xy = lerp(n_x.x, n_x.y, fade_xy.y); - return 2.3 * n_xy; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } + + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } + + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } + } -uniform texture2d Burn_Gradient = "burngradient.png"; -uniform float Speed = 0.33; -uniform float Gradient_Adjust = 0.85; -uniform float Dissolve_Value = 1.43; -uniform bool Animated; -uniform bool Apply_to_Channel; -uniform bool Apply_Smoke = true; -uniform float Smoke_Horizonal_Speed = 0.3; -uniform float Smoke_Vertical_Speed = 0.17; -uniform int Iterations = 4; -uniform string Notes< - string widget_type = "info"; -> = "Animate refers to the burn effect. Speed is general and is reversed with negative numbers. Gradient Adjust is the width of the burn gradient. Use the burngradient.png. Dissolve Value is important. Apply Smoke adds the scrolling smoke."; -float4 mainImage(VertData v_in) : TARGET -{ - float4 c = image.Sample(textureSampler, v_in.uv); - float4 smoke = float4(1.0,1.0,1.0,1.0); - float4 result = smoke; - float t = elapsed_time * Speed; - float cycle = 1 - max((sin(t) * 2) - 1, 0); //create a negative cycle time as a delay - float2 dir = float2(Smoke_Horizonal_Speed, Smoke_Vertical_Speed); - //float largestDistance = sqrt(pow(uv_size.x, 2) + pow(uv_size.y, 2)); +} - float perlin = 0.5; - float smoke_perlin = 0; - float scale = 1; - float w = 0.5; + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSMonitor { - for (int i = 0; i < Iterations; i++) { - //float2 coord = v_in.uv * scale;// (v_in.uv + t * dir)* scale; - float2 coord = (v_in.uv + t * (dir * .1)) * scale; - float2 period = scale * dir; - perlin += pnoise(coord, period) * w; - if (Apply_Smoke) - smoke_perlin += cnoise((v_in.uv + t * dir) * scale) * w * .5; - scale *= 2.0; - w *= 0.5; - } +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetMonitorList')] +[Alias('obs.powershell.websocket.GetMonitorList')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - //float toPoint = abs(length(v_in.uv - (v_in.uv * .5)) / ((1.0001 - t) * largestDistance)); - if (!Animated) - cycle = 1; - float d = clamp(((Dissolve_Value * cycle + perlin) ) - 1.0, -.01, 0.99); - float overOne = saturate(d * Gradient_Adjust); - float4 burn = Burn_Gradient.Sample(textureSampler, float2(overOne, 0.5)); - if (Apply_to_Channel) { - result = c * burn; - } - else { - result = float4(perlin, perlin, perlin, 1.0) * burn; - } +process { - if (smoke_perlin > 0) { - smoke *= smoke_perlin; - if (result.a <= 0.04) - result = float4(smoke.rgb, smoke_perlin); - result += smoke; - } - return result; -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -8473,286 +6246,209 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSCartoonShader { +function Get-OBSOutput { -[Alias('Set-OBSCartoonShader','Add-OBSCartoonShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetOutputList')] +[Alias('obs.powershell.websocket.GetOutputList')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the ViewProj of OBSCartoonShader -[ComponentModel.DefaultBindingProperty('ViewProj')] -[Single[][]] -$ViewProj, -# Set the image of OBSCartoonShader -[ComponentModel.DefaultBindingProperty('image')] -[String] -$Image, -# Set the elapsed_time of OBSCartoonShader -[Alias('elapsed_time')] -[ComponentModel.DefaultBindingProperty('elapsed_time')] -[Single] -$ElapsedTime, -# Set the uv_offset of OBSCartoonShader -[Alias('uv_offset')] -[ComponentModel.DefaultBindingProperty('uv_offset')] -[Single[]] -$UvOffset, -# Set the uv_scale of OBSCartoonShader -[Alias('uv_scale')] -[ComponentModel.DefaultBindingProperty('uv_scale')] -[Single[]] -$UvScale, -# Set the uv_pixel_interval of OBSCartoonShader -[Alias('uv_pixel_interval')] -[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] -[Single[]] -$UvPixelInterval, -# Set the rand_f of OBSCartoonShader -[Alias('rand_f')] -[ComponentModel.DefaultBindingProperty('rand_f')] -[Single] -$RandF, -# Set the uv_size of OBSCartoonShader -[Alias('uv_size')] -[ComponentModel.DefaultBindingProperty('uv_size')] -[Single[]] -$UvSize, -# Set the notes of OBSCartoonShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# Set the hue_steps of OBSCartoonShader -[Alias('hue_steps')] -[ComponentModel.DefaultBindingProperty('hue_steps')] -[Int32] -$HueSteps, -# Set the value_steps of OBSCartoonShader -[Alias('value_steps')] -[ComponentModel.DefaultBindingProperty('value_steps')] -[Int32] -$ValueSteps, -# Set the Apply_To_Alpha_Layer of OBSCartoonShader -[Alias('Apply_To_Alpha_Layer')] -[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] -[Management.Automation.SwitchParameter] -$ApplyToAlphaLayer, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'cartoon' -$ShaderNoun = 'OBSCartoonShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//Darklink''s shader modified to by Charles ''Surn'' Fettinger for use with obs-shaderfilter 3/2019 -uniform float4x4 ViewProj; -uniform texture2d image; -uniform float elapsed_time; -uniform float2 uv_offset; -uniform float2 uv_scale; -uniform float2 uv_pixel_interval; -uniform float rand_f; -uniform float2 uv_size; -uniform string notes = "5/2 seems reasonable"; - -uniform int hue_steps = 5; -uniform int value_steps = 2; -uniform bool Apply_To_Alpha_Layer = true; - -sampler_state textureSampler { - Filter = Linear; - AddressU = Clamp; - AddressV = Clamp; -}; -struct VertDataIn { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -struct VertDataOut { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -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; -} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -float3 rgb2hsv(float3 c) -{ - float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g)); - float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r)); + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -float3 hsv2rgb(float3 c) -{ - float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y); } -float fit(float v, int factor) -{ - return round(v * factor) / factor; -} -float hue_wrap(float h) -{ - return fmod(h + 1, 2) - 1; - if(h > 1) - return h - 2; - if(h < -1) - return h + 2; - return h; -} +} -float4 PassThrough(VertDataOut v_in) : TARGET -{ - float4 rgba = image.Sample(textureSampler, v_in.uv); - if (rgba.a > 0.0 || Apply_To_Alpha_Layer == false) - { - float3 hsv = rgb2hsv(rgba.rgb); - hsv = float3(fit(hsv.x, hue_steps), hsv.y, fit(hsv.z, value_steps)); - //hsv = float3(hue_wrap(hsv.x + 0.5), 1, hsv.z); - rgba = float4(hsv2rgb(hsv), rgba.a); - //return float4(fit(rgba.r), fit(rgba.g), fit(rgba.b), rgba.a); - } - return rgba; -} + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSOutputSettings { -technique Draw -{ - pass - { - vertex_shader = VSDefault(v_in); - pixel_shader = PassThrough(v_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 - } - } +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetOutputSettings')] +[Alias('obs.powershell.websocket.GetOutputSettings')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName - } +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('outputName')] +[string] +$OutputName, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -8761,217 +6457,219 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSCellShadedShader { +function Get-OBSOutputStatus { -[Alias('Set-OBSCellShadedShader','Add-OBSCellShadedShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetOutputStatus')] +[Alias('obs.powershell.websocket.GetOutputStatus')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the Angle_Steps of OBSCellShadedShader -[Alias('Angle_Steps')] -[ComponentModel.DefaultBindingProperty('Angle_Steps')] -[Int32] -$AngleSteps, -# Set the Radius_Steps of OBSCellShadedShader -[Alias('Radius_Steps')] -[ComponentModel.DefaultBindingProperty('Radius_Steps')] -[Int32] -$RadiusSteps, -# Set the ampFactor of OBSCellShadedShader -[ComponentModel.DefaultBindingProperty('ampFactor')] -[Single] -$AmpFactor, -# Set the notes of OBSCellShadedShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# 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(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('outputName')] +[string] +$OutputName, +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'cell_shaded' -$ShaderNoun = 'OBSCellShadedShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Cell Shaded shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 -//https://github.com/Oncorporation/obs-shaderfilter -//Converted to OpenGL by Q-mii & Exeldro February 18, 2022 -uniform int Angle_Steps< - string label = "Angle Steps"; - string widget_type = "slider"; - int minimum = 1; - int maximum = 20; - int step = 1; -> = 5; -uniform int Radius_Steps< - string label = "Radius Steps"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 20; - int step = 1; -> = 9; -uniform float ampFactor< - string label = "amp Factor"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 2.0; -uniform string notes< - string widget_type = "info"; -> = "Steps limited in range from 0 to 20. Edit cell_shaded.shader to remove limits at your own risk."; - -float4 mainImage(VertData v_in) : TARGET -{ - float radiusSteps = clamp(Radius_Steps, 0, 20); - float angleSteps = clamp(Angle_Steps, 1, 20); - float PI = 3.1415926535897932384626433832795;//acos(-1); - int totalSteps = int(radiusSteps * angleSteps); - float minRadius = (3 * uv_pixel_interval.y); - float maxRadius = (24 * uv_pixel_interval.y); - - float angleDelta = ((2 * PI) / angleSteps); - float radiusDelta = ((maxRadius - minRadius) / radiusSteps); - - float4 c0 = image.Sample(textureSampler, v_in.uv); - float4 origColor = c0; - float4 accumulatedColor = float4(0,0,0,0); - - for (int radiusStep = 0; radiusStep < radiusSteps; radiusStep++) { - float radius = minRadius + radiusStep * radiusDelta; - for (float angle=0; angle <(2*PI); angle += angleDelta) { - float2 currentCoord; - float xDiff = radius * cos(angle); - float yDiff = radius * sin(angle); - - currentCoord = v_in.uv + float2(xDiff, yDiff); - float4 currentColor = image.Sample(textureSampler, currentCoord); - float4 colorDiff = abs(c0 - currentColor); - float currentFraction = (radiusSteps + 1 - radiusStep) / (radiusSteps + 1); - accumulatedColor += currentFraction * colorDiff / totalSteps; - - } - } - accumulatedColor *= ampFactor; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - return c0 - accumulatedColor; // Cell shaded style -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -' -} -$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 '|' + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } - ))" - 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] + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam } - continue nextParameter - } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - $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 - } + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSPersistentData { - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetPersistentData')] +[Alias('obs.powershell.websocket.GetPersistentData')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('realm')] +[string] +$Realm, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('slotName')] +[string] +$SlotName, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) + + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } + + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } + + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -8980,376 +6678,317 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSChromaticAberrationShader { +function Get-OBSProfile { -[Alias('Set-OBSChromaticAberrationShader','Add-OBSChromaticAberrationShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetProfileList')] +[Alias('obs.powershell.websocket.GetProfileList')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the power of OBSChromaticAberrationShader -[ComponentModel.DefaultBindingProperty('power')] -[Single] -$Power, -# Set the gamma of OBSChromaticAberrationShader -[ComponentModel.DefaultBindingProperty('gamma')] -[Single] -$Gamma, -# Set the num_iter of OBSChromaticAberrationShader -[Alias('num_iter')] -[ComponentModel.DefaultBindingProperty('num_iter')] -[Int32] -$NumIter, -# Set the distort_radial of OBSChromaticAberrationShader -[Alias('distort_radial')] -[ComponentModel.DefaultBindingProperty('distort_radial')] -[Management.Automation.SwitchParameter] -$DistortRadial, -# Set the distort_barrel of OBSChromaticAberrationShader -[Alias('distort_barrel')] -[ComponentModel.DefaultBindingProperty('distort_barrel')] -[Management.Automation.SwitchParameter] -$DistortBarrel, -# Set the offset_spectrum_ycgco of OBSChromaticAberrationShader -[Alias('offset_spectrum_ycgco')] -[ComponentModel.DefaultBindingProperty('offset_spectrum_ycgco')] -[Management.Automation.SwitchParameter] -$OffsetSpectrumYcgco, -# Set the offset_spectrum_yuv of OBSChromaticAberrationShader -[Alias('offset_spectrum_yuv')] -[ComponentModel.DefaultBindingProperty('offset_spectrum_yuv')] -[Management.Automation.SwitchParameter] -$OffsetSpectrumYuv, -# Set the use_random of OBSChromaticAberrationShader -[Alias('use_random')] -[ComponentModel.DefaultBindingProperty('use_random')] -[Management.Automation.SwitchParameter] -$UseRandom, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'chromatic-aberration' -$ShaderNoun = 'OBSChromaticAberrationShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//based on https://www.shadertoy.com/view/XssGz8 -//Converted to OpenGL by Exeldro February 14, 2022 + black background removed February 23, 2022 -uniform float power< - string label = "Power"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2.0; - float step = 0.01; -> = 0.01; -uniform float gamma< - string label = "Gamma"; - string widget_type = "slider"; - float minimum = 0.01; - float maximum = 3.0; - float step = 0.01; -> = 2.2; -uniform int num_iter< - string label = "Number iterations"; - string widget_type = "slider"; - int minimum = 3; - int maximum = 25; - int step = 1; -> = 7; -uniform bool distort_radial = false; -uniform bool distort_barrel = false; -uniform bool offset_spectrum_ycgco = false; -uniform bool offset_spectrum_yuv = false; -uniform bool use_random = true; -float2 remap( float2 t, float2 a, float2 b ) { - return clamp( (t - a) / (b - a), 0.0, 1.0 ); -} -float3 spectrum_offset_rgb( float t ) -{ - float t0 = 3.0 * t - 1.5; - float3 ret = clamp( float3( -t0, 1.0-abs(t0), t0), 0.0, 1.0); - return ret; -} + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -float3 lin2srgb( float3 c ) -{ - return pow( c, float3(gamma, gamma, gamma) ); -} -float3 srgb2lin( float3 c ) -{ - return pow( c, float3(1.0/gamma, 1.0/gamma, 1.0/gamma)); -} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -float3 yCgCo2rgb(float3 ycc) -{ - float R = ycc.x - ycc.y + ycc.z; - float G = ycc.x + ycc.y; - float B = ycc.x - ycc.y - ycc.z; - return float3(R,G,B); -} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -float3 spectrum_offset_ycgco( float t ) -{ - //float3 ygo = float3( 1.0, 1.5*t, 0.0 ); //green-pink - //float3 ygo = float3( 1.0, -1.5*t, 0.0 ); //green-purple - float3 ygo = float3( 1.0, 0.0, -1.25*t ); //cyan-orange - //float3 ygo = float3( 1.0, 0.0, 1.5*t ); //brownyello-blue - return yCgCo2rgb( ygo ); -} + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -float3 yuv2rgb( float3 yuv ) -{ - float3 rgb; - rgb.r = yuv.x + yuv.z * 1.13983; - rgb.g = yuv.x + dot( float2(-0.39465, -0.58060), yuv.yz ); - rgb.b = yuv.x + yuv.y * 2.03211; - return rgb; } -float2 radialdistort(float2 coord, float2 amt) -{ - float2 cc = coord - 0.5; - return coord + 2.0 * cc * amt; -} -float2 barrelDistortion( float2 p, float2 amt ) -{ - p = 2.0 * p - 1.0; +} - /* - const float maxBarrelPower = 5.0; - //note: http://glsl.heroku.com/e#3290.7 , copied from Little Grasshopper - float theta = atan(p.y, p.x); - float2 radius = float2( length(p) ); - radius = pow(radius, 1.0 + maxBarrelPower * amt); - p.x = radius.x * cos(theta); - p.y = radius.y * sin(theta); + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSProfileParameter { - /*/ - // much faster version - //const float maxBarrelPower = 5.0; - //float radius = length(p); - float maxBarrelPower = sqrt(5.0); - float radius = dot(p,p); //faster but doesn''t match above accurately - p *= pow(float2(radius, radius), maxBarrelPower * amt); - /* */ - return p * 0.5 + 0.5; -} +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetProfileParameter')] +[Alias('obs.powershell.websocket.GetProfileParameter')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( -float2 brownConradyDistortion(float2 uv, float dist) -{ - uv = uv * 2.0 - 1.0; - // positive values of K1 give barrel distortion, negative give pincushion - float barrelDistortion1 = 0.1 * dist; // K1 in text books - float barrelDistortion2 = -0.025 * dist; // K2 in text books +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('parameterCategory')] +[string] +$ParameterCategory, - float r2 = dot(uv,uv); - uv *= 1.0 + barrelDistortion1 * r2 + barrelDistortion2 * r2 * r2; - //uv *= 1.0 + barrelDistortion1 * r2; - - // tangential distortion (due to off center lens elements) - // is not modeled in this function, but if it was, the terms would go here - return uv * 0.5 + 0.5; -} +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('parameterName')] +[string] +$ParameterName, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) -float2 distort( float2 uv, float t, float2 min_distort, float2 max_distort ) -{ - float2 dist = float2(min_distort.x * (1.0-t) +max_distort.x * t, min_distort.y * (1.0-t) +max_distort.y * t); - //float2 dist = mix( min_distort, max_distort, t ); - if (distort_radial) - return radialdistort( uv, 2.0 * dist ); - - if(distort_barrel) - return barrelDistortion( uv, 1.75 * dist ); //distortion at center - return brownConradyDistortion( uv, 75.0 * dist.x ); -} -// ==== +process { -float3 spectrum_offset_yuv( float t ) -{ - //float3 yuv = float3( 1.0, 3.0*t, 0.0 ); //purple-green - //float3 yuv = float3( 1.0, 0.0, 2.0*t ); //purple-green - float3 yuv = float3( 1.0, 0.0, -1.0*t ); //cyan-orange - //float3 yuv = float3( 1.0, -0.75*t, 0.0 ); //brownyello-blue - return yuv2rgb( yuv ); -} -float3 spectrum_offset( float t ) -{ - if(offset_spectrum_ycgco) - return spectrum_offset_ycgco( t ); - if(offset_spectrum_yuv) - return spectrum_offset_yuv( t ); - return spectrum_offset_rgb( t ); - //return srgb2lin( spectrum_offset_rgb( t ) ); - //return lin2srgb( spectrum_offset_rgb( t ) ); -} + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -float4 mainImage(VertData v_in) : TARGET -{ - float2 max_distort = float2(power, power); - float2 min_distort = 0.5 * max_distort; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } - float2 oversiz = distort(float2(1.0, 1.0), 1.0, min_distort, max_distort); + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } - float2 uv = remap( v_in.uv, 1.0-oversiz, oversiz ); - - //debug oversiz - //float2 distuv = distort( uv, 1.0, max_distort ); - //if ( abs(distuv.x-0.5)>0.5 || abs(distuv.y-0.5)>0.5) - //{ - // fragColor = float4( 1.0, 0.0, 0.0, 1.0 ); return; - //} - - - float stepsiz = 1.0 / (float(num_iter)-1.0); - float rnd = 0.0; - if(use_random) - rnd = rand_f; + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" - float t = rnd * stepsiz; + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } - float3 sumcol = float3(0.0, 0.0, 0.0); - float3 sumw = float3(0.0, 0.0, 0.0); - float colA = 0.0; - - for ( int i=0; iAdd|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 - } + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - 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] - } +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSRecordDirectory { + + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetRecordDirectory')] +[Alias('obs.powershell.websocket.GetRecordDirectory')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) + + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -9358,205 +6997,101 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSChromaUVDistortionShader { +function Get-OBSRecordStatus { -[Alias('Set-OBSChromaUVDistortionShader','Add-OBSChromaUVDistortionShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetRecordStatus')] +[Alias('obs.powershell.websocket.GetRecordStatus')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the distortion of OBSChromaUVDistortionShader -[ComponentModel.DefaultBindingProperty('distortion')] -[Single] -$Distortion, -# Set the amplitude of OBSChromaUVDistortionShader -[ComponentModel.DefaultBindingProperty('amplitude')] -[Single] -$Amplitude, -# Set the chroma of OBSChromaUVDistortionShader -[ComponentModel.DefaultBindingProperty('chroma')] -[Single] -$Chroma, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'Chroma+UV-Distortion' -$ShaderNoun = 'OBSChromaUVDistortionShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//based on https://www.shadertoy.com/view/WsdyRN - -//Higher values = less distortion -uniform float distortion< - string label = "Distortion"; - string widget_type = "slider"; - float minimum = 5.0; - float maximum = 1000.0; - float step = 0.01; -> = 75.; -//Higher values = tighter distortion -uniform float amplitude< - string label = "Amplitude"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 10.; -//Higher values = more color distortion -uniform float chroma< - string label = "Chroma"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 6.28318531; - float step = 0.01; -> = .5; - -float2 zoomUv(float2 uv, float zoom) { - float2 uv1 = uv; - uv1 += .5; - uv1 += zoom/2.-1.; - uv1 /= zoom; - return uv1; -} -float4 mainImage(VertData v_in) : TARGET -{ - float2 uvt = v_in.uv; - - float2 uvtR = uvt; - float2 uvtG = uvt; - float2 uvtB = uvt; - - //Uncomment the following line to get varying chroma distortion - //chroma = sin(elapsed_time)/2.+.5; - - uvtR += float2(sin(uvt.y*amplitude+elapsed_time)/distortion, cos(uvt.x*amplitude+elapsed_time)/distortion); - uvtG += float2(sin(uvt.y*amplitude+elapsed_time+chroma)/distortion, cos(uvt.x*amplitude+elapsed_time+chroma)/distortion); - uvtB += float2(sin(uvt.y*amplitude+elapsed_time+(chroma*2.))/distortion, cos(uvt.x*amplitude+elapsed_time+(chroma*2.))/distortion); - - float2 uvR = zoomUv(uvtR, 1.1); - float2 uvG = zoomUv(uvtG, 1.1); - float2 uvB = zoomUv(uvtB, 1.1); - - float4 colR = image.Sample(textureSampler, uvR); - float4 colG = image.Sample(textureSampler, uvG); - float4 colB = image.Sample(textureSampler, uvB); - return float4(colR.r, colG.g, colB.b, (colR.a + colG.a + colB.a) / 3.0); -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -9565,238 +7100,204 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSCircleMaskFilterShader { +function Get-OBSReplayBufferStatus { -[Alias('Set-OBSCircleMaskFilterShader','Add-OBSCircleMaskFilterShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetReplayBufferStatus')] +[Alias('obs.powershell.websocket.GetReplayBufferStatus')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the Radius of OBSCircleMaskFilterShader -[ComponentModel.DefaultBindingProperty('Radius')] -[Single] -$Radius, -# Set the Circle_Offset_X of OBSCircleMaskFilterShader -[Alias('Circle_Offset_X')] -[ComponentModel.DefaultBindingProperty('Circle_Offset_X')] -[Int32] -$CircleOffsetX, -# Set the Circle_Offset_Y of OBSCircleMaskFilterShader -[Alias('Circle_Offset_Y')] -[ComponentModel.DefaultBindingProperty('Circle_Offset_Y')] -[Int32] -$CircleOffsetY, -# Set the Source_Offset_X of OBSCircleMaskFilterShader -[Alias('Source_Offset_X')] -[ComponentModel.DefaultBindingProperty('Source_Offset_X')] -[Int32] -$SourceOffsetX, -# Set the Source_Offset_Y of OBSCircleMaskFilterShader -[Alias('Source_Offset_Y')] -[ComponentModel.DefaultBindingProperty('Source_Offset_Y')] -[Int32] -$SourceOffsetY, -# Set the Antialiasing of OBSCircleMaskFilterShader -[ComponentModel.DefaultBindingProperty('Antialiasing')] -[Management.Automation.SwitchParameter] -$Antialiasing, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'circle-mask-filter' -$ShaderNoun = 'OBSCircleMaskFilterShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Circle Mask Filter version 1.01, for OBS Shaderfilter -// Copyright 2022 by SkeletonBow -// Twitter: -// Twitch: -// License: GNU GPLv2 -// -// Changelog: -// 1.01 - Don''t saturate() Radius parameter to allow oversizing to cover entire input texture. -// 1.0 - Initial release - -uniform float Radius< - string label = "Radius"; - string widget_type = "slider"; - float minimum = 0; - float maximum = 100.0; - float step = 0.01; -> = 50.0; -uniform int Circle_Offset_X< - string label = "Circle Offset X"; - string widget_type = "slider"; - int minimum = -1000; - int maximum = 1000; - int step = 1; -> = 0; -uniform int Circle_Offset_Y< - string label = "Circle Offset X"; - string widget_type = "slider"; - int minimum = -1000; - int maximum = 1000; - int step = 1; -> = 0; -uniform int Source_Offset_X< - string label = "Source Offset X"; - string widget_type = "slider"; - int minimum = -1000; - int maximum = 1000; - int step = 1; -> = 0.0; -uniform int Source_Offset_Y< - string label = "Source Offset Y"; - string widget_type = "slider"; - int minimum = -1000; - int maximum = 1000; - int step = 1; -> = 0.0; - -uniform bool Antialiasing = true; -#define Smoothness 100.00 -#define AAwidth 4 - -#define uv_pi uv_pixel_interval -float4 mainImage( VertData v_in ) : TARGET -{ - float2 uv = v_in.uv; - float2 coffset = float2(Circle_Offset_X, Circle_Offset_Y)/uv_size; - float2 soffset = float2( Source_Offset_X, Source_Offset_Y )/uv_size; - float radius = Radius * 0.01; - float smwidth = radius * Smoothness * 0.01; - - float4 obstex = image.Sample( textureSampler, uv - soffset); - float4 color = obstex; - // Account for aspect ratio - uv.x = (uv.x - 0.5) * uv_size.x / uv_size.y + 0.5; - float2 cuv = 0.5 + coffset; - float dist = distance(cuv,uv); - // Anti-aliased or pixelated edge - if( Antialiasing ) { - color.a = smoothstep( radius, (radius+(uv_pi.x)) - (uv_pi.x * AAwidth), dist); - } else { - color.a = step( dist, radius ); - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - return float4(color.rgb, color.a); -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -' -} -$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 '|' + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } - ))" - 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] + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam } - continue nextParameter - } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } +} - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSScene { + + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneList')] +[Alias('obs.powershell.websocket.GetSceneList')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) + + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -9805,346 +7306,214 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSClockAnalogShader { +function Get-OBSSceneCollection { -[Alias('Set-OBSClockAnalogShader','Add-OBSClockAnalogShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneCollectionList')] +[Alias('obs.powershell.websocket.GetSceneCollectionList')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the current_time_ms of OBSClockAnalogShader -[Alias('current_time_ms')] -[ComponentModel.DefaultBindingProperty('current_time_ms')] -[Int32] -$CurrentTimeMs, -# Set the current_time_sec of OBSClockAnalogShader -[Alias('current_time_sec')] -[ComponentModel.DefaultBindingProperty('current_time_sec')] -[Int32] -$CurrentTimeSec, -# Set the current_time_min of OBSClockAnalogShader -[Alias('current_time_min')] -[ComponentModel.DefaultBindingProperty('current_time_min')] -[Int32] -$CurrentTimeMin, -# Set the current_time_hour of OBSClockAnalogShader -[Alias('current_time_hour')] -[ComponentModel.DefaultBindingProperty('current_time_hour')] -[Int32] -$CurrentTimeHour, -# Set the hour_handle_color of OBSClockAnalogShader -[Alias('hour_handle_color')] -[ComponentModel.DefaultBindingProperty('hour_handle_color')] -[Single[]] -$HourHandleColor, -# Set the minute_handle_color of OBSClockAnalogShader -[Alias('minute_handle_color')] -[ComponentModel.DefaultBindingProperty('minute_handle_color')] -[Single[]] -$MinuteHandleColor, -# Set the second_handle_color of OBSClockAnalogShader -[Alias('second_handle_color')] -[ComponentModel.DefaultBindingProperty('second_handle_color')] -[Single[]] -$SecondHandleColor, -# Set the outline_color of OBSClockAnalogShader -[Alias('outline_color')] -[ComponentModel.DefaultBindingProperty('outline_color')] -[Single[]] -$OutlineColor, -# Set the top_line_color of OBSClockAnalogShader -[Alias('top_line_color')] -[ComponentModel.DefaultBindingProperty('top_line_color')] -[Single[]] -$TopLineColor, -# Set the background_color of OBSClockAnalogShader -[Alias('background_color')] -[ComponentModel.DefaultBindingProperty('background_color')] -[Single[]] -$BackgroundColor, -# Set the time_offset_hours of OBSClockAnalogShader -[Alias('time_offset_hours')] -[ComponentModel.DefaultBindingProperty('time_offset_hours')] -[Int32] -$TimeOffsetHours, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'clock_analog' -$ShaderNoun = 'OBSClockAnalogShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//Based on https://www.shadertoy.com/view/XdKXzy -uniform int current_time_ms; -uniform int current_time_sec; -uniform int current_time_min; -uniform int current_time_hour; -uniform float3 hour_handle_color = {1.0,1.0,1.0}; -uniform float3 minute_handle_color = {1.0,1.0,1.0}; -uniform float3 second_handle_color = {1.0,0.0,0.0}; -uniform float3 outline_color = {1.0,1.0,1.0}; -uniform float3 top_line_color = {1.0,0.0,0.0}; -uniform float3 background_color = {.5,.5,.5}; -uniform int time_offset_hours = 0; -#ifndef OPENGL -#define mod(x,y) (x - y * floor(x / y)) -#endif -// this is my first try to actually use glsl almost from scratch -// so far all i''ve done is learning by doing / reading glsl docs. -// this is inspired by my non glsl „elapsed_time“ projects -// especially this one: https://www.gottz.de/analoguhr.htm -// i will most likely use a buffer in future to calculate the elapsed_time -// aswell as to draw the background of the clock only once. -// tell me if thats a bad idea. + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -// update: -// screenshot: http://i.imgur.com/dF0nHDk.png -// as soon as i think its in a usefull state i''ll release the source -// of that particular c++ application on github. -// i hope sommeone might find it usefull :D + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -#define PI 3.141592653589793238462643383 + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } + + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -// from https://www.shadertoy.com/view/4s3XDn <3 -float ln(float2 p, float2 a, float2 b) -{ - float2 pa = p - a; - float2 ba = b - a; - float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); - return length(pa - ba * h); } -// i think i should spend some elapsed_time reading docs in order to minimize this. -// hints apreciated -// (Rotated LiNe) -float rln(float2 uv, float start, float end, float perc) { - float inp = perc * PI * 2.0; - float2 coord = float2(sin(inp), cos(inp)); - return ln(uv, coord * start, coord * end); -} -// i need this to have an alphachannel in the output -// i intend to use an optimized version of this shader for a transparent desktop widget experiment -float4 mixer(float4 c1, float4 c2) { - // please tell me if you think this would boost performance. - // the elapsed_time i implemented mix myself it sure did reduce - // the amount of operations but i''m not sure now - // if (c2.a <= 0.0) return c1; - // if (c2.a >= 1.0) return c2; - return float4(lerp(c1.rgb, c2.rgb, c2.a), c1.a + c2.a); - // in case you are curious how you could implement mix yourself: - // return float4(c2.rgb * c2.a + c1.rgb * (1.0-c2.a), c1.a+c2.a); -} - -float4 styleHandle(float4 color, float px, float dist, float3 handleColor, float width, float shadow) { - if (dist <= width + shadow) { - // lets draw the shadow - color = mixer(color, float4(0.0, 0.0, 0.0, - (1.0-pow(smoothstep(width, width + shadow, dist),0.2))*0.2)); - // now lets draw the antialiased handle - color = mixer(color, float4(handleColor, smoothstep(width, max(width - 3.0 * px, 0.0), dist))); - } - return color; -} +} -float4 mainImage(VertData v_in) : TARGET -{ - float2 R = uv_size; - // calculate the size of a pixel - float px = 1.0 / R.y; - // create percentages of the coordinate system - float2 p = (v_in.uv * uv_size).xy / R; - // center the scene and add perspective - float2 uv = (2.0 * (float2(v_in.uv.x,1.0-v_in.uv.y) * uv_size) - R) / min(R.x, R.y); - - /*float2 uv = -1.0 + 2.0 * p.xy; - // lets add perspective for mobile device support - if (uv_size.x > uv_size.y) - uv.x *= uv_size.x / uv_size.y; - else - uv.y *= uv_size.y / uv_size.x;*/ - - // lets scale the scene a bit down: - uv *= 1.1; - px *= 0.9; - - float width = 0.015; - float dist = 1.0; - float centerdist = length(uv); - - float4 color = image.Sample(textureSampler, v_in.uv); - - // background of the clock - if (centerdist < 1.0 - width) color = mixer(color, float4(background_color, 0.4*(1.8-length(uv)))); - - float isRed = 1.0; - if (centerdist > 1.0 - 12.0 * width && centerdist <= 1.1) { - // minute bars - for (float i = 0.0; i <= 15.0; i += 1.0) { - if (mod(i, 5.0) == 0.0) { - dist = min(dist, rln(abs(uv), 1.0 - 10.0 * width, 1.0 - 2.0 * width, i / 60.0)); - // draw first bar red - if (i == 0.0 && uv.y > 0.0) { - isRed = dist; - dist = smoothstep(width, max(width - 3.0 * px, 0.0), dist); - color = mixer(color, float4(top_line_color, dist)); - dist = 1.0; - } - } - else { - dist = min(dist, rln(abs(uv), 1.0 - 10.0 * width, 1.0 - 7.0 * width, i / 60.0)); - } - } +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSSceneItem { - // outline circle - dist = min(dist, abs(1.0-width-length(uv))); - // draw clock shadow - if (centerdist > 1.0) - color = mixer(color, float4(0.0,0.0,0.0, 0.3*smoothstep(1.0 + width*2.0, 1.0, centerdist))); - // draw outline + minute bars in white - color = mixer(color, float4(0.0, 0.0, 0.0, - (1.0 - pow(smoothstep(width, width + 0.02, min(isRed, dist)), 0.4))*0.2)); - color = mixer(color, float4(outline_color, smoothstep(width, max(width - 3.0 * px, 0.0), dist))); - } - - if (centerdist < 1.0) { - float elapsed_time = float((time_offset_hours+current_time_hour)*3600+current_time_min*60+current_time_sec) + pow(float(current_time_ms)/1000.0,16.0); - // hour - color = styleHandle(color, px, - rln(uv, -0.05, 0.5, elapsed_time / 3600.0 / 12.0), - hour_handle_color, 0.03, 0.02); +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneItemList')] +[Alias('obs.powershell.websocket.GetSceneItemList')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( - // minute - color = styleHandle(color, px, - rln(uv, -0.075, 0.7, elapsed_time / 3600.0), - minute_handle_color, 0.02, 0.02); +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, - // second - color = styleHandle(color, px, - min(rln(uv, -0.1, 0.9, elapsed_time / 60.0), length(uv)-0.01), - second_handle_color, 0.01, 0.02); - } - - - return color; -} -' -} -$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 - } - } +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName - } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } +process { - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -10153,381 +7522,236 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSClockDigitalLedShader { +function Get-OBSSceneItemBlendMode { -[Alias('Set-OBSClockDigitalLedShader','Add-OBSClockDigitalLedShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneItemBlendMode')] +[Alias('obs.powershell.websocket.GetSceneItemBlendMode')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the current_time_sec of OBSClockDigitalLedShader -[Alias('current_time_sec')] -[ComponentModel.DefaultBindingProperty('current_time_sec')] -[Int32] -$CurrentTimeSec, -# Set the current_time_min of OBSClockDigitalLedShader -[Alias('current_time_min')] -[ComponentModel.DefaultBindingProperty('current_time_min')] -[Int32] -$CurrentTimeMin, -# Set the current_time_hour of OBSClockDigitalLedShader -[Alias('current_time_hour')] -[ComponentModel.DefaultBindingProperty('current_time_hour')] -[Int32] -$CurrentTimeHour, -# Set the timeMode of OBSClockDigitalLedShader -[ComponentModel.DefaultBindingProperty('timeMode')] -[Int32] -$TimeMode, -# Set the showMatrix of OBSClockDigitalLedShader -[ComponentModel.DefaultBindingProperty('showMatrix')] -[Management.Automation.SwitchParameter] -$ShowMatrix, -# Set the showOff of OBSClockDigitalLedShader -[ComponentModel.DefaultBindingProperty('showOff')] -[Management.Automation.SwitchParameter] -$ShowOff, -# Set the ampm of OBSClockDigitalLedShader -[ComponentModel.DefaultBindingProperty('ampm')] -[Management.Automation.SwitchParameter] -$Ampm, -# Set the ledColor of OBSClockDigitalLedShader -[ComponentModel.DefaultBindingProperty('ledColor')] -[String] -$LedColor, -# Set the offsetHours of OBSClockDigitalLedShader -[ComponentModel.DefaultBindingProperty('offsetHours')] -[Int32] -$OffsetHours, -# Set the offsetSeconds of OBSClockDigitalLedShader -[ComponentModel.DefaultBindingProperty('offsetSeconds')] -[Int32] -$OffsetSeconds, -# 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. +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, + [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] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemId')] +[ValidateRange(0,[int]::MaxValue)] +[double] +$SceneItemId, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'clock_digital_led' -$ShaderNoun = 'OBSClockDigitalLedShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// based on https://www.shadertoy.com/view/MdfGzf -// cmarangu has linked all 7 segments in his comments -// https://www.shadertoy.com/view/3dtSRj -#ifndef OPENGL -#define mod(x,y) (x - y * floor(x / y)) -#endif -uniform int current_time_sec; -uniform int current_time_min; -uniform int current_time_hour; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -uniform int timeMode< - string label = "Time mode"; - string widget_type = "select"; - int option_0_value = 0; - string option_0_label = "Time"; - int option_1_value = 1; - string option_1_label = "Enable duration"; - int option_2_value = 2; - string option_2_label = "Active duration"; - int option_3_value = 3; - string option_3_label = "Show duration"; - int option_4_value = 4; - string option_4_label = "Load duration"; -> = 0; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -uniform bool showMatrix = false; -uniform bool showOff = false; -uniform bool ampm = false; -uniform float4 ledColor = {1.0,0,0,1.0}; -uniform int offsetHours = 0; -uniform int offsetSeconds = 0; + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -float segment(float2 uv, bool On) -{ - if (!On && !showOff) - return 0.0; - - float seg = (1.0-smoothstep(0.08,0.09+float(On)*0.02,abs(uv.x)))* - (1.0-smoothstep(0.46,0.47+float(On)*0.02,abs(uv.y)+abs(uv.x))); - - //Fiddle with lights and matrix - //uv.x += sin(elapsed_time*60.0*6.26)/14.0; - //uv.y += cos(elapsed_time*60.0*6.26)/14.0; - - //led like brightness - if (On){ - seg *= (1.0-length(uv*float2(3.8,0.9)));//-sin(elapsed_time*25.0*6.26)*0.04; - } else { - seg *= -(0.05+length(uv*float2(0.2,0.1))); - } - return seg; -} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } + + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -float sevenSegment(float2 uv,int num) -{ - float seg= 0.0; - seg += segment(uv.yx+float2(-1.0, 0.0),num!=-1 && num!=1 && num!=4 ); - seg += segment(uv.xy+float2(-0.5,-0.5),num!=-1 && num!=1 && num!=2 && num!=3 && num!=7); - seg += segment(uv.xy+float2( 0.5,-0.5),num!=-1 && num!=5 && num!=6 ); - seg += segment(uv.yx+float2( 0.0, 0.0),num!=-1 && num!=0 && num!=1 && num!=7 ); - seg += segment(uv.xy+float2(-0.5, 0.5),num==0 || num==2 || num==6 || num==8 ); - seg += segment(uv.xy+float2( 0.5, 0.5),num!=-1 && num!=2 ); - seg += segment(uv.yx+float2( 1.0, 0.0),num!=-1 && num!=1 && num!=4 && num!=7 ); - - return seg; } -float showNum(float2 uv,int nr, bool zeroTrim) -{ - //Speed optimization, leave if pixel is not in segment - if (abs(uv.x)>1.5 || abs(uv.y)>1.2) - return 0.0; - - float seg= 0.0; - if (uv.x>0.0) - { - nr /= 10; - if (nr==0 && zeroTrim) - nr = -1; - seg += sevenSegment(uv+float2(-0.75,0.0),nr); - } else { - seg += sevenSegment(uv+float2( 0.75,0.0),int(mod(float(nr),10.0))); - } - return seg; -} +} -float dots(float2 uv) -{ - float seg = 0.0; - uv.y -= 0.5; - seg += (1.0-smoothstep(0.11,0.13,length(uv))) * (1.0-length(uv)*2.0); - uv.y += 1.0; - seg += (1.0-smoothstep(0.11,0.13,length(uv))) * (1.0-length(uv)*2.0); - return seg; -} + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSSceneItemEnabled { -float4 mainImage(VertData v_in) : TARGET -{ - float2 uv = ((float2(v_in.uv.x, 1.0-v_in.uv.y) * uv_size).xy-0.5*uv_size) / - min(uv_size.x,uv_size.y); - - if (uv_size.x>uv_size.y) - { - uv *= 6.0; - } - else - { - uv *= 12.0; - } - - uv.x *= -1.0; - uv.x += uv.y/12.0; - //wobble - //uv.x += sin(uv.y*3.0+elapsed_time*14.0)/25.0; - //uv.y += cos(uv.x*3.0+elapsed_time*14.0)/25.0; - uv.x += 3.5; - float seg = 0.0; - if(timeMode == 0){ - seg += showNum(uv,current_time_sec,false); - uv.x -= 1.75; - seg += dots(uv); - uv.x -= 1.75; - seg += showNum(uv,current_time_min,false); - uv.x -= 1.75; - seg += dots(uv); - uv.x -= 1.75; - if (ampm) { - if(current_time_hour == 0){ - seg += showNum(uv,12,true); - }else if(current_time_hour > 12){ - seg += showNum(uv,current_time_hour-12,true); - }else{ - seg += showNum(uv,current_time_hour,true); - } - } else { - seg += showNum(uv,current_time_hour,true); - } - }else{ - float timeSecs = 0.0; - if(timeMode == 1){ - timeSecs = elapsed_time_enable; - }else if(timeMode == 2){ - timeSecs = elapsed_time_active; - }else if(timeMode == 3){ - timeSecs = elapsed_time_show; - }else if(timeMode == 4){ - timeSecs = elapsed_time_start; - } +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneItemEnabled')] +[Alias('obs.powershell.websocket.GetSceneItemEnabled')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( - timeSecs += offsetSeconds + offsetHours*3600; - if(timeSecs < 0) - timeSecs = 0.9999-timeSecs; - seg += showNum(uv,int(mod(timeSecs,60.0)),false); - - timeSecs = floor(timeSecs/60.0); - - uv.x -= 1.75; +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, - seg += dots(uv); - - uv.x -= 1.75; - - seg += showNum(uv,int(mod(timeSecs,60.0)),false); - - timeSecs = floor(timeSecs/60.0); - if (ampm) - { - if(timeSecs == 0.0){ - timeSecs = 12.0; - }else if (timeSecs > 12.0){ - timeSecs = mod(timeSecs,12.0); - } - }else if (timeSecs > 24.0) { - timeSecs = mod(timeSecs,24.0); - } - - uv.x -= 1.75; - - seg += dots(uv); - - uv.x -= 1.75; - seg += showNum(uv,int(mod(timeSecs,60.0)),true); - } +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, - - if (seg==0.0){ - return image.Sample(textureSampler, v_in.uv); - } - // matrix over segment - if (showMatrix) - { - seg *= 0.8+0.2*smoothstep(0.02,0.04,mod(uv.y+uv.x,0.06025)); - //seg *= 0.8+0.2*smoothstep(0.02,0.04,mod(uv.y-uv.x,0.06025)); - } - if (seg<0.0) - { - seg = -seg;; - return float4(seg,seg,seg,1.0); - } - return float4(ledColor.rgb * seg, ledColor.a); -} -' -} -$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 - } - } +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemId')] +[ValidateRange(0,[int]::MaxValue)] +[double] +$SceneItemId, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName - } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } +process { - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -10536,658 +7760,360 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSClockDigitalNixieShader { +function Get-OBSSceneItemId { -[Alias('Set-OBSClockDigitalNixieShader','Add-OBSClockDigitalNixieShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneItemId')] +[Alias('obs.powershell.websocket.GetSceneItemId')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the current_time_ms of OBSClockDigitalNixieShader -[Alias('current_time_ms')] -[ComponentModel.DefaultBindingProperty('current_time_ms')] -[Int32] -$CurrentTimeMs, -# Set the current_time_sec of OBSClockDigitalNixieShader -[Alias('current_time_sec')] -[ComponentModel.DefaultBindingProperty('current_time_sec')] -[Int32] -$CurrentTimeSec, -# Set the current_time_min of OBSClockDigitalNixieShader -[Alias('current_time_min')] -[ComponentModel.DefaultBindingProperty('current_time_min')] -[Int32] -$CurrentTimeMin, -# Set the current_time_hour of OBSClockDigitalNixieShader -[Alias('current_time_hour')] -[ComponentModel.DefaultBindingProperty('current_time_hour')] -[Int32] -$CurrentTimeHour, -# Set the timeMode of OBSClockDigitalNixieShader -[ComponentModel.DefaultBindingProperty('timeMode')] -[Int32] -$TimeMode, -# Set the offsetHours of OBSClockDigitalNixieShader -[ComponentModel.DefaultBindingProperty('offsetHours')] -[Int32] -$OffsetHours, -# Set the offsetSeconds of OBSClockDigitalNixieShader -[ComponentModel.DefaultBindingProperty('offsetSeconds')] -[Int32] -$OffsetSeconds, -# Set the corecolor of OBSClockDigitalNixieShader -[ComponentModel.DefaultBindingProperty('corecolor')] -[Single[]] -$Corecolor, -# Set the halocolor of OBSClockDigitalNixieShader -[ComponentModel.DefaultBindingProperty('halocolor')] -[Single[]] -$Halocolor, -# Set the flarecolor of OBSClockDigitalNixieShader -[ComponentModel.DefaultBindingProperty('flarecolor')] -[Single[]] -$Flarecolor, -# Set the anodecolor of OBSClockDigitalNixieShader -[ComponentModel.DefaultBindingProperty('anodecolor')] -[Single[]] -$Anodecolor, -# Set the anodehighlightscolor of OBSClockDigitalNixieShader -[ComponentModel.DefaultBindingProperty('anodehighlightscolor')] -[Single[]] -$Anodehighlightscolor, -# The name of the source. This must be provided when adding an item for the first time + [Parameter(ValueFromPipelineByPropertyName)] -[Alias('SceneItemName')] -[String] +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sourceName')] +[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] +[ComponentModel.DefaultBindingProperty('searchOffset')] +[ValidateRange(-1,[int]::MaxValue)] +[double] +$SearchOffset, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'clock_digital_nixie' -$ShaderNoun = 'OBSClockDigitalNixieShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//based on https://www.shadertoy.com/view/fsBcRm -uniform int current_time_ms; -uniform int current_time_sec; -uniform int current_time_min; -uniform int current_time_hour; -uniform int timeMode< - string label = "Time mode"; - string widget_type = "select"; - int option_0_value = 0; - string option_0_label = "Time"; - int option_1_value = 1; - string option_1_label = "Enable duration"; - int option_2_value = 2; - string option_2_label = "Active duration"; - int option_3_value = 3; - string option_3_label = "Show duration"; - int option_4_value = 4; - string option_4_label = "Load duration"; -> = 0; - -uniform int offsetHours = 0; -uniform int offsetSeconds = 0; - -// Colors as named variables, if you want to tweak them -uniform float3 corecolor = {1.0,0.7,0.0}; -uniform float3 halocolor = {1.0,0.5,0.0}; -uniform float3 flarecolor = {1.0,0.3,0.0}; -uniform float3 anodecolor = {0.2,0.1,0.1}; -uniform float3 anodehighlightscolor = {1.0,0.5,0.0}; -#ifndef OPENGL -#define mod(x,y) (x - y * floor(x / y)) -#define lessThan(a,b) (a < b) -#define greaterThan(a,b) (a > b) -#endif -// psrdnoise (c) Stefan Gustavson and Ian McEwan, -// ver. 2021-12-02, published under the MIT license: -// https://github.com/stegu/psrdnoise/ -float psrdnoise(float2 x, float2 period, float alpha, out float2 gradient) -{ - float2 uv = float2(x.x+x.y*0.5, x.y); - float2 i0 = floor(uv), f0 = frac(uv); - float cmp = step(f0.y, f0.x); - float2 o1 = float2(cmp, 1.0-cmp); - float2 i1 = i0 + o1, i2 = i0 + 1.0; - float2 v0 = float2(i0.x - i0.y*0.5, i0.y); - float2 v1 = float2(v0.x + o1.x - o1.y*0.5, v0.y + o1.y); - float2 v2 = float2(v0.x + 0.5, v0.y + 1.0); - float2 x0 = x - v0, x1 = x - v1, x2 = x - v2; - float3 iu, iv, xw, yw; - if(any(greaterThan(period, float2(0.0,0.0)))) { - xw = float3(v0.x, v1.x, v2.x); - yw = float3(v0.y, v1.y, v2.y); - if(period.x > 0.0) - xw = mod(float3(v0.x, v1.x, v2.x), period.x); - if(period.y > 0.0) - yw = mod(float3(v0.y, v1.y, v2.y), period.y); - iu = floor(xw + 0.5*yw + 0.5); iv = floor(yw + 0.5); - } else { - iu = float3(i0.x, i1.x, i2.x); iv = float3(i0.y, i1.y, i2.y); - } - float3 hash = mod(iu, 289.0); - hash = mod((hash*51.0 + 2.0)*hash + iv, 289.0); - hash = mod((hash*34.0 + 10.0)*hash, 289.0); - float3 psi = hash*0.07482 + alpha; - float3 gx = cos(psi); float3 gy = sin(psi); - float2 g0 = float2(gx.x, gy.x); - float2 g1 = float2(gx.y, gy.y); - float2 g2 = float2(gx.z, gy.z); - float3 w = 0.8 - float3(dot(x0, x0), dot(x1, x1), dot(x2, x2)); - w = max(w, 0.0); float3 w2 = w*w; float3 w4 = w2*w2; - float3 gdotx = float3(dot(g0, x0), dot(g1, x1), dot(g2, x2)); - float n = dot(w4, gdotx); - float3 w3 = w2*w; float3 dw = -8.0*w3*gdotx; - float2 dn0 = w4.x*g0 + dw.x*x0; - float2 dn1 = w4.y*g1 + dw.y*x1; - float2 dn2 = w4.z*g2 + dw.z*x2; - gradient = 10.9*(dn0 + dn1 + dn2); - return 10.9*n; -} + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -// Compute the shortest distance from p -// to a line segment from p1 to p2. -float lined(float2 p1, float2 p2, float2 p) { - float2 p1p2 = p2 - p1; - float2 v = normalize(p1p2); - float2 s = p - p1; - float t = dot(v, s); - if (t<0.0) return length(s); - if (t>length(p1p2)) return length(p - p2); - return length(s - t*v); -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -// Compute the shortest distance from p to a circle -// with center at c and radius r. (Extremely simple.) -float circled(float2 c, float r, float2 p) { - return abs(length(p - c) - r); -} - -// Compute the shortest distance from p to a -// circular arc with center c from p1 to p2. -// p1, p2 are in the +angle direction (ccw), -// to resolve the major/minor arc ambiguity, so -// specifying p1, p2 in the wrong order will -// yield the complement to the arc you wanted. -// If p1 = p2, the entire circle is drawn, but -// you don''t want to use this function to draw -// a circle. Use the simple circled() instead. -// If p1 and p2 have different distances to c, -// the end of the arc will not look right. If -// this is inconvenient, uncomment the 3rd line. -float arcd(float2 c, float2 p1, float2 p2, float2 p) { - - float2 v1 = p1 - c; - float2 v2 = p2 - c; - // Optional: make sure p1, p2 are both on the circle - // v2 = normalize(v2)*length(v1); - float2 v = p - c; - - float2 w = float2(dot(v, -float2(-v1.y, v1.x)), dot(v, float2(-v2.y, v2.x))); + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } - if(dot(v1, float2(-v2.y, v2.x)) >= 0.0) { // Arc angle <= pi - if(all(lessThan(float2(0.0,0.0), w))) { - return min(length(p1-p), length(p2-p)); // nearest end - } else { - return abs(length(v) - length(v1)); // dist to arc + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - } else { // Arc angle > pi - if(any(lessThan(float2(0.0,0.0), w))) { - return min(length(p1-p), length(p2-p)); - } else { - return abs(length(v) - length(v1)); + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - } -} -// A convenient anti-aliased step() using auto derivatives -float aastep(float threshold, float value) { - float afwidth = 0.7 * length(float2(ddx(value), ddy(value))); - return smoothstep(threshold-afwidth, threshold+afwidth, value); -} + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -// A smoothstep() that blends to an aastep() under minification -float aasmoothstep(float t1, float t2, float v) { - float aw = 0.7 * length(float2(ddx(v), ddy(v))); - float sw = max(0.5*(t2-t1), aw); - float st = 0.5*(t1+t2); - return smoothstep(st-sw, st+sw, v); } -// Distance field of a hexagonal (simplex) grid -// The return vector contains the distances to the -// three closest points, sorted by magnitude. -float3 hexgrid(float2 p) { - const float stretch = 1.0/0.8660; - - // v.y = v.y + 0.0001; // needed if no stretching (rounding errors) - p.y = p.y * stretch; - // Transform to grid space (axis-aligned "simplex" grid) - float2 uv = float2(p.x + p.y*0.5, p.y); - // Determine which simplex we''re in, with i0 being the "base" - float2 i0 = floor(uv); - float2 f0 = frac(uv); - // o1 is the offset in simplex space to the second corner - float cmp = step(f0.y, f0.x); - float2 o1 = float2(cmp, 1.0-cmp); - // Enumerate the remaining simplex corners - float2 i1 = i0 + o1; - float2 i2 = i0 + float2(1.0, 1.0); - // Transform corners back to texture space - float2 p0 = float2(i0.x - i0.y * 0.5, i0.y); - float2 p1 = float2(p0.x + o1.x - o1.y * 0.5, p0.y + o1.y); - float2 p2 = float2(p0.x + 0.5, p0.y + 1.0); - float3 d = float3(length(p-p0), length(p-p1), length(p-p2)); - // Only three values - bubble sort is just fine. - d.yz = (d.y < d.z) ? d.yz : d.zy; - d.xy = (d.x < d.y) ? d.xy : d.yx; - d.yz = (d.y < d.z) ? d.yz : d.zy; - return d; -} +} -// The digits. Simple functions, only a lot of them. + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSSceneItemIndex { -// These glyphs and their implementation as distance fields -// are the original work of me (stefan.gustavson@gmail.com), -// and the code below is released under the MIT license: -// https://opensource.org/licenses/MIT -// (If that is inconvenient for you, let me know. I''m reasonable.) -// -// Experts say mortals should not attempt to design character shapes. -// "It''s just ten simple digits", I thought, "How hard can it be?" -// A week later, after countless little tweaks to proportions and -// curvature, and with a notepad full of sketches and pen-and-paper -// math, some of it horribly wrong because it was decades since I -// solved this kind of equations by hand, I know the answer: -// It can be *really* hard. But also loads of fun! -// -float nixie0(float2 p) { - // Special hack instead of pasting together arcs and lines - float d = lined(float2(2.0,2.0), float2(2.0, 6.0), p); - return abs(d - 2.0); -} -float nixie1(float2 p) { - float d1 = lined(float2(2.0, 0.0), float2(2.0, 8.0), p); - float d2 = lined(float2(2.0, 8.0), float2(1.0, 6.0), p); - return min(d1, d2); -} +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneItemIndex')] +[Alias('obs.powershell.websocket.GetSceneItemIndex')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( -float nixie1alt(float2 p) { // Straight line - return lined(float2(2.0, 0.0), float2(2.0, 8.0), p); -} +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, -float nixie2(float2 p) { - const float x = 3.2368345; // Icky coordinates, - const float y = 4.4283002; // used twice below - float d1 = lined(float2(4.25, 0.0), float2(-0.25, 0.0), p); - float d2 = arcd(float2(10.657842, -5.001899), // Also icky - float2(x, y), float2(-0.25, 0.0), p); - float d3 = arcd(float2(2.0, 6.0), float2(x, y), float2(0.0, 6.0), p); - return min(min(d1, d2), d3); -} +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, -float nixie2alt(float2 p) { // Straight neck - float d1 = lined(float2(4.0, 0.0), float2(0.0,0.0), p); - float d2 = lined(float2(0.0,0.0), float2(3.6, 4.8), p); - float d3 = arcd(float2(2.0, 6.0), float2(3.6, 4.8), float2(0.0, 6.0), p); - return min(min(d1, d2), d3); -} +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemId')] +[ValidateRange(0,[int]::MaxValue)] +[double] +$SceneItemId, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) -float nixie3(float2 p) { - // Two round parts: - // float d1 = arcd(float2(2.0, 2.1), float2(-0.1, 2.1), float2(2.0, 4.2), p); - // float d2 = arcd(float2(2.0, 6.1), float2(2.0, 4.2), float2(0.1, 6.1), p); - // Angled top, more like classic Nixie tube digits: - float d1 = arcd(float2(2.0, 2.25), float2(-0.25, 2.25), float2(2.0, 4.5), p); - float d2 = lined(float2(2.0, 4.5), float2(4.0, 7.75), p); - float d3 = lined(float2(4.0, 7.75), float2(0.0, 7.75), p); - return min(min(d1, d2), d3); -} -float nixie3alt(float2 p) { // Two round parts of the same size - float d1 = arcd(float2(2.0,2.0), float2(0.0, 2.0), float2(2.0, 4.0), p); - float d2 = arcd(float2(2.0, 6.0), float2(2.0, 4.0), float2(0.0, 6.0), p); - return min(d1, d2); -} +process { -float nixie4(float2 p) { - // This digit is 5.0 units wide, most others are 4.0 or 4.5 - float d1 = lined(float2(4.0, 0.0), float2(4.0, 8.0), p); - float d2 = lined(float2(4.0, 8.0), float2(0.0, 2.0), p); - float d3 = lined(float2(0.0, 2.0), float2(5.0, 2.0), p); - return min(min(d1, d2), d3); -} -float nixie4alt(float2 p) { - // This digit is 4.0 units wide, but looks cropped - float d1 = lined(float2(4.0, 0.0), float2(4.0, 8.0), p); - float d2 = lined(float2(4.0, 8.0), float2(0.0, 2.0), p); - float d3 = lined(float2(0.0, 2.0), float2(4.0, 2.0), p); - return min(min(d1, d2), d3); -} + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -float nixie5(float2 p) { - float d1 = lined(float2(4.0, 7.75), float2(0.5, 7.75), p); - float d2 = lined(float2(0.5, 7.75), float2(0.0, 4.5), p); - float d3 = lined(float2(0.0, 4.5), float2(2.0, 4.5), p); - float d4 = arcd(float2(2.0, 2.25), float2(-0.25, 2.25), float2(2.0, 4.5), p); - return min(min(d1, d2), min(d3, d4)); -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -float nixie5alt(float2 p) { - float d1 = lined(float2(4.0, 8.0), float2(0.0, 8.0), p); - float d2 = lined(float2(0.0, 8.0), float2(0.0, 5.0), p); - float d3 = lined(float2(0.0, 5.0), float2(2.0, 5.0), p); - float d4 = arcd(float2(2.0, 3.0), float2(4.0, 3.0), float2(2.0, 5.0), p); - float d5 = lined(float2(4.0, 3.0), float2(4.0, 2.0), p); - float d6 = arcd(float2(2.0,2.0), float2(0.0, 2.0), float2(4.0, 2.0), p); - return min(min(min(d1, d2), min(d3, d4)), min(d5, d6)); -} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -float nixie6(float2 p) { - float d1 = arcd(float2(84.0/13.0, 2.25), float2(3.0, 8.0), float2(-0.25, 2.25), p); - float d2 = circled(float2(2.0, 2.25), 2.25, p); - return min(d1, d2); -} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -float nixie6alt(float2 p) { // Straight neck - float d1 = lined(float2(0.4, 3.2), float2(3.0, 8.0), p); - float d2 = circled(float2(2.0,2.0), 2.0, p); - return min(d1, d2); -} + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -float nixie7(float2 p) { // Ugly coordinates, but these expressions are exact - float d1 = lined(float2(0.0, 7.75), float2(0.25*sqrt(2259.0)-8.0, 7.75), p); - float d2 = arcd(float2(-8.0, 12.0), float2(2.5, 5.0), float2(0.25*sqrt(2259.0)-8.0, 7.75), p); - float d3 = arcd(float2(10.0, 0.0), float2(2.5, 5.0), float2(10.0-2.5*sqrt(13.0), 0.0), p); - return min(min(d1, d2), d3); } -float nixie7alt(float2 p) { // Straight neck - float d1 = lined(float2(0.0, 8.0), float2(4.0, 8.0), p); - float d2 = lined(float2(4.0, 8.0), float2(1.0, 0.0), p); - return min(d1, d2); -} -float nixie8(float2 p) { - float d1 = circled(float2(2.0, 2.2), 2.2, p); - float d2 = circled(float2(2.0, 6.2), 1.8, p); - return min(d1, d2); -} +} -float nixie8alt(float2 p) { // Same size loops - float d1 = circled(float2(2.0,2.0), 2.0, p); - float d2 = circled(float2(2.0, 6.0), 2.0, p); - return min(d1, d2); -} + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSSceneItemLocked { -float nixie9(float2 p) { - float d1 = arcd(float2(-32.0/13.0, 5.75), float2(1.0, 0.0), float2(4.25, 5.75), p); - float d2 = circled(float2(2.0, 5.75), 2.25, p); - return min(d1, d2); -} -float nixie9alt(float2 p) { // Straight neck - float d1 = lined(float2(3.6, 4.8), float2(1.0, 0.0), p); - float d2 = circled(float2(2.0, 6.0), 2.0, p); - return min(d1, d2); -} +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneItemLocked')] +[Alias('obs.powershell.websocket.GetSceneItemLocked')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( -float nixieminus(float2 p) { - return lined(float2(0.5, 4.0), float2(3.5, 4.0), p); -} +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, -float nixieequals(float2 p) { - float d1 = lined(float2(0.5, 3.0), float2(3.5, 3.0), p); - float d2 = lined(float2(0.5, 5.0), float2(3.5, 5.0), p); - return min(d1, d2); -} +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, -float nixieplus(float2 p) { - float d1 = lined(float2(0.0, 4.0), float2(4.0, 4.0), p); - float d2 = lined(float2(2.0, 2.0), float2(2.0, 6.0), p); - return min(d1, d2); -} +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemId')] +[ValidateRange(0,[int]::MaxValue)] +[double] +$SceneItemId, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) -float nixiedot(float2 p) { - // circled with r=0 yields a point, but with more work - return length(p - float2(2.0, 0.0)); -} -float nixiecolon(float2 p) { - float d1 = length(p - float2(2.0,2.0)); - float d2 = length(p - float2(2.0, 5.0)); - return min(d1, d2); -} +process { -// End of MIT-licensed code -float number(int n, float2 p) { - switch(n) { - case 0: return nixie0(p); - case 1: return nixie1(p); - case 2: return nixie2(p); - case 3: return nixie3(p); - case 4: return nixie4(p); - case 5: return nixie5(p); - case 6: return nixie6(p); - case 7: return nixie7(p); - case 8: return nixie8(p); - case 9: return nixie9(p); - default: return 1e10; - } -} -// Display the current time with a retro Nixie-tube look -// Stefan Gustavson (stegu on shadertoy.com) 2022-01-26 -// All code in the "Image" tab is public domain. -// Functions in the "Common" tab are also public domain, -// except where a separate license is specified. -float4 mainImage(VertData v_in) : TARGET -{ - float2 uv = ((float2(v_in.uv.x,1.0-v_in.uv.y) * uv_size)/uv_size.x); - float time = 0.0; - if(timeMode == 0){ - time = float(current_time_hour*3600+current_time_min*60+current_time_sec) + float(current_time_ms)/1000.0; - }else if(timeMode == 1){ - time = elapsed_time_enable; - }else if(timeMode == 2){ - time = elapsed_time_active; - }else if(timeMode == 3){ - time = elapsed_time_show; - }else if(timeMode == 4){ - time = elapsed_time_start; - } - time += offsetSeconds + offsetHours * 3600; - if(time < 0) - time = 0.9999-time; - float2 p = -3.0+uv*50.0 - float2(0.0,9.0); + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - float bbox = 1.0-max(max(1.0-aastep(-3.0, p.x), aastep(47.0, p.x)), - max(1.0-aastep(-3.0, p.y), aastep(11.0, p.y))); + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } - // Some relief for the GPU: exit early if we''re in the black margins - if(bbox == 0.0) { - return float4(float3(0.0,0.0,0.0),1.0); - } - - // If not, well, let''s put that GPU to good use! - float secs = floor(mod(time, 60.0)); - float mins = floor(mod(time, 3600.0)/60.0); - float hrs = floor(time/3600.0); - int h10 = int(floor(hrs/10.0)); - int h1 = int(floor(mod(hrs, 10.0))); - int m10 = int(floor(mins/10.0)); - int m1 = int(floor(mod(mins, 10.0))); - int s10 = int(floor(secs/10.0)); - int s1 = int(floor(mod(secs, 10.0))); + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } - float2 wspace = float2(6.5, 0.0); - float2 nspace = float2(3.5, 0.0); - float d = 1e10; - d = min(d, number(h10, p)); - d = min(d, number(h1, p-wspace)); - d = min(d, nixiecolon(p-wspace-1.45*nspace)-0.2); - d = min(d, number(m10, p-2.0*wspace-nspace)); - d = min(d, number(m1, p-3.0*wspace-nspace)); - d = min(d, nixiecolon(p-3.0*wspace-2.4*nspace)-0.2); - d = min(d, number(s10, p-4.0*wspace-2.0*nspace)); - d = min(d, number(s1, p-5.0*wspace-2.0*nspace)); - - float2 g; // For gradients returned from psrdnoise() - - // Digit outlines - float core = 1.0-aastep(0.2, d); - // "flare" is a wide blurry region around the characters, and - // "flarenoise" is a spatio-temporal modulation of its extents - // (slight flickering, but not all characters at the same time) - float flarenoise = psrdnoise(float2(p.x*0.1,5.0*elapsed_time), float2(0.0,0.0), 0.0, g); - float flare = 1.0-smoothstep(0.0, 2.5, d + 0.05*flarenoise); - flare *= flare; // A more rapid decline towards the edge - // "glow" is a variation in the intensity of the glowy cathode (core) - float glow = 0.8+0.2*psrdnoise(p - float2(0.0, 2.0*elapsed_time), float2(0.0,0.0), 4.0*time, g); - // Now we mess up the distance field a little for the "halo" effect - d += 0.1*psrdnoise(p - float2(0.0, 2.0*elapsed_time), float2(0.0,0.0), 8.0*time, g); - d += 0.05*psrdnoise(2.0*p - float2(0.0, 4.0*elapsed_time) + 0.15*g, float2(0.0,0.0), -16.0*time, g); - // "halo" is a kind of flame/plasma cloud near the core. A real Nixie tube - // doesn''t have this, but it adds some appealing visual detail. - // Looks more like hot filaments than "cold cathodes", but... oh, well. - float halo = 1.0-smoothstep(-0.3, 0.3, d); - - // Brittle parameters! This scale/shift of p has a strong impact - // on the pattern at the edges of the grid through "anodefade". - float3 anodedists = hexgrid(1.7*p+float2(0.1,0.23)); - float anodedist = anodedists.y - anodedists.x; // Voronoi cell borders - // Fade the hexagonal holes in the anode towards the edges - float anodefade = max(max(1.0-aasmoothstep(-2.2, -1.5, p.x), aasmoothstep(45.5, 46.2, p.x)), - max(1.0-aasmoothstep(-2.0, -1.6, p.y), aasmoothstep(9.4, 10.0, p.y))); - float anode = 1.0 - aastep(0.1, anodedist - anodefade); - - float anodecolornoise = 0.02*psrdnoise(p*float2(0.2,2.0), float2(0.0,0.0), 0.0, g); - float3 anodecolorresult = anodecolor+ anodecolornoise*anodehighlightscolor; // Long variable names, I know - - float3 mixcolor = float3(0.0,0.0,0.0); // Mix additively from black - mixcolor = lerp(mixcolor, flarecolor, 0.5*flare); - mixcolor = lerp(mixcolor, halocolor, 0.9*halo); - mixcolor = lerp(mixcolor, corecolor, core*glow); - mixcolor = lerp(mixcolor, anodecolorresult, anode); - mixcolor *= bbox; // AA-mask to black at the very edge of the bounding box - return float4(mixcolor,1.0); -} - -' -} -$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] + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam } - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -11196,172 +8122,117 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSColorDepthShader { +function Get-OBSSceneItemSource { -[Alias('Set-OBSColorDepthShader','Add-OBSColorDepthShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneItemSource')] +[Alias('obs.powershell.websocket.GetSceneItemSource')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the colorDepth of OBSColorDepthShader -[ComponentModel.DefaultBindingProperty('colorDepth')] -[Single] -$ColorDepth, -# Set the pixelSize of OBSColorDepthShader -[ComponentModel.DefaultBindingProperty('pixelSize')] -[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. +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, + [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] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemId')] +[ValidateRange(0,[int]::MaxValue)] +[double] +$SceneItemId, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'color-depth' -$ShaderNoun = 'OBSColorDepthShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//based on https://www.shadertoy.com/view/tscfWM -uniform float colorDepth< - string label = "Color depth"; - string widget_type = "slider"; - float minimum = 0.01; - float maximum = 100.0; - float step = 0.01; -> = 5.0; - -uniform float pixelSize< - string label = "Pixel Size"; - string widget_type = "slider"; - float minimum = 1.0; - float maximum = 100.0; - float step = 0.01; -> = 5.0; -float4 mainImage(VertData v_in) : TARGET -{ - // Change these to change results - float2 size = uv_size / pixelSize; - float2 uv = v_in.uv; - // Maps UV onto grid of variable size to pixilate the image - uv = round(uv*size)/size; - float4 col = image.Sample(textureSampler, uv); - // Maps color onto the specified color depth - return float4(round(col.r * colorDepth) / colorDepth, - round(col.g * colorDepth) / colorDepth, - round(col.b * colorDepth) / colorDepth, 1.0); -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -11370,225 +8241,117 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSColorGradeFilterShader { +function Get-OBSSceneItemTransform { -[Alias('Set-OBSColorGradeFilterShader','Add-OBSColorGradeFilterShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneItemTransform')] +[Alias('obs.powershell.websocket.GetSceneItemTransform')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the notes of OBSColorGradeFilterShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# Set the lut of OBSColorGradeFilterShader -[ComponentModel.DefaultBindingProperty('lut')] -[String] -$Lut, -# Set the lut_amount_percent of OBSColorGradeFilterShader -[Alias('lut_amount_percent')] -[ComponentModel.DefaultBindingProperty('lut_amount_percent')] -[Int32] -$LutAmountPercent, -# Set the lut_scale_percent of OBSColorGradeFilterShader -[Alias('lut_scale_percent')] -[ComponentModel.DefaultBindingProperty('lut_scale_percent')] -[Int32] -$LutScalePercent, -# Set the lut_offset_percent of OBSColorGradeFilterShader -[Alias('lut_offset_percent')] -[ComponentModel.DefaultBindingProperty('lut_offset_percent')] -[Int32] -$LutOffsetPercent, -# 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. +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, + [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] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemId')] +[ValidateRange(0,[int]::MaxValue)] +[double] +$SceneItemId, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'color_grade_filter' -$ShaderNoun = 'OBSColorGradeFilterShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Color Grade Filter by Charles Fettinger for obs-shaderfilter plugin 4/2020 -//https://github.com/Oncorporation/obs-shaderfilter -//OBS messed up the LUT system, this is basically the old LUT system -//Converted to OpenGL by Q-mii & Exeldro February 25, 2022 -uniform string notes< - string widget_type = "info"; -> = "Choose LUT, Default LUT amount is 100, scale = 100, offset = 0. Valid values: -200 to 200"; -uniform texture2d lut< - string label = "LUT"; ->; -uniform int lut_amount_percent< - string label = "LUT amount percentage"; - string widget_type = "slider"; - int minimum = -200; - int maximum = 200; - int step = 1; -> = 100; -uniform int lut_scale_percent< - string label = "LUT scale percentage"; - string widget_type = "slider"; - int minimum = -200; - int maximum = 200; - int step = 1; -> = 100; -uniform int lut_offset_percent< - string label = "LUT offset percentage"; - string widget_type = "slider"; - int minimum = -200; - int maximum = 200; - int step = 1; -> = 0; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -float4 mainImage(VertData v_in) : TARGET -{ - float lut_amount = clamp(lut_amount_percent *.01, -2.0, 2.0); - float lut_scale = clamp(lut_scale_percent *.01,-2.0, 2.0); - float lut_offset = clamp(lut_offset_percent *.01,-2.0, 2.0); - - float4 textureColor = image.Sample(textureSampler, v_in.uv); - float lumaLevel = textureColor.r * 0.2126 + textureColor.g * 0.7152 + textureColor.b * 0.0722; - float blueColor = float(lumaLevel);//textureColor.b * 63.0 - - float2 quad1; - quad1.y = floor(floor(float(blueColor)) / 8.0); - quad1.x = floor(float(blueColor)) - (quad1.y * 8.0); - - float2 quad2; - quad2.y = floor(ceil(float(blueColor)) / 8.0); - quad2.x = ceil(float(blueColor)) - (quad2.y * 8.0); - - float2 texPos1; - texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r); - texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g); - - float2 texPos2; - texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r); - texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g); - - float4 newColor1 = lut.Sample(textureSampler, texPos1); - newColor1.rgb = newColor1.rgb * lut_scale + lut_offset; - float4 newColor2 = lut.Sample(textureSampler, texPos2); - newColor2.rgb = newColor2.rgb * lut_scale + lut_offset; - float4 luttedColor = lerp(newColor1, newColor2, frac(float(blueColor))); - - float4 final_color = lerp(textureColor, luttedColor, lut_amount); - return float4(final_color.rgb, textureColor.a); -} -' -} -$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 + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -11597,358 +8360,214 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSCornerPinShader { +function Get-OBSSceneSceneTransitionOverride { -[Alias('Set-OBSCornerPinShader','Add-OBSCornerPinShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneSceneTransitionOverride')] +[Alias('obs.powershell.websocket.GetSceneSceneTransitionOverride')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the Antialias_Edges of OBSCornerPinShader -[Alias('Antialias_Edges')] -[ComponentModel.DefaultBindingProperty('Antialias_Edges')] -[Management.Automation.SwitchParameter] -$AntialiasEdges, -# Set the Top_Left_X of OBSCornerPinShader -[Alias('Top_Left_X')] -[ComponentModel.DefaultBindingProperty('Top_Left_X')] -[Single] -$TopLeftX, -# Set the Top_Left_Y of OBSCornerPinShader -[Alias('Top_Left_Y')] -[ComponentModel.DefaultBindingProperty('Top_Left_Y')] -[Single] -$TopLeftY, -# Set the Top_Right_X of OBSCornerPinShader -[Alias('Top_Right_X')] -[ComponentModel.DefaultBindingProperty('Top_Right_X')] -[Single] -$TopRightX, -# Set the Top_Right_Y of OBSCornerPinShader -[Alias('Top_Right_Y')] -[ComponentModel.DefaultBindingProperty('Top_Right_Y')] -[Single] -$TopRightY, -# Set the Bottom_Left_X of OBSCornerPinShader -[Alias('Bottom_Left_X')] -[ComponentModel.DefaultBindingProperty('Bottom_Left_X')] -[Single] -$BottomLeftX, -# Set the Bottom_Left_Y of OBSCornerPinShader -[Alias('Bottom_Left_Y')] -[ComponentModel.DefaultBindingProperty('Bottom_Left_Y')] -[Single] -$BottomLeftY, -# Set the Bottom_Right_X of OBSCornerPinShader -[Alias('Bottom_Right_X')] -[ComponentModel.DefaultBindingProperty('Bottom_Right_X')] -[Single] -$BottomRightX, -# Set the Bottom_Right_Y of OBSCornerPinShader -[Alias('Bottom_Right_Y')] -[ComponentModel.DefaultBindingProperty('Bottom_Right_Y')] -[Single] -$BottomRightY, -# 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. +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, + [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] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'corner-pin' -$ShaderNoun = 'OBSCornerPinShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Corner Pin, Version 0.1, for OBS Shaderfilter -// Copyright ©️ 2022 by SkeletonBow -// License: GNU General Public License, version 2 -// Contact info: -// Twitter: -// Twitch: -// -// Based on: -// Original work by Inigo Quilez: https://www.iquilezles.org/www/articles/ibilinear/ibilinear.htm -// https://www.youtube.com/c/InigoQuilez -// https://iquilezles.org/ -// and the derivative StreamFX Corner Pin effect by Xaymar -// https://github.com/Xaymar/obs-StreamFX -// -// Description: -// Corner Pin allows you to pin the corners of an image onto the corners of an arbitrarily -// angled picture frame, TV screen or other rectangular surface in 3D space in an underlying -// image with proper perspective without distortion. -// -// TODO: -// - Add feature to automatically quantize corners to pixel centers -// -// Changelog: -// 0.1 - Initial release based on the StreamFX Corner Pin effect, as well as the original work by -// Inigo Quilez that it was based upon. - -uniform bool Antialias_Edges = true; -uniform float Top_Left_X< - string label = "Top left x"; - string widget_type = "slider"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.1; -> = -100.; -uniform float Top_Left_Y< - string label = "Top left y"; - string widget_type = "slider"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.1; -> = -100.; -uniform float Top_Right_X< - string label = "Top right x"; - string widget_type = "slider"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.1; -> = 100.; -uniform float Top_Right_Y< - string label = "Top right y"; - string widget_type = "slider"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.1; -> = -100.; -uniform float Bottom_Left_X< - string label = "Bottom left x"; - string widget_type = "slider"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.1; -> = -100.; -uniform float Bottom_Left_Y< - string label = "Bottom left y"; - string widget_type = "slider"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.1; -> = 100.; -uniform float Bottom_Right_X< - string label = "Bottom right x"; - string widget_type = "slider"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.1; -> = 100.; -uniform float Bottom_Right_Y< - string label = "Bottom right y"; - string widget_type = "slider"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.1; -> = 100.; -// DEVELOPMENTAL DEBUGGING OPTIONS -//uniform float AAstrength = 1.0; -//uniform float AAdist = 1.0; -//uniform float debug_psmult = 1.0; -//#define PIXEL_SIZE_MULT 2.0 + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -float cross2d(in float2 a, in float2 b) -{ - return (a.x * b.y) - (a.y * b.x); -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -float2 inverse_bilinear(in float2 p, in float2 a, in float2 b, in float2 c, in float2 d) -{ - float2 result = float2(-1., -1.); + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } - float2 e = b - a; - float2 f = d - a; - float2 g = a-b+c-d; - float2 h = p-a; + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } - float k2 = cross2d(g, f); - float k1 = cross2d(e, f) + cross2d(h, g); - float k0 = cross2d(h, e); + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } - if (abs(k2) < .001) { // Edges are likely parallel, so this is a linear equation. - result = float2( - (h.x * k1 + f.x * k0) / (e.x * k1 - g.x * k0), - -k0 / k1 - ); - } else { // It''s a quadratic equation. - float w = k1 * k1 - 4.0 * k0 * k2; - if (w < 0.0) { // Prevent GPUs from going insane. - return result; - } - w = sqrt(w); +} - float ik2 = 0.5/k2; - float v = (-k1 - w) * ik2; - float u = (h.x - f.x * v) / (e.x + g.x * v); - if (u < 0.0 || u > 1.0 || v < 0.0 || v > 1.0) { - v = (-k1 + w) * ik2; - u = (h.x - f.x * v) / (e.x + g.x * v); - } +} - result = float2(u, v); - } + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSSceneTransition { - return result; -} -// distance to a line segment -float sdSegment( in float2 p, in float2 a, in float2 b ) -{ - p -= a; b -= a; - return length( p-b*saturate(dot(p,b)/dot(b,b)) ); -} +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneTransitionList')] +[Alias('obs.powershell.websocket.GetSceneTransitionList')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) -// Anti-alias edges - EXPERIMENTAL - (SkeletonBow) -float aastepEdgeAlpha(in float alpha, in float2 p, in float2 a, in float2 b) -{ - //float ps = 2.0 * (2.0/uv_size.y); // Original -// float ps = debug_psmult * (2.0/uv_size.y); - float ps = (2.0/uv_size.y); -// float ps = fwidth(p)*2.; // Try using fwidth() - goes haywire on AMD Radeon HD7850 at least, disable for now - return lerp( alpha, 0.0, 1.0 - smoothstep(0.0,ps,sdSegment(p,a,b))); -} -float4 mainImage( VertData v_in ) : TARGET { - float2 p = 2.* v_in.uv - 1.; - - float2 Top_Left = float2(Top_Left_X, Top_Left_Y) * .01; - float2 Top_Right = float2(Top_Right_X, Top_Right_Y) * .01; - float2 Bottom_Left = float2(Bottom_Left_X, Bottom_Left_Y) * .01; - float2 Bottom_Right = float2(Bottom_Right_X, Bottom_Right_Y) * .01; - - // Convert from screen coords to potential Quad UV coordinates - float2 uv = inverse_bilinear(p, Top_Left, Top_Right, Bottom_Right, Bottom_Left); +process { - if (max(abs(uv.x - .5), abs(uv.y - .5)) >= .5) { - return float4(0.0, 0.0, 0.0, 0.0); - } - float4 texel = image.Sample(textureSampler, uv); + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if ( Antialias_Edges ) { - // Anti-alias edges of texture - texel.a = aastepEdgeAlpha(texel.a, p, Top_Left, Top_Right); - texel.a = aastepEdgeAlpha(texel.a, p, Top_Right, Bottom_Right); - texel.a = aastepEdgeAlpha(texel.a, p, Bottom_Right, Bottom_Left); - texel.a = aastepEdgeAlpha(texel.a, p, Bottom_Left, Top_Left); - } - return texel; -} - -' -} -$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 + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -11957,185 +8576,111 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSCrtCurvatureShader { +function Get-OBSSourceActive { -[Alias('Set-OBSCrtCurvatureShader','Add-OBSCrtCurvatureShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSourceActive')] +[Alias('obs.powershell.websocket.GetSourceActive')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the strength of OBSCrtCurvatureShader -[ComponentModel.DefaultBindingProperty('strength')] -[Single] -$Strength, -# Set the border of OBSCrtCurvatureShader -[ComponentModel.DefaultBindingProperty('border')] -[String] -$Border, -# Set the feathering of OBSCrtCurvatureShader -[ComponentModel.DefaultBindingProperty('feathering')] -[Single] -$Feathering, -# The name of the source. This must be provided when adding an item for the first time + [Parameter(ValueFromPipelineByPropertyName)] -[Alias('SceneItemName')] -[String] +[ComponentModel.DefaultBindingProperty('sourceName')] +[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] +[ComponentModel.DefaultBindingProperty('sourceUuid')] +[string] +$SourceUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'crt-curvature' -$ShaderNoun = 'OBSCrtCurvatureShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform float strength< - string label = "Strength"; - string widget_type = "slider"; - float minimum = 0.; - float maximum = 200.; - float step = 0.01; -> = 33.33; - -uniform float4 border< - string label = "Border Color"; -> = {0., 0., 0., 1.}; - -uniform float feathering< - string label = "Feathering"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 33.33; - - -float4 mainImage(VertData v_in) : TARGET -{ - float2 cc = v_in.uv - float2(0.5, 0.5); - float dist = dot(cc, cc) * strength / 100.0; - float2 bent = v_in.uv + cc * (1.0 + dist) * dist; - if ((bent.x <= 0.0 || bent.x >= 1.0) || (bent.y <= 0.0 || bent.y >= 1.0)) { - return border; - } - if (feathering >= .01) { - float2 borderArea = float2(0.5, 0.5) * feathering / 100.0; - float2 borderDistance = (float2(0.5, 0.5) - abs(bent - float2(0.5, 0.5))) / float2(0.5, 0.5); - borderDistance = (min(borderDistance - float2(0.5, 0.5) * feathering / 100.0, 0) + borderArea) / borderArea; - float borderFade = sin(borderDistance.x * 1.570796326) * sin(borderDistance.y * 1.570796326); - return lerp(border, image.Sample(textureSampler, bent), borderFade); - } - return image.Sample(textureSampler, bent); -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -12144,187 +8689,116 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSCurveShader { +function Get-OBSSourceFilter { -[Alias('Set-OBSCurveShader','Add-OBSCurveShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSourceFilter')] +[Alias('obs.powershell.websocket.GetSourceFilter')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the strength of OBSCurveShader -[ComponentModel.DefaultBindingProperty('strength')] -[Single] -$Strength, -# Set the scale of OBSCurveShader -[ComponentModel.DefaultBindingProperty('scale')] -[Single] -$Scale, -# Set the curve_color of OBSCurveShader -[Alias('curve_color')] -[ComponentModel.DefaultBindingProperty('curve_color')] -[String] -$CurveColor, -# The name of the source. This must be provided when adding an item for the first time + [Parameter(ValueFromPipelineByPropertyName)] -[Alias('SceneItemName')] -[String] +[ComponentModel.DefaultBindingProperty('sourceName')] +[string] $SourceName, -# The name of the filter. If this is not provided, this will default to the shader name. + [Parameter(ValueFromPipelineByPropertyName)] -[String] +[ComponentModel.DefaultBindingProperty('sourceUuid')] +[string] +$SourceUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('filterName')] +[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] +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'curve' -$ShaderNoun = 'OBSCurveShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -#define PI 3.14159265359 -uniform float strength< - string label = "Strength"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.5; -uniform float scale< - string label = "Scale"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 1.0; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -uniform float4 curve_color = {0,0,0,0}; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -float4 mainImage(VertData v_in) : TARGET -{ - float2 uv = v_in.uv; - const float ydiff = 1.0; - uv -= float2(0.5,ydiff); - uv.x *= ( uv_size.x / uv_size.y); - uv /= scale; - if(strength > 0.0){ - float d = tan((1.0-strength)*PI/2.0); - float r = length(float2(0.5*(uv_size.x / uv_size.y), d)); - float2 center = float2(0.0,(1.0-ydiff)+d); - float pd = distance(uv, center); - if(pd < r) - return curve_color; - float angle = atan2(center.x-uv.x,center.y-uv.y); - uv = float2(uv.x + sin(angle)*(pd-r),(1.0-ydiff)-(pd-r)); - } - uv.x /= ( uv_size.x / uv_size.y); - uv += float2(0.5,ydiff); - return image.Sample(textureSampler,uv); -} -' -} -$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] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } } - 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 = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -12333,548 +8807,209 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSCutRectPerCornerShader { +function Get-OBSSourceFilterDefaultSettings { -[Alias('Set-OBSCutRectPerCornerShader','Add-OBSCutRectPerCornerShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSourceFilterDefaultSettings')] +[Alias('obs.powershell.websocket.GetSourceFilterDefaultSettings')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the corner_tl of OBSCutRectPerCornerShader -[Alias('corner_tl')] -[ComponentModel.DefaultBindingProperty('corner_tl')] -[Int32] -$CornerTl, -# Set the corner_tr of OBSCutRectPerCornerShader -[Alias('corner_tr')] -[ComponentModel.DefaultBindingProperty('corner_tr')] -[Int32] -$CornerTr, -# Set the corner_br of OBSCutRectPerCornerShader -[Alias('corner_br')] -[ComponentModel.DefaultBindingProperty('corner_br')] -[Int32] -$CornerBr, -# Set the corner_bl of OBSCutRectPerCornerShader -[Alias('corner_bl')] -[ComponentModel.DefaultBindingProperty('corner_bl')] -[Int32] -$CornerBl, -# Set the border_thickness of OBSCutRectPerCornerShader -[Alias('border_thickness')] -[ComponentModel.DefaultBindingProperty('border_thickness')] -[Int32] -$BorderThickness, -# Set the border_color of OBSCutRectPerCornerShader -[Alias('border_color')] -[ComponentModel.DefaultBindingProperty('border_color')] -[String] -$BorderColor, -# Set the border_alpha_start of OBSCutRectPerCornerShader -[Alias('border_alpha_start')] -[ComponentModel.DefaultBindingProperty('border_alpha_start')] -[Single] -$BorderAlphaStart, -# Set the border_alpha_end of OBSCutRectPerCornerShader -[Alias('border_alpha_end')] -[ComponentModel.DefaultBindingProperty('border_alpha_end')] -[Single] -$BorderAlphaEnd, -# Set the alpha_cut_off of OBSCutRectPerCornerShader -[Alias('alpha_cut_off')] -[ComponentModel.DefaultBindingProperty('alpha_cut_off')] -[Single] -$AlphaCutOff, -# 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(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('filterKind')] +[string] +$FilterKind, +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'cut_rect_per_corner' -$ShaderNoun = 'OBSCutRectPerCornerShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//Converted to OpenGL by Q-mii & Exeldro February 18, 2022 -uniform int corner_tl< - string label = "Corner top left"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; ->; -uniform int corner_tr< - string label = "Corner top right"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; ->; -uniform int corner_br< - string label = "Corner bottom right"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; ->; -uniform int corner_bl< - string label = "Corner bottom left"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; ->; -uniform int border_thickness< - string label = "Border thickness"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; ->; -uniform float4 border_color; -uniform float border_alpha_start< - string label = "Border aplha start"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 1.0; -uniform float border_alpha_end< - string label = "Border aplha start"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.0; -uniform float alpha_cut_off< - string label = "Alpha cut off"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.5; -float4 mainImage(VertData v_in) : TARGET -{ - float4 pixel = image.Sample(textureSampler, v_in.uv); - int closedEdgeX = 0; - int closedEdgeY = 0; - if(pixel.a < alpha_cut_off){ - return float4(1.0,0.0,0.0,0.0); - } - int corner_top = corner_tl>corner_tr?corner_tl:corner_tr; - int corner_right = corner_tr>corner_br?corner_tr:corner_br; - int corner_bottom = corner_bl>corner_br?corner_bl:corner_br; - int corner_left = corner_tl>corner_bl?corner_tl:corner_bl; - - if(image.Sample(textureSampler, v_in.uv + float2(corner_right*uv_pixel_interval.x,0)).a < alpha_cut_off){ - closedEdgeX = corner_right; - }else if(image.Sample(textureSampler, v_in.uv + float2(-corner_left*uv_pixel_interval.x,0)).a < alpha_cut_off){ - closedEdgeX = -corner_left; - } - if(image.Sample(textureSampler, v_in.uv + float2(0,corner_bottom*uv_pixel_interval.y)).a < alpha_cut_off){ - closedEdgeY = corner_bottom; - }else if(image.Sample(textureSampler, v_in.uv + float2(0,-corner_top*uv_pixel_interval.y)).a < alpha_cut_off){ - closedEdgeY = -corner_top; - } - if(closedEdgeX == 0 && closedEdgeY == 0){ - return pixel; - } - if(closedEdgeX != 0){ - [loop] for(int x = 1;x 0 && closedEdgeY < 0){ - corner_radius = corner_tr; - }else if(closedEdgeX > 0 && closedEdgeY > 0){ - corner_radius = corner_br; - }else if(closedEdgeX < 0 && closedEdgeY > 0){ - corner_radius = corner_bl; - } - if(closedEdgeXabs > corner_radius && closedEdgeYabs > corner_radius){ - return pixel; - } - if(closedEdgeXabs == 0){ - if(closedEdgeYabs <= border_thickness){ - float4 fade_color = border_color; - fade_color.a = border_alpha_end + (float(closedEdgeYabs) / float(border_thickness))*(border_alpha_start-border_alpha_end); - return fade_color; - }else{ - return pixel; - } - } - if(closedEdgeYabs == 0){ - if(closedEdgeXabs <= border_thickness){ - float4 fade_color = border_color; - fade_color.a = border_alpha_end + (float(closedEdgeXabs) / float(border_thickness))*(border_alpha_start-border_alpha_end); - return fade_color; - }else{ - return pixel; - } - } - if(closedEdgeXabs > corner_radius){ - if(closedEdgeYabs <= border_thickness){ - float4 fade_color = border_color; - fade_color.a = border_alpha_end + (float(closedEdgeYabs) / float(border_thickness))*(border_alpha_start-border_alpha_end); - return fade_color; - }else{ - return pixel; - } - } - if(closedEdgeYabs > corner_radius){ - if(closedEdgeXabs <= border_thickness){ - float4 fade_color = border_color; - fade_color.a = border_alpha_end + (float(closedEdgeXabs) / float(border_thickness))*(border_alpha_start-border_alpha_end); - return fade_color; - }else{ - return pixel; - } - } - float d = closedEdgeXabs+closedEdgeYabs; - if(d>corner_radius){ - if(d-corner_radius <= border_thickness){ - float4 fade_color = border_color; - fade_color.a = border_alpha_end + ((d-corner_radius)/ float(border_thickness))*(border_alpha_start-border_alpha_end); - return fade_color; - }else{ - return pixel; + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - } - return float4(0.0,0.0,0.0,0.0); -} -' -} -$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 + + if ($PassThru) { + [PSCustomObject]$requestPayload } 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 - } + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - 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 = @{} - } + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSSourceFilterKind { - 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 - } - } -} - -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSCylinderShader { -[Alias('Set-OBSCylinderShader','Add-OBSCylinderShader')] +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSourceFilterKindList')] +[Alias('obs.powershell.websocket.GetSourceFilterKindList')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the cylinder_factor of OBSCylinderShader -[Alias('cylinder_factor')] -[ComponentModel.DefaultBindingProperty('cylinder_factor')] -[Single] -$CylinderFactor, -# Set the background_cut of OBSCylinderShader -[Alias('background_cut')] -[ComponentModel.DefaultBindingProperty('background_cut')] -[Single] -$BackgroundCut, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'cylinder' -$ShaderNoun = 'OBSCylinderShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform float cylinder_factor< - string label = "Cylinder factor"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.2; -uniform float background_cut< - string label = "Background cut"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.1; -float4 mainImage(VertData v_in) : TARGET -{ - float2 uv = v_in.uv; - uv.x -= 0.5; - float bend = sqrt(1.0 - uv.x*uv.x*4); - uv.y = uv.y/(1.0 - cylinder_factor)-bend*cylinder_factor; - uv.y-=cylinder_factor/2; - uv.x /= 2; - uv.x += 0.5; - float4 front_color = image.Sample(textureSampler, uv); - front_color.rgb *= bend/2+0.5; - if(front_color.a >= 1.0) - return front_color; - - uv = v_in.uv; - uv.x -= 0.5; - if(abs(uv.x) < background_cut) - return front_color; - uv.y = uv.y/(1.0 - cylinder_factor)+bend*cylinder_factor; - uv.y-=cylinder_factor/2; - uv.x /= 2; - if(uv.x > 0){ - uv.x = 1.0 - uv.x; - }else{ - uv.x = 0 - uv.x; - } - float4 back_color = image.Sample(textureSampler, uv); - back_color.rgb *= 0.5-bend/2; - front_color.rgb *= front_color.a; - front_color.rgb += back_color.rgb * (1.0 - front_color.a) * back_color.a; - front_color.a = back_color.a * (1.0 - front_color.a) + front_color.a; - return front_color; -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -12883,161 +9018,111 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSDarkenShader { +function Get-OBSSourceFilterList { -[Alias('Set-OBSDarkenShader','Add-OBSDarkenShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSourceFilterList')] +[Alias('obs.powershell.websocket.GetSourceFilterList')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the Opacity_Percentage of OBSDarkenShader -[Alias('Opacity_Percentage')] -[ComponentModel.DefaultBindingProperty('Opacity_Percentage')] -[Single] -$OpacityPercentage, -# Set the Fill_Percentage of OBSDarkenShader -[Alias('Fill_Percentage')] -[ComponentModel.DefaultBindingProperty('Fill_Percentage')] -[Single] -$FillPercentage, -# Set the Notes of OBSDarkenShader -[ComponentModel.DefaultBindingProperty('Notes')] -[String] -$Notes, -# The name of the source. This must be provided when adding an item for the first time + [Parameter(ValueFromPipelineByPropertyName)] -[Alias('SceneItemName')] -[String] +[ComponentModel.DefaultBindingProperty('sourceName')] +[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] +[ComponentModel.DefaultBindingProperty('sourceUuid')] +[string] +$SourceUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'darken' -$ShaderNoun = 'OBSDarkenShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform float Opacity_Percentage = 100.0; -uniform float Fill_Percentage = 100.0; -uniform string Notes = "Simulates a photo editing darken layer blending mode. Fill percentage is the interior alpha and Opacity is the layer alpha."; - -float4 mainImage(VertData v_in) : TARGET -{ - float4 other = float4(1.0, 1.0, 1.0, 1.0); - float4 base = image.Sample(textureSampler, v_in.uv); - float luminance = dot(base.rgb, float3(0.299, 0.587, 0.114)); - float4 gray = float4(luminance,luminance,luminance, 1.0); - return min(base,other); -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -13046,198 +9131,237 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSDeadPixelFixerShader { +function Get-OBSSourceScreenshot { -[Alias('Set-OBSDeadPixelFixerShader','Add-OBSDeadPixelFixerShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSourceScreenshot')] +[Alias('obs.powershell.websocket.GetSourceScreenshot')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the Dead_Pixel_X of OBSDeadPixelFixerShader -[Alias('Dead_Pixel_X')] -[ComponentModel.DefaultBindingProperty('Dead_Pixel_X')] -[Int32] -$DeadPixelX, -# Set the Dead_Pixel_Y of OBSDeadPixelFixerShader -[Alias('Dead_Pixel_Y')] -[ComponentModel.DefaultBindingProperty('Dead_Pixel_Y')] -[Int32] -$DeadPixelY, -# The name of the source. This must be provided when adding an item for the first time + [Parameter(ValueFromPipelineByPropertyName)] -[Alias('SceneItemName')] -[String] +[ComponentModel.DefaultBindingProperty('sourceName')] +[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 +[ComponentModel.DefaultBindingProperty('sourceUuid')] +[string] +$SourceUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('imageFormat')] +[string] +$ImageFormat, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('imageWidth')] +[ValidateRange(8,4096)] +[double] +$ImageWidth, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('imageHeight')] +[ValidateRange(8,4096)] +[double] +$ImageHeight, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('imageCompressionQuality')] +[ValidateRange(-1,100)] +[double] +$ImageCompressionQuality, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'dead-pixel-fixer' -$ShaderNoun = 'OBSDeadPixelFixerShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Dead Pixel Fixer, Version 0.01, for OBS Shaderfilter -// Copyright ©️ 2022 by SkeletonBow -// License: GNU General Public License, version 2 -// Contact info: -// Twitter: -// Twitch: -// -// Description: Intended for use with an input source that has a dead pixel on its sensor such as a webcam. -// The pixel located at the user configured offset will have its color overridden by taking the average of the -// color of the 8 pixels immediately surrounding it, effectively hiding the dead pixel. -// -// Changelog: -// 0.01 - Initial release - -uniform int Dead_Pixel_X< - string label = "Dead Pixel X"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 2000; - int step = 1; -> = 0; -uniform int Dead_Pixel_Y< - string label = "Dead Pixel Y"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 2000; - int step = 1; -> = 0; -float3 blur_dead_pixel(in float2 pos) -{ - float3 color; - color = image.Sample(textureSampler, (pos + float2(-1.0, -0.5))/uv_size).rgb; - color += image.Sample(textureSampler, (pos + float2(0.5, -1.0))/uv_size).rgb; - color += image.Sample(textureSampler, (pos + float2(1.0, 0.5))/uv_size).rgb; - color += image.Sample(textureSampler, (pos + float2(-0.5, 1.0))/uv_size).rgb; - return color * 0.25; -} -float4 mainImage( VertData v_in ) : TARGET -{ - float2 uv = v_in.uv; - float2 pos = v_in.pos.xy; - float2 dp_pos = clamp( float2(Dead_Pixel_X, Dead_Pixel_Y), float2(0.0,0.0), uv_size - 1); - float4 obstex = image.Sample(textureSampler, uv); - float3 color; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if(floor(pos.x) == floor(dp_pos.x) && floor(pos.y) == floor(dp_pos.y) ) { - color = blur_dead_pixel(pos); - } else { - color.rgb = obstex.rgb; - } - return float4( color, obstex.a); -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -' -} -$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 '|' + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } - ))" - 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] + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam } - continue nextParameter - } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } +} - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSSpecialInputs { + + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSpecialInputs')] +[Alias('obs.powershell.websocket.GetSpecialInputs')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) + + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -13246,488 +9370,204 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSDensitySatHueShader { +function Get-OBSStats { -[Alias('Set-OBSDensitySatHueShader','Add-OBSDensitySatHueShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetStats')] +[Alias('obs.powershell.websocket.GetStats')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the notes of OBSDensitySatHueShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# Set the density_r of OBSDensitySatHueShader -[Alias('density_r')] -[ComponentModel.DefaultBindingProperty('density_r')] -[Single] -$DensityR, -# Set the saturation_r of OBSDensitySatHueShader -[Alias('saturation_r')] -[ComponentModel.DefaultBindingProperty('saturation_r')] -[Single] -$SaturationR, -# Set the hueShift_r of OBSDensitySatHueShader -[Alias('hueShift_r')] -[ComponentModel.DefaultBindingProperty('hueShift_r')] -[Single] -$HueShiftR, -# Set the density_y of OBSDensitySatHueShader -[Alias('density_y')] -[ComponentModel.DefaultBindingProperty('density_y')] -[Single] -$DensityY, -# Set the saturation_y of OBSDensitySatHueShader -[Alias('saturation_y')] -[ComponentModel.DefaultBindingProperty('saturation_y')] -[Single] -$SaturationY, -# Set the hueShift_y of OBSDensitySatHueShader -[Alias('hueShift_y')] -[ComponentModel.DefaultBindingProperty('hueShift_y')] -[Single] -$HueShiftY, -# Set the density_g of OBSDensitySatHueShader -[Alias('density_g')] -[ComponentModel.DefaultBindingProperty('density_g')] -[Single] -$DensityG, -# Set the saturation_g of OBSDensitySatHueShader -[Alias('saturation_g')] -[ComponentModel.DefaultBindingProperty('saturation_g')] -[Single] -$SaturationG, -# Set the hueShift_g of OBSDensitySatHueShader -[Alias('hueShift_g')] -[ComponentModel.DefaultBindingProperty('hueShift_g')] -[Single] -$HueShiftG, -# Set the density_c of OBSDensitySatHueShader -[Alias('density_c')] -[ComponentModel.DefaultBindingProperty('density_c')] -[Single] -$DensityC, -# Set the saturation_c of OBSDensitySatHueShader -[Alias('saturation_c')] -[ComponentModel.DefaultBindingProperty('saturation_c')] -[Single] -$SaturationC, -# Set the hueShift_c of OBSDensitySatHueShader -[Alias('hueShift_c')] -[ComponentModel.DefaultBindingProperty('hueShift_c')] -[Single] -$HueShiftC, -# Set the density_b of OBSDensitySatHueShader -[Alias('density_b')] -[ComponentModel.DefaultBindingProperty('density_b')] -[Single] -$DensityB, -# Set the saturation_b of OBSDensitySatHueShader -[Alias('saturation_b')] -[ComponentModel.DefaultBindingProperty('saturation_b')] -[Single] -$SaturationB, -# Set the hueShift_b of OBSDensitySatHueShader -[Alias('hueShift_b')] -[ComponentModel.DefaultBindingProperty('hueShift_b')] -[Single] -$HueShiftB, -# Set the density_m of OBSDensitySatHueShader -[Alias('density_m')] -[ComponentModel.DefaultBindingProperty('density_m')] -[Single] -$DensityM, -# Set the saturation_m of OBSDensitySatHueShader -[Alias('saturation_m')] -[ComponentModel.DefaultBindingProperty('saturation_m')] -[Single] -$SaturationM, -# Set the hueShift_m of OBSDensitySatHueShader -[Alias('hueShift_m')] -[ComponentModel.DefaultBindingProperty('hueShift_m')] -[Single] -$HueShiftM, -# Set the global_density of OBSDensitySatHueShader -[Alias('global_density')] -[ComponentModel.DefaultBindingProperty('global_density')] -[Single] -$GlobalDensity, -# Set the global_saturation of OBSDensitySatHueShader -[Alias('global_saturation')] -[ComponentModel.DefaultBindingProperty('global_saturation')] -[Single] -$GlobalSaturation, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'density_sat_hue' -$ShaderNoun = 'OBSDensitySatHueShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Density-Saturation-Hue Shader for OBS Shaderfilter -// Modified by CameraTim for use with obs-shaderfilter 12/2024 v.12 - -uniform string notes< - string widget_type = "info"; -> = "Density adjustment shader: Density reduces luminance, while saturation is subtractively increased to avoid greyish colors."; -uniform float density_r < - string label = "Red Density"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; -uniform float saturation_r < - string label = "Red Sat"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -uniform float hueShift_r < - string label = "Red Hue Shift"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -uniform float density_y < - string label = "Yellow Density"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; - -uniform float saturation_y < - string label = "Yellow Sat"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; - -uniform float hueShift_y < - string label = "Yellow Hue Shift"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; - -uniform float density_g < - string label = "Green Density"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; - -uniform float saturation_g < - string label = "Green Sat"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -uniform float hueShift_g < - string label = "Green Hue Shift"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -uniform float density_c < - string label = "Cyan Density"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -uniform float saturation_c < - string label = "Cyan Sat"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; +} -uniform float hueShift_c < - string label = "Cyan Hue Shift"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; -uniform float density_b < - string label = "Blue Density"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; +} -uniform float saturation_b < - string label = "Blue Sat"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSStreamServiceSettings { -uniform float hueShift_b < - string label = "Blue Hue Shift"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; -uniform float density_m < - string label = "Magenta Density"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetStreamServiceSettings')] +[Alias('obs.powershell.websocket.GetStreamServiceSettings')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) -uniform float saturation_m < - string label = "Magenta Sat"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; -uniform float hueShift_m < - string label = "Magenta Hue Shift"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; +process { -uniform float global_density < - string label = "Global Density"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; -uniform float global_saturation < - string label = "Global Sat"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -// Tetrahedral interpolation based on the ordering of the input color channels -float3 applyAdjustments(float3 p) { - // Pre-calculate the flipped density values for each channel: - float d_r = -(density_r + global_density); - float d_y = -(density_y + global_density); - float d_g = -(density_g + global_density); - float d_c = -(density_c + global_density); - float d_b = -(density_b + global_density); - float d_m = -(density_m + global_density); - - // Compute the color vectors for each hue region using the flipped densities: - float3 red = float3( - 1.0 + d_r, - d_r - (saturation_r + global_saturation), - d_r + hueShift_r - (saturation_r + global_saturation) - ); - - float3 yellow = float3( - 1.0 + hueShift_y + d_y, - 1.0 + d_y, - d_y - (saturation_y + global_saturation) - ); - - float3 green = float3( - d_g - (saturation_g + global_saturation), - 1.0 + d_g, - d_g + hueShift_g - (saturation_g + global_saturation) - ); - - float3 cyan = float3( - d_c - (saturation_c + global_saturation), - 1.0 + hueShift_c + d_c, - 1.0 + d_c - ); - - float3 blue = float3( - d_b + hueShift_b - (saturation_b + global_saturation), - d_b - (saturation_b + global_saturation), - 1.0 + d_b - ); - - float3 magenta = float3( - 1.0 + d_m, - d_m - (saturation_m + global_saturation), - 1.0 + hueShift_m + d_m - ); - - // Define the black and white endpoints: - float3 blk = float3(0.0, 0.0, 0.0); - float3 wht = float3(1.0, 1.0, 1.0); - - float3 rgb; - if (p.r > p.g) { - if (p.g > p.b) { - // p.r >= p.g >= p.b - rgb = p.r * (red - blk) + blk + p.g * (yellow - red) + p.b * (wht - yellow); - } else if (p.r > p.b) { - // p.r >= p.b > p.g - rgb = p.r * (red - blk) + blk + p.g * (wht - magenta) + p.b * (magenta - red); - } else { - // p.b >= p.r > p.g - rgb = p.r * (magenta - blue) + p.g * (wht - magenta) + p.b * (blue - blk) + blk; - } - } else { - if (p.b > p.g) { - // p.b >= p.g >= p.r - rgb = p.r * (wht - cyan) + p.g * (cyan - blue) + p.b * (blue - blk) + blk; - } else if (p.b > p.r) { - // p.g >= p.r and p.b > p.r - rgb = p.r * (wht - cyan) + p.g * (green - blk) + blk + p.b * (cyan - green); - } else { - // p.g >= p.b >= p.r - rgb = p.r * (yellow - green) + p.g * (green - blk) + blk + p.b * (wht - yellow); + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - } - return clamp(rgb, 0.0, 1.0); -} - -float4 mainImage(VertData v_in) : TARGET { - float4 inputColor = image.Sample(textureSampler, v_in.uv); - float3 adjustedColor = applyAdjustments(inputColor.rgb); - return float4(adjustedColor, inputColor.a); -} -' -} -$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] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } } - 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 = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -13736,242 +9576,204 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSDiffuseTransitionShader { +function Get-OBSStreamStatus { -[Alias('Set-OBSDiffuseTransitionShader','Add-OBSDiffuseTransitionShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetStreamStatus')] +[Alias('obs.powershell.websocket.GetStreamStatus')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the image_a of OBSDiffuseTransitionShader -[Alias('image_a')] -[ComponentModel.DefaultBindingProperty('image_a')] -[String] -$ImageA, -# Set the image_b of OBSDiffuseTransitionShader -[Alias('image_b')] -[ComponentModel.DefaultBindingProperty('image_b')] -[String] -$ImageB, -# Set the transition_time of OBSDiffuseTransitionShader -[Alias('transition_time')] -[ComponentModel.DefaultBindingProperty('transition_time')] -[Single] -$TransitionTime, -# Set the convert_linear of OBSDiffuseTransitionShader -[Alias('convert_linear')] -[ComponentModel.DefaultBindingProperty('convert_linear')] -[Management.Automation.SwitchParameter] -$ConvertLinear, -# Set the num_samples of OBSDiffuseTransitionShader -[Alias('num_samples')] -[ComponentModel.DefaultBindingProperty('num_samples')] -[Int32] -$NumSamples, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'diffuse_transition' -$ShaderNoun = 'OBSDiffuseTransitionShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//based on https://www.shadertoy.com/view/4cK3z1 -uniform texture2d image_a; -uniform texture2d image_b; -uniform float transition_time = 0.5; -uniform bool convert_linear = true; -// Diffuse (move pixels) between two 2D images -// Demo inspired by Iterative-(de)Blending (see Figure 9 in https://arxiv.org/pdf/2305.03486.pdf) -// Note: the approach in this demo is different - rather than randomising paths we use means -// increase for greater precision - this is O(n^2) :( -uniform int num_samples< - string label = "Number of samples (10)"; - string widget_type = "slider"; - int minimum = 2; - int maximum = 100; - int step = 1; -> = 10; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -float4 mainImage(VertData v_in) : TARGET -{ - float2 uv = v_in.uv; - - if (transition_time < 0.00001) { - return image_a.Sample(textureSampler, uv); - } - - // we need to normalise the distributions so just sum the samples for a division later - // note: could calculate this once per image in a buffer or something - float3 from_total = float3(0.0,0.0,0.0); - float3 to_total = float3(0.0,0.0,0.0); + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } - for (int i=0; iAdd|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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -13980,232 +9782,204 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSDigitalRainShader { +function Get-OBSTransitionKind { -[Alias('Set-OBSDigitalRainShader','Add-OBSDigitalRainShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetTransitionKindList')] +[Alias('obs.powershell.websocket.GetTransitionKindList')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the font of OBSDigitalRainShader -[ComponentModel.DefaultBindingProperty('font')] -[String] -$Font, -# Set the noise of OBSDigitalRainShader -[ComponentModel.DefaultBindingProperty('noise')] -[String] -$Noise, -# Set the base_color of OBSDigitalRainShader -[Alias('base_color')] -[ComponentModel.DefaultBindingProperty('base_color')] -[String] -$BaseColor, -# Set the rain_speed of OBSDigitalRainShader -[Alias('rain_speed')] -[ComponentModel.DefaultBindingProperty('rain_speed')] -[Single] -$RainSpeed, -# Set the char_speed of OBSDigitalRainShader -[Alias('char_speed')] -[ComponentModel.DefaultBindingProperty('char_speed')] -[Single] -$CharSpeed, -# Set the glow_contrast of OBSDigitalRainShader -[Alias('glow_contrast')] -[ComponentModel.DefaultBindingProperty('glow_contrast')] -[Single] -$GlowContrast, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'digital-rain' -$ShaderNoun = 'OBSDigitalRainShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// based on https://www.shadertoy.com/view/ldccW4 by WillKirkby -#ifndef OPENGL -#define fract frac -#define mix lerp -#endif + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -uniform texture2d font = "font.png"; -uniform texture2d noise = "noise.png"; -uniform float4 base_color = {.1, 1.0, .35, 1.0}; -uniform float rain_speed< - string label = "Rain Speed"; - string widget_type = "slider"; - float minimum = 0.001; - float maximum = 2.0; - float step = .001; -> = 1.0; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -uniform float char_speed< - string label = "Character Speed"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2.0; - float step = .001; -> = 1.0; + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -uniform float glow_contrast< - string label = "Glow contrast"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2.5; - float step = .001; -> = 1.0; + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -float mod(float x, float y) -{ - return x - y * floor(x/y); } -float2 mod2(float2 x, float2 y) -{ - return x - y * floor(x/y); -} -float text(float2 fragCoord) -{ - float2 uv = mod2(fragCoord, float2(16.0, 16.0) )/16.0; - float2 block = (fragCoord*.0625 - uv)/uv_size*16.0; - uv = uv*.8+.1; // scale the letters up a bit - block += elapsed_time*.002*char_speed; - uv += floor(noise.Sample(textureSampler, fract(block)).xy * 16.); // randomize letters - uv *= .0625; // bring back into 0-1 range - return font.Sample(textureSampler, uv).r; -} +} -float3 rain(float2 fragCoord) -{ - fragCoord.x -= mod(fragCoord.x, 16.); - float offset=sin(fragCoord.x*15.); - float speed=(cos(fragCoord.x*3.)*.3+.7)*rain_speed; - - float y = fract(fragCoord.y/uv_size.y + elapsed_time*speed + offset); - return base_color.rgb / pow(y*20.0, glow_contrast); -} + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSVersion { -float4 mainImage(VertData v_in) : TARGET -{ - return mix(image.Sample(textureSampler, v_in.uv),float4(rain(float2(v_in.uv.x,1.0-v_in.uv.y)*uv_size),1.0), text(v_in.uv*uv_size)); -} -' -} -$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 - } +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetVersion')] +[Alias('obs.powershell.websocket.GetVersion')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -14214,236 +9988,204 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSDivideRotateShader { +function Get-OBSVideoSettings { -[Alias('Set-OBSDivideRotateShader','Add-OBSDivideRotateShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetVideoSettings')] +[Alias('obs.powershell.websocket.GetVideoSettings')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the iChannel0 of OBSDivideRotateShader -[ComponentModel.DefaultBindingProperty('iChannel0')] -[String] -$IChannel0, -# Set the speed_percentage of OBSDivideRotateShader -[Alias('speed_percentage')] -[ComponentModel.DefaultBindingProperty('speed_percentage')] -[Int32] -$SpeedPercentage, -# Set the alpha_percentage of OBSDivideRotateShader -[Alias('alpha_percentage')] -[ComponentModel.DefaultBindingProperty('alpha_percentage')] -[Int32] -$AlphaPercentage, -# Set the Apply_To_Alpha_Layer of OBSDivideRotateShader -[Alias('Apply_To_Alpha_Layer')] -[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] -[Management.Automation.SwitchParameter] -$ApplyToAlphaLayer, -# Set the notes of OBSDivideRotateShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'divide_rotate' -$ShaderNoun = 'OBSDivideRotateShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// divide and rotate shader for OBS Studio shaderfilter plugin -// originally from shadertoy (https://www.shadertoy.com/view/3sy3Dh) -// Modified by Charles Fettinger (https://github.com/Oncorporation) 10/2019 -//Converted to OpenGL by Q-mii & Exeldro February 18, 2022 -uniform texture2d iChannel0; -uniform int speed_percentage< - string label = "Speed"; - string widget_type = "slider"; - int minimum = -10; - int maximum = 10; - int step = 1; -> = 5; -uniform int alpha_percentage< - string label = "Opacity Percentage"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; -uniform bool Apply_To_Alpha_Layer = true; -uniform string notes< - string widget_type = "info"; -> = "add rotation and speed"; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -float2 cm(float2 a, float2 b) { - return float2(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x); -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -float2 iter(float2 uv, float2 rot, float scale) { - float2 gv = frac(cm(uv, rot) * scale); - float boundDist = 1. - max(abs(gv.x), abs(gv.y)); - float mask = step(.03, boundDist); - gv *= mask; - return gv; -} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -float4 mainImage(VertData v_in) : TARGET -{ - float alpha = clamp(alpha_percentage * 0.01, 0.0, 1.0); - float speed = clamp(speed_percentage * 0.01, -10.0, 10.0); + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } - // Normalize coords - //float2 uv = (v_in.uv * uv_scale + uv_offset); - float2 uv = (float2(v_in.uv.x, (1 - v_in.uv.y)) * uv_scale + uv_offset) - .5 * (v_in.uv * uv_scale + uv_offset);// / v_in.uv.y; - float2 mouse = (v_in.uv.xy - .5 * v_in.uv.xy) / v_in.uv.y; + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } - // Add some time rotation and offset - float t = elapsed_time * speed; - float2 time = float2(sin(t), cos(t)); - uv += time; +} - // Imaginary component has to be mirrored for natural feeling rotation - mouse.y *= -1.0; - // Draw few layers of this to bend space - float2 rot = cm(mouse, time); - for (float i=1.0; i<=3.0; i++) { - uv = iter(uv, rot, 1.5); - } +} - // Combine background with new image - float4 background_color = image.Sample(textureSampler, v_in.uv); - float4 col = iChannel0.Sample(textureSampler, uv); + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSVirtualCamStatus { - // Border - if (uv.x == 0.0 && uv.y == 0.0) { - col = float4(0,0,0,alpha); - } - // if not appling to alpha layer, set output alpha - if (Apply_To_Alpha_Layer == false) - col.a = alpha; +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetVirtualCamStatus')] +[Alias('obs.powershell.websocket.GetVirtualCamStatus')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - //output color is combined with background image - col.rgb = lerp(background_color.rgb,col.rgb,clamp(alpha, 0.0, 1.0)); - return col; -} -' -} -$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 - } - } +process { - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName - } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -14452,271 +10194,222 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSDoodleShader { +function Open-OBSInputFiltersDialog { -[Alias('Set-OBSDoodleShader','Add-OBSDoodleShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'OpenInputFiltersDialog')] +[Alias('obs.powershell.websocket.OpenInputFiltersDialog')] param( -# Set the ViewProj of OBSDoodleShader -[ComponentModel.DefaultBindingProperty('ViewProj')] -[Single[][]] -$ViewProj, -# Set the image of OBSDoodleShader -[ComponentModel.DefaultBindingProperty('image')] -[String] -$Image, -# Set the elapsed_time of OBSDoodleShader -[Alias('elapsed_time')] -[ComponentModel.DefaultBindingProperty('elapsed_time')] -[Single] -$ElapsedTime, -# Set the uv_offset of OBSDoodleShader -[Alias('uv_offset')] -[ComponentModel.DefaultBindingProperty('uv_offset')] -[Single[]] -$UvOffset, -# Set the uv_scale of OBSDoodleShader -[Alias('uv_scale')] -[ComponentModel.DefaultBindingProperty('uv_scale')] -[Single[]] -$UvScale, -# Set the uv_pixel_interval of OBSDoodleShader -[Alias('uv_pixel_interval')] -[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] -[Single[]] -$UvPixelInterval, -# Set the rand_f of OBSDoodleShader -[Alias('rand_f')] -[ComponentModel.DefaultBindingProperty('rand_f')] -[Single] -$RandF, -# Set the uv_size of OBSDoodleShader -[Alias('uv_size')] -[ComponentModel.DefaultBindingProperty('uv_size')] -[Single[]] -$UvSize, -# Set the Doodle_Scale_Percent of OBSDoodleShader -[Alias('Doodle_Scale_Percent')] -[ComponentModel.DefaultBindingProperty('Doodle_Scale_Percent')] -[Single] -$DoodleScalePercent, -# Set the Snap_Percent of OBSDoodleShader -[Alias('Snap_Percent')] -[ComponentModel.DefaultBindingProperty('Snap_Percent')] -[Single] -$SnapPercent, -# Set the Notes of OBSDoodleShader -[ComponentModel.DefaultBindingProperty('Notes')] -[String] -$Notes, -# 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. +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + [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] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'doodle' -$ShaderNoun = 'OBSDoodleShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// doodle effect by Charles Fettinger (https://github.com/Oncorporation) 5/2019 -// for use with obs-shaderfilter 1.0 -uniform float4x4 ViewProj; -uniform texture2d image; -uniform float elapsed_time; -uniform float2 uv_offset; -uniform float2 uv_scale; -uniform float2 uv_pixel_interval; -uniform float rand_f; -uniform float2 uv_size; -uniform float Doodle_Scale_Percent< - string label = "Doodle Scale Percent"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.1; -> = 2.5; -uniform float Snap_Percent< - string label = "Snap Percent"; - string widget_type = "slider"; - float minimum = 1.0; - float maximum = 100.0; - float step = 0.1; -> = 7.5; -uniform string Notes< - string widget_type = "info"; -> = "Doodle skews the image by the Scale Percent, Snap Percent controls the number of doodles per second."; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -sampler_state textureSampler { - Filter = Linear; - AddressU = Border; - AddressV = Border; - BorderColor = 00000000; -}; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -struct VertData { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -float3 rand3(float3 co) -{ - float j = 4096.0*sin(dot(co, float3(17.0, 59.4, 15.0))); - float3 result; - result.z = frac(512.0*j); - j *= .125; - result.x = frac(512.0*j); - j *= .125; - result.y = frac(512.0*j); - return result - 0.5; -} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } + + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -float snap(float x, float snap) -{ - return snap * round(x / max(0.01,snap)); } -VertData mainTransform(VertData v_in) -{ - VertData vert_out; - vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); - vert_out.uv = v_in.uv * uv_scale + uv_offset; - float time = snap((1 + sin(elapsed_time)) * 0.5, Snap_Percent * .01); - float rand = snap(rand_f, Snap_Percent *.01); - float2 noise = rand3(v_in.pos.xyz + float3(time,0.0,0.0)).xy * (Doodle_Scale_Percent * .01); - vert_out.uv.xy += noise; - return vert_out; -} +} -float4 mainImage(VertData v_in) : TARGET -{ - return image.Sample(textureSampler, v_in.uv); -} + +#.ExternalHelp obs-powershell-Help.xml +function Open-OBSInputInteractDialog { -technique Draw -{ - pass p0 - { - vertex_shader = mainTransform(v_in); - pixel_shader = mainImage(v_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 - } - } +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'OpenInputInteractDialog')] +[Alias('obs.powershell.websocket.OpenInputInteractDialog')] +param( - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName - } +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -14725,275 +10418,110 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSDrawingsShader { +function Open-OBSInputPropertiesDialog { -[Alias('Set-OBSDrawingsShader','Add-OBSDrawingsShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'OpenInputPropertiesDialog')] +[Alias('obs.powershell.websocket.OpenInputPropertiesDialog')] param( -# Set the AngleNum of OBSDrawingsShader -[ComponentModel.DefaultBindingProperty('AngleNum')] -[Int32] -$AngleNum, -# Set the SampNum of OBSDrawingsShader -[ComponentModel.DefaultBindingProperty('SampNum')] -[Int32] -$SampNum, -# 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. +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + [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] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'drawings' -$ShaderNoun = 'OBSDrawingsShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//based on https://www.shadertoy.com/view/ldlcWs -uniform int AngleNum< - string label = "Number of angles"; - string widget_type = "slider"; - int minimum = 0.0; - int maximum = 25; - int step = 1; -> = 3; -uniform int SampNum< - string label = "Number of samples"; - string widget_type = "slider"; - int minimum = 0.0; - int maximum = 25; - int step = 1; -> = 9; -float4 getCol(float2 pos) -{ - // take aspect ratio into account - float2 uv=pos; - float4 c1=image.Sample(textureSampler, uv); - float4 e=smoothstep(float4(-0.05,-0.05,-0.05,-0.05),float4(-0.0,-0.0,-0.0,-0.0),float4(uv,float2(1,1)-uv)); - c1=lerp(float4(1,1,1,0),c1,e.x*e.y*e.z*e.w); - float d=clamp(dot(c1.xyz,float3(-.5,1.,-.5)),0.0,1.0); - float4 c2=float4(.7,.7,.7,.7); - return min(lerp(c1,c2,1.8*d),.7); -} + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -float4 getColHT(float2 pos) -{ - return smoothstep(0.795,1.05,getCol(pos)*.8+.2+1.0); -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -float getVal(float2 pos) -{ - float4 c=getCol(pos); - return pow(dot(c.xyz,float3(.333,.333,.333)),1.)*1.; -} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -float2 getGrad(float2 pos, float eps) -{ - float2 d=float2(eps,0.); - return float2( - getVal(pos+d.xy)-getVal(pos-d.xy), - getVal(pos+d.yx)-getVal(pos-d.yx) - )/eps/2.; -} - - - float lum( float3 c) { - return dot(c, float3(0.3, 0.59, 0.11)); - } - - - float3 clipcolor( float3 c) { - float l = lum(c); - float n = min(min(c.r, c.g), c.b); - float x = max(max(c.r, c.g), c.b); - - if (n < 0.0) { - c.r = l + ((c.r - l) * l) / (l - n); - c.g = l + ((c.g - l) * l) / (l - n); - c.b = l + ((c.b - l) * l) / (l - n); - } - if (x > 1.25) { - c.r = l + ((c.r - l) * (1.0 - l)) / (x - l); - c.g = l + ((c.g - l) * (1.0 - l)) / (x - l); - c.b = l + ((c.b - l) * (1.0 - l)) / (x - l); - } - return c; - } - - float3 setlum( float3 c, float l) { - float d = l - lum(c); - c = c + float3(d,d,d); - return clipcolor(0.85*c); - } - -float4 mainImage(VertData v_in) : TARGET -{ - float2 pos = v_in.uv; - float3 col = float3(0,0,0); - float3 col2 = float3(0,0,0); - float sum=0.; - - for(int i=0;iAdd|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] + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam } - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -15002,218 +10530,120 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSDropShadowShader { +function Open-OBSSourceProjector { -[Alias('Set-OBSDropShadowShader','Add-OBSDropShadowShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'OpenSourceProjector')] +[Alias('obs.powershell.websocket.OpenSourceProjector')] param( -# Set the shadow_offset_x of OBSDropShadowShader -[Alias('shadow_offset_x')] -[ComponentModel.DefaultBindingProperty('shadow_offset_x')] -[Int32] -$ShadowOffsetX, -# Set the shadow_offset_y of OBSDropShadowShader -[Alias('shadow_offset_y')] -[ComponentModel.DefaultBindingProperty('shadow_offset_y')] -[Int32] -$ShadowOffsetY, -# Set the shadow_blur_size of OBSDropShadowShader -[Alias('shadow_blur_size')] -[ComponentModel.DefaultBindingProperty('shadow_blur_size')] -[Int32] -$ShadowBlurSize, -# Set the notes of OBSDropShadowShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# Set the shadow_color of OBSDropShadowShader -[Alias('shadow_color')] -[ComponentModel.DefaultBindingProperty('shadow_color')] -[String] -$ShadowColor, -# Set the is_alpha_premultiplied of OBSDropShadowShader -[Alias('is_alpha_premultiplied')] -[ComponentModel.DefaultBindingProperty('is_alpha_premultiplied')] -[Management.Automation.SwitchParameter] -$IsAlphaPremultiplied, -# The name of the source. This must be provided when adding an item for the first time + [Parameter(ValueFromPipelineByPropertyName)] -[Alias('SceneItemName')] -[String] +[ComponentModel.DefaultBindingProperty('sourceName')] +[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] +[ComponentModel.DefaultBindingProperty('sourceUuid')] +[string] +$SourceUuid, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('monitorIndex')] +[double] +$MonitorIndex, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('projectorGeometry')] +[string] +$ProjectorGeometry, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'drop_shadow' -$ShaderNoun = 'OBSDropShadowShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Drop Shadow shader modified by Charles Fettinger -// impose a limiter to keep from crashing the system -//Converted to OpenGL by Exeldro February 19, 2022 -uniform int shadow_offset_x< - string label = "Shadow offset x"; - string widget_type = "slider"; - int minimum = -100; - int maximum = 100; - int step = 1; -> = 5; -uniform int shadow_offset_y< - string label = "Shadow offset y"; - string widget_type = "slider"; - int minimum = -100; - int maximum = 100; - int step = 1; -> = 5; -uniform int shadow_blur_size< - string label = "Shadow blur size"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 15; - int step = 1; -> = 3; -uniform string notes< - string widget_type = "info"; -> = "blur size is limited to a max of 15 to ensure GPU"; -uniform float4 shadow_color; -uniform bool is_alpha_premultiplied; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -float4 mainImage(VertData v_in) : TARGET -{ - int shadow_blur_size_limited = max(0, min(15, shadow_blur_size)); - int shadow_blur_samples = int(pow(float(shadow_blur_size_limited * 2 + 1), 2.0)); - - float4 color = image.Sample(textureSampler, v_in.uv); - float2 shadow_uv = float2(v_in.uv.x - uv_pixel_interval.x * float(shadow_offset_x), - v_in.uv.y - uv_pixel_interval.y * float(shadow_offset_y)); - - float sampled_shadow_alpha = 0.0; - - for (int blur_x = -shadow_blur_size_limited; blur_x <= shadow_blur_size_limited; blur_x++) - { - for (int blur_y = -shadow_blur_size_limited; blur_y <= shadow_blur_size_limited; blur_y++) - { - float2 blur_uv = shadow_uv + float2(uv_pixel_interval.x * float(blur_x), uv_pixel_interval.y * float(blur_y)); - sampled_shadow_alpha += image.Sample(textureSampler, blur_uv).a / float(shadow_blur_samples); + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - } - - float4 final_shadow_color = float4(shadow_color.r, shadow_color.g, shadow_color.b, shadow_color.a * sampled_shadow_alpha); - return final_shadow_color * (1.0-color.a) + color * (is_alpha_premultiplied?color.a:1.0); -} -' -} -$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] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } } - 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 = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -15222,336 +10652,227 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSDrunkShader { +function Open-OBSVideoMixProjector { -[Alias('Set-OBSDrunkShader','Add-OBSDrunkShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'OpenVideoMixProjector')] +[Alias('obs.powershell.websocket.OpenVideoMixProjector')] param( -# Set the color_matrix of OBSDrunkShader -[Alias('color_matrix')] -[ComponentModel.DefaultBindingProperty('color_matrix')] -[Single[][]] -$ColorMatrix, -# Set the glow_percent of OBSDrunkShader -[Alias('glow_percent')] -[ComponentModel.DefaultBindingProperty('glow_percent')] -[Int32] -$GlowPercent, -# Set the blur of OBSDrunkShader -[ComponentModel.DefaultBindingProperty('blur')] -[Int32] -$Blur, -# Set the min_brightness of OBSDrunkShader -[Alias('min_brightness')] -[ComponentModel.DefaultBindingProperty('min_brightness')] -[Int32] -$MinBrightness, -# Set the max_brightness of OBSDrunkShader -[Alias('max_brightness')] -[ComponentModel.DefaultBindingProperty('max_brightness')] -[Int32] -$MaxBrightness, -# Set the pulse_speed_percent of OBSDrunkShader -[Alias('pulse_speed_percent')] -[ComponentModel.DefaultBindingProperty('pulse_speed_percent')] -[Int32] -$PulseSpeedPercent, -# Set the Apply_To_Alpha_Layer of OBSDrunkShader -[Alias('Apply_To_Alpha_Layer')] -[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] -[Management.Automation.SwitchParameter] -$ApplyToAlphaLayer, -# Set the glow_color of OBSDrunkShader -[Alias('glow_color')] -[ComponentModel.DefaultBindingProperty('glow_color')] -[String] -$GlowColor, -# Set the ease of OBSDrunkShader -[ComponentModel.DefaultBindingProperty('ease')] -[Management.Automation.SwitchParameter] -$Ease, -# Set the glitch of OBSDrunkShader -[ComponentModel.DefaultBindingProperty('glitch')] -[Management.Automation.SwitchParameter] -$Glitch, -# Set the notes of OBSDrunkShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# The name of the source. This must be provided when adding an item for the first time + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('videoMixType')] +[string] +$VideoMixType, + [Parameter(ValueFromPipelineByPropertyName)] -[Alias('SceneItemName')] -[String] -$SourceName, -# The name of the filter. If this is not provided, this will default to the shader name. +[ComponentModel.DefaultBindingProperty('monitorIndex')] +[double] +$MonitorIndex, + [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] +[ComponentModel.DefaultBindingProperty('projectorGeometry')] +[string] +$ProjectorGeometry, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'drunk' -$ShaderNoun = 'OBSDrunkShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Drunk shader by Charles Fettinger (https://github.com/Oncorporation) 2/2019 -//Converted to OpenGL by Q-mii & Exeldro March 11, 2022 -uniform float4x4 color_matrix; - -uniform int glow_percent< - string label = "Glow percent"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 10; -uniform int blur< - string label = "Blur"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 1; -uniform int min_brightness< - string label = "Min brightness"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 27; -uniform int max_brightness< - string label = "Max brightness"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 100; -uniform int pulse_speed_percent< - string label = "Pulse speed percent"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 0; -uniform bool Apply_To_Alpha_Layer = true; -uniform float4 glow_color; -uniform bool ease; -uniform bool glitch; -uniform string notes< - string widget_type = "info"; -> ="''drunk refers to the bad blur effect of using 4 coordinates to blur. ''blur'' - the distance between the 4 copies (recommend 1-4)"; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -// Gaussian Blur -float Gaussian(float x, float o) { - const float pivalue = 3.1415926535897932384626433832795; - return (1.0 / (o * sqrt(2.0 * pivalue))) * exp((-(x * x)) / (2 * (o * o))); -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -float EaseInOutCircTimer(float t,float b,float c,float d){ - t /= d/2; - if (t < 1) return -c/2 * (sqrt(1 - t*t) - 1) + b; - t -= 2; - return c/2 * (sqrt(1 - t*t) + 1) + b; -} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -float BlurStyler(float t,float b,float c,float d,bool ease) -{ - if (ease) return EaseInOutCircTimer(t,0,c,d); - return t; -} + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -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 mainImage(VertData v_in) : TARGET -{ - float2 offsets[4]; - offsets[0] = float2(-0.05, 0.066); - offsets[1] = float2(-0.05, -0.066); - offsets[2] = float2(0.05, -0.066); - offsets[3] = float2(0.05, 0.066); - // convert input for vector math - float blur_amount = float(blur) /100; - float glow_amount = float(glow_percent) * 0.1; - float speed = float(pulse_speed_percent) * 0.01; - float luminance_floor = float(min_brightness) * 0.01; - float luminance_ceiling = float(max_brightness) * 0.01; +} - float4 color = image.Sample(textureSampler, v_in.uv); - float4 temp_color = color; - bool glitch_on = glitch; + +#.ExternalHelp obs-powershell-Help.xml +function Remove-OBSInput { - //circular easing variable - float t = 1 + sin(elapsed_time * speed); - float b = 0.0; //start value - float c = 2.0; //change value - float d = 2.0; //duration - //if(color.a <= 0.0) color.rgb = float3(0.0,0.0,0.0); - float4 glitch_color = glow_color; +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'RemoveInput')] +[Alias('obs.powershell.websocket.RemoveInput')] +param( - for (int n = 0; n < 4; n++){ - //blur sample - b = BlurStyler(t,0,c,d,ease); - float4 ncolor = image.Sample(textureSampler, v_in.uv + (blur_amount * b) * offsets[n]) ; +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, - //test for rand_f color - if (glitch) { - glitch_color = float4(glow_color.rgb * rand_f,glow_color.a); - if ((color.r == rand_f) || (color.g == rand_f) || (color.b == rand_f)) - { - glitch_on = true; - } - } +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - float intensity = ncolor.r * 0.299 + ncolor.g * 0.587 + ncolor.b * 0.114; - if (((intensity >= luminance_floor) && (intensity <= luminance_ceiling)) || // test luminance - ((color.r == glow_color.r) && (color.g == glow_color.g) && (color.b == glow_color.b)) || //test for chosen color - glitch_on) //test for rand color - { - //glow calc - if (ncolor.a > 0.0 || Apply_To_Alpha_Layer == false) - { - ncolor.a = clamp(ncolor.a * glow_amount, 0.0, 1.0); - //temp_color = max(temp_color,ncolor) * glow_color ;//* ((1-ncolor.a) + color * ncolor.a); - //temp_color += (ncolor * float4(glow_color.rbg, glow_amount)); - // use temp_color as floor, add glow, use highest alpha of blur pixels, then multiply by glow color - // max is used to simulate addition of vector texture color - temp_color = float4(max(temp_color.rgb, ncolor.rgb * (glow_amount * (b / 2))), // color effected by glow over time - max(temp_color.a, (glow_amount * (b / 2)))) // alpha affected by glow over time - * (glitch_color * (b / 2)); // glow color affected by glow over time - } - } - } - // grab lighter color - return max(color,temp_color); -} +process { -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -15560,470 +10881,105 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSDynamicMaskShader { +function Remove-OBSProfile { -[Alias('Set-OBSDynamicMaskShader','Add-OBSDynamicMaskShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'RemoveProfile')] +[Alias('obs.powershell.websocket.RemoveProfile')] param( -# Set the input_source of OBSDynamicMaskShader -[Alias('input_source')] -[ComponentModel.DefaultBindingProperty('input_source')] -[String] -$InputSource, -# Set the red_base_value of OBSDynamicMaskShader -[Alias('red_base_value')] -[ComponentModel.DefaultBindingProperty('red_base_value')] -[Single] -$RedBaseValue, -# Set the red_red_input_value of OBSDynamicMaskShader -[Alias('red_red_input_value')] -[ComponentModel.DefaultBindingProperty('red_red_input_value')] -[Single] -$RedRedInputValue, -# Set the red_green_input_value of OBSDynamicMaskShader -[Alias('red_green_input_value')] -[ComponentModel.DefaultBindingProperty('red_green_input_value')] -[Single] -$RedGreenInputValue, -# Set the red_blue_input_value of OBSDynamicMaskShader -[Alias('red_blue_input_value')] -[ComponentModel.DefaultBindingProperty('red_blue_input_value')] -[Single] -$RedBlueInputValue, -# Set the red_alpha_input_value of OBSDynamicMaskShader -[Alias('red_alpha_input_value')] -[ComponentModel.DefaultBindingProperty('red_alpha_input_value')] -[Single] -$RedAlphaInputValue, -# Set the red_multiplier of OBSDynamicMaskShader -[Alias('red_multiplier')] -[ComponentModel.DefaultBindingProperty('red_multiplier')] -[Single] -$RedMultiplier, -# Set the green_base_value of OBSDynamicMaskShader -[Alias('green_base_value')] -[ComponentModel.DefaultBindingProperty('green_base_value')] -[Single] -$GreenBaseValue, -# Set the green_red_input_value of OBSDynamicMaskShader -[Alias('green_red_input_value')] -[ComponentModel.DefaultBindingProperty('green_red_input_value')] -[Single] -$GreenRedInputValue, -# Set the green_green_input_value of OBSDynamicMaskShader -[Alias('green_green_input_value')] -[ComponentModel.DefaultBindingProperty('green_green_input_value')] -[Single] -$GreenGreenInputValue, -# Set the green_blue_input_value of OBSDynamicMaskShader -[Alias('green_blue_input_value')] -[ComponentModel.DefaultBindingProperty('green_blue_input_value')] -[Single] -$GreenBlueInputValue, -# Set the green_alpha_input_value of OBSDynamicMaskShader -[Alias('green_alpha_input_value')] -[ComponentModel.DefaultBindingProperty('green_alpha_input_value')] -[Single] -$GreenAlphaInputValue, -# Set the green_multiplier of OBSDynamicMaskShader -[Alias('green_multiplier')] -[ComponentModel.DefaultBindingProperty('green_multiplier')] -[Single] -$GreenMultiplier, -# Set the blue_base_value of OBSDynamicMaskShader -[Alias('blue_base_value')] -[ComponentModel.DefaultBindingProperty('blue_base_value')] -[Single] -$BlueBaseValue, -# Set the blue_red_input_value of OBSDynamicMaskShader -[Alias('blue_red_input_value')] -[ComponentModel.DefaultBindingProperty('blue_red_input_value')] -[Single] -$BlueRedInputValue, -# Set the blue_green_input_value of OBSDynamicMaskShader -[Alias('blue_green_input_value')] -[ComponentModel.DefaultBindingProperty('blue_green_input_value')] -[Single] -$BlueGreenInputValue, -# Set the blue_blue_input_value of OBSDynamicMaskShader -[Alias('blue_blue_input_value')] -[ComponentModel.DefaultBindingProperty('blue_blue_input_value')] -[Single] -$BlueBlueInputValue, -# Set the blue_alpha_input_value of OBSDynamicMaskShader -[Alias('blue_alpha_input_value')] -[ComponentModel.DefaultBindingProperty('blue_alpha_input_value')] -[Single] -$BlueAlphaInputValue, -# Set the blue_multiplier of OBSDynamicMaskShader -[Alias('blue_multiplier')] -[ComponentModel.DefaultBindingProperty('blue_multiplier')] -[Single] -$BlueMultiplier, -# Set the alpha_base_value of OBSDynamicMaskShader -[Alias('alpha_base_value')] -[ComponentModel.DefaultBindingProperty('alpha_base_value')] -[Single] -$AlphaBaseValue, -# Set the alpha_red_input_value of OBSDynamicMaskShader -[Alias('alpha_red_input_value')] -[ComponentModel.DefaultBindingProperty('alpha_red_input_value')] -[Single] -$AlphaRedInputValue, -# Set the alpha_green_input_value of OBSDynamicMaskShader -[Alias('alpha_green_input_value')] -[ComponentModel.DefaultBindingProperty('alpha_green_input_value')] -[Single] -$AlphaGreenInputValue, -# Set the alpha_blue_input_value of OBSDynamicMaskShader -[Alias('alpha_blue_input_value')] -[ComponentModel.DefaultBindingProperty('alpha_blue_input_value')] -[Single] -$AlphaBlueInputValue, -# Set the alpha_alpha_input_value of OBSDynamicMaskShader -[Alias('alpha_alpha_input_value')] -[ComponentModel.DefaultBindingProperty('alpha_alpha_input_value')] -[Single] -$AlphaAlphaInputValue, -# Set the alpha_multiplier of OBSDynamicMaskShader -[Alias('alpha_multiplier')] -[ComponentModel.DefaultBindingProperty('alpha_multiplier')] -[Single] -$AlphaMultiplier, -# 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(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('profileName')] +[string] +$ProfileName, +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'dynamic-mask' -$ShaderNoun = 'OBSDynamicMaskShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform texture2d input_source< - string label = "Input Source"; ->; - -uniform float red_base_value< - string label = "Base Value"; - string widget_type = "slider"; - string group = "Red Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 1.0; -uniform float red_red_input_value< - string label = "Red Input Value"; - string widget_type = "slider"; - string group = "Red Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 0.0; -uniform float red_green_input_value< - string label = "Green Input Value"; - string widget_type = "slider"; - string group = "Red Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 0.0; -uniform float red_blue_input_value< - string label = "Blue Input Value"; - string widget_type = "slider"; - string group = "Red Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 0.0; -uniform float red_alpha_input_value< - string label = "Alpha Input Value"; - string widget_type = "slider"; - string group = "Red Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 0.0; -uniform float red_multiplier< - string label = "Multiplier"; - string widget_type = "slider"; - string group = "Red Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 1.0; - -uniform float green_base_value< - string label = "Base Value"; - string widget_type = "slider"; - string group = "Green Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 1.0; -uniform float green_red_input_value< - string label = "Red Input Value"; - string widget_type = "slider"; - string group = "Green Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 0.0; -uniform float green_green_input_value< - string label = "Green Input Value"; - string widget_type = "slider"; - string group = "Green Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 0.0; -uniform float green_blue_input_value< - string label = "Blue Input Value"; - string widget_type = "slider"; - string group = "Green Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 0.0; -uniform float green_alpha_input_value< - string label = "Alpha Input Value"; - string widget_type = "slider"; - string group = "Green Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 0.0; -uniform float green_multiplier< - string label = "Multiplier"; - string widget_type = "slider"; - string group = "Green Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 1.0; - -uniform float blue_base_value< - string label = "Base Value"; - string widget_type = "slider"; - string group = "Blue Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 1.0; -uniform float blue_red_input_value< - string label = "Red Input Value"; - string widget_type = "slider"; - string group = "Blue Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 0.0; -uniform float blue_green_input_value< - string label = "Green Input Value"; - string widget_type = "slider"; - string group = "Blue Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 0.0; -uniform float blue_blue_input_value< - string label = "Blue Input Value"; - string widget_type = "slider"; - string group = "Blue Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 0.0; -uniform float blue_alpha_input_value< - string label = "Alpha Input Value"; - string widget_type = "slider"; - string group = "Blue Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 0.0; -uniform float blue_multiplier< - string label = "Multiplier"; - string widget_type = "slider"; - string group = "Blue Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 1.0; - -uniform float alpha_base_value< - string label = "Base Value"; - string widget_type = "slider"; - string group = "Alpha Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 1.0; -uniform float alpha_red_input_value< - string label = "Red Input Value"; - string widget_type = "slider"; - string group = "Alpha Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 0.0; -uniform float alpha_green_input_value< - string label = "Green Input Value"; - string widget_type = "slider"; - string group = "Alpha Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 0.0; -uniform float alpha_blue_input_value< - string label = "Blue Input Value"; - string widget_type = "slider"; - string group = "Alpha Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 0.0; -uniform float alpha_alpha_input_value< - string label = "Alpha Input Value"; - string widget_type = "slider"; - string group = "Alpha Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 0.0; -uniform float alpha_multiplier< - string label = "Multiplier"; - string widget_type = "slider"; - string group = "Alpha Channel"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 1.0; -float4 mainImage(VertData v_in) : TARGET -{ - float4 input_color = input_source.Sample(textureSampler, v_in.uv); - float4 mask; - mask.r = (red_base_value + red_red_input_value * input_color.r + red_green_input_value * input_color.g + red_blue_input_value * input_color.b + red_alpha_input_value * input_color.a) * red_multiplier; - mask.g = (green_base_value + green_red_input_value * input_color.r + green_green_input_value * input_color.g + green_blue_input_value * input_color.b + green_alpha_input_value * input_color.a) * green_multiplier; - mask.b = (blue_base_value + blue_red_input_value * input_color.r + blue_green_input_value * input_color.g + blue_blue_input_value * input_color.b + blue_alpha_input_value * input_color.a) * blue_multiplier; - mask.a = (alpha_base_value + alpha_red_input_value * input_color.r + alpha_green_input_value * input_color.g + alpha_blue_input_value * input_color.b + alpha_alpha_input_value * input_color.a) * alpha_multiplier; - float4 base = image.Sample(textureSampler, v_in.uv); - return base * mask; -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -16032,278 +10988,110 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSEdgeDetectionShader { +function Remove-OBSScene { -[Alias('Set-OBSEdgeDetectionShader','Add-OBSEdgeDetectionShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'RemoveScene')] +[Alias('obs.powershell.websocket.RemoveScene')] param( -# Set the sensitivity of OBSEdgeDetectionShader -[ComponentModel.DefaultBindingProperty('sensitivity')] -[Single] -$Sensitivity, -# Set the invert_edge of OBSEdgeDetectionShader -[Alias('invert_edge')] -[ComponentModel.DefaultBindingProperty('invert_edge')] -[Management.Automation.SwitchParameter] -$InvertEdge, -# Set the edge_color of OBSEdgeDetectionShader -[Alias('edge_color')] -[ComponentModel.DefaultBindingProperty('edge_color')] -[String] -$EdgeColor, -# Set the edge_multiply of OBSEdgeDetectionShader -[Alias('edge_multiply')] -[ComponentModel.DefaultBindingProperty('edge_multiply')] -[Management.Automation.SwitchParameter] -$EdgeMultiply, -# Set the non_edge_color of OBSEdgeDetectionShader -[Alias('non_edge_color')] -[ComponentModel.DefaultBindingProperty('non_edge_color')] -[String] -$NonEdgeColor, -# Set the non_edge_multiply of OBSEdgeDetectionShader -[Alias('non_edge_multiply')] -[ComponentModel.DefaultBindingProperty('non_edge_multiply')] -[Management.Automation.SwitchParameter] -$NonEdgeMultiply, -# Set the alpha_channel of OBSEdgeDetectionShader -[Alias('alpha_channel')] -[ComponentModel.DefaultBindingProperty('alpha_channel')] -[Management.Automation.SwitchParameter] -$AlphaChannel, -# Set the alpha_level of OBSEdgeDetectionShader -[Alias('alpha_level')] -[ComponentModel.DefaultBindingProperty('alpha_level')] -[Single] -$AlphaLevel, -# Set the alpha_invert of OBSEdgeDetectionShader -[Alias('alpha_invert')] -[ComponentModel.DefaultBindingProperty('alpha_invert')] -[Management.Automation.SwitchParameter] -$AlphaInvert, -# Set the rand_f of OBSEdgeDetectionShader -[Alias('rand_f')] -[ComponentModel.DefaultBindingProperty('rand_f')] -[Single] -$RandF, -# Set the notes of OBSEdgeDetectionShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# 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. +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, + [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] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'edge_detection' -$ShaderNoun = 'OBSEdgeDetectionShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Edge Detection for OBS Studio -// originally from Andersama (https://github.com/Andersama) -// Modified and improved my Charles Fettinger (https://github.com/Oncorporation) 1/2019 -//Converted to OpenGL by Q-mii & Exeldro March 8, 2022 -uniform float sensitivity< - string label = "Sensitivity"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.05; -uniform bool invert_edge; -uniform float4 edge_color = {1.0,1.0,1.0,1.0}; -uniform bool edge_multiply; -uniform float4 non_edge_color = {0.0,0.0,0.0,0.0}; -uniform bool non_edge_multiply; -uniform bool alpha_channel; -uniform float alpha_level< - string label = "Alpha level"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 1.0; -> = 100.0; -uniform bool alpha_invert; -uniform float rand_f; - -uniform string notes< - string widget_type = "info"; -> = "''sensitivity'' - 0.01 is max and will create the most edges. Increasing this value decreases the number of edges detected. ''edge non edge color'' - the color to recolor vs the original image. ''edge or non edge multiply'' - multiplies the color against the original color giving it a tint instead of replacing the color. White represents no tint. ''invert edge'' - flips the sensativity and is great for testing and fine tuning. ''alpha channel'' - use an alpha channel to replace original color with transparency. ''alpha_level'' - transparency amount modifier where 1.0 = base luminance (recommend 0.00 - 2.00). ''alpha_invert'' - flip what is transparent from darks (default) to lights"; - -float4 mainImage(VertData v_in) : TARGET -{ - float4 c = image.Sample(textureSampler, v_in.uv); - - float s = 3; - float hstep = uv_pixel_interval.x; - float vstep = uv_pixel_interval.y; - - float offsetx = (hstep * s) / 2.0; - float offsety = (vstep * s) / 2.0; - - float4 lum = float4(0.30, 0.59, 0.11, 1 ); - float samples[9]; - - int index = 0; - for(int i = 0; i < s; i++){ - for(int j = 0; j < s; j++){ - samples[index] = dot(image.Sample(textureSampler, float2(v_in.uv.x + (i * hstep) - offsetx, v_in.uv.y + (j * vstep) - offsety )), lum); - index++; - } - } - - float vert = samples[2] + samples[8] + (2 * samples[5]) - samples[0] - (2 * samples[3]) - samples[6]; - float hori = samples[6] + (2 * samples[7]) + samples[8] - samples[0] - (2 * samples[1]) - samples[2]; - float4 col; - - float o = ((vert * vert) + (hori * hori)); - bool isEdge = o > sensitivity; - if(invert_edge){ - isEdge = !isEdge; - } - if(isEdge) { - col = edge_color; - if(edge_multiply){ - col *= c; - } - } else { - col = non_edge_color; - if(non_edge_multiply){ - col *= c; - } - } - - if (alpha_invert) { - lum = 1.0 - lum; - } - if(alpha_channel){ - if (edge_multiply && isEdge) { - return clamp(lerp(c, col, alpha_level), 0.0, 1.0); - } - else { - // use max instead of multiply - return clamp(lerp(c, float4(max(c.r, col.r), max(c.g, col.g), max(c.b, col.b), 1.0), alpha_level), 0.0, 1.0); - } - } else { - // col.a = col.a * alpha_level; - return col; - } -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -16312,599 +11100,437 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSEmbersShader { +function Remove-OBSSceneItem { -[Alias('Set-OBSEmbersShader','Add-OBSEmbersShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'RemoveSceneItem')] +[Alias('obs.powershell.websocket.RemoveSceneItem')] param( -# Set the ViewProj of OBSEmbersShader -[ComponentModel.DefaultBindingProperty('ViewProj')] -[Single[][]] -$ViewProj, -# Set the image of OBSEmbersShader -[ComponentModel.DefaultBindingProperty('image')] -[String] -$Image, -# Set the elapsed_time of OBSEmbersShader -[Alias('elapsed_time')] -[ComponentModel.DefaultBindingProperty('elapsed_time')] -[Single] -$ElapsedTime, -# Set the uv_offset of OBSEmbersShader -[Alias('uv_offset')] -[ComponentModel.DefaultBindingProperty('uv_offset')] -[Single[]] -$UvOffset, -# Set the uv_scale of OBSEmbersShader -[Alias('uv_scale')] -[ComponentModel.DefaultBindingProperty('uv_scale')] -[Single[]] -$UvScale, -# Set the uv_size of OBSEmbersShader -[Alias('uv_size')] -[ComponentModel.DefaultBindingProperty('uv_size')] -[Single[]] -$UvSize, -# Set the uv_pixel_interval of OBSEmbersShader -[Alias('uv_pixel_interval')] -[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] -[Single[]] -$UvPixelInterval, -# Set the rand_f of OBSEmbersShader -[Alias('rand_f')] -[ComponentModel.DefaultBindingProperty('rand_f')] -[Single] -$RandF, -# Set the rand_instance_f of OBSEmbersShader -[Alias('rand_instance_f')] -[ComponentModel.DefaultBindingProperty('rand_instance_f')] -[Single] -$RandInstanceF, -# Set the rand_activation_f of OBSEmbersShader -[Alias('rand_activation_f')] -[ComponentModel.DefaultBindingProperty('rand_activation_f')] -[Single] -$RandActivationF, -# Set the loops of OBSEmbersShader -[ComponentModel.DefaultBindingProperty('loops')] -[Int32] -$Loops, -# Set the local_time of OBSEmbersShader -[Alias('local_time')] -[ComponentModel.DefaultBindingProperty('local_time')] -[Single] -$LocalTime, -# Set the notes of OBSEmbersShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# Set the Animation_Speed of OBSEmbersShader -[Alias('Animation_Speed')] -[ComponentModel.DefaultBindingProperty('Animation_Speed')] -[Single] -$AnimationSpeed, -# Set the Movement_Direction_Horizontal of OBSEmbersShader -[Alias('Movement_Direction_Horizontal')] -[ComponentModel.DefaultBindingProperty('Movement_Direction_Horizontal')] -[Single] -$MovementDirectionHorizontal, -# Set the Movement_Direction_Vertical of OBSEmbersShader -[Alias('Movement_Direction_Vertical')] -[ComponentModel.DefaultBindingProperty('Movement_Direction_Vertical')] -[Single] -$MovementDirectionVertical, -# Set the Movement_Speed_Percent of OBSEmbersShader -[Alias('Movement_Speed_Percent')] -[ComponentModel.DefaultBindingProperty('Movement_Speed_Percent')] -[Int32] -$MovementSpeedPercent, -# Set the Layers_Count of OBSEmbersShader -[Alias('Layers_Count')] -[ComponentModel.DefaultBindingProperty('Layers_Count')] -[Int32] -$LayersCount, -# Set the lumaMin of OBSEmbersShader -[ComponentModel.DefaultBindingProperty('lumaMin')] -[Single] -$LumaMin, -# Set the lumaMinSmooth of OBSEmbersShader -[ComponentModel.DefaultBindingProperty('lumaMinSmooth')] -[Single] -$LumaMinSmooth, -# Set the Alpha_Percentage of OBSEmbersShader -[Alias('Alpha_Percentage')] -[ComponentModel.DefaultBindingProperty('Alpha_Percentage')] -[Single] -$AlphaPercentage, -# Set the Apply_To_Alpha_Layer of OBSEmbersShader -[Alias('Apply_To_Alpha_Layer')] -[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] -[Management.Automation.SwitchParameter] -$ApplyToAlphaLayer, -# 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. +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, + [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] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemId')] +[ValidateRange(0,[int]::MaxValue)] +[double] +$SceneItemId, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'embers' -$ShaderNoun = 'OBSEmbersShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Embers effect by Charles Fettinger for obs-shaderfilter plugin 8/2020 v.1 -// https://github.com/Oncorporation/obs-shaderfilter -// https://www.shadertoy.com/view/wl2Gzc - coverted from and updated - -uniform float4x4 ViewProj; -uniform texture2d image; -uniform float elapsed_time; -uniform float2 uv_offset; -uniform float2 uv_scale; -uniform float2 uv_size; -uniform float2 uv_pixel_interval; -uniform float rand_f; -uniform float rand_instance_f; -uniform float rand_activation_f; -uniform int loops; -uniform float local_time; -uniform string notes< - string widget_type = "info"; -> = "luma is applied with Apply to Alpha Layer. Movement Speed and Direction can be negatives"; -#ifndef OPENGL -#define mat2 float2x2 -#define fract frac -#define mix lerp -#endif + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -sampler_state textureSampler { - Filter = Linear; - AddressU = Clamp; - AddressV = Clamp; -}; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -uniform float Animation_Speed < - string label = "Animation Speed"; - string widget_type = "slider"; - float minimum = 0.1; - float maximum = 10.0; - float step = 0.01; - float scale = 1.; -> = 1.5; + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -uniform float Movement_Direction_Horizontal< - string label = "Movement Direction Horizontal"; - string widget_type = "slider"; - float minimum = -100.0; - float maximum = 100.0; - float step = 1.0; -> = 5.0; -uniform float Movement_Direction_Vertical< - string label = "Movement Direction Vertical"; - string widget_type = "slider"; - float minimum = -100.0; - float maximum = 100.0; - float step = 1.0; -> = 10.0; + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -uniform int Movement_Speed_Percent< - string label = "Movement Speed Percent"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 5; + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -uniform int Layers_Count < - string label = "Layers"; - string widget_type = "slider"; - int minimum = 1.0; - int maximum = 100.0; - int step = 1; -> = 15; -/* ps start -*/ +} -uniform float lumaMin< - string label = "Luma Min"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.01; -uniform float lumaMinSmooth< - string label = "Luma Min Smooth"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.01; -uniform float Alpha_Percentage< - string label = "Alpha Percentage"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.1; -> = 100.0; -uniform bool Apply_To_Alpha_Layer = true; +} -#define PI 3.1415927 -#define TWO_PI 6.283185 + +#.ExternalHelp obs-powershell-Help.xml +function Remove-OBSSourceFilter { -#define PARTICLE_SIZE 0.009 -#define PARTICLE_SCALE float2(0.5, 1.6) -#define PARTICLE_SCALE_VAR float2(0.25, 0.2) +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'RemoveSourceFilter')] +[Alias('obs.powershell.websocket.RemoveSourceFilter')] +param( -#define PARTICLE_BLOOM_SCALE float2(0.5, 0.8) -#define PARTICLE_BLOOM_SCALE_VAR float2(0.3, 0.1) +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sourceName')] +[string] +$SourceName, -#define SPARK_COLOR float3(1.0, 0.4, 0.05) * 1.5 -#define BLOOM_COLOR float3(1.0, 0.4, 0.05) * 0.8 -#define SMOKE_COLOR float3(1.0, 0.43, 0.1) * 0.8 +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sourceUuid')] +[string] +$SourceUuid, -#define SIZE_MOD 1.05 -#define ALPHA_MOD 0.9 -#define Movement_Direction float2(Movement_Direction_Horizontal, Movement_Direction_Vertical) -#define Movement_Speed Movement_Speed_Percent * 0.01 -#define UV float2(fragCoord.xy / uv_size) +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('filterName')] +[string] +$FilterName, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) -float hash1_2(float2 x) -{ - return fract(sin(dot(x, float2(52.127, 61.2871))) * 521.582); -} -float2 hash2_2(float2 x) -{ - mat2 m = mat2(20.52, 24.1994, 70.291, 80.171); - float2 y = mul(x, m); - return fract(sin(y) * 492.194); -} +process { -//Simple interpolated noise -float2 noise2_2(float2 uv) -{ - //float2 f = fract(uv); - float2 f = smoothstep(0.0, 1.0, fract(uv)); - - float2 uv00 = floor(uv); - float2 uv01 = uv00 + float2(0, 1); - float2 uv10 = uv00 + float2(1, 0); - float2 uv11 = uv00 + 1.0; - float2 v00 = hash2_2(uv00); - float2 v01 = hash2_2(uv01); - float2 v10 = hash2_2(uv10); - float2 v11 = hash2_2(uv11); - - float2 v0 = mix(v00, v01, f.y); - float2 v1 = mix(v10, v11, f.y); - float2 v = mix(v0, v1, f.x); - - return v; -} -//Simple interpolated noise -float noise1_2(float2 uv) -{ - float2 f = fract(uv); - - float2 uv00 = floor(uv); - float2 uv01 = uv00 + float2(0, 1); - float2 uv10 = uv00 + float2(1, 0); - float2 uv11 = uv00 + 1.0; - - float v00 = hash1_2(uv00); - float v01 = hash1_2(uv01); - float v10 = hash1_2(uv10); - float v11 = hash1_2(uv11); - - float v0 = mix(v00, v01, f.y); - float v1 = mix(v10, v11, f.y); - float v = mix(v0, v1, f.x); - - return v; -} + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -float layeredNoise1_2(float2 uv, float sizeMod, float alphaMod, int layers, float animation) -{ - float noise = 0.0; - float alpha = 1.0; - float size = 1.0; - float2 offset; - for (int i = 0; i < layers; i++) - { - offset += hash2_2(float2(alpha, size)) * 10.0; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } + + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } - //Adding noise with movement - noise += noise1_2(uv * size + elapsed_time * animation * 8.0 * Movement_Direction * Movement_Speed + offset) * alpha; - alpha *= alphaMod; - size *= sizeMod; - } + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" - noise *= (1.0 - alphaMod) / (1.0 - pow(alphaMod, float(layers))); - return noise; -} + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -//Rotates point around 0,0 -float2 rotate(float2 vpoint, float deg) -{ - float s = sin(deg); - float c = cos(deg); - mat2 m = mat2(s, c, -c, s); - return mul(vpoint, m); -} + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -//Cell center from point on the grid -float2 voronoiPointFromRoot(float2 root, float deg) -{ - float2 vpoint = hash2_2(root) - 0.5; - float s = sin(deg); - float c = cos(deg); - mat2 m = mat2(s, c, -c, s); - vpoint = mul(vpoint, m) * 0.66; - vpoint += root + 0.5; - return vpoint; } -//Voronoi cell point rotation degrees -float degFromRootUV(in float2 uv) -{ - return elapsed_time * Animation_Speed * (hash1_2(uv) - 0.5) * 2.0; -} -float2 randomAround2_2(in float2 vpoint, in float2 range, in float2 uv) -{ - return vpoint + (hash2_2(uv) - 0.5) * range; -} +} + +#.ExternalHelp obs-powershell-Help.xml +function Resume-OBSRecord { -float3 fireParticles(in float2 uv, in float2 originalUV) -{ - float3 particles = float3(0.0, 0.0, 0.0); - float2 rootUV = floor(uv); - float deg = degFromRootUV(rootUV); - float2 pointUV = voronoiPointFromRoot(rootUV, deg); - float dist = 2.0; - float distBloom = 0.0; - - //UV manipulation for the faster particle movement - float2 tempUV = uv + (noise2_2(uv * 2.0) - 0.5) * 0.1; - tempUV += -(noise2_2(uv * 3.0 + elapsed_time) - 0.5) * 0.07; - //Sparks sdf - dist = length(rotate(tempUV - pointUV, 0.7) * randomAround2_2(PARTICLE_SCALE, PARTICLE_SCALE_VAR, rootUV)); - - //Bloom sdf - distBloom = length(rotate(tempUV - pointUV, 0.7) * randomAround2_2(PARTICLE_BLOOM_SCALE, PARTICLE_BLOOM_SCALE_VAR, rootUV)); +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'ResumeRecord')] +[Alias('obs.powershell.websocket.ResumeRecord')] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - //Add sparks - particles += (1.0 - smoothstep(PARTICLE_SIZE * 0.6, PARTICLE_SIZE * 3.0, dist)) * SPARK_COLOR; - - //Add bloom - particles += pow((1.0 - smoothstep(0.0, PARTICLE_SIZE * 6.0, distBloom)) * 1.0, 3.0) * BLOOM_COLOR; - //Upper disappear curve randomization - float border = (hash1_2(rootUV) - 0.5) * 2.0; - float disappear = 1.0 - smoothstep(border, border + 0.5, originalUV.y); - - //Lower appear curve randomization - border = (hash1_2(rootUV + 0.214) - 1.8) * 0.7; - float appear = smoothstep(border, border + 0.4, originalUV.y); - - return particles * disappear * appear; -} +process { -//Layering particles to imitate 3D view -float3 layeredParticles(in float2 uv, in float sizeMod, in float alphaMod, in int layers, in float smoke) -{ - float3 particles = float3(0.0, 0.0, 0.0); - float size = 1.0; - float alpha = 1.0; - float2 offset = float2(0.0, 0.0); - float2 noiseOffset; - float2 bokehUV; - - for (int i = 0; i < layers; i++) - { - //Particle noise movement - noiseOffset = (noise2_2(uv * size * 2.0 + 0.5) - 0.5) * 0.15; - - //UV with applied movement - bokehUV = (uv * size + elapsed_time * Movement_Direction * Movement_Speed) + offset + noiseOffset; - - //Adding particles if there is more smoke, remove smaller particles - particles += fireParticles(bokehUV, uv) * alpha * (1.0 - smoothstep(0.0, 1.0, smoke) * (float(i) / float(layers))); - - //Moving uv origin to avoid generating the same particles - offset += hash2_2(float2(alpha, alpha)) * 10.0; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } + + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } - alpha *= alphaMod; - size *= sizeMod; - } + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" - return particles; + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } + + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } + } -void mainImage(out float4 fragColor, in float2 fragCoord) -{ - float2 uv = (2.0 * fragCoord - uv_size.xy) / uv_size.x; - float vignette = 1.0 - smoothstep(0.4, 1.4, length(uv + float2(0.0, 0.3))); - - uv *= 1.8; - float alpha = clamp(Alpha_Percentage * .01, 0, 1.0); - - float smokeIntensity = layeredNoise1_2(uv * 10.0 + elapsed_time * 4.0 * Movement_Direction * Movement_Speed, 1.7, 0.7, 6, 0.2); - smokeIntensity *= pow(1.0 - smoothstep(-1.0, 1.6, uv.y), 2.0); - float3 smoke = smokeIntensity * SMOKE_COLOR * 0.8 * vignette; - - //Cutting holes in smoke - smoke *= pow(layeredNoise1_2(uv * 4.0 + elapsed_time * 0.5 * Movement_Direction * Movement_Speed, 1.8, 0.5, 3, 0.2), - 2.0) * 1.5; - - float3 particles = layeredParticles(uv, SIZE_MOD, ALPHA_MOD, Layers_Count, smokeIntensity); - - float4 col = float4(particles + smoke + SMOKE_COLOR * 0.02, alpha); - col.rgb *= vignette; - col.rgb = smoothstep(-0.08, 1.0, col.rgb); - - if (Apply_To_Alpha_Layer) - { - float4 original_color = image.Sample(textureSampler, UV); +} + - float luma = dot(col.rgb, float3(0.299, 0.587, 0.114)); - float luma_min = smoothstep(lumaMin, lumaMin + lumaMinSmooth, luma); - col.a = clamp(luma_min, 0.0, 1.0); - - col.rgb = lerp(original_color.rgb, col.rgb, alpha); //apply alpha slider - col = lerp(original_color, col, col.a); //remove black background color - } +#.ExternalHelp obs-powershell-Help.xml +function Save-OBSReplayBuffer { - fragColor = col; -} -/*ps end*/ +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SaveReplayBuffer')] +[Alias('obs.powershell.websocket.SaveReplayBuffer')] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) -struct VertFragData { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; -VertFragData VSDefault(VertFragData vtx) { - vtx.pos = mul(float4(vtx.pos.xyz, 1.0), ViewProj); - return vtx; -} +process { -float4 PSDefault(VertFragData vtx) : TARGET { - float4 col = float4(1., 1., 1., 1.); - mainImage(col, vtx.uv * uv_size); - return col; -} -technique Draw -{ - pass - { - vertex_shader = VSDefault(vtx); - pixel_shader = PSDefault(vtx); - } -} - -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -16913,243 +11539,146 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSEmbossColorShader { +function Save-OBSSourceScreenshot { -[Alias('Set-OBSEmbossColorShader','Add-OBSEmbossColorShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SaveSourceScreenshot')] +[Alias('obs.powershell.websocket.SaveSourceScreenshot')] param( -# Set the Angle_Steps of OBSEmbossColorShader -[Alias('Angle_Steps')] -[ComponentModel.DefaultBindingProperty('Angle_Steps')] -[Int32] -$AngleSteps, -# Set the Radius_Steps of OBSEmbossColorShader -[Alias('Radius_Steps')] -[ComponentModel.DefaultBindingProperty('Radius_Steps')] -[Int32] -$RadiusSteps, -# Set the ampFactor of OBSEmbossColorShader -[ComponentModel.DefaultBindingProperty('ampFactor')] -[Single] -$AmpFactor, -# Set the Up_Down_Percent of OBSEmbossColorShader -[Alias('Up_Down_Percent')] -[ComponentModel.DefaultBindingProperty('Up_Down_Percent')] -[Int32] -$UpDownPercent, -# Set the Apply_To_Alpha_Layer of OBSEmbossColorShader -[Alias('Apply_To_Alpha_Layer')] -[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] -[Management.Automation.SwitchParameter] -$ApplyToAlphaLayer, -# Set the notes of OBSEmbossColorShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# The name of the source. This must be provided when adding an item for the first time + [Parameter(ValueFromPipelineByPropertyName)] -[Alias('SceneItemName')] -[String] +[ComponentModel.DefaultBindingProperty('sourceName')] +[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 = 'emboss_color' -$ShaderNoun = 'OBSEmbossColorShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Color Emboss shader by Charles Fettinger for obs-shaderfilter plugin 4/2019 -//https://github.com/Oncorporation/obs-shaderfilter -//Converted to OpenGL by Q-mii & Exeldro February 18, 2022 -uniform int Angle_Steps< - string label = "Angle Steps"; - string widget_type = "slider"; - int minimum = 1; - int maximum = 20; - int step = 1; -> = 9; // -uniform int Radius_Steps< - string label = "Radius Steps"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 20; - int step = 1; -> = 4; // -uniform float ampFactor< - string label = "amp Factor"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.01; -> = 12.0; -uniform int Up_Down_Percent< - string label = "Up Down Percent"; - string widget_type = "slider"; - int minimum = -100; - int maximum = 100; - int step = 1; -> = 0; -uniform bool Apply_To_Alpha_Layer = true; -uniform string notes< - string widget_type = "info"; -> = "Steps limited in range from 0 to 20. Edit shader to remove limits at your own risk."; -float4 mainImage(VertData v_in) : TARGET -{ - float radiusSteps = clamp(Radius_Steps, 0, 20); - float angleSteps = clamp(Angle_Steps, 1, 20); - float PI = 3.1415926535897932384626433832795;//acos(-1); - int totalSteps = int(radiusSteps * angleSteps); - float minRadius = (1 * uv_pixel_interval.y); - float maxRadius = (6 * uv_pixel_interval.y); +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sourceUuid')] +[string] +$SourceUuid, - float angleDelta = ((2 * PI) / angleSteps); - float radiusDelta = ((maxRadius - minRadius) / radiusSteps); - float embossAngle = 0.25 * PI; +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('imageFormat')] +[string] +$ImageFormat, - float4 c0 = image.Sample(textureSampler, v_in.uv); - float4 origColor = c0; - float4 accumulatedColor = float4(0,0,0,0); +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('imageFilePath')] +[string] +$ImageFilePath, - if (c0.a > 0.0 || Apply_To_Alpha_Layer == false) - { - for (int radiusStep = 0; radiusStep < radiusSteps; radiusStep++) { - float radius = minRadius + radiusStep * radiusDelta; +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('imageWidth')] +[ValidateRange(8,4096)] +[double] +$ImageWidth, - for (float angle = 0; angle < (2 * PI); angle += angleDelta) { - float2 currentCoord; +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('imageHeight')] +[ValidateRange(8,4096)] +[double] +$ImageHeight, - float xDiff = radius * cos(angle); - float yDiff = radius * sin(angle); +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('imageCompressionQuality')] +[ValidateRange(-1,100)] +[double] +$ImageCompressionQuality, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - currentCoord = v_in.uv + float2(xDiff, yDiff); - float4 currentColor = image.Sample(textureSampler, currentCoord); - float4 colorDiff = abs(c0 - currentColor); - float currentFraction = ((radiusSteps + 1 - radiusStep)) / (radiusSteps + 1); - accumulatedColor += currentFraction * colorDiff / totalSteps * sign(angle - PI);; - } - } - accumulatedColor *= ampFactor; +process { - c0 = lerp(c0 + accumulatedColor, c0 - accumulatedColor, (Up_Down_Percent * 0.01)); - } - //return c0 + accumulatedColor; // down; - //return c0 - accumulatedColor; // up - return c0; -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} + + Get-Item $paramCopy["imageFilePath"] | + Add-Member NoteProperty InputName $paramCopy["SourceName"] -Force -PassThru | + Add-Member NoteProperty SourceName $paramCopy["SourceName"] -Force -PassThru | + Add-Member NoteProperty ImageWidth $paramCopy["ImageWidth"] -Force -PassThru | + Add-Member NoteProperty ImageHeight $paramCopy["ImageHeight"] -Force -PassThru + } @@ -17157,177 +11686,223 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSEmbossShader { +function Send-OBSCallVendorRequest { -[Alias('Set-OBSEmbossShader','Add-OBSEmbossShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'CallVendorRequest')] +[Alias('obs.powershell.websocket.CallVendorRequest')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the Use_Color of OBSEmbossShader -[Alias('Use_Color')] -[ComponentModel.DefaultBindingProperty('Use_Color')] -[Management.Automation.SwitchParameter] -$UseColor, -# Set the Apply_To_Alpha_Layer of OBSEmbossShader -[Alias('Apply_To_Alpha_Layer')] -[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] -[Management.Automation.SwitchParameter] -$ApplyToAlphaLayer, -# The name of the source. This must be provided when adding an item for the first time + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('vendorName')] +[string] +$VendorName, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('requestType')] +[string] +$RequestType, + [Parameter(ValueFromPipelineByPropertyName)] -[Alias('SceneItemName')] -[String] -$SourceName, -# The name of the filter. If this is not provided, this will default to the shader name. +[ComponentModel.DefaultBindingProperty('requestData')] +[PSObject] +$RequestData, +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'emboss' -$ShaderNoun = 'OBSEmbossShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Spotlight By Charles Fettinger (https://github.com/Oncorporation) 4/2019 -//Converted to OpenGL by Q-mii & Exeldro March 8, 2022 -uniform bool Use_Color; -uniform bool Apply_To_Alpha_Layer = true; - -float4 mainImage(VertData v_in) : TARGET -{ - float dx = 1 / uv_size.x; - float dy = 1 / uv_size.y; - - float4 c0 = image.Sample(textureSampler, v_in.uv); - if (c0.a > 0.0 || Apply_To_Alpha_Layer == false) - { - float4 c1 = image.Sample(textureSampler, v_in.uv + float2(-dx, -dy)); - float4 c2 = image.Sample(textureSampler, v_in.uv + float2(0, -dy)); - float4 c4 = image.Sample(textureSampler, v_in.uv + float2(-dx, 0)); - float4 c6 = image.Sample(textureSampler, v_in.uv + float2(dx, 0)); - float4 c8 = image.Sample(textureSampler, v_in.uv + float2(0, dy)); - float4 c9 = image.Sample(textureSampler, v_in.uv + float2(dx, dy)); - c0 = (-c1 - c2 - c4 + c6 + c8 + c9); - float c = (c0.r + c0.g + c0.b) / 3 + 0.5; - c0 = float4(c,c,c,c); + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (Use_Color) - { - float4 rgba = image.Sample(textureSampler, v_in.uv); - return (0.5 * rgba) + c0; - } - } - return c0; -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -' -} -$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 '|' + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } - ))" - 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] + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam } - continue nextParameter - } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } +} - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Send-OBSCustomEvent { + + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'BroadcastCustomEvent')] +[Alias('obs.powershell.websocket.BroadcastCustomEvent')] +param( + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('eventData')] +[PSObject] +$EventData, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) + + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -17336,300 +11911,115 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSExeldroBentCameraShader { +function Send-OBSOffsetMediaInputCursor { -[Alias('Set-OBSExeldroBentCameraShader','Add-OBSExeldroBentCameraShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'OffsetMediaInputCursor')] +[Alias('obs.powershell.websocket.OffsetMediaInputCursor')] param( -# Set the left_side_width of OBSExeldroBentCameraShader -[Alias('left_side_width')] -[ComponentModel.DefaultBindingProperty('left_side_width')] -[Single] -$LeftSideWidth, -# Set the left_side_size of OBSExeldroBentCameraShader -[Alias('left_side_size')] -[ComponentModel.DefaultBindingProperty('left_side_size')] -[Single] -$LeftSideSize, -# Set the left_side_shadow of OBSExeldroBentCameraShader -[Alias('left_side_shadow')] -[ComponentModel.DefaultBindingProperty('left_side_shadow')] -[Single] -$LeftSideShadow, -# Set the left_flip_width of OBSExeldroBentCameraShader -[Alias('left_flip_width')] -[ComponentModel.DefaultBindingProperty('left_flip_width')] -[Single] -$LeftFlipWidth, -# Set the left_flip_shadow of OBSExeldroBentCameraShader -[Alias('left_flip_shadow')] -[ComponentModel.DefaultBindingProperty('left_flip_shadow')] -[Single] -$LeftFlipShadow, -# Set the right_side_width of OBSExeldroBentCameraShader -[Alias('right_side_width')] -[ComponentModel.DefaultBindingProperty('right_side_width')] -[Single] -$RightSideWidth, -# Set the right_side_size of OBSExeldroBentCameraShader -[Alias('right_side_size')] -[ComponentModel.DefaultBindingProperty('right_side_size')] -[Single] -$RightSideSize, -# Set the right_side_shadow of OBSExeldroBentCameraShader -[Alias('right_side_shadow')] -[ComponentModel.DefaultBindingProperty('right_side_shadow')] -[Single] -$RightSideShadow, -# Set the right_flip_width of OBSExeldroBentCameraShader -[Alias('right_flip_width')] -[ComponentModel.DefaultBindingProperty('right_flip_width')] -[Single] -$RightFlipWidth, -# Set the right_flip_shadow of OBSExeldroBentCameraShader -[Alias('right_flip_shadow')] -[ComponentModel.DefaultBindingProperty('right_flip_shadow')] -[Single] -$RightFlipShadow, -# 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. +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + [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] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('mediaCursorOffset')] +[double] +$MediaCursorOffset, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'exeldro-bent-camera' -$ShaderNoun = 'OBSExeldroBentCameraShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform float left_side_width< - string label = "Left side width"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.1; -uniform float left_side_size< - string label = "Left side size"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.9; -uniform float left_side_shadow< - string label = "Left side shadow"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.8; -uniform float left_flip_width< - string label = "Left flip width"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.05; -uniform float left_flip_shadow< - string label = "Left flip shadow"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.6; -uniform float right_side_width< - string label = "Right side width"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.1; -uniform float right_side_size< - string label = "Right side size"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.9; -uniform float right_side_shadow< - string label = "Right side shadow"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.8; -uniform float right_flip_width< - string label = "Right flip width"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.05; -uniform float right_flip_shadow< - string label = "Right flip shadow"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.6; -float4 mainImage(VertData v_in) : TARGET -{ - float2 pos=v_in.uv; - float shadow = 1.0; - if(pos.x < left_side_width){ - pos.y -= 0.5; - pos.y /= left_side_size; - pos.y += 0.5; - pos.x -= left_side_width + left_flip_width / 2.0; - pos.x /= left_side_size; - pos.x += left_side_width + left_flip_width / 2.0; - shadow = left_side_shadow; - }else if(pos.x < left_side_width + left_flip_width){ - float factor = 1.0 - ((left_side_width + left_flip_width)-pos.x)/left_flip_width*(1.0 - left_side_size); - pos.y -= 0.5; - pos.y /= factor; - pos.y += 0.5; - pos.x -= left_side_width + left_flip_width; - pos.x /= factor; - pos.x += left_side_width + left_flip_width; - shadow = left_flip_shadow; - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if(1.0 - pos.x < right_side_width){ - pos.y -= 0.5; - pos.y /= right_side_size; - pos.y += 0.5; - pos.x -= 1.0 - (right_side_width + right_flip_width / 2.0); - pos.x /= right_side_size; - pos.x += 1.0 - (right_side_width + right_flip_width / 2.0); - shadow = right_side_shadow; - }else if(1.0 - pos.x < right_side_width + right_flip_width){ - float factor = 1.0 - ((right_side_width + right_flip_width) - (1.0 - pos.x))/right_flip_width*(1.0 - right_side_size); - pos.y -= 0.5; - pos.y /= factor; - pos.y += 0.5; - pos.x -= 1.0 - (right_side_width + right_flip_width); - pos.x /= factor; - pos.x += 1.0 -(right_side_width + right_flip_width); - shadow = right_flip_shadow; - } - float4 p_color = image.Sample(textureSampler, pos); - p_color.rgb *= shadow; - return p_color; -} -' -} -$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 + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -17638,173 +12028,100 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSFadeTransitionShader { +function Send-OBSPauseRecord { -[Alias('Set-OBSFadeTransitionShader','Add-OBSFadeTransitionShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'PauseRecord')] +[Alias('obs.powershell.websocket.PauseRecord')] param( -# Set the image_a of OBSFadeTransitionShader -[Alias('image_a')] -[ComponentModel.DefaultBindingProperty('image_a')] -[String] -$ImageA, -# Set the image_b of OBSFadeTransitionShader -[Alias('image_b')] -[ComponentModel.DefaultBindingProperty('image_b')] -[String] -$ImageB, -# Set the transition_time of OBSFadeTransitionShader -[Alias('transition_time')] -[ComponentModel.DefaultBindingProperty('transition_time')] -[Single] -$TransitionTime, -# Set the convert_linear of OBSFadeTransitionShader -[Alias('convert_linear')] -[ComponentModel.DefaultBindingProperty('convert_linear')] -[Management.Automation.SwitchParameter] -$ConvertLinear, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'fade-transition' -$ShaderNoun = 'OBSFadeTransitionShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform texture2d image_a; -uniform texture2d image_b; -uniform float transition_time< - string label = "Transittion Time"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.5; -uniform bool convert_linear = true; -float4 mainImage(VertData v_in) : TARGET -{ - float4 a_val = image_a.Sample(textureSampler, v_in.uv); - float4 b_val = image_b.Sample(textureSampler, v_in.uv); - float4 rgba = lerp(a_val, b_val, transition_time); - if(convert_linear) - rgba.rgb = srgb_nonlinear_to_linear(rgba.rgb); - return rgba; -} -' -} -$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 - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -17813,230 +12130,115 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSFillColorGradientShader { +function Send-OBSPressInputPropertiesButton { -[Alias('Set-OBSFillColorGradientShader','Add-OBSFillColorGradientShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'PressInputPropertiesButton')] +[Alias('obs.powershell.websocket.PressInputPropertiesButton')] param( -# Set the Fill of OBSFillColorGradientShader -[ComponentModel.DefaultBindingProperty('Fill')] -[Single] -$Fill, -# Set the Gradient_Width of OBSFillColorGradientShader -[Alias('Gradient_Width')] -[ComponentModel.DefaultBindingProperty('Gradient_Width')] -[Single] -$GradientWidth, -# Set the Gradient_Offset of OBSFillColorGradientShader -[Alias('Gradient_Offset')] -[ComponentModel.DefaultBindingProperty('Gradient_Offset')] -[Single] -$GradientOffset, -# Set the Fill_Direction of OBSFillColorGradientShader -[Alias('Fill_Direction')] -[ComponentModel.DefaultBindingProperty('Fill_Direction')] -[Int32] -$FillDirection, -# Set the Fill_Color of OBSFillColorGradientShader -[Alias('Fill_Color')] -[ComponentModel.DefaultBindingProperty('Fill_Color')] -[String] -$FillColor, -# 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. +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + [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] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('propertyName')] +[string] +$PropertyName, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'fill_color_gradient' -$ShaderNoun = 'OBSFillColorGradientShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform float Fill< - string label = "Fill"; - string widget_type = "slider"; - float minimum = 0; - float maximum = 1; - float step = 0.005; -> = 0.500; - -uniform float Gradient_Width< - string label = "Gradient Width"; - string widget_type = "slider"; - float minimum = 0; - float maximum = 0.15; // Adjust the maximum value as needed - float step = 0.01; -> = 0.05; - -uniform float Gradient_Offset< - string label = "Gradient Offset"; - string widget_type = "slider"; - float minimum = 0; - float maximum = 0.100; // Adjust the maximum value as needed - float step = 0.005; -> = 0.00; -uniform int Fill_Direction< - string label = "Fill from:"; - string widget_type = "select"; - int option_0_value = 0; - string option_0_label = "Left"; - int option_1_value = 1; - string option_1_label = "Right"; - int option_2_value = 2; - string option_2_label = "Bottom"; - int option_3_value = 3; - string option_3_label = "Top"; -> = 0; -uniform float4 Fill_Color; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -float4 mainImage(VertData v_in) : TARGET -{ - float distanceToEdge = 0.0; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } - // Calculate distance to the fill edge based on the selected direction - if (Fill_Direction == 0) - distanceToEdge = Fill - v_in.uv.x; - else if (Fill_Direction == 1) - distanceToEdge = v_in.uv.x - (1.0 - Fill); - else if (Fill_Direction == 2) - distanceToEdge = v_in.uv.y - (1.0 - Fill); - else if (Fill_Direction == 3) - distanceToEdge = Fill - v_in.uv.y; + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } - // Calculate the gradient factor based on the distance to the edge and the gradient width - float gradientOffset = (Fill == 0.0) ? 0.0 : (Fill == 1.0 ? 0.0 : Gradient_Offset); - float gradientWidth = (Fill == 0.0 || Fill == 1.0) ? 0.0 : Gradient_Width; - - // Adjust distanceToEdge by the Gradient_Offset - distanceToEdge += gradientOffset; - - // Normalize the distance to be between 0 and 1 - distanceToEdge = saturate(distanceToEdge); - - // float gradientWidth = Fill < 1.0 ? Gradient_Width : Gradient_Width * (1.0 - Fill); - // float gradientFactor = smoothstep(0.0, gradientWidth, distanceToEdge); - float gradientFactor = clamp(distanceToEdge / gradientWidth, 0.0, 1.0); - - // Blend between the fill color and the original image color using the gradient factor - float4 finalColor = lerp(image.Sample(textureSampler, v_in.uv), Fill_Color, gradientFactor); - - return finalColor; -} - -' -} -$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] + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam } - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -18045,195 +12247,112 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSFillColorLinearShader { +function Send-OBSSleep { -[Alias('Set-OBSFillColorLinearShader','Add-OBSFillColorLinearShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'Sleep')] +[Alias('obs.powershell.websocket.Sleep')] param( -# Set the Fill of OBSFillColorLinearShader -[ComponentModel.DefaultBindingProperty('Fill')] -[Single] -$Fill, -# Set the Fill_Direction of OBSFillColorLinearShader -[Alias('Fill_Direction')] -[ComponentModel.DefaultBindingProperty('Fill_Direction')] -[Int32] -$FillDirection, -# Set the Fill_Color of OBSFillColorLinearShader -[Alias('Fill_Color')] -[ComponentModel.DefaultBindingProperty('Fill_Color')] -[String] -$FillColor, -# 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. +[ComponentModel.DefaultBindingProperty('sleepMillis')] +[ValidateRange(0,50000)] +[double] +$SleepMillis, + [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] +[ComponentModel.DefaultBindingProperty('sleepFrames')] +[ValidateRange(0,10000)] +[double] +$SleepFrames, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'fill_color_linear' -$ShaderNoun = 'OBSFillColorLinearShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform float Fill< - string label = "Fill"; - string widget_type = "slider"; - float minimum = 0; - float maximum = 1; - float step = 0.005; ->; -uniform int Fill_Direction< - string label = "Fill from:"; - string widget_type = "select"; - int option_0_value = 0; - string option_0_label = "Left"; - int option_1_value = 1; - string option_1_label = "Right"; - int option_2_value = 2; - string option_2_label = "Top"; - int option_3_value = 3; - string option_3_label = "Bottom"; -> = 0; -uniform float4 Fill_Color; -float4 mainImage(VertData v_in) : TARGET -{ - bool is_inside_fill = true; - - // Check if the pixel is within the specified "fill width" on the left side - if(Fill_Direction == 0){ - is_inside_fill = v_in.uv.x > Fill; - } - if(Fill_Direction == 1) - { - is_inside_fill = v_in.uv.x < (1.0 - Fill); - } - if(Fill_Direction == 2) - { - is_inside_fill = v_in.uv.y > Fill; - } - if(Fill_Direction == 3) - { - is_inside_fill = v_in.uv.y < (1.0 - Fill); - } - - // Invert is_inside_fill - is_inside_fill = !is_inside_fill; - - // If inside the "fill," make the pixel selected colour; otherwise, use the original image color - return is_inside_fill ? Fill_Color : image.Sample(textureSampler, v_in.uv); -} -' -} -$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 - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -18242,249 +12361,237 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSFillColorRadialDegreesShader { +function Send-OBSStreamCaption { -[Alias('Set-OBSFillColorRadialDegreesShader','Add-OBSFillColorRadialDegreesShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SendStreamCaption')] +[Alias('obs.powershell.websocket.SendStreamCaption')] param( -# Set the Fill_Direction of OBSFillColorRadialDegreesShader -[Alias('Fill_Direction')] -[ComponentModel.DefaultBindingProperty('Fill_Direction')] -[Int32] -$FillDirection, -# Set the Fill of OBSFillColorRadialDegreesShader -[ComponentModel.DefaultBindingProperty('Fill')] -[Single] -$Fill, -# Set the Start_Angle of OBSFillColorRadialDegreesShader -[Alias('Start_Angle')] -[ComponentModel.DefaultBindingProperty('Start_Angle')] -[Single] -$StartAngle, -# Set the Offset_X of OBSFillColorRadialDegreesShader -[Alias('Offset_X')] -[ComponentModel.DefaultBindingProperty('Offset_X')] -[Single] -$OffsetX, -# Set the Offset_Y of OBSFillColorRadialDegreesShader -[Alias('Offset_Y')] -[ComponentModel.DefaultBindingProperty('Offset_Y')] -[Single] -$OffsetY, -# Set the Fill_Color of OBSFillColorRadialDegreesShader -[Alias('Fill_Color')] -[ComponentModel.DefaultBindingProperty('Fill_Color')] -[String] -$FillColor, -# 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(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('captionText')] +[string] +$CaptionText, +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'fill_color_radial_degrees' -$ShaderNoun = 'OBSFillColorRadialDegreesShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -#define PI 3.141592653589793238 - -uniform int Fill_Direction< - string label = "Fill Direction"; - string widget_type = "select"; - int option_0_value = 0; - string option_0_label = "Clockwise"; - int option_1_value = 1; - string option_1_label = "Counter-Clockwise"; -> = 0; -uniform float Fill< - string label = "Fill"; - string widget_type = "slider"; - float minimum = 0; - float maximum = 360; - float step = 1.00000; ->; -uniform float Start_Angle< - string label = "Start Angle"; - string widget_type = "slider"; - float minimum = 0; - float maximum = 720; - float step = 1.00000; -> = 360.0; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -uniform float Offset_X< - string label = "Offset X"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.01; -> = 0.0; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -uniform float Offset_Y< - string label = "Offset Y"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.01; -> = 0.0; + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -uniform float4 Fill_Color; + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -float4 mainImage(VertData v_in) : TARGET -{ - // Calculate the center of the screen based on aspect ratio - float aspectRatioX = uv_size.x / uv_size.y; - float2 center = float2(0.5 * aspectRatioX + Offset_X, 0.5 + Offset_Y); + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } - // Normalize the UV coordinates based on aspect ratio - float2 normalizedUV = v_in.uv * float2(aspectRatioX, 1.0); +} - // Calculate the direction vector from the center to the current pixel - float2 dir = normalizedUV - center; - // Calculate the angle in radians - float angle = atan2(dir.y, dir.x); +} - // Convert angle from radians to degrees - angle = degrees(angle); + +#.ExternalHelp obs-powershell-Help.xml +function Send-OBSTriggerHotkeyByKeySequence { - // Offset the angle to start from the specified starting angle - angle += Start_Angle + 90.0; // Subtract 90 degrees to start at 12 o''clock - if (angle >= 360.0) - angle -= 360.0; - // Adjust the angle based on the selected fill direction - if (Fill_Direction == 1) { - // Counter-clockwise fill - angle = 360.0 - angle; - } +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'TriggerHotkeyByKeySequence')] +[Alias('obs.powershell.websocket.TriggerHotkeyByKeySequence')] +param( - // Ensure angle is within [0, 360] range - if (angle < 0.0) - angle += 360.0; - else if (angle >= 360.0) - angle -= 360.0; +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('keyId')] +[string] +$KeyId, - // Check if the angle is within the specified "fill width" - bool is_inside_fill = angle < Fill; +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('keyModifiers')] +[PSObject] +$KeyModifiers, - // If inside the "fill," make the pixel selected color; otherwise, use the original image color - return is_inside_fill ? Fill_Color : image.Sample(textureSampler, v_in.uv); -} +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('keyModifiers.shift')] +[switch] +$KeyModifiersshift, -' -} -$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 - } - } +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('keyModifiers.control')] +[switch] +$KeyModifierscontrol, - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName - } +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('keyModifiers.alt')] +[switch] +$KeyModifiersalt, - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('keyModifiers.command')] +[switch] +$KeyModifierscommand, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -18493,252 +12600,227 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSFillColorRadialPercentageShader { +function Send-OBSTriggerHotkeyByName { -[Alias('Set-OBSFillColorRadialPercentageShader','Add-OBSFillColorRadialPercentageShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'TriggerHotkeyByName')] +[Alias('obs.powershell.websocket.TriggerHotkeyByName')] param( -# Set the Fill_Direction of OBSFillColorRadialPercentageShader -[Alias('Fill_Direction')] -[ComponentModel.DefaultBindingProperty('Fill_Direction')] -[Int32] -$FillDirection, -# Set the Fill of OBSFillColorRadialPercentageShader -[ComponentModel.DefaultBindingProperty('Fill')] -[Single] -$Fill, -# Set the Start_Angle of OBSFillColorRadialPercentageShader -[Alias('Start_Angle')] -[ComponentModel.DefaultBindingProperty('Start_Angle')] -[Single] -$StartAngle, -# Set the Offset_X of OBSFillColorRadialPercentageShader -[Alias('Offset_X')] -[ComponentModel.DefaultBindingProperty('Offset_X')] -[Single] -$OffsetX, -# Set the Offset_Y of OBSFillColorRadialPercentageShader -[Alias('Offset_Y')] -[ComponentModel.DefaultBindingProperty('Offset_Y')] -[Single] -$OffsetY, -# Set the Fill_Color of OBSFillColorRadialPercentageShader -[Alias('Fill_Color')] -[ComponentModel.DefaultBindingProperty('Fill_Color')] -[String] -$FillColor, -# The name of the source. This must be provided when adding an item for the first time + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('hotkeyName')] +[string] +$HotkeyName, + [Parameter(ValueFromPipelineByPropertyName)] -[Alias('SceneItemName')] -[String] -$SourceName, -# The name of the filter. If this is not provided, this will default to the shader name. +[ComponentModel.DefaultBindingProperty('contextName')] +[string] +$ContextName, +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'fill_color_radial_percentage' -$ShaderNoun = 'OBSFillColorRadialPercentageShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -#define PI 3.141592653589793238 - -uniform int Fill_Direction< - string label = "Fill Direction"; - string widget_type = "select"; - int option_0_value = 0; - string option_0_label = "Clockwise"; - int option_1_value = 1; - string option_1_label = "Counter-Clockwise"; -> = 0; -uniform float Fill< - string label = "Fill"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.00005; -> = 0.0; -uniform float Start_Angle< - string label = "Start Angle"; - string widget_type = "slider"; - float minimum = 0; - float maximum = 720; - float step = 1.00000; -> = 360.0; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -uniform float Offset_X< - string label = "Offset X"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.01; -> = 0.0; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -uniform float Offset_Y< - string label = "Offset Y"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.01; -> = 0.0; + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -uniform float4 Fill_Color; + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -float4 mainImage(VertData v_in) : TARGET -{ - // Calculate the center of the screen based on aspect ratio - float aspectRatioX = uv_size.x / uv_size.y; - float2 center = float2(0.5 * aspectRatioX + Offset_X, 0.5 + Offset_Y); + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } - // Normalize the UV coordinates based on aspect ratio - float2 normalizedUV = v_in.uv * float2(aspectRatioX, 1.0); +} - // Calculate the direction vector from the center to the current pixel - float2 dir = normalizedUV - center; - // Calculate the angle in radians - float angle = atan2(dir.y, dir.x); +} - // Convert angle from radians to degrees - angle = degrees(angle); + +#.ExternalHelp obs-powershell-Help.xml +function Send-OBSTriggerMediaInputAction { - // Offset the angle to start from the specified starting angle - angle += Start_Angle + 90.0; // Subtract 90 degrees to start at 12 o''clock - if (angle >= 360.0) - angle -= 360.0; - // Adjust the angle based on the selected fill direction - if (Fill_Direction == 1) { - // Counter-clockwise fill - angle = 360.0 - angle; - } +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'TriggerMediaInputAction')] +[Alias('obs.powershell.websocket.TriggerMediaInputAction')] +param( - // Ensure angle is within [0, 360] range - if (angle < 0.0) - angle += 360.0; - else if (angle >= 360.0) - angle -= 360.0; +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, - // Calculate the percentage of the angle - float anglePercentage = angle / 360.0; +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, - // Check if the angle percentage is within the specified "fill percentage" - bool is_inside_fill = anglePercentage < Fill; +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('mediaAction')] +[string] +$MediaAction, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - // If inside the "fill," make the pixel selected color; otherwise, use the original image color - return is_inside_fill ? Fill_Color : image.Sample(textureSampler, v_in.uv); -} -' -} -$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 - } - } +process { - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName - } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -18747,259 +12829,100 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSFilterTemplateShader { +function Send-OBSTriggerStudioModeTransition { -[Alias('Set-OBSFilterTemplateShader','Add-OBSFilterTemplateShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'TriggerStudioModeTransition')] +[Alias('obs.powershell.websocket.TriggerStudioModeTransition')] param( -# Set the ViewProj of OBSFilterTemplateShader -[ComponentModel.DefaultBindingProperty('ViewProj')] -[Single[][]] -$ViewProj, -# Set the image of OBSFilterTemplateShader -[ComponentModel.DefaultBindingProperty('image')] -[String] -$Image, -# Set the elapsed_time of OBSFilterTemplateShader -[Alias('elapsed_time')] -[ComponentModel.DefaultBindingProperty('elapsed_time')] -[Single] -$ElapsedTime, -# Set the uv_offset of OBSFilterTemplateShader -[Alias('uv_offset')] -[ComponentModel.DefaultBindingProperty('uv_offset')] -[Single[]] -$UvOffset, -# Set the uv_scale of OBSFilterTemplateShader -[Alias('uv_scale')] -[ComponentModel.DefaultBindingProperty('uv_scale')] -[Single[]] -$UvScale, -# Set the uv_pixel_interval of OBSFilterTemplateShader -[Alias('uv_pixel_interval')] -[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] -[Single[]] -$UvPixelInterval, -# Set the uv_size of OBSFilterTemplateShader -[Alias('uv_size')] -[ComponentModel.DefaultBindingProperty('uv_size')] -[Single[]] -$UvSize, -# Set the rand_f of OBSFilterTemplateShader -[Alias('rand_f')] -[ComponentModel.DefaultBindingProperty('rand_f')] -[Single] -$RandF, -# Set the rand_instance_f of OBSFilterTemplateShader -[Alias('rand_instance_f')] -[ComponentModel.DefaultBindingProperty('rand_instance_f')] -[Single] -$RandInstanceF, -# Set the rand_activation_f of OBSFilterTemplateShader -[Alias('rand_activation_f')] -[ComponentModel.DefaultBindingProperty('rand_activation_f')] -[Single] -$RandActivationF, -# Set the loops of OBSFilterTemplateShader -[ComponentModel.DefaultBindingProperty('loops')] -[Int32] -$Loops, -# Set the local_time of OBSFilterTemplateShader -[Alias('local_time')] -[ComponentModel.DefaultBindingProperty('local_time')] -[Single] -$LocalTime, -# Set the notes of OBSFilterTemplateShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'filter_template' -$ShaderNoun = 'OBSFilterTemplateShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//My shader modified by Me for use with obs-shaderfilter month/year v.02 - -//Section to converting GLSL to HLSL - can delete if unneeded -#define vec2 float2 -#define vec3 float3 -#define vec4 float4 -#define ivec2 int2 -#define ivec3 int3 -#define ivec4 int4 -#define mat2 float2x2 -#define mat3 float3x3 -#define mat4 float4x4 -#define fract frac -#define mix lerp -#define iTime float -#define iTime elapsed_time -#define iResolution float4(uv_size,uv_pixel_interval) - -/* -**Shaders have these variables pre loaded by the plugin** -**this section can be deleted** - -struct VertData { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; - -uniform float4x4 ViewProj; -uniform texture2d image; - -uniform float elapsed_time; -uniform float2 uv_offset; -uniform float2 uv_scale; -uniform float2 uv_pixel_interval; -uniform float2 uv_size; -uniform float rand_f; -uniform float rand_instance_f; -uniform float rand_activation_f; -uniform int loops; -uniform float local_time; -*/ -uniform string notes< - string widget_type = "info"; -> = "add notes here"; - - -float4 mainImage(VertData v_in) : TARGET -{ - return image.Sample(textureSampler, v_in.uv); -} - -/* -**Shaders use the built in Draw technique** -**this section can be deleted** -technique Draw -{ - pass - { - vertex_shader = mainTransform(v_in); - pixel_shader = mainImage(v_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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -19008,699 +12931,436 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSFire3Shader { +function Set-OBSCurrentPreviewScene { -[Alias('Set-OBSFire3Shader','Add-OBSFire3Shader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetCurrentPreviewScene')] +[Alias('obs.powershell.websocket.SetCurrentPreviewScene')] param( -# Set the ViewProj of OBSFire3Shader -[ComponentModel.DefaultBindingProperty('ViewProj')] -[Single[][]] -$ViewProj, -# Set the image of OBSFire3Shader -[ComponentModel.DefaultBindingProperty('image')] -[String] -$Image, -# Set the elapsed_time of OBSFire3Shader -[Alias('elapsed_time')] -[ComponentModel.DefaultBindingProperty('elapsed_time')] -[Single] -$ElapsedTime, -# Set the uv_offset of OBSFire3Shader -[Alias('uv_offset')] -[ComponentModel.DefaultBindingProperty('uv_offset')] -[Single[]] -$UvOffset, -# Set the uv_scale of OBSFire3Shader -[Alias('uv_scale')] -[ComponentModel.DefaultBindingProperty('uv_scale')] -[Single[]] -$UvScale, -# Set the uv_pixel_interval of OBSFire3Shader -[Alias('uv_pixel_interval')] -[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] -[Single[]] -$UvPixelInterval, -# Set the uv_size of OBSFire3Shader -[Alias('uv_size')] -[ComponentModel.DefaultBindingProperty('uv_size')] -[Single[]] -$UvSize, -# Set the rand_f of OBSFire3Shader -[Alias('rand_f')] -[ComponentModel.DefaultBindingProperty('rand_f')] -[Single] -$RandF, -# Set the rand_instance_f of OBSFire3Shader -[Alias('rand_instance_f')] -[ComponentModel.DefaultBindingProperty('rand_instance_f')] -[Single] -$RandInstanceF, -# Set the rand_activation_f of OBSFire3Shader -[Alias('rand_activation_f')] -[ComponentModel.DefaultBindingProperty('rand_activation_f')] -[Single] -$RandActivationF, -# Set the loops of OBSFire3Shader -[ComponentModel.DefaultBindingProperty('loops')] -[Int32] -$Loops, -# Set the local_time of OBSFire3Shader -[Alias('local_time')] -[ComponentModel.DefaultBindingProperty('local_time')] -[Single] -$LocalTime, -# Set the Movement_Direction_Horizontal of OBSFire3Shader -[Alias('Movement_Direction_Horizontal')] -[ComponentModel.DefaultBindingProperty('Movement_Direction_Horizontal')] -[Single] -$MovementDirectionHorizontal, -# Set the Movement_Direction_Vertical of OBSFire3Shader -[Alias('Movement_Direction_Vertical')] -[ComponentModel.DefaultBindingProperty('Movement_Direction_Vertical')] -[Single] -$MovementDirectionVertical, -# Set the Alpha_Percentage of OBSFire3Shader -[Alias('Alpha_Percentage')] -[ComponentModel.DefaultBindingProperty('Alpha_Percentage')] -[Int32] -$AlphaPercentage, -# Set the Speed of OBSFire3Shader -[ComponentModel.DefaultBindingProperty('Speed')] -[Int32] -$Speed, -# Set the Invert of OBSFire3Shader -[ComponentModel.DefaultBindingProperty('Invert')] -[Management.Automation.SwitchParameter] -$Invert, -# Set the lumaMin of OBSFire3Shader -[ComponentModel.DefaultBindingProperty('lumaMin')] -[Single] -$LumaMin, -# Set the lumaMinSmooth of OBSFire3Shader -[ComponentModel.DefaultBindingProperty('lumaMinSmooth')] -[Single] -$LumaMinSmooth, -# Set the Apply_To_Image of OBSFire3Shader -[Alias('Apply_To_Image')] -[ComponentModel.DefaultBindingProperty('Apply_To_Image')] -[Management.Automation.SwitchParameter] -$ApplyToImage, -# Set the Replace_Image_Color of OBSFire3Shader -[Alias('Replace_Image_Color')] -[ComponentModel.DefaultBindingProperty('Replace_Image_Color')] -[Management.Automation.SwitchParameter] -$ReplaceImageColor, -# Set the Color_To_Replace of OBSFire3Shader -[Alias('Color_To_Replace')] -[ComponentModel.DefaultBindingProperty('Color_To_Replace')] -[String] -$ColorToReplace, -# Set the Apply_To_Specific_Color of OBSFire3Shader -[Alias('Apply_To_Specific_Color')] -[ComponentModel.DefaultBindingProperty('Apply_To_Specific_Color')] -[Management.Automation.SwitchParameter] -$ApplyToSpecificColor, -# Set the Full_Width of OBSFire3Shader -[Alias('Full_Width')] -[ComponentModel.DefaultBindingProperty('Full_Width')] -[Management.Automation.SwitchParameter] -$FullWidth, -# Set the Flame_Size of OBSFire3Shader -[Alias('Flame_Size')] -[ComponentModel.DefaultBindingProperty('Flame_Size')] -[Single] -$FlameSize, -# Set the Spark_Grid_Height of OBSFire3Shader -[Alias('Spark_Grid_Height')] -[ComponentModel.DefaultBindingProperty('Spark_Grid_Height')] -[Single] -$SparkGridHeight, -# Set the Flame_Modifier of OBSFire3Shader -[Alias('Flame_Modifier')] -[ComponentModel.DefaultBindingProperty('Flame_Modifier')] -[Single] -$FlameModifier, -# Set the Flame_Tongue_Size of OBSFire3Shader -[Alias('Flame_Tongue_Size')] -[ComponentModel.DefaultBindingProperty('Flame_Tongue_Size')] -[Single] -$FlameTongueSize, -# 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. +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, + [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] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'fire-3' -$ShaderNoun = 'OBSFire3Shader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//My effect modified by Me for use with obs-shaderfilter month/year v.02 -//Converted to OpenGL by Q-mii & Exeldro February 22, 2022 -uniform float4x4 ViewProj; -uniform texture2d image; - -//Section to converting GLSL to HLSL - can delete -#define vec2 float2 -#define vec3 float3 -#define vec4 float4 -#define ivec2 int2 -#define ivec3 int3 -#define ivec4 int4 -#define mat2 float2x2 -#define mat3 float3x3 -#define mat4 float4x4 -#define fract frac -#define mix lerp - - -uniform float elapsed_time; -uniform float2 uv_offset; -uniform float2 uv_scale; -uniform float2 uv_pixel_interval; -uniform float2 uv_size; -uniform float rand_f; -uniform float rand_instance_f; -uniform float rand_activation_f; -uniform int loops; -uniform float local_time; -uniform float Movement_Direction_Horizontal< - string label = "Movement Direction Horizontal"; - string widget_type = "slider"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 0.0; -uniform float Movement_Direction_Vertical< - string label = "Movement Direction Vertical"; - string widget_type = "slider"; - float minimum = -100.0; - float maximum = 100.0; - float step = 0.01; -> = 0.0; -#define iTime elapsed_time -#define iResolution float4(uv_size,uv_pixel_interval) -#define Movement_Direction float2(Movement_Direction_Horizontal, Movement_Direction_Vertical) + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -uniform int Alpha_Percentage< - string label = "Alpha Percentage"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 90; -uniform int Speed< - string label = "Speed"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 80; -uniform bool Invert = false; -uniform float lumaMin< - string label = "Luma Min"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.01; -uniform float lumaMinSmooth< - string label = "Luma Min Smooth"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.04; -uniform bool Apply_To_Image = true; -uniform bool Replace_Image_Color = true; -uniform float4 Color_To_Replace; -uniform bool Apply_To_Specific_Color = false; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -sampler_state textureSampler { - Filter = Linear; - AddressU = Border; - AddressV = Border; - BorderColor = 00000000; -}; + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -struct VertData { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -VertData mainTransform(VertData v_in) -{ - VertData vert_out; - vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); - float2 uv = v_in.uv; - if(Invert) - uv = 1.0 - v_in.uv; - vert_out.uv = v_in.uv * uv_scale + uv_offset; - return vert_out; -} + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -int2 iMouse() -{ - return int2(Movement_Direction.x * uv_size.x, Movement_Direction.y * uv_size.y); } -float mod(float x, float y) -{ - return x - y * floor(x / y); -} - -float2 mod2(float2 x, float2 y) -{ - return x - y * floor(x / y); -} +} -/*ps start*/ -#define PI 3.1415926535897932384626433832795 -uniform bool Full_Width = false; + +#.ExternalHelp obs-powershell-Help.xml +function Set-OBSCurrentProfile { -uniform float Flame_Size< - string label = "Flame Size"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.01; -> = 1.0; -uniform float Spark_Grid_Height< - string label = "Spark Grid Size"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 50.0; +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetCurrentProfile')] +[Alias('obs.powershell.websocket.SetCurrentProfile')] +param( -uniform float Flame_Modifier< - string label = "Flame Modifier"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2.0; - float step = 0.01; -> = 1.0; +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('profileName')] +[string] +$ProfileName, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) -uniform float Flame_Tongue_Size< - string label = "Flame Tongue Size"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2.0; - float step = 0.01; -> = 8.5; -// -// Description : Array and textureless GLSL 2D/3D/4D simplex -// noise functions. -// Author : Ian McEwan, Ashima Arts. -// Maintainer : ijm -// Lastmod : 20110822 (ijm) -// License : Copyright (C) 2011 Ashima Arts. All rights reserved. -// Distributed under the MIT License. See LICENSE file. -// https://github.com/ashima/webgl-noise -// +process { -vec3 mod2893(vec3 x) -{ - return x - floor(x * (1.0 / 289.0)) * 289.0; -} -vec4 mod289(vec4 x) -{ - return x - floor(x * (1.0 / 289.0)) * 289.0; -} + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -vec4 permute(vec4 x) -{ - return mod289(((x * 34.0) + 1.0) * x); -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -vec4 taylorInvSqrt(vec4 r) -{ - return 1.79284291400159 - 0.85373472095314 * r; -} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -float snoise(vec3 v) -{ - const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0); - const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -// First corner - vec3 i = floor(v + dot(v, C.yyy)); - vec3 x0 = v - i + dot(i, C.xxx); + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -// Other corners - vec3 g = step(x0.yzx, x0.xyz); - vec3 l = 1.0 - g; - vec3 i1 = min(g.xyz, l.zxy); - vec3 i2 = max(g.xyz, l.zxy); +} - // x0 = x0 - 0.0 + 0.0 * C.xxx; - // x1 = x0 - i1 + 1.0 * C.xxx; - // x2 = x0 - i2 + 2.0 * C.xxx; - // x3 = x0 - 1.0 + 3.0 * C.xxx; - vec3 x1 = x0 - i1 + C.xxx; - vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y - vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y -// Permutations - i = mod2893(i); - vec4 p = permute(permute(permute( - i.z + vec4(0.0, i1.z, i2.z, 1.0)) - + i.y + vec4(0.0, i1.y, i2.y, 1.0)) - + i.x + vec4(0.0, i1.x, i2.x, 1.0)); +} -// Gradients: 7x7 points over a square, mapped onto an octahedron. -// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) - float n_ = 0.142857142857; // 1.0/7.0 - vec3 ns = n_ * D.wyz - D.xzx; + +#.ExternalHelp obs-powershell-Help.xml +function Set-OBSCurrentProgramScene { - vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) - vec4 x_ = floor(j * ns.z); - vec4 y_ = floor(j - 7.0 * x_); // mod(j,N) +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetCurrentProgramScene')] +[Alias('obs.powershell.websocket.SetCurrentProgramScene')] +param( - vec4 x = x_ * ns.x + ns.yyyy; - vec4 y = y_ * ns.x + ns.yyyy; - vec4 h = 1.0 - abs(x) - abs(y); +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, - vec4 b0 = vec4(x.xy, y.xy); - vec4 b1 = vec4(x.zw, y.zw); +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; - //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; - vec4 s0 = floor(b0) * 2.0 + 1.0; - vec4 s1 = floor(b1) * 2.0 + 1.0; - vec4 sh = -step(h, vec4(0.0, 0.0, 0.0, 0.0)); - vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; - vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww; +process { - vec3 p0 = vec3(a0.xy, h.x); - vec3 p1 = vec3(a0.zw, h.y); - vec3 p2 = vec3(a1.xy, h.z); - vec3 p3 = vec3(a1.zw, h.w); -//Normalise gradients - //vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); - vec4 norm = rsqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); - p0 *= norm.x; - p1 *= norm.y; - p2 *= norm.z; - p3 *= norm.w; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -// Mix final noise value - vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0); - m = m * m; - return 42.0 * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3))); -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -////////////////////////////////////////////////////////////// + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -// PRNG -// From https://www.shadertoy.com/view/4djSRW -float prng(in vec2 seed) -{ - seed = fract(seed * vec2(5.3983, 5.4427)); - seed += dot(seed.yx, seed.xy + vec2(21.5351, 14.3137)); - return fract(seed.x * seed.y * 95.4337); -} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -////////////////////////////////////////////////////////////// + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -float noiseStack(vec3 pos, int octaves, float falloff) -{ - float noise = snoise(vec3(pos)); - float off = 1.0; - if (octaves > 1) - { - pos *= 2.0; - off *= falloff; - noise = (1.0 - off) * noise + off * snoise(vec3(pos)); - } - if (octaves > 2) - { - pos *= 2.0; - off *= falloff; - noise = (1.0 - off) * noise + off * snoise(vec3(pos)); - } - if (octaves > 3) - { - pos *= 2.0; - off *= falloff; - noise = (1.0 - off) * noise + off * snoise(vec3(pos)); - } - return (1.0 + noise) / 2.0; } -vec2 noiseStackUV(vec3 pos, int octaves, float falloff, float diff) -{ - float displaceA = noiseStack(pos, octaves, falloff); - float displaceB = noiseStack(pos + vec3(3984.293, 423.21, 5235.19), octaves, falloff); - return vec2(displaceA, displaceB); -} -float4 mainImage(VertData v_in) : TARGET -{ - float2 UV = (1.0 - v_in.uv) * uv_scale; - if (Invert) - UV = v_in.uv * uv_scale; - float alpha = saturate(Alpha_Percentage * .01); - float flame_size = clamp(Flame_Size * .01, 0.0, 4.0); - - vec2 resolution = (.25 * uv_scale * UV.xy) + (0.75 * uv_scale); - if (Full_Width) - { - resolution = (2.0 * (UV.xy)) / 1.0; //iResolution.xy; - - } - resolution.x = mul(resolution.x, 1 / 1); - float time = iTime * (Speed * 0.01); - //vec2 drag = iMouse().xy; - vec2 offset = iMouse().xy; - // - float xpart = UV.x / resolution.x; - float ypart = UV.y / resolution.y; - // - - float ypartClip = UV.y / ( flame_size * 75.0); - float ypartClippedFalloff = clamp(2.0 - ypartClip, 0.0, 1.0); - float ypartClipped = min(ypartClip, 1.0); - float ypartClippedn = (1 - ypartClipped); - // - float xfuel = pow(1.0 - abs(2.0 * xpart - 1.0), 0.5); //pow(1.0-abs(2.0*xpart-1.0),0.5); - // - float timeSpeed = 0.5 * (Speed * 0.01); - float realTime = -1.0 * timeSpeed * time; - // - vec2 coordScaled = -1 * Flame_Tongue_Size * UV - 0.1 * offset; - vec3 position = vec3(coordScaled, 0.0); // +vec3(1223.0, 6434.0, 8425.0); - vec3 flow = vec3(4.1 * (0.5 - xpart) * pow(ypartClippedn, 4.0), -2.0 * xfuel * pow(ypartClippedn, 64.0), 0.0); - vec3 timing = realTime * vec3(0.0, -1.7, 1.1) + flow; - // - vec3 displacePos = vec3(1.0, 0.5, 1.0) * 2.4 * position + realTime * vec3(0.01, -0.7, 1.3); - vec3 displace3 = vec3(noiseStackUV(displacePos, 2, 0.4, 0.1), 0.0); - // - vec3 noiseCoord = (vec3(2.0, 1.0, 1.0) * position + timing + 0.4 * displace3) / 1.0; - float noise = noiseStack(noiseCoord, 3, 0.4); - // - float flames = pow(ypartClipped, 0.3 * xfuel) * pow(noise, 0.3 * xfuel); - // - float f = ypartClippedFalloff * pow(Flame_Modifier - flames * flames * flames, 8.0); - float fff = f * f * f; - vec3 fire = 1.5 * vec3(f, fff, fff * fff); - // - // smoke - float smokeNoise = 0.5 + snoise(0.4 * position + timing * vec3(1.0, 1.0, 0.2)) / 2.0; - float smokePart = 0.3 * pow(xfuel, 3.0) * pow(ypart, 2.0) * (smokeNoise + 0.4 * (1.0 - noise)); - vec3 smoke = vec3(smokePart, smokePart, smokePart); - // - // sparks - float sparkGridSize = Spark_Grid_Height; - vec2 sparkCoord = UV *uv_size - vec2(2.0 * offset.x, 190.0 * sin(realTime)); - sparkCoord -= 30.0 * noiseStackUV(0.01 * vec3(sparkCoord, 15.0 * time), 1, 0.4, 0.1); - sparkCoord += 100.0 * flow.xy; - if (mod(sparkCoord.y / sparkGridSize, 2.0) < 1.0) - sparkCoord.x += 0.5 * sparkGridSize; - vec2 sparkGridIndex = vec2(floor(sparkCoord / sparkGridSize)); - float sparkRandom = prng( sparkGridIndex); - float sparkLife = min(10.0 * (1.0 - min((sparkGridIndex.y + (190.0 * realTime / sparkGridSize)) / (24.0 - 20.0 * sparkRandom), 1.0)), 1.0); - vec3 sparks = vec3(0.0, 0.0, 0.0); - if (sparkLife > 0.0) - { - float sparkSize = xfuel * xfuel * sparkRandom * 0.08; - float sparkRadians = 999.0 * sparkRandom * 2.0 * PI + 2.0 * time; - vec2 sparkCircular = vec2(sin(sparkRadians), cos(sparkRadians)); - vec2 sparkOffset = (0.5 - sparkSize) * sparkGridSize * sparkCircular; - vec2 sparkModulus = mod2(sparkCoord + sparkOffset, float2(sparkGridSize, sparkGridSize)) - 0.5 * float2(sparkGridSize, sparkGridSize); - float sparkLength = length(sparkModulus); - float sparksGray = max(0.0, 1.0 - sparkLength / (sparkSize * sparkGridSize)); - sparks = sparkLife * sparksGray * vec3(1.0, 0.3, 0.0); - } - // - float4 rgba = vec4(max(fire, sparks) + smoke, 1.0); - - // remove dark areas per user - float luma_fire = dot(rgba.rgb, float3(0.299, 0.587, 0.114)); - float luma_min_fire = smoothstep(lumaMin, lumaMin + lumaMinSmooth, luma_fire); - rgba.a = clamp(luma_min_fire, 0.0, alpha); - - float4 color; - float4 original_color; - if (Apply_To_Image) - { - float4 color = image.Sample(textureSampler, v_in.uv); - float4 original_color = color; - if (color.a > 0.0) - { - float luma = color.r * 0.299 + color.g * 0.587 + color.b * 0.114; - if (Replace_Image_Color) - color = float4(luma, luma, luma, luma); - rgba = lerp(original_color, lerp(original_color,rgba * color,rgba.a), alpha); - } - else - { - rgba = color; - } - - } - if (Apply_To_Specific_Color) - { - color = image.Sample(textureSampler, v_in.uv); - original_color = color; - color = (distance(color.rgb, Color_To_Replace.rgb) <= 0.075) ? rgba : color; - rgba = lerp(original_color, color, alpha); - } - - return rgba; -} +} -technique Draw -{ - pass - { - vertex_shader = mainTransform(v_in); - pixel_shader = mainImage(v_in); - } -} + +#.ExternalHelp obs-powershell-Help.xml +function Set-OBSCurrentSceneCollection { -' -} -$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 - } +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetCurrentSceneCollection')] +[Alias('obs.powershell.websocket.SetCurrentSceneCollection')] +param( - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneCollectionName')] +[string] +$SceneCollectionName, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -19709,434 +13369,213 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSFireShader { +function Set-OBSCurrentSceneTransition { -[Alias('Set-OBSFireShader','Add-OBSFireShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetCurrentSceneTransition')] +[Alias('obs.powershell.websocket.SetCurrentSceneTransition')] param( -# Set the Alpha_Percentage of OBSFireShader -[Alias('Alpha_Percentage')] -[ComponentModel.DefaultBindingProperty('Alpha_Percentage')] -[Int32] -$AlphaPercentage, -# Set the Speed of OBSFireShader -[ComponentModel.DefaultBindingProperty('Speed')] -[Int32] -$Speed, -# Set the Flame_Size of OBSFireShader -[Alias('Flame_Size')] -[ComponentModel.DefaultBindingProperty('Flame_Size')] -[Int32] -$FlameSize, -# Set the Fire_Type of OBSFireShader -[Alias('Fire_Type')] -[ComponentModel.DefaultBindingProperty('Fire_Type')] -[Int32] -$FireType, -# Set the Invert of OBSFireShader -[ComponentModel.DefaultBindingProperty('Invert')] -[Management.Automation.SwitchParameter] -$Invert, -# Set the lumaMin of OBSFireShader -[ComponentModel.DefaultBindingProperty('lumaMin')] -[Single] -$LumaMin, -# Set the lumaMinSmooth of OBSFireShader -[ComponentModel.DefaultBindingProperty('lumaMinSmooth')] -[Single] -$LumaMinSmooth, -# Set the Apply_To_Image of OBSFireShader -[Alias('Apply_To_Image')] -[ComponentModel.DefaultBindingProperty('Apply_To_Image')] -[Management.Automation.SwitchParameter] -$ApplyToImage, -# Set the Replace_Image_Color of OBSFireShader -[Alias('Replace_Image_Color')] -[ComponentModel.DefaultBindingProperty('Replace_Image_Color')] -[Management.Automation.SwitchParameter] -$ReplaceImageColor, -# Set the Apply_To_Specific_Color of OBSFireShader -[Alias('Apply_To_Specific_Color')] -[ComponentModel.DefaultBindingProperty('Apply_To_Specific_Color')] -[Management.Automation.SwitchParameter] -$ApplyToSpecificColor, -# Set the Color_To_Replace of OBSFireShader -[Alias('Color_To_Replace')] -[ComponentModel.DefaultBindingProperty('Color_To_Replace')] -[String] -$ColorToReplace, -# Set the Notes of OBSFireShader -[ComponentModel.DefaultBindingProperty('Notes')] -[String] -$Notes, -# 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(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('transitionName')] +[string] +$TransitionName, +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'fire' -$ShaderNoun = 'OBSFireShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//fire shader modified by Charles Fettinger for use with obs-shaderfilter 07/20 v.6 -// https://github.com/Oncorporation/obs-shaderfilter plugin -// https://www.shadertoy.com/view/MtcGD7 original version -//Converted to OpenGL by Q-mii & Exeldro February 22, 2022 -//v.5 -// flicker -// flame type -// apply to image -// replace image color -// speed -// flame size -// alpha -// invert direction/position - - -//Section to converting GLSL to HLSL - can delete -#define vec2 float2 -#define vec3 float3 -#define vec4 float4 -#define ivec2 int2 -#define ivec3 int3 -#define ivec4 int4 -#define mat2 float2x2 -#define mat3 float3x3 -#define mat4 float4x4 -#define fract frac -#define mix lerp - -uniform int Alpha_Percentage< - string label = "Aplha Percentage"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 90; -uniform int Speed< - string label = "Speed"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 200; - int step = 1; -> = 100; -uniform int Flame_Size< - string label = "Flame Size"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 200; - int step = 1; -> = 70; -uniform int Fire_Type< - string label = "Fire Type"; - string widget_type = "select"; - int option_0_value = 0; - string option_0_label = "Smaller and more whisps"; - int option_1_value = 1; - string option_1_label = "Larger and more volume"; -> = 1; -uniform bool Invert < - string name = "Invert"; -> = false; -uniform float lumaMin< - string label = "Luma min"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.01; -uniform float lumaMinSmooth< - string label = "Luma min smooth"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.04; -uniform bool Apply_To_Image; -uniform bool Replace_Image_Color; -uniform bool Apply_To_Specific_Color; -uniform float4 Color_To_Replace; -uniform string Notes< - string widget_type = "info"; -> = "Luma cuts reveals background, flame size is percentage screen size, Alpha Percentage adjusts color"; -vec3 rgb2hsv(vec3 c) -{ - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -vec3 hsv2rgb(vec3 c) -{ - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -float rand(vec2 n) -{ - return fract(sin(cos(dot(n, vec2(12.9898, 12.1414)))) * 83758.5453); - //return sin(rand_f, n); -} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -float noise(vec2 n) -{ - const vec2 d = vec2(0.0, 1.0); - vec2 b = floor(n), f = smoothstep(vec2(0.0, 0.0), vec2(1.0, 1.0), fract(n)); - return mix(mix(rand(b), rand(b + d.yx), f.x), mix(rand(b + d.xy), rand(b + d.yy), f.x), f.y); -} + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -float fbm(vec2 n) -{ - float total = 0.0, amplitude = 1.0; - for (int i = 0; i < 5; i++) - { - total += noise(n) * amplitude; - n += n * 1.7; - amplitude *= 0.47; - } - return total; } -float4 mainImage(VertData v_in) : TARGET -{ - float2 iResolution = uv_scale; - float flame_size = clamp(Flame_Size * .01,-5,5); - - // inverting direction is logically inverted to allow the bottom up to be normal - float fire_base = (v_in.uv.y / iResolution.y); - float2 fire_pix = v_in.uv.xy + float2(flame_size -1,0); - float direction = -1.0 * clamp(Speed*.01,-5,5); - if (!Invert) - { - direction *= -1.0; - fire_base = 1 - fire_base; - fire_pix = 1 - fire_pix; - } - float iTime = direction * elapsed_time; - - const vec3 c1 = vec3(0.5, 0.0, 0.1); - const vec3 c2 = vec3(0.9, 0.1, 0.0); - const vec3 c3 = vec3(0.2, 0.1, 0.7); - const vec3 c4 = vec3(1.0, 0.9, 0.1); - const vec3 c5 = vec3(0.1, 0.1, 0.1); - const vec3 c6 = vec3(0.9, 0.9, 0.9); - vec2 speed = vec2(1.2, 0.1) * clamp(Speed*.01,-5,5); - float shift = 1.327 * (1/flame_size) - sin(iTime * 2.0) / 2.4; - float alpha = saturate(Alpha_Percentage * .01); - - //change the constant term for all kinds of cool distance versions, - //make plus/minus to switch between - //ground fire and fire rain! - float dist = 3.5 - sin(iTime * 0.4) / 1.89; - - vec2 p = fire_pix * dist / iResolution.xx; - p.x -= iTime / 1.1; - float3 black = float3(0,0,0); - vec3 fire; +} - if (Fire_Type == 1) - { - //fire version 1 larger and more volume - float q = fbm(p - iTime * 0.01 + 1.0 * sin(iTime) / 10.0); - float qb = fbm(p - iTime * 0.002 + 0.1 * cos(iTime) / 5.0); - float q2 = fbm(p - iTime * 0.44 - 5.0 * cos(iTime) / 7.0) -6.0; - float q3 = fbm(p - iTime * 0.9 - 10.0 * cos(iTime) / 30.0) -4.0; - float q4 = fbm(p - iTime * 2.0 - 20.0 * sin(iTime) / 20.0) +2.0; - q = (q + qb - .4 * q2 - 2.0 * q3 + .6 * q4) / 3.8; + +#.ExternalHelp obs-powershell-Help.xml +function Set-OBSCurrentSceneTransitionDuration { - vec2 r = vec2(fbm(p + q / 2.0 - iTime* speed.x - p.x - p.y), - fbm(p - q - iTime* speed.y)) ; - vec3 c = mix(c1, c2, fbm(p + r)) + mix(c3, c4, r.x) - mix(c5, c6, r.y); - fire = vec3(c * max(cos(shift * fire_base) - (rand_f *.05),0.05)); - fire += .05; - fire.r *= .8; - vec3 hsv = rgb2hsv(fire); - hsv.y *= hsv.z * 1.1; - hsv.z *= hsv.y * 1.13; - hsv.y = (2.2 - hsv.z * .9) * 1.20; - fire = hsv2rgb(hsv); - } - else - { - // fire version 0 - smaller and more whisps - p += (rand_f *.01); - float q = fbm(p - iTime * 0.3+1.0*sin(iTime+0.5)/2.0); - float qb = fbm(p - iTime * 0.4+0.1*cos(iTime)/2.0); - float q2 = fbm(p - iTime * 0.44 - 5.0*cos(iTime)/2.0) - 6.0; - float q3 = fbm(p - iTime * 0.9 - 10.0*cos(iTime)/15.0)-4.0; - float q4 = fbm(p - iTime * 1.4 - 20.0*sin(iTime)/14.0)+2.0; - q = (q + qb - .4 * q2 -2.0*q3 + .6*q4)/3.8; +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetCurrentSceneTransitionDuration')] +[Alias('obs.powershell.websocket.SetCurrentSceneTransitionDuration')] +param( - vec2 r = vec2(fbm(p + q /2.0 + iTime * speed.x - p.x - p.y), - fbm(p + q - iTime * speed.y)) * shift; - vec3 c = mix(c1, c2, fbm(p + r)) + mix(c3, c4, r.x) - mix(c5, c6, r.y); - //fire = vec3(1.0/(pow(c+1.61,vec3(4.0,4.0,4.0))) * max(cos(shift * fire_base),0)); - - fire = vec3(1.0,.2,.05)/(pow((r.y+r.y)* max(.0,p.y)+0.1, 4.0)) ;//* max(.1,(cos(shift * fire_base))); - fire += (black*0.01*pow((r.y+r.y)*.65,5.0)+0.055)*mix( vec3(.9,.4,.3),vec3(.7,.5,.2), v_in.uv.y); - fire = fire/(1.0+max(black,fire)); - } - float4 rgba = vec4(fire.x, fire.y, fire.z, alpha); - - // remove dark areas per user - float luma_fire = dot(rgba.rgb,float3(0.299,0.587,0.114)); - float luma_min_fire = smoothstep(lumaMin, lumaMin + lumaMinSmooth, luma_fire); - rgba.a = clamp(luma_min_fire,0.0,alpha); - - float4 color; - float4 original_color; - if (Apply_To_Image) - { - color = image.Sample(textureSampler, v_in.uv); - original_color = color; - if (color.a > 0.0) - { - float luma = color.r * 0.299 + color.g * 0.587 + color.b * 0.114; - if (Replace_Image_Color) - color = float4(luma, luma, luma, luma); - rgba = lerp(original_color, lerp(original_color,rgba * color,rgba.a), alpha); - } - else - { - rgba = color; - } - - } - if (Apply_To_Specific_Color) - { - color = image.Sample(textureSampler, v_in.uv); - original_color = color; - color = (distance(color.rgb, Color_To_Replace.rgb) <= 0.075) ? rgba : color; - rgba = lerp(original_color, color, alpha); - } - return rgba; -} +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('transitionDuration')] +[ValidateRange(50,20000)] +[double] +$TransitionDuration, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) +process { -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -20145,256 +13584,110 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSFireworks2Shader { +function Set-OBSCurrentSceneTransitionSettings { -[Alias('Set-OBSFireworks2Shader','Add-OBSFireworks2Shader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetCurrentSceneTransitionSettings')] +[Alias('obs.powershell.websocket.SetCurrentSceneTransitionSettings')] param( -# Set the Speed of OBSFireworks2Shader -[ComponentModel.DefaultBindingProperty('Speed')] -[Single] -$Speed, -# The name of the source. This must be provided when adding an item for the first time + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('transitionSettings')] +[PSObject] +$TransitionSettings, + [Parameter(ValueFromPipelineByPropertyName)] -[Alias('SceneItemName')] -[String] -$SourceName, -# The name of the filter. If this is not provided, this will default to the shader name. +[ComponentModel.DefaultBindingProperty('overlay')] +[switch] +$Overlay, +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'fireworks2' -$ShaderNoun = 'OBSFireworks2Shader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// based on https://www.shadertoy.com/view/4dBGRw - -uniform float Speed< - string label = "Speed"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 200.0; - float step = 1.0; -> = 100.0; - -#ifndef OPENGL -#define mat2 float2x2 -#define mix lerp -float mod(float x, float y) -{ - return x - y * floor(x / y); -} -#endif -//Creates a diagonal red-and-white striped pattern. -float3 barberpole(float2 pos, float2 rocketpos){ - float d = (pos.x-rocketpos.x)+(pos.y-rocketpos.y); - float3 col=float3(1.0,1.0,1.0); - - d = mod(d*20.,2.0); - if(d>1.0){ - col=float3(1.0,0.0,0.0); - } - return col; -} - -float4 rocket(float2 pos, float2 rocketpos){ - float4 col = float4(0.0,0.0,0.0,0.0); - float f = 0.; - float absx= abs(rocketpos.x - pos.x); - float absy = abs(rocketpos.y-pos.y); - //wooden stick - if(absx<0.01&&absy<0.22){ - col=float4(1.0,0.5,0.5,1.0); - } - - //Barberpole - - if(absx<0.05&&absy<0.15){ - col=float4(barberpole(pos, rocketpos),1.0); - } - //Rocket Point - float pointw=(rocketpos.y-pos.y-0.25)*-0.7; - if((rocketpos.y-pos.y)>0.1){ - f=smoothstep(pointw-0.001,pointw+0.001,absx); - - col=mix(float4(1.0,0.0,0.0,1.0),col, f); - } - //Shadow - - f =-.5 + smoothstep(-0.05, 0.05, (rocketpos.x-pos.x)); - col.rgb *= 0.7+f; - - return col; -} - - - -float rand(float val, float seed){ - return cos(val*sin(val*seed)*seed); -} - -float distance2( in float2 a, in float2 b ) { return dot(a-b,a-b); } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -float4 drawParticles(float2 pos, float3 particolor, float time, float2 cpos, float gravity, float seed, float timelength){ - float4 col= float4(0.0,0.0,0.0,0.0); - float2 pp = float2(1.0,0.0); - mat2 rr = mat2( cos(1.0), -sin(1.0), sin(1.0), cos(1.0) ); - for(float i=1.0;i<=128.0;i++){ - float d=rand(i, seed); - float fade=(i/128.0)*time; - float2 particpos = cpos + time*pp*d; - pp = mul(rr,pp); - col.rgb = mix(particolor/fade, col, smoothstep(0.0, 0.0001, distance2(particpos, pos))); - } - col.rgb*=smoothstep(0.0,1.0,(timelength-time)/timelength); - col.a = col.r+col.g+col.b; - return col; -} -float4 drawFireworks(float time, float2 uv, float3 particolor, float seed){ - - float timeoffset = 2.0; - float4 col=float4(0.0,0.0,0.0,0.0); - if(time<=0.){ - return col; - } - time *= Speed /100.0; - if(mod(time, 6.0)>timeoffset){ - col= drawParticles(uv, particolor, mod(time, 6.0)-timeoffset, float2(rand(ceil(time/6.0),seed),-0.5), 0.5, ceil(time/6.0), seed); - }else{ - - col= rocket(uv*3., float2(3.*rand(ceil(time/6.0),seed),3.*(-0.5+(timeoffset-mod(time, 6.0))))); - } - return col; -} - -float4 mainImage(VertData v_in) : TARGET -{ - float2 uv =float2(1.0,1.0) - 2.0* v_in.uv; - uv.y = -uv.y; - uv.x *= uv_size.x/uv_size.y; - float4 col = image.Sample(textureSampler, v_in.uv); - //col.rgb += 0.1*uv.y; - float4 c; - c = drawFireworks(elapsed_time , uv,float3(1.0,0.1,0.1), 1.); - col = mix(col, c, c.a); - c = drawFireworks(elapsed_time-2.0, uv,float3(0.0,1.0,0.5), 2.); - col = mix(col, c, c.a); - c = drawFireworks(elapsed_time-4.0, uv,float3(1.0,1.0,0.1), 3.); - col = mix(col, c, c.a); - - return col; -} -' -} -$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 + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -20403,313 +13696,233 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSFireworksShader { +function Set-OBSInputAudioBalance { -[Alias('Set-OBSFireworksShader','Add-OBSFireworksShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetInputAudioBalance')] +[Alias('obs.powershell.websocket.SetInputAudioBalance')] param( -# Set the show_flash of OBSFireworksShader -[Alias('show_flash')] -[ComponentModel.DefaultBindingProperty('show_flash')] -[Management.Automation.SwitchParameter] -$ShowFlash, -# Set the show_stars of OBSFireworksShader -[Alias('show_stars')] -[ComponentModel.DefaultBindingProperty('show_stars')] -[Management.Automation.SwitchParameter] -$ShowStars, -# Set the use_transparancy of OBSFireworksShader -[Alias('use_transparancy')] -[ComponentModel.DefaultBindingProperty('use_transparancy')] -[Management.Automation.SwitchParameter] -$UseTransparancy, -# 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. +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + [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] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputAudioBalance')] +[ValidateRange(0,1)] +[double] +$InputAudioBalance, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'fireworks' -$ShaderNoun = 'OBSFireworksShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -#ifndef OPENGL -#define mat2 float2x2 -#define fract frac -#define mix lerp -#endif -uniform bool show_flash = true; -uniform bool show_stars = true; -uniform bool use_transparancy = true; -float distLine(float2 p, float2 a, float2 b) { - float2 pa = p - a; - float2 ba = b - a; - float t = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); - return length(pa - ba * t); -} + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -float linef(float2 uv, float2 a, float2 b, float w) { - //return smoothstep(w, w - 0.01, distLine(uv, a, b)); - return w / distLine(uv, a, b); -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -float N21(float2 p) { - p = fract(p * float2(233.34, 851.73)); - p += dot(p, p + 23.45); - return fract(p.x * p.y); -} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -float2 N22(float2 p) { - float n = N21(p); - return float2(n, N21(p + n)); -} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -float N11(float n) { - return fract(sin(dot(float2(cos(n), sin(n)) ,float2(27.9898, 38.233))) * 88.5453); -} + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -float particle(float2 uv, float2 p, float2 v, float r, float t) { - float g = -9.81; - float x = p.x + v.x * t; - float y = p.y + v.y * t + g / 2.0 * t * t; - float2 j = (float2(x, y) - uv) * 20.0; - float sparkle = 1.0 / dot(j, j); - return sparkle; } -float2 p1(float2 p, float h, float t) { - return float2(p.x, p.y + clamp(pow(t, 5.0), 0.0, h)); -} -float2 p2(float2 p, float h, float t) { - return float2(p.x, p.y + clamp(pow(0.95 * t, 5.0), 0.0, h)); -} +} -float endTime(float h) { - return pow(h, 1.0 / 5.0) * 1.1; -} + +#.ExternalHelp obs-powershell-Help.xml +function Set-OBSInputAudioMonitorType { -float explosion(float2 uv, float2 p, float s, float n, float f, float t) { - float m = 0.0; - float dt = 0.5; - float seed2 = 0.32; - for(float i = 0.0; i < n; i++) { - seed2 += i; - float2 rand = float2(1.0, 2.0) * (float2(-1.0, 1.0) + 2.0 * N22(float2(seed2, i))); - float2 v = float2(cos(seed2), sin(seed2)) + rand; - m += particle(uv, p, v, s, t) * smoothstep(2.0, 2.0 - dt, t) * smoothstep(0.0, dt, t); - } - return m; -} +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetInputAudioMonitorType')] +[Alias('obs.powershell.websocket.SetInputAudioMonitorType')] +param( -float fireworks(float2 uv, float2 p, float h, float n, float s, float f, float t) { - float2 p1v = p1(p, h, t); - float e = endTime(h); - return explosion(uv, p1v, s, n, f, t - e * 0.9); -} +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, -float shaft(float2 uv, float2 p, float w, float h, float t) { - float2 p1v = p1(p, h, t) + float2(0.0, 0.3); - float2 p2v = p2(p, h, t); - float e = 1.0 / 0.95 * endTime(h); - float2 j = (p1v - uv) * 15.0; - float sparkle = 1.0 / dot(j, j); - return (linef(uv, p1v, p2v, w) + sparkle) * smoothstep(e, e - 0.5, t) * 0.5; -} +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, -float3 base(float2 uv) { - return 0.5 + 0.5 * cos(elapsed_time + uv.xyx + float3(0, 2, 4)); -} +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('monitorType')] +[string] +$MonitorType, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) -float back(float2 uv, float2 p, float t) { - float dt = 0.3; - float j = length(p - uv); - float m = exp(-0.005 * j * j); - return 0.2 * m * smoothstep(-dt / 4.0, 0.0, t) * smoothstep(dt, 0.0, t); -} -float stars(float2 uv) { - float r = N21(uv); - return smoothstep(0.001, 0.0, r); -} +process { -float mod(float x, float y) -{ - return x - y * floor(x / y); -} -float4 mainImage( VertData v_in ) : TARGET -{ - float2 uv = v_in.uv - float2(0.5,0.5); - uv.y = uv.y * -1; - float t = elapsed_time / 10.0; - float scale = 10.0; - uv *= scale; - // - float4 col = image.Sample(textureSampler, v_in.uv); - if(show_stars){ - float c = stars(uv); - if(use_transparancy){ - col += float4(c,c,c,c)*(1.0-col.a); - }else{ - col += float4(c,c,c,c);//*(1.0-orig_col.a); - } - - } - - float a = -0.035 * sin(t * 15.0); - float co = cos(a); - float si = sin(a); - mat2 trans1 = mat2(float2(co, si), float2(-si, co)); - float2 trans2 = float2(-15.0 * a, 0.0); -#ifndef OPENGL - uv = mul(uv, trans1); -#else - uv *= trans1; -#endif - uv += trans2; - - for(float i = 0.0; i < 1.0; i += 1.0 / 8.0) { - float ti = mod(t * 9.0 - i * 5.0, 4.0); - float scale = mix(2.0, 0.3, ti / 4.0); - float2 uvs = uv * scale; - float rand = N11(i); - float h = 10.0 + rand * 4.0; - float w = 0.02; - float n = 80.0; - float s = 0.9; - float f = 1.5; - float2 p = float2(mix(-8.0, 8.0, rand), -10.0); - float fw = fireworks(uvs, p, h, n, s, f, ti); - float3 bc = base(uv); - col += float4(bc*fw, fw); - col += shaft(uvs, p, w, h, ti); - if(show_flash){ - if(use_transparancy){ - col += back(uvs, float2(p.x, p.y + h), ti - 1.8)*col.a; - }else{ - col += back(uvs, float2(p.x, p.y + h), ti - 1.8); - } - } - } - - return col; -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -20718,188 +13931,116 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSFisheyeShader { +function Set-OBSInputAudioSyncOffset { -[Alias('Set-OBSFisheyeShader','Add-OBSFisheyeShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetInputAudioSyncOffset')] +[Alias('obs.powershell.websocket.SetInputAudioSyncOffset')] param( -# Set the center_x_percent of OBSFisheyeShader -[Alias('center_x_percent')] -[ComponentModel.DefaultBindingProperty('center_x_percent')] -[Single] -$CenterXPercent, -# Set the center_y_percent of OBSFisheyeShader -[Alias('center_y_percent')] -[ComponentModel.DefaultBindingProperty('center_y_percent')] -[Single] -$CenterYPercent, -# Set the power of OBSFisheyeShader -[ComponentModel.DefaultBindingProperty('power')] -[Single] -$Power, -# 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. +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + [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] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputAudioSyncOffset')] +[ValidateRange(-950,20000)] +[double] +$InputAudioSyncOffset, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'fisheye' -$ShaderNoun = 'OBSFisheyeShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform float center_x_percent< - string label = "Center x percent"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 50.0; -uniform float center_y_percent< - string label = "Center y percent"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 50.0; -uniform float power< - string label = "Power"; - string widget_type = "slider"; - float minimum = -2.0; - float maximum = 2.0; - float step = 0.01; -> = 1.75; -float4 mainImage(VertData v_in) : TARGET -{ - float2 center_pos = float2(center_x_percent * .01, center_y_percent * .01); - float2 uv = v_in.uv; - if (power >= 0.0001){ - float b = sqrt(dot(center_pos, center_pos)); - uv = center_pos + normalize(v_in.uv - center_pos) * tan(distance(center_pos, v_in.uv) * power) * b / tan( b * power); - } else if(power <= -0.0001){ - float b; - if (uv_pixel_interval.x < uv_pixel_interval.y){ - b = center_pos.x; - } else { - b = center_pos.y; - } - uv = center_pos + normalize(v_in.uv - center_pos) * atan(distance(center_pos, v_in.uv) * -power * 10.0) * b / atan(-power * b * 10.0); - } - return image.Sample(textureSampler, uv); -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -20908,213 +14049,115 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSFisheyeXyShader { +function Set-OBSInputAudioTracks { -[Alias('Set-OBSFisheyeXyShader','Add-OBSFisheyeXyShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetInputAudioTracks')] +[Alias('obs.powershell.websocket.SetInputAudioTracks')] param( -# Set the center_x_percent of OBSFisheyeXyShader -[Alias('center_x_percent')] -[ComponentModel.DefaultBindingProperty('center_x_percent')] -[Single] -$CenterXPercent, -# Set the center_y_percent of OBSFisheyeXyShader -[Alias('center_y_percent')] -[ComponentModel.DefaultBindingProperty('center_y_percent')] -[Single] -$CenterYPercent, -# Set the power_x of OBSFisheyeXyShader -[Alias('power_x')] -[ComponentModel.DefaultBindingProperty('power_x')] -[Single] -$PowerX, -# Set the power_y of OBSFisheyeXyShader -[Alias('power_y')] -[ComponentModel.DefaultBindingProperty('power_y')] -[Single] -$PowerY, -# 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. +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + [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] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputAudioTracks')] +[PSObject] +$InputAudioTracks, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'fisheye-xy' -$ShaderNoun = 'OBSFisheyeXyShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform float center_x_percent< - string label = "Center x percent"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 50.0; -uniform float center_y_percent< - string label = "Center y percent"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 50.0; -uniform float power_x< - string label = "Power x"; - string widget_type = "slider"; - float minimum = -2.0; - float maximum = 2.0; - float step = 0.01; -> = 1.75; -uniform float power_y< - string label = "Power y"; - string widget_type = "slider"; - float minimum = -2.0; - float maximum = 2.0; - float step = 0.01; -> = 1.75; -float4 mainImage(VertData v_in) : TARGET -{ - float2 center_pos = float2(center_x_percent * .01, center_y_percent * .01); - float2 uv = v_in.uv; - if (power_x >= 0.0001){ - float b = sqrt(dot(center_pos, center_pos)); - uv.x = (center_pos + normalize(v_in.uv - center_pos) * tan(distance(center_pos, v_in.uv) * power_x) * b / tan( b * power_x)).x; - } else if(power_x <= -0.0001){ - float b; - if (uv_pixel_interval.x < uv_pixel_interval.y){ - b = center_pos.x; - } else { - b = center_pos.y; - } - uv.x = (center_pos + normalize(v_in.uv - center_pos) * atan(distance(center_pos, v_in.uv) * -power_x * 10.0) * b / atan(-power_x * b * 10.0)).x; - } - if (power_y >= 0.0001){ - float b = sqrt(dot(center_pos, center_pos)); - uv.y = (center_pos + normalize(v_in.uv - center_pos) * tan(distance(center_pos, v_in.uv) * power_y) * b / tan( b * power_y)).y; - } else if(power_y <= -0.0001){ - float b; - if (uv_pixel_interval.x < uv_pixel_interval.y){ - b = center_pos.x; - } else { - b = center_pos.y; - } - uv.y = (center_pos + normalize(v_in.uv - center_pos) * atan(distance(center_pos, v_in.uv) * -power_y * 10.0) * b / atan(-power_y * b * 10.0)).y; - } - return image.Sample(textureSampler, uv); -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -21123,163 +14166,115 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSFlipShader { +function Set-OBSInputMute { -[Alias('Set-OBSFlipShader','Add-OBSFlipShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetInputMute')] +[Alias('obs.powershell.websocket.SetInputMute')] param( -# Set the Horizontal of OBSFlipShader -[ComponentModel.DefaultBindingProperty('Horizontal')] -[Management.Automation.SwitchParameter] -$Horizontal, -# Set the Vertical of OBSFlipShader -[ComponentModel.DefaultBindingProperty('Vertical')] -[Management.Automation.SwitchParameter] -$Vertical, -# 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. +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + [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] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputMuted')] +[switch] +$InputMuted, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'Flip' -$ShaderNoun = 'OBSFlipShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// A Simple Flip Shader - -uniform bool Horizontal< - string label = "Flip horizontally"; -> = true; -uniform bool Vertical< - string label = "Flip vertically"; -> = true; -float4 mainImage(VertData v_in) : TARGET -{ - float2 pos = v_in.uv; - if (Horizontal == true) { - pos.x = 1 - pos.x; - } - if (Vertical == true) { - pos.y = 1 - pos.y; - } - - return image.Sample(textureSampler, pos); -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -21288,238 +14283,115 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSFrostedGlassShader { +function Set-OBSInputName { -[Alias('Set-OBSFrostedGlassShader','Add-OBSFrostedGlassShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetInputName')] +[Alias('obs.powershell.websocket.SetInputName')] param( -# Set the Alpha_Percent of OBSFrostedGlassShader -[Alias('Alpha_Percent')] -[ComponentModel.DefaultBindingProperty('Alpha_Percent')] -[Single] -$AlphaPercent, -# Set the Amount of OBSFrostedGlassShader -[ComponentModel.DefaultBindingProperty('Amount')] -[Single] -$Amount, -# Set the Scale of OBSFrostedGlassShader -[ComponentModel.DefaultBindingProperty('Scale')] -[Single] -$Scale, -# Set the Animate of OBSFrostedGlassShader -[ComponentModel.DefaultBindingProperty('Animate')] -[Management.Automation.SwitchParameter] -$Animate, -# Set the Horizontal_Border of OBSFrostedGlassShader -[Alias('Horizontal_Border')] -[ComponentModel.DefaultBindingProperty('Horizontal_Border')] -[Management.Automation.SwitchParameter] -$HorizontalBorder, -# Set the Border_Offset of OBSFrostedGlassShader -[Alias('Border_Offset')] -[ComponentModel.DefaultBindingProperty('Border_Offset')] -[Single] -$BorderOffset, -# Set the Border_Color of OBSFrostedGlassShader -[Alias('Border_Color')] -[ComponentModel.DefaultBindingProperty('Border_Color')] -[String] -$BorderColor, -# Set the notes of OBSFrostedGlassShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# 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. +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + [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] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('newInputName')] +[string] +$NewInputName, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'frosted_glass' -$ShaderNoun = 'OBSFrostedGlassShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Frosted Glass shader by Charles Fettinger for obs-shaderfilter plugin 4/2019 -//https://github.com/Oncorporation/obs-shaderfilter - -uniform float Alpha_Percent< - string label = "Alpha Percent"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.1; -> = 100.0; -uniform float Amount< - string label = "Amount"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.03; -uniform float Scale< - string label = "Scale"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.01; -> = 5.1; -uniform bool Animate; -uniform bool Horizontal_Border; -uniform float Border_Offset< - string label = "Border Offset"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2.0; - float step = 0.01; -> = 1.1; -uniform float4 Border_Color = {.8,.5,1.0,1.0}; -uniform string notes< - string widget_type = "info"; -> = "Change shader with Scale and Amount, move Border with Border Offset. Alpha is Opacity of overlay."; - -float rand(float2 co) -{ - float scale = Scale; - if (Animate) - scale *= rand_f; - float2 v1 = float2(92.0,80.0); - float2 v2 = float2(41.0,62.0); - return frac(sin(dot(co.xy ,v1)) + cos(dot(co.xy ,v2)) * scale); -} - -float4 mainImage(VertData v_in) : TARGET -{ - float4 rgba = image.Sample(textureSampler, v_in.uv); - float3 tc = rgba.rgb * Border_Color.rgb; - - float uv_compare = v_in.uv.x; - if (Horizontal_Border) - uv_compare = v_in.uv.y; - if (uv_compare < (Border_Offset - 0.005)) - { - float2 randv = float2(rand(v_in.uv.yx),rand(v_in.uv.yx)); - tc = image.Sample(textureSampler, v_in.uv + (randv*Amount)).rgb; - } - else if (uv_compare >= (Border_Offset + 0.005)) - { - tc = image.Sample(textureSampler, v_in.uv).rgb; - } - return lerp(rgba,float4(tc,1.0),(Alpha_Percent * 0.01)); -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -21528,184 +14400,120 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSGammaCorrectionShader { +function Set-OBSInputSettings { -[Alias('Set-OBSGammaCorrectionShader','Add-OBSGammaCorrectionShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetInputSettings')] +[Alias('obs.powershell.websocket.SetInputSettings')] param( -# Set the Red of OBSGammaCorrectionShader -[ComponentModel.DefaultBindingProperty('Red')] -[Single] -$Red, -# Set the Green of OBSGammaCorrectionShader -[ComponentModel.DefaultBindingProperty('Green')] -[Single] -$Green, -# Set the Blue of OBSGammaCorrectionShader -[ComponentModel.DefaultBindingProperty('Blue')] -[Single] -$Blue, -# Set the notes of OBSGammaCorrectionShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# 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. +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + [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] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputSettings')] +[PSObject] +$InputSettings, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('overlay')] +[switch] +$Overlay, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'gamma_correction' -$ShaderNoun = 'OBSGammaCorrectionShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Gamma Correction shader by Charles Fettinger for obs-shaderfilter plugin 4/2019 -//https://github.com/Oncorporation/obs-shaderfilter -uniform float Red< - string label = "Red"; - string widget_type = "slider"; - float minimum = 0.1; - float maximum = 10.0; - float step = 0.01; -> = 2.2; -uniform float Green< - string label = "Green"; - string widget_type = "slider"; - float minimum = 0.1; - float maximum = 10.0; - float step = 0.01; -> = 2.2; -uniform float Blue< - string label = "Blue"; - string widget_type = "slider"; - float minimum = 0.1; - float maximum = 10.0; - float step = 0.01; -> = 2.2; -uniform string notes< - string widget_type = "info"; -> = "Modify Colors to correct for gamma, use equal values for general correction." -float4 mainImage(VertData v_in) : TARGET -{ - float3 gammaRGB = float3(clamp(Red,0.1,10.0),clamp(Green,0.1,10.0),clamp(Blue,0.1,10.0)); - float4 c = image.Sample(textureSampler, v_in.uv); - c.rgb = pow(c.rgb, 1.0 / gammaRGB); - return c; -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -21714,264 +14522,122 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSGaussianBlurAdvancedShader { +function Set-OBSInputVolume { -[Alias('Set-OBSGaussianBlurAdvancedShader','Add-OBSGaussianBlurAdvancedShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetInputVolume')] +[Alias('obs.powershell.websocket.SetInputVolume')] param( -# Set the Directions of OBSGaussianBlurAdvancedShader -[ComponentModel.DefaultBindingProperty('Directions')] -[Single] -$Directions, -# Set the Quality of OBSGaussianBlurAdvancedShader -[ComponentModel.DefaultBindingProperty('Quality')] -[Single] -$Quality, -# Set the Size of OBSGaussianBlurAdvancedShader -[ComponentModel.DefaultBindingProperty('Size')] -[Single] -$Size, -# Set the Mask_Left of OBSGaussianBlurAdvancedShader -[Alias('Mask_Left')] -[ComponentModel.DefaultBindingProperty('Mask_Left')] -[Single] -$MaskLeft, -# Set the Mask_Right of OBSGaussianBlurAdvancedShader -[Alias('Mask_Right')] -[ComponentModel.DefaultBindingProperty('Mask_Right')] -[Single] -$MaskRight, -# Set the Mask_Top of OBSGaussianBlurAdvancedShader -[Alias('Mask_Top')] -[ComponentModel.DefaultBindingProperty('Mask_Top')] -[Single] -$MaskTop, -# Set the Mask_Bottom of OBSGaussianBlurAdvancedShader -[Alias('Mask_Bottom')] -[ComponentModel.DefaultBindingProperty('Mask_Bottom')] -[Single] -$MaskBottom, -# 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. +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + [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] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputVolumeMul')] +[ValidateRange(0,20)] +[double] +$InputVolumeMul, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputVolumeDb')] +[ValidateRange(-100,26)] +[double] +$InputVolumeDb, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'gaussian-blur-advanced' -$ShaderNoun = 'OBSGaussianBlurAdvancedShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform float Directions< - string label = "Directions (16.0)"; - string widget_type = "slider"; - float minimum = 1.0; - float maximum = 100.0; - float step = 1.0; -> = 16.0; // BLUR DIRECTIONS (Default 16.0 - More is better but slower) -uniform float Quality< - string label = "Quality (4.0)"; - string widget_type = "slider"; - float minimum = 1.0; - float maximum = 100.0; - float step = 1.0; -> = 4.0; // BLUR QUALITY (Default 4.0 - More is better but slower) -uniform float Size< - string label = "Size (8.0)"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 1.0; -> = 8.0; // BLUR SIZE (Radius) -uniform float Mask_Left< - string label = "Mask left (1.0)"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 1.0; -uniform float Mask_Right< - string label = "Mask right (1.0)"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 1.0; -uniform float Mask_Top< - string label = "Mask top (1.0)"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 1.0; -uniform float Mask_Bottom< - string label = "Mask bottom (1.0)"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 1.0; - -float4 mainImage(VertData v_in) : TARGET -{ - if(Mask_Left + Mask_Right > 1.0){ - if(v_in.uv.x > Mask_Left || 1.0 - v_in.uv.x > Mask_Right ){ - return image.Sample(textureSampler, v_in.uv); - } - }else{ - if((v_in.uv.x > Mask_Left) && (1.0-v_in.uv.x > Mask_Right)){ - return image.Sample(textureSampler, v_in.uv); - } - } - if(Mask_Top + Mask_Bottom > 1.0){ - if(v_in.uv.y > Mask_Top || 1.0 - v_in.uv.y > Mask_Bottom){ - return image.Sample(textureSampler, v_in.uv); - } - }else { - if((v_in.uv.y > Mask_Top) && (1.0-v_in.uv.y > Mask_Bottom)){ - return image.Sample(textureSampler, v_in.uv); - } - } - - float Pi = 6.28318530718; // Pi*2 - - float4 c = image.Sample(textureSampler, v_in.uv); - float4 oc = c; - float transparent = oc.a; - int count = 1; - float samples = oc.a; - - // Blur calculations - [loop] for( float d=0.0; d 0.0) - c /= samples; - c.a = transparent / count; - return c; -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -21980,342 +14646,116 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSGaussianBlurShader { +function Set-OBSMediaInputCursor { -[Alias('Set-OBSGaussianBlurShader','Add-OBSGaussianBlurShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetMediaInputCursor')] +[Alias('obs.powershell.websocket.SetMediaInputCursor')] 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. +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, + [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] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('mediaCursor')] +[ValidateRange(0,[int]::MaxValue)] +[double] +$MediaCursor, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) 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; -}; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -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))); -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -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; -} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -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] + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam } - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -22324,249 +14764,110 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSGaussianBlurSimpleShader { +function Set-OBSOutputSettings { -[Alias('Set-OBSGaussianBlurSimpleShader','Add-OBSGaussianBlurSimpleShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetOutputSettings')] +[Alias('obs.powershell.websocket.SetOutputSettings')] param( -# Set the Strength of OBSGaussianBlurSimpleShader -[ComponentModel.DefaultBindingProperty('Strength')] -[Int32] -$Strength, -# Set the Mask_Left of OBSGaussianBlurSimpleShader -[Alias('Mask_Left')] -[ComponentModel.DefaultBindingProperty('Mask_Left')] -[Single] -$MaskLeft, -# Set the Mask_Right of OBSGaussianBlurSimpleShader -[Alias('Mask_Right')] -[ComponentModel.DefaultBindingProperty('Mask_Right')] -[Single] -$MaskRight, -# Set the Mask_Top of OBSGaussianBlurSimpleShader -[Alias('Mask_Top')] -[ComponentModel.DefaultBindingProperty('Mask_Top')] -[Single] -$MaskTop, -# Set the Mask_Bottom of OBSGaussianBlurSimpleShader -[Alias('Mask_Bottom')] -[ComponentModel.DefaultBindingProperty('Mask_Bottom')] -[Single] -$MaskBottom, -# 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(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('outputName')] +[string] +$OutputName, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('outputSettings')] +[PSObject] +$OutputSettings, +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'gaussian-blur-simple' -$ShaderNoun = 'OBSGaussianBlurSimpleShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform int Strength< - string label = "Strength (1)"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 25; - int step = 1; -> = 1.0; -uniform float Mask_Left< - string label = "Mask left (1.0)"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 1.0; -uniform float Mask_Right< - string label = "Mask right (1.0)"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 1.0; -uniform float Mask_Top< - string label = "Mask top (1.0)"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 1.0; -uniform float Mask_Bottom< - string label = "Mask bottom (1.0)"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 1.0; - -float4 mainImage(VertData v_in) : TARGET -{ - if(Strength <= 0) - return image.Sample(textureSampler, v_in.uv); - - if(Mask_Left + Mask_Right > 1.0){ - if(v_in.uv.x > Mask_Left || 1.0 - v_in.uv.x > Mask_Right ){ - return image.Sample(textureSampler, v_in.uv); - } - }else{ - if((v_in.uv.x > Mask_Left) && (1.0-v_in.uv.x > Mask_Right)){ - return image.Sample(textureSampler, v_in.uv); - } - } - if(Mask_Top + Mask_Bottom > 1.0){ - if(v_in.uv.y > Mask_Top || 1.0 - v_in.uv.y > Mask_Bottom){ - return image.Sample(textureSampler, v_in.uv); - } - }else { - if((v_in.uv.y > Mask_Top) && (1.0-v_in.uv.y > Mask_Bottom)){ - return image.Sample(textureSampler, v_in.uv); - } - } - - float Pi = 6.28318530718; // Pi*2 - - float Directions = float(Strength) * 4.0; // BLUR DIRECTIONS (Default 16.0 - More is better but slower) - float Quality = float(Strength); // BLUR QUALITY (Default 4.0 - More is better but slower) - float Size = float(Strength) * float(Strength); // BLUR SIZE (Radius) - - float4 c = image.Sample(textureSampler, v_in.uv); - float4 oc = c; - float transparent = oc.a; - int count = 1; - float samples = oc.a; - - // Blur calculations - [loop] for( float d=0.0; d 0.0) - c /= samples; - c.a = transparent / count; - return c; -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -22575,378 +14876,232 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSGaussianExampleShader { +function Set-OBSPersistentData { -[Alias('Set-OBSGaussianExampleShader','Add-OBSGaussianExampleShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetPersistentData')] +[Alias('obs.powershell.websocket.SetPersistentData')] param( -# Set the ViewProj of OBSGaussianExampleShader -[ComponentModel.DefaultBindingProperty('ViewProj')] -[Single[][]] -$ViewProj, -# Set the image of OBSGaussianExampleShader -[ComponentModel.DefaultBindingProperty('image')] -[String] -$Image, -# Set the elapsed_time of OBSGaussianExampleShader -[Alias('elapsed_time')] -[ComponentModel.DefaultBindingProperty('elapsed_time')] -[Single] -$ElapsedTime, -# Set the uv_offset of OBSGaussianExampleShader -[Alias('uv_offset')] -[ComponentModel.DefaultBindingProperty('uv_offset')] -[Single[]] -$UvOffset, -# Set the uv_scale of OBSGaussianExampleShader -[Alias('uv_scale')] -[ComponentModel.DefaultBindingProperty('uv_scale')] -[Single[]] -$UvScale, -# Set the uv_size of OBSGaussianExampleShader -[Alias('uv_size')] -[ComponentModel.DefaultBindingProperty('uv_size')] -[Single[]] -$UvSize, -# Set the uv_pixel_interval of OBSGaussianExampleShader -[Alias('uv_pixel_interval')] -[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] -[Single[]] -$UvPixelInterval, -# Set the initial_image of OBSGaussianExampleShader -[Alias('initial_image')] -[ComponentModel.DefaultBindingProperty('initial_image')] -[String] -$InitialImage, -# Set the before_image of OBSGaussianExampleShader -[Alias('before_image')] -[ComponentModel.DefaultBindingProperty('before_image')] -[String] -$BeforeImage, -# Set the after_image of OBSGaussianExampleShader -[Alias('after_image')] -[ComponentModel.DefaultBindingProperty('after_image')] -[String] -$AfterImage, -# Set the text_color of OBSGaussianExampleShader -[Alias('text_color')] -[ComponentModel.DefaultBindingProperty('text_color')] -[String] -$TextColor, -# Set the max_distance of OBSGaussianExampleShader -[Alias('max_distance')] -[ComponentModel.DefaultBindingProperty('max_distance')] -[Single] -$MaxDistance, -# Set the exp of OBSGaussianExampleShader -[ComponentModel.DefaultBindingProperty('exp')] -[Single] -$Exp, -# 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(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('realm')] +[string] +$Realm, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('slotName')] +[string] +$SlotName, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('slotValue')] +[PSObject] +$SlotValue, +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'gaussian-example' -$ShaderNoun = 'OBSGaussianExampleShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform float4x4 ViewProj; -uniform texture2d image; - -uniform float elapsed_time; -uniform float2 uv_offset; -uniform float2 uv_scale; -uniform float2 uv_size; -uniform float2 uv_pixel_interval; - -/*-------------------------. -| :: Texture and sampler:: | -''-------------------------*/ - - -uniform texture2d initial_image; -sampler_state initial_sampler -{ - Filter = Linear; - AddressU = Border; - AddressV = Border; - BorderColor = 00000000; - texture2d = initial_image; -}; - -uniform texture2d before_image; -sampler_state before_sampler { - Filter = Linear; - AddressU = Border; - AddressV = Border; - BorderColor = 00000000; - texture2d = before_image; -}; - -uniform texture2d after_image; -sampler_state after_sampler { - Filter = Linear; - AddressU = Border; - AddressV = Border; - BorderColor = 00000000; - texture2d = after_image; -}; - -sampler_state textureSampler { - Filter = Linear; - AddressU = Border; - AddressV = Border; - BorderColor = 00000000; -}; -struct VertData { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; - -struct ColorData { - float4 initial_color : SV_TARGET0; - float4 before_color: SV_TARGET1; - float4 after_color : SV_TARGET2; -}; -uniform float4 text_color; -uniform float max_distance; -uniform float exp; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -#define PI 3.141592653589793238462643383279502884197169399375105820974 + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -VertData mainTransform(VertData v_in) -{ - VertData vert_out = v_in; - vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); - vert_out.uv = v_in.uv * uv_scale + uv_offset; - return vert_out; -} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -float4 grayscale(float4 color) -{ - float grayscale = color.r * 0.3 + color.g * 0.59 + color.b * 0.11; - return float4(grayscale, grayscale, grayscale, color.a); -} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -float4 gaussian(VertData v_in, float angle) -{ - float rad = radians(angle); - float2 dir = float2(sin(rad), cos(rad)) * (uv_pixel_interval * max_distance); - float2 dir_2 = dir * 2.0; - float4 ret = image.Sample(textureSampler, v_in.uv) * 0.375; - - float4 px_away = image.Sample(textureSampler, v_in.uv + dir); - px_away += image.Sample(textureSampler, v_in.uv - dir); - px_away *= 0.25; - - float4 px_2_away = image.Sample(textureSampler, v_in.uv + dir_2); - px_2_away += image.Sample(textureSampler, v_in.uv + dir_2); - px_2_away *= 0.0625; - - return ret + px_away + px_2_away; -} + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -ColorData setColorData(VertData v_in): SV_TARGET0 -{ - //string RenderTarget0 = "initial_image"; - ColorData cd;// = (ColorData)0; - cd.initial_color = image.Sample(textureSampler, v_in.uv); - cd.before_color = float4(0.0,0.0,1.0,1.0); - cd.after_color = float4(1.0,0.0,0.0,1.0); - return cd; } -float4 blurImageH(VertData v_in) : SV_TARGET1 -{ - //string RenderTarget1 = "before_image"; - //ColorData cd = (ColorData)0; - //cd.initial_color = image.Sample(textureSampler, v_in.uv); - //cd.before_color = float4(0.0,0.0,1.0,1.0);//gaussian(v_in, 0); - return float4(0.0,0.0,1.0,1.0); -} -float4 blurImageV(VertData v_in) : SV_TARGET2 -{ - //string RenderTarget2 = "after_image"; - //ColorData cd = (ColorData)0; - //cd.after_color = float4(1.0,0.0,0.0,1.0); //gaussian(v_in, 90); - return float4(1.0,0.0,0.0,1.0); -} +} -float4 mainImage(VertData v_in) : SV_TARGET0 -{ - float4 color; - ColorData cd;// = (ColorData)0; - - //cd.initial_color = initial_image.Sample(initial_sampler, v_in.uv); - //cd.before_color = before_image.Sample(before_sampler, v_in.uv); - cd.after_color = after_image.Sample(before_sampler, v_in.uv); - - if (max_distance <= 5) { - color = cd.before_color; - } - else { - color = cd.after_color;//image.Sample(textureSampler, v_in.uv); - } + +#.ExternalHelp obs-powershell-Help.xml +function Set-OBSProfileParameter { - float4 gray = grayscale(color); - float4 gray_text = grayscale(text_color); - float d = distance(gray.rgb, gray_text.rgb); - if (d <= dot(max_distance, uv_pixel_interval.x * max_distance)){ - float d_c = pow(d*2, exp) / pow(2, exp); - d_c = sin(d_c * PI / 2); - d = pow(1.0 - sin(d * PI/4), exp); - color.rgb = float3(d,d,d); - } +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetProfileParameter')] +[Alias('obs.powershell.websocket.SetProfileParameter')] +param( - return color; -} +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('parameterCategory')] +[string] +$ParameterCategory, -technique Draw -{ - pass pre - { - vertex_shader = mainTransform(v_in); - pixel_shader = setColorData(v_in); - } +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('parameterName')] +[string] +$ParameterName, - pass b0 - { - vertex_shader = mainTransform(v_in); - pixel_shader = blurImageH(v_in); - } +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('parameterValue')] +[string] +$ParameterValue, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - pass b1 - { - vertex_shader = mainTransform(v_in); - pixel_shader = blurImageV(v_in); - } - pass p0 - { - vertex_shader = mainTransform(v_in); - pixel_shader = mainImage(v_in); - } +process { -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -22955,290 +15110,228 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSGaussianSimpleShader { +function Set-OBSRecordDirectory { -[Alias('Set-OBSGaussianSimpleShader','Add-OBSGaussianSimpleShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetRecordDirectory')] +[Alias('obs.powershell.websocket.SetRecordDirectory')] param( -# Set the ViewProj of OBSGaussianSimpleShader -[ComponentModel.DefaultBindingProperty('ViewProj')] -[Single[][]] -$ViewProj, -# Set the image of OBSGaussianSimpleShader -[ComponentModel.DefaultBindingProperty('image')] -[String] -$Image, -# Set the elapsed_time of OBSGaussianSimpleShader -[Alias('elapsed_time')] -[ComponentModel.DefaultBindingProperty('elapsed_time')] -[Single] -$ElapsedTime, -# Set the uv_offset of OBSGaussianSimpleShader -[Alias('uv_offset')] -[ComponentModel.DefaultBindingProperty('uv_offset')] -[Single[]] -$UvOffset, -# Set the uv_scale of OBSGaussianSimpleShader -[Alias('uv_scale')] -[ComponentModel.DefaultBindingProperty('uv_scale')] -[Single[]] -$UvScale, -# Set the uv_pixel_interval of OBSGaussianSimpleShader -[Alias('uv_pixel_interval')] -[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] -[Single[]] -$UvPixelInterval, -# Set the uv_size of OBSGaussianSimpleShader -[Alias('uv_size')] -[ComponentModel.DefaultBindingProperty('uv_size')] -[Single[]] -$UvSize, -# Set the rand_f of OBSGaussianSimpleShader -[Alias('rand_f')] -[ComponentModel.DefaultBindingProperty('rand_f')] -[Single] -$RandF, -# Set the rand_instance_f of OBSGaussianSimpleShader -[Alias('rand_instance_f')] -[ComponentModel.DefaultBindingProperty('rand_instance_f')] -[Single] -$RandInstanceF, -# Set the rand_activation_f of OBSGaussianSimpleShader -[Alias('rand_activation_f')] -[ComponentModel.DefaultBindingProperty('rand_activation_f')] -[Single] -$RandActivationF, -# Set the loops of OBSGaussianSimpleShader -[ComponentModel.DefaultBindingProperty('loops')] -[Int32] -$Loops, -# Set the local_time of OBSGaussianSimpleShader -[Alias('local_time')] -[ComponentModel.DefaultBindingProperty('local_time')] -[Single] -$LocalTime, -# Set the samples of OBSGaussianSimpleShader -[ComponentModel.DefaultBindingProperty('samples')] -[Int32] -$Samples, -# Set the LOD of OBSGaussianSimpleShader -[ComponentModel.DefaultBindingProperty('LOD')] -[Int32] -$LOD, -# 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(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('recordDirectory')] +[string] +$RecordDirectory, +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'gaussian-simple' -$ShaderNoun = 'OBSGaussianSimpleShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Single-pass gaussian blur - fast shader modified by Charles Fettinger for use with obs-shaderfilter 7/2020 v.01 -// https://github.com/Oncorporation/obs-shaderfilter -// https://www.shadertoy.com/view/ltScRG Converted inspiration -//Section to converting GLSL to HLSL - can delete -#define vec2 float2 -#define vec3 float3 -#define vec4 float4 -#define ivec2 int2 -#define ivec3 int3 -#define ivec4 int4 -#define mat2 float2x2 -#define mat3 float3x3 -#define mat4 float4x4 -#define fract frac -#define mix lerp -#define iTime float -/* -**Shaders have these variables pre loaded by the plugin** -**this section can be deleted** + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -uniform float4x4 ViewProj; -uniform texture2d image; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -uniform float elapsed_time; -uniform float2 uv_offset; -uniform float2 uv_scale; -uniform float2 uv_pixel_interval; -uniform float2 uv_size; -uniform float rand_f; -uniform float rand_instance_f; -uniform float rand_activation_f; -uniform int loops; -uniform float local_time; -*/ + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -// 16x acceleration of https://www.shadertoy.com/view/4tSyzy -// by applying gaussian at intermediate MIPmap level. + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -uniform int samples< - string label = "Samples"; - string widget_type = "slider"; - int minimum = 1; - int maximum = 25; - int step = 1; -> = 16; -uniform int LOD< - string label = "LOD"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 25; - int step = 1; -> = 2; // gaussian done on MIPmap at scale LOD + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -float gaussian(vec2 i) -{ - float sigma = (float(samples) * .25); - return exp(-.5 * dot(i /= sigma, i)) / (6.28 * sigma * sigma); } -vec4 blur(vec2 U, vec2 scale) -{ - vec4 O = vec4(0,0,0,0); - int sLOD = (1 << LOD); // tile size = 2^LOD - int s = samples / sLOD; - - for (int i = 0; i < s * s; i++) - { - vec2 d = vec2(i % s, i / s) * float(sLOD) - float(samples) * 0.5; - O += gaussian(d) * image.SampleLevel(textureSampler, U + (scale * gaussian(d)), float(LOD)); - //O += gaussian(d) * image.Sample(textureSampler, U + i * d * float(LOD)); - //O += image.Sample(textureSampler, U + gaussian(d) * float(LOD)); - } - - return O / O.a; -} -float4 mainImage(VertData v_in) : TARGET -{ - float2 iResolution = uv_scale;//uv_size * uv_scale + uv_offset; - //float2 iResolution = 1 - v_in.uv + 1.0; - //float4 rgba = image.SampleLevel(textureSampler, v_in.uv * uv_scale + uv_offset,4.0); - return blur(v_in.uv / iResolution, 1.0 / iResolution); - //return rgba; -} +} + +#.ExternalHelp obs-powershell-Help.xml +function Set-OBSSceneItemBlendMode { +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSceneItemBlendMode')] +[Alias('obs.powershell.websocket.SetSceneItemBlendMode')] +param( +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, -' -} -$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 - } - } +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemId')] +[ValidateRange(0,[int]::MaxValue)] +[double] +$SceneItemId, - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName - } +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemBlendMode')] +[string] +$SceneItemBlendMode, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -23247,335 +15340,245 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSGbCameraShader { +function Set-OBSSceneItemEnabled { -[Alias('Set-OBSGbCameraShader','Add-OBSGbCameraShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSceneItemEnabled')] +[Alias('obs.powershell.websocket.SetSceneItemEnabled')] param( -# Set the pixelSize of OBSGbCameraShader -[ComponentModel.DefaultBindingProperty('pixelSize')] -[Single] -$PixelSize, -# Set the dither_factor of OBSGbCameraShader -[Alias('dither_factor')] -[ComponentModel.DefaultBindingProperty('dither_factor')] -[Single] -$DitherFactor, -# Set the alternative_bayer of OBSGbCameraShader -[Alias('alternative_bayer')] -[ComponentModel.DefaultBindingProperty('alternative_bayer')] -[Management.Automation.SwitchParameter] -$AlternativeBayer, -# Set the brightness of OBSGbCameraShader -[ComponentModel.DefaultBindingProperty('brightness')] -[Single] -$Brightness, -# Set the contrast of OBSGbCameraShader -[ComponentModel.DefaultBindingProperty('contrast')] -[Single] -$Contrast, -# Set the gamma of OBSGbCameraShader -[ComponentModel.DefaultBindingProperty('gamma')] -[Single] -$Gamma, -# Set the color_1 of OBSGbCameraShader -[Alias('color_1')] -[ComponentModel.DefaultBindingProperty('color_1')] -[String] -$Color1, -# Set the color_2 of OBSGbCameraShader -[Alias('color_2')] -[ComponentModel.DefaultBindingProperty('color_2')] -[String] -$Color2, -# Set the color_3 of OBSGbCameraShader -[Alias('color_3')] -[ComponentModel.DefaultBindingProperty('color_3')] -[String] -$Color3, -# Set the color_4 of OBSGbCameraShader -[Alias('color_4')] -[ComponentModel.DefaultBindingProperty('color_4')] -[String] -$Color4, -# 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. +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, + [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 +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemId')] +[ValidateRange(0,[int]::MaxValue)] +[double] +$SceneItemId, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemEnabled')] +[switch] +$SceneItemEnabled, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'gb-camera' -$ShaderNoun = 'OBSGbCameraShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -/* - * ------------------------------------------------------------ - * "THE BEERWARE LICENSE" (Revision 42): - * maple wrote this code. As long as you retain this - * notice, you can do whatever you want with this stuff. If we - * meet someday, and you think this stuff is worth it, you can - * buy me a beer in return. - * ------------------------------------------------------------ - * from https://www.shadertoy.com/view/3tSXRh - * adopted for OBS by Exeldro - * ------------------------------------------------------------ - */ -uniform float pixelSize< - string label = "Pixel Size"; - string widget_type = "slider"; - float minimum = 1.0; - float maximum = 50.0; - float step = 0.1; -> = 3.0; -uniform float dither_factor< - string label = "Dither Factor"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.01; -> = 0.8; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -uniform bool alternative_bayer; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -uniform float brightness< - string label = "Brightness"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.01; -> = 0.0; -uniform float contrast< - string label = "Contrast"; - string widget_type = "slider"; - float minimum = -10.0; - float maximum = 10.0; - float step = 0.01; -> = 1.0; -uniform float gamma< - string label = "Gamma"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.01; -> = 0.6; + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -uniform float4 color_1 = {0.18, 0, 0.18, 1.0}; -uniform float4 color_2 = {0.37, 0.15, 0.47, 1.0}; -uniform float4 color_3 = {0.97, 0.56, 0.12, 1.0}; -uniform float4 color_4 = {0.97, 0.94, 0.53, 1.0}; + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -// quantize coords to low resolution -float2 pixelize(float2 uv, float2 pixelSize) { - float2 factor = pixelSize / uv_size; - return floor(uv / factor) * factor; -} + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -float3 colorLUT(float3 color) { - float gray = color.r*0.3 + color.g*0.59 + color.b*0.11; - if(gray < 0.25) - return color_1.rgb; - if(gray < 0.50) - return color_2.rgb; - if(gray < 0.75) - return color_3.rgb; - return color_4.rgb; } -// adjust brightness, contrast and gamma levels of a color -float3 levels(float3 color, float brightness, float contrast, float3 gamma) { - float3 value = (color - 0.5) * contrast + 0.5; - value = clamp(value + brightness, 0.0, 1.0); - return clamp(float3(pow(abs(value.r), gamma.x),pow(abs(value.g), gamma.y),pow(abs(value.b), gamma.z)), 0.0, 1.0); -} -float3 levels(float3 color, float brightness, float contrast, float gamma) { - return levels(color, brightness, contrast, float3(gamma, gamma, gamma)); -} -// applies the dithering filter to a color map -float3 dither8x8(float2 coord, float3 color, float2 pixelSize) { - // reduces pixel space to the selected pixel size - float2 pixelCoord = floor((coord * uv_size) / pixelSize + float2(0.5, 0.5)); - - // applies the bayer matrix filter to the color map - pixelCoord = pixelCoord - 8.0 * floor(pixelCoord/8.0); - int index = int(pixelCoord.x + (pixelCoord.y * 8.0)); - float bayer; - if (alternative_bayer){ -#ifdef OPENGL - const int[64] bayer8 = int[64]( -#else - const int bayer8[64] = { -#endif - 0, 32, 8, 40, 2, 34, 10, 42, /* 8x8 Bayer ordered dithering */ - 48, 16, 56, 24, 50, 18, 58, 26, /* pattern. Each input pixel */ - 12, 44, 4, 36, 14, 46, 6, 38, /* is scaled to the 0..63 range */ - 60, 28, 52, 20, 62, 30, 54, 22, /* before looking in this table */ - 3, 35, 11, 43, 1, 33, 9, 41, /* to determine the action. */ - 51, 19, 59, 27, 49, 17, 57, 25, - 15, 47, 7, 39, 13, 45, 5, 37, - 63, 31, 55, 23, 61, 29, 53, 21 -#ifdef OPENGL - ); -#else - }; -#endif - bayer = (bayer8[index]-31.0)/32.0; - } else { -#ifdef OPENGL - const int[64] bayer8 = int[64]( -#else - const int bayer8[64] = { -#endif - 0, 48, 12, 60, 3, 51, 15, 63, - 32, 16, 44, 28, 35, 19, 47, 31, - 8, 56, 4, 52, 11, 59, 7, 55, - 40, 24, 36, 20, 43, 27, 39, 23, - 2, 50, 14, 62, 1, 49, 13, 61, - 34, 18, 46, 30, 33, 17, 45, 29, - 10, 58, 6, 54, 9, 57, 5, 53, - 42, 26, 38, 22, 41, 25, 37, 21 -#ifdef OPENGL - ); -#else - }; -#endif - bayer = (bayer8[index]-31.0)/32.0; - } - float3 bayerColor = (color + float3(bayer,bayer,bayer) * (dither_factor / 8.0)); - // limits it to the selected palette - color = colorLUT(bayerColor); +} - return color; -} + +#.ExternalHelp obs-powershell-Help.xml +function Set-OBSSceneItemIndex { -float4 mainImage(VertData v_in) : TARGET -{ - float2 texcoord = pixelize(v_in.uv, float2(pixelSize,pixelSize)); - texcoord = clamp(texcoord, 0.001, 1.0); - float4 c = image.Sample(textureSampler, texcoord); - float3 color = c.rgb; - - color = levels(color, brightness, contrast, float3(gamma, gamma, gamma)); - - color = dither8x8(texcoord, color, float2(pixelSize,pixelSize)); - - return float4(color.r, color.g, color.b, c.a); -} -' -} -$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 - } - } +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSceneItemIndex')] +[Alias('obs.powershell.websocket.SetSceneItemIndex')] +param( - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName - } +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemId')] +[ValidateRange(0,[int]::MaxValue)] +[double] +$SceneItemId, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemIndex')] +[ValidateRange(0,[int]::MaxValue)] +[double] +$SceneItemIndex, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) + + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -23584,267 +15587,121 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSGlassShader { +function Set-OBSSceneItemLocked { -[Alias('Set-OBSGlassShader','Add-OBSGlassShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSceneItemLocked')] +[Alias('obs.powershell.websocket.SetSceneItemLocked')] param( -# Set the Alpha_Percent of OBSGlassShader -[Alias('Alpha_Percent')] -[ComponentModel.DefaultBindingProperty('Alpha_Percent')] -[Single] -$AlphaPercent, -# Set the Offset_Amount of OBSGlassShader -[Alias('Offset_Amount')] -[ComponentModel.DefaultBindingProperty('Offset_Amount')] -[Single] -$OffsetAmount, -# Set the xSize of OBSGlassShader -[ComponentModel.DefaultBindingProperty('xSize')] -[Int32] -$XSize, -# Set the ySize of OBSGlassShader -[ComponentModel.DefaultBindingProperty('ySize')] -[Int32] -$YSize, -# Set the Reflection_Offset of OBSGlassShader -[Alias('Reflection_Offset')] -[ComponentModel.DefaultBindingProperty('Reflection_Offset')] -[Int32] -$ReflectionOffset, -# Set the Horizontal_Border of OBSGlassShader -[Alias('Horizontal_Border')] -[ComponentModel.DefaultBindingProperty('Horizontal_Border')] -[Management.Automation.SwitchParameter] -$HorizontalBorder, -# Set the Border_Offset of OBSGlassShader -[Alias('Border_Offset')] -[ComponentModel.DefaultBindingProperty('Border_Offset')] -[Single] -$BorderOffset, -# Set the Border_Color of OBSGlassShader -[Alias('Border_Color')] -[ComponentModel.DefaultBindingProperty('Border_Color')] -[String] -$BorderColor, -# Set the Glass_Color of OBSGlassShader -[Alias('Glass_Color')] -[ComponentModel.DefaultBindingProperty('Glass_Color')] -[String] -$GlassColor, -# Set the notes of OBSGlassShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# 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 -) +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, -process { -$shaderName = 'glass' -$ShaderNoun = 'OBSGlassShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Glass shader by Charles Fettinger for obs-shaderfilter plugin 4/2019 -//https://github.com/Oncorporation/obs-shaderfilter -//Converted to OpenGl by Q-mii & Exeldro February 25, 2022 -uniform float Alpha_Percent< - string label = "Alpha Percent"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.1; -> = 100.0; -uniform float Offset_Amount< - string label = "Offset Amount"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.01; -> = 0.8; -uniform int xSize< - string label = "x Size"; - string widget_type = "slider"; - int minimum = 1; - int maximum = 100; - int step = 1; -> = 8; -uniform int ySize< - string label = "y Size"; - string widget_type = "slider"; - int minimum = 1; - int maximum = 100; - int step = 1; -> = 8; -uniform int Reflection_Offset< - string label = "Reflection Offset"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 2; -uniform bool Horizontal_Border; -uniform float Border_Offset< - string label = "Border Offset"; - string widget_type = "slider"; - float minimum = -0.01; - float maximum = 1.01; - float step = 0.01; -> = 0.5; -uniform float4 Border_Color = {.8,.5,1.0,1.0}; -uniform float4 Glass_Color; -uniform string notes< - string widget_type = "info"; -> = "xSize, ySize are for distortion. Offset Amount and Reflection Offset change glass properties. Alpha is Opacity of overlay."; +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, -float mod(float a, float b){ - float d = a / b; - return (d-floor(d))*b; -} +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemId')] +[ValidateRange(0,[int]::MaxValue)] +[double] +$SceneItemId, -float4 mainImage(VertData v_in) : TARGET -{ - +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemLocked')] +[switch] +$SceneItemLocked, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - int xSubPixel = int(mod((v_in.uv.x * uv_size.x) , float(clamp(xSize,1,100)))); - int ySubPixel = int(mod((v_in.uv.y * uv_size.y) , float(clamp(ySize,1,100)))); - float2 offsets = float2(Offset_Amount * xSubPixel / uv_size.x, Offset_Amount * ySubPixel / uv_size.y); - float2 uv = v_in.uv + offsets; - float2 uv2 = float2(uv.x + (Reflection_Offset / uv_size.x),uv.y + (Reflection_Offset / uv_size.y)); - float4 rgba = image.Sample(textureSampler, v_in.uv); - float4 rgba_output = float4(rgba.rgb * Border_Color.rgb, rgba.a); - rgba = image.Sample(textureSampler, uv); - float4 rgba_glass = image.Sample(textureSampler, uv2); - - float uv_compare = v_in.uv.x; - if (Horizontal_Border) - uv_compare = v_in.uv.y; +process { - if (uv_compare < (Border_Offset - 0.005)) - { - rgba_output = (rgba + rgba_glass) *.5 * Glass_Color; - } - else if (uv_compare >= (Border_Offset + 0.005)) - { - rgba_output = image.Sample(textureSampler, v_in.uv); - } - return lerp(rgba,rgba_output,(Alpha_Percent * 0.01)); -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -23853,352 +15710,121 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSGlitchAnalogShader { +function Set-OBSSceneItemTransform { -[Alias('Set-OBSGlitchAnalogShader','Add-OBSGlitchAnalogShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSceneItemTransform')] +[Alias('obs.powershell.websocket.SetSceneItemTransform')] param( -# Set the scan_line_jitter_displacement of OBSGlitchAnalogShader -[Alias('scan_line_jitter_displacement')] -[ComponentModel.DefaultBindingProperty('scan_line_jitter_displacement')] -[Single] -$ScanLineJitterDisplacement, -# Set the scan_line_jitter_threshold_percent of OBSGlitchAnalogShader -[Alias('scan_line_jitter_threshold_percent')] -[ComponentModel.DefaultBindingProperty('scan_line_jitter_threshold_percent')] -[Int32] -$ScanLineJitterThresholdPercent, -# Set the vertical_jump_amount of OBSGlitchAnalogShader -[Alias('vertical_jump_amount')] -[ComponentModel.DefaultBindingProperty('vertical_jump_amount')] -[Single] -$VerticalJumpAmount, -# Set the vertical_speed of OBSGlitchAnalogShader -[Alias('vertical_speed')] -[ComponentModel.DefaultBindingProperty('vertical_speed')] -[Single] -$VerticalSpeed, -# Set the horizontal_shake of OBSGlitchAnalogShader -[Alias('horizontal_shake')] -[ComponentModel.DefaultBindingProperty('horizontal_shake')] -[Single] -$HorizontalShake, -# Set the color_drift_amount of OBSGlitchAnalogShader -[Alias('color_drift_amount')] -[ComponentModel.DefaultBindingProperty('color_drift_amount')] -[Single] -$ColorDriftAmount, -# Set the color_drift_speed of OBSGlitchAnalogShader -[Alias('color_drift_speed')] -[ComponentModel.DefaultBindingProperty('color_drift_speed')] -[Single] -$ColorDriftSpeed, -# Set the pulse_speed_percent of OBSGlitchAnalogShader -[Alias('pulse_speed_percent')] -[ComponentModel.DefaultBindingProperty('pulse_speed_percent')] -[Int32] -$PulseSpeedPercent, -# Set the alpha_percent of OBSGlitchAnalogShader -[Alias('alpha_percent')] -[ComponentModel.DefaultBindingProperty('alpha_percent')] -[Int32] -$AlphaPercent, -# Set the rotate_colors of OBSGlitchAnalogShader -[Alias('rotate_colors')] -[ComponentModel.DefaultBindingProperty('rotate_colors')] -[Management.Automation.SwitchParameter] -$RotateColors, -# Set the Apply_To_Alpha_Layer of OBSGlitchAnalogShader -[Alias('Apply_To_Alpha_Layer')] -[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] -[Management.Automation.SwitchParameter] -$ApplyToAlphaLayer, -# Set the Replace_Image_Color of OBSGlitchAnalogShader -[Alias('Replace_Image_Color')] -[ComponentModel.DefaultBindingProperty('Replace_Image_Color')] -[Management.Automation.SwitchParameter] -$ReplaceImageColor, -# Set the Apply_To_Specific_Color of OBSGlitchAnalogShader -[Alias('Apply_To_Specific_Color')] -[ComponentModel.DefaultBindingProperty('Apply_To_Specific_Color')] -[Management.Automation.SwitchParameter] -$ApplyToSpecificColor, -# Set the Color_To_Replace of OBSGlitchAnalogShader -[Alias('Color_To_Replace')] -[ComponentModel.DefaultBindingProperty('Color_To_Replace')] -[String] -$ColorToReplace, -# Set the notes of OBSGlitchAnalogShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# 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. +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, + [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] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemId')] +[ValidateRange(0,[int]::MaxValue)] +[double] +$SceneItemId, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sceneItemTransform')] +[PSObject] +$SceneItemTransform, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'glitch_analog' -$ShaderNoun = 'OBSGlitchAnalogShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// analog glitch shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 -//https://github.com/Oncorporation/obs-shaderfilter -//Converted to OpenGL by Q-mii & Exeldro February 22, 2022 -uniform float scan_line_jitter_displacement< - string label = "Scan line jitter"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 33.0; // (displacement, threshold) -uniform int scan_line_jitter_threshold_percent< - string label = "scan line jitter threshold percent"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 95; -uniform float vertical_jump_amount< - string label = "Vertical jump amount"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; ->; -uniform float vertical_speed< - string label = "Vertical speed"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; ->;// (amount, speed) -uniform float horizontal_shake< - string label = "Horizontal shake"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; ->; -uniform float color_drift_amount< - string label = "Color drift amount"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; ->; -uniform float color_drift_speed< - string label = "Color drift speed"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; ->;// (amount, speed) -uniform int pulse_speed_percent< - string label = "Pulse speed percent"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 0; -uniform int alpha_percent< - string label = "Aplha percent"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 100; -uniform bool rotate_colors; -uniform bool Apply_To_Alpha_Layer = false; -uniform bool Replace_Image_Color; -uniform bool Apply_To_Specific_Color; -uniform float4 Color_To_Replace; -uniform string notes< - string widget_type = "info"; -> ="play with settings!"; - - -float nrand(float x, float y) -{ - float value = dot(float2(x, y), float2(12.9898 , 78.233 )); - return frac(sin(value) * 43758.5453); -} -float4 mainImage(VertData v_in) : TARGET -{ - float speed = pulse_speed_percent * 0.01; - float alpha = alpha_percent * 0.01; - float scan_line_jitter_threshold = scan_line_jitter_threshold_percent * 0.01; - float u = v_in.uv.x; - float v = v_in.uv.y; - float t = sin(elapsed_time * speed) * 2 - 1; - float4 rgba = image.Sample(textureSampler, v_in.uv); - // Scan line jitter - float jitter = nrand(v, t) * 2 - 1; - jitter *= step(scan_line_jitter_threshold, abs(jitter)) * scan_line_jitter_displacement; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - // Vertical jump - float jump = lerp(v, frac(v + (t * vertical_speed)), vertical_jump_amount); + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } - // Horizontal shake - float shake = ((t * (u + rand_f)/2) - 0.5) * horizontal_shake; + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } - //// Color drift - float drift = sin(jump + color_drift_speed) * color_drift_amount; - - float2 src1 = float2(rgba.x, rgba.z) * clamp(frac(float2(u + jitter + shake, jump)), -10.0, 10.0); - float2 src2 = float2(rgba.y, rgba.w) * frac(float2(u + jitter + shake + drift, jump)); - - if(rotate_colors) - { - // get general time number between 0 and 4 - float tx = (t + 1) * 2; - // 3 steps c1->c2, c2->c3, c3->c1 - //when between 0 - 1 only c1 rises then falls - //(min(tx, 2.0) * 0.5) range between 0-2 converted to 0-1-0 - src1.x = lerp(src1.x, rgba.x, clamp((min(tx, 2.0) * 0.5),0.0,0.5)); - //((min(max(1.0, tx),3.0) - 1) * 0.5) range between 1-3 converted to 0-1-0 - src2.x = lerp(src2.x, rgba.y, clamp(((min(max(1.0, tx),3.0) - 1) * 0.5),0.0,0.5)); - //((min(2.0, tx) -2) * 0.5) range between 2 and 4 converted to 0-1-0 - src1.y = lerp(src1.y, rgba.z, clamp(((min(2.0, tx) -2) * 0.5),0.0,0.5)); - - } - - float4 color = rgba; - float4 original_color = color; - rgba = float4(src1.x, src2.x, src1.y, alpha); - - if (Apply_To_Alpha_Layer) - { - float luma = color.r * 0.299 + color.g * 0.587 + color.b * 0.114; - if (Replace_Image_Color) - color = float4(luma, luma, luma, luma); - rgba = lerp(original_color, rgba * color, alpha); - } - - if (Apply_To_Specific_Color) - { - color = original_color; - color = (distance(color.rgb, Color_To_Replace.rgb) <= 0.075) ? rgba : color; - rgba = lerp(original_color, color, alpha); - } - - return rgba; -} - -' -} -$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] + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam } - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -24207,213 +15833,115 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSGlitchShader { +function Set-OBSSceneName { -[Alias('Set-OBSGlitchShader','Add-OBSGlitchShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSceneName')] +[Alias('obs.powershell.websocket.SetSceneName')] param( -# Set the AMT of OBSGlitchShader -[ComponentModel.DefaultBindingProperty('AMT')] -[Single] -$AMT, -# Set the SPEED of OBSGlitchShader -[ComponentModel.DefaultBindingProperty('SPEED')] -[Single] -$SPEED, -# 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. +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, + [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] +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('newSceneName')] +[string] +$NewSceneName, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'glitch' -$ShaderNoun = 'OBSGlitchShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//based on https://www.shadertoy.com/view/MtXBDs -//inputs -uniform float AMT< - string label = "AMT"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.2; //0 - 1 glitch amount -uniform float SPEED< - string label = "Speed"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.6; //0 - 1 speed - -//2D (returns 0 - 1) -float random2d(float2 n) { - return frac(sin(dot(n, float2(12.9898, 4.1414))) * 43758.5453); -} - -float randomRange (in float2 seed, in float min, in float max) { - return min + random2d(seed) * (max - min); -} - -// return 1 if v inside 1d range -float insideRange(float v, float bottom, float top) { - return step(bottom, v) - step(top, v); -} - -float4 mainImage(VertData v_in) : TARGET -{ - - float time = floor(elapsed_time * SPEED * 60.0); - float2 uv = v_in.uv; - - //copy orig - float4 outCol = image.Sample(textureSampler, uv); - - //randomly offset slices horizontally - float maxOffset = AMT/2.0; - for (float i = 0.0; i < 10.0 * AMT; i += 1.0) { - float sliceY = random2d(float2(time , 2345.0 + float(i))); - float sliceH = random2d(float2(time , 9035.0 + float(i))) * 0.25; - float hOffset = randomRange(float2(time , 9625.0 + float(i)), -maxOffset, maxOffset); - float2 uvOff = uv; - uvOff.x += hOffset; - if (insideRange(uv.y, sliceY, frac(sliceY+sliceH)) == 1.0 ){ - outCol = image.Sample(textureSampler, uvOff); - } - } - - //do slight offset on one entire channel - float maxColOffset = AMT/6.0; - float rnd = random2d(float2(time , 9545.0)); - float2 colOffset = float2(randomRange(float2(time , 9545.0),-maxColOffset,maxColOffset), - randomRange(float2(time , 7205.0),-maxColOffset,maxColOffset)); - if (rnd < 0.33){ - outCol.r = image.Sample(textureSampler, uv + colOffset).r; - - }else if (rnd < 0.66){ - outCol.g = image.Sample(textureSampler, uv + colOffset).g; - - } else{ - outCol.b = image.Sample(textureSampler, uv + colOffset).b; - } - - return outCol; -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -24422,260 +15950,243 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSGlowShader { +function Set-OBSSceneSceneTransitionOverride { -[Alias('Set-OBSGlowShader','Add-OBSGlowShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSceneSceneTransitionOverride')] +[Alias('obs.powershell.websocket.SetSceneSceneTransitionOverride')] param( -# Set the glow_percent of OBSGlowShader -[Alias('glow_percent')] -[ComponentModel.DefaultBindingProperty('glow_percent')] -[Int32] -$GlowPercent, -# Set the blur of OBSGlowShader -[ComponentModel.DefaultBindingProperty('blur')] -[Int32] -$Blur, -# Set the min_brightness of OBSGlowShader -[Alias('min_brightness')] -[ComponentModel.DefaultBindingProperty('min_brightness')] -[Int32] -$MinBrightness, -# Set the max_brightness of OBSGlowShader -[Alias('max_brightness')] -[ComponentModel.DefaultBindingProperty('max_brightness')] -[Int32] -$MaxBrightness, -# Set the pulse_speed of OBSGlowShader -[Alias('pulse_speed')] -[ComponentModel.DefaultBindingProperty('pulse_speed')] -[Int32] -$PulseSpeed, -# Set the ease of OBSGlowShader -[ComponentModel.DefaultBindingProperty('ease')] -[Management.Automation.SwitchParameter] -$Ease, -# Set the notes of OBSGlowShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# 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. +[ComponentModel.DefaultBindingProperty('sceneName')] +[string] +$SceneName, + [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 -) +[ComponentModel.DefaultBindingProperty('sceneUuid')] +[string] +$SceneUuid, +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('transitionName')] +[string] +$TransitionName, -process { -$shaderName = 'glow' -$ShaderNoun = 'OBSGlowShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//Converted to OpenGL by Exeldro February 21, 2022 -uniform int glow_percent< - string label = "Glow percent"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 10; -uniform int blur< - string label = "Blur"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 1; -uniform int min_brightness< - string label = "Min brightness"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 27; -uniform int max_brightness< - string label = "Max brightness"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 100; -uniform int pulse_speed< - string label = "Pulse speed"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 0; -uniform bool ease; -uniform string notes< - string widget_type = "info"; -> = "''ease'' - makes the animation pause at the begin and end for a moment,''glow_percent'' - how much brightness to add (recommend 0-100). ''blur'' - how far should the glow extend (recommend 1-4).''pulse_speed'' - (0-100). ''min/max brightness'' - floor and ceiling brightness level to target for glows."; - - -float EaseInOutCircTimer(float t,float b,float c,float d){ - t /= d/2.0; - if (t < 1.0) return -c/2.0 * (sqrt(1.0 - t*t) - 1.0) + b; - t -= 2.0; - return c/2.0 * (sqrt(1.0 - t*t) + 1.0) + b; -} - -float BlurStyler(float t,float b,float c,float d,bool ease) -{ - if (ease) return EaseInOutCircTimer(t,0.0,c,d); - return t; -} +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('transitionDuration')] +[ValidateRange(50,20000)] +[double] +$TransitionDuration, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) -float4 mainImage(VertData v_in) : TARGET -{ - float2 offsets[4]; - offsets[0] = float2(-0.1, 0.125); - offsets[1] = float2(-0.1, -0.125); - offsets[2] = float2(0.1, -0.125); - offsets[3] = float2(0.1, 0.125); - // convert input for vector math - float4 col = image.Sample(textureSampler, v_in.uv); - float blur_amount = float(blur) /100.0; - float glow_amount = float(glow_percent) * 0.01; - float speed = float(pulse_speed) * 0.01; - float luminance_floor = float(min_brightness) /100.0; - float luminance_ceiling = float(max_brightness) /100.0; +process { - if (col.a > 0.0) - { - //circular easing variable - float t = 1.0 + sin(elapsed_time * speed); - float b = 0.0; //start value - float c = 2.0; //change value - float d = 2.0; //duration - // simple glow calc - for (int n = 0; n < 4; n++) { - b = BlurStyler(t, 0, c, d, ease); - float4 ncolor = image.Sample(textureSampler, v_in.uv + (blur_amount * b) * offsets[n]); - float intensity = ncolor.r * 0.299 + ncolor.g * 0.587 + ncolor.b * 0.114; - if ((intensity >= luminance_floor) && (intensity <= luminance_ceiling)) - { - ncolor.a = clamp(ncolor.a * glow_amount, 0.0, 1.0); - col += (ncolor * (glow_amount * b)); - } - } - } - return col; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -' -} -$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 '|' + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } - ))" - 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] + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam } - continue nextParameter - } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } +} - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Set-OBSSourceFilterEnabled { + + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSourceFilterEnabled')] +[Alias('obs.powershell.websocket.SetSourceFilterEnabled')] +param( + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sourceName')] +[string] +$SourceName, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sourceUuid')] +[string] +$SourceUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('filterName')] +[string] +$FilterName, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('filterEnabled')] +[switch] +$FilterEnabled, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) + + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -24684,418 +16195,243 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSGradientShader { +function Set-OBSSourceFilterIndex { -[Alias('Set-OBSGradientShader','Add-OBSGradientShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSourceFilterIndex')] +[Alias('obs.powershell.websocket.SetSourceFilterIndex')] param( -# Set the start_color of OBSGradientShader -[Alias('start_color')] -[ComponentModel.DefaultBindingProperty('start_color')] -[String] -$StartColor, -# Set the start_step of OBSGradientShader -[Alias('start_step')] -[ComponentModel.DefaultBindingProperty('start_step')] -[Single] -$StartStep, -# Set the middle_color of OBSGradientShader -[Alias('middle_color')] -[ComponentModel.DefaultBindingProperty('middle_color')] -[String] -$MiddleColor, -# Set the middle_step of OBSGradientShader -[Alias('middle_step')] -[ComponentModel.DefaultBindingProperty('middle_step')] -[Single] -$MiddleStep, -# Set the end_color of OBSGradientShader -[Alias('end_color')] -[ComponentModel.DefaultBindingProperty('end_color')] -[String] -$EndColor, -# Set the end_step of OBSGradientShader -[Alias('end_step')] -[ComponentModel.DefaultBindingProperty('end_step')] -[Single] -$EndStep, -# Set the alpha_percent of OBSGradientShader -[Alias('alpha_percent')] -[ComponentModel.DefaultBindingProperty('alpha_percent')] -[Int32] -$AlphaPercent, -# Set the pulse_speed of OBSGradientShader -[Alias('pulse_speed')] -[ComponentModel.DefaultBindingProperty('pulse_speed')] -[Int32] -$PulseSpeed, -# Set the ease of OBSGradientShader -[ComponentModel.DefaultBindingProperty('ease')] -[Management.Automation.SwitchParameter] -$Ease, -# Set the rotate_colors of OBSGradientShader -[Alias('rotate_colors')] -[ComponentModel.DefaultBindingProperty('rotate_colors')] -[Management.Automation.SwitchParameter] -$RotateColors, -# Set the Apply_To_Alpha_Layer of OBSGradientShader -[Alias('Apply_To_Alpha_Layer')] -[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] -[Management.Automation.SwitchParameter] -$ApplyToAlphaLayer, -# Set the Apply_To_Specific_Color of OBSGradientShader -[Alias('Apply_To_Specific_Color')] -[ComponentModel.DefaultBindingProperty('Apply_To_Specific_Color')] -[Management.Automation.SwitchParameter] -$ApplyToSpecificColor, -# Set the Color_To_Replace of OBSGradientShader -[Alias('Color_To_Replace')] -[ComponentModel.DefaultBindingProperty('Color_To_Replace')] -[String] -$ColorToReplace, -# Set the horizontal of OBSGradientShader -[ComponentModel.DefaultBindingProperty('horizontal')] -[Management.Automation.SwitchParameter] -$Horizontal, -# Set the vertical of OBSGradientShader -[ComponentModel.DefaultBindingProperty('vertical')] -[Management.Automation.SwitchParameter] -$Vertical, -# Set the gradient_center_width_percentage of OBSGradientShader -[Alias('gradient_center_width_percentage')] -[ComponentModel.DefaultBindingProperty('gradient_center_width_percentage')] -[Int32] -$GradientCenterWidthPercentage, -# Set the gradient_center_height_percentage of OBSGradientShader -[Alias('gradient_center_height_percentage')] -[ComponentModel.DefaultBindingProperty('gradient_center_height_percentage')] -[Int32] -$GradientCenterHeightPercentage, -# Set the notes of OBSGradientShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# The name of the source. This must be provided when adding an item for the first time + [Parameter(ValueFromPipelineByPropertyName)] -[Alias('SceneItemName')] -[String] +[ComponentModel.DefaultBindingProperty('sourceName')] +[string] $SourceName, -# The name of the filter. If this is not provided, this will default to the shader name. + [Parameter(ValueFromPipelineByPropertyName)] -[String] +[ComponentModel.DefaultBindingProperty('sourceUuid')] +[string] +$SourceUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('filterName')] +[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] + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('filterIndex')] +[ValidateRange(0,[int]::MaxValue)] +[double] +$FilterIndex, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'gradient' -$ShaderNoun = 'OBSGradientShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// gradient shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 -//https://github.com/Oncorporation/obs-shaderfilter -//Converted to OpenGL by Q-mii & Exeldro February 25, 2022 -uniform float4 start_color = { 0.1, 0.3, 0.1, 1.0 }; -uniform float start_step< - string label = "Start step"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.15; -uniform float4 middle_color = { 1.0, 1.0, 1.0, 1.0 }; -uniform float middle_step< - string label = "Middle step"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.4; -uniform float4 end_color = { 0.75, 0.75, 0.75, 1.0}; -uniform float end_step< - string label = "End step"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.9; -uniform int alpha_percent< - string label = "Alpha percent"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 90; -uniform int pulse_speed< - string label = "Pulse speed"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 0; -uniform bool ease; -uniform bool rotate_colors; -uniform bool Apply_To_Alpha_Layer = true; -uniform bool Apply_To_Specific_Color; -uniform float4 Color_To_Replace; -uniform bool horizontal; -uniform bool vertical; -uniform int gradient_center_width_percentage< - string label = "gradient center width percentage"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; -uniform int gradient_center_height_percentage< - string label = "gradient center height percentage"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; -uniform string notes< - string widget_type = "info"; -> = "gradient center items will change the center location. Pulse Speed greater than 0 will animate. Easing seem to be too fast."; -float EaseInOutCircTimer(float t, float b, float c, float d) { - t /= d / 2; - if (t < 1) return -c / 2 * (sqrt(1 - t * t) - 1) + b; - t -= 2; - return c / 2 * (sqrt(1 - t * t) + 1) + b; -} -float BlurStyler(float t, float b, float c, float d, bool ease) -{ - if (ease) return EaseInOutCircTimer(t, 0, c, d); - return t; -} + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -struct gradient -{ - float4 color; - float step; -}; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -float4 mainImage(VertData v_in) : TARGET -{ - const float PI = 3.14159265f;//acos(-1); - float speed = float(pulse_speed) * 0.01; - float alpha = float(alpha_percent) * 0.01; - - //circular easing variable - float t = sin(elapsed_time * speed) * 2 - 1; - float b = 0.0; //start value - float c = 2.0; //change value - float d = 2.0; //duration + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } - float2 gradient_center = float2(float(gradient_center_width_percentage) * 0.01,float(gradient_center_height_percentage) * 0.01); - float4 color = image.Sample(textureSampler, v_in.uv); - float luminance = color.a * 0.299 + color.g * 0.587 + color.b * 0.114; - float4 gray = float4(luminance,luminance,luminance, 1); + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } - // skip if (alpha is zero and only apply to alpha layer is true) - if (!(color.a <= 0.0 && Apply_To_Alpha_Layer == true)) - { - b = BlurStyler(t, 0, c, d, ease); +} - const int no_colors = 3; - float4 s_color = start_color; - float4 m_color = middle_color; - float4 e_color = end_color; - if (rotate_colors) - { - // get general time number between 0 and 4 - float tx = (b + 1) * 2; - // 3 steps c1->c2, c2->c3, c3->c1 - //when between 0 - 1 only c1 rises then falls +} - if (tx <= 2.0) - { - s_color = lerp(start_color, middle_color, clamp((min(tx, 2.0) * 0.5) * 2, 0.0, 1.0)); - m_color = lerp(middle_color, end_color, clamp((min(tx, 2.0) * 0.5) * 2, 0.0, 1.0)); - e_color = lerp(end_color, start_color, clamp((min(tx, 2.0) * 0.5) * 2, 0.0, 1.0)); - } + +#.ExternalHelp obs-powershell-Help.xml +function Set-OBSSourceFilterName { - if ((tx >= 1.0) && (tx <= 3.0)) - { - s_color = lerp(middle_color, end_color, clamp(((min(max(1.0, tx), 3.0) - 1) * 0.5) * 2, 0.0, 1.0)); - m_color = lerp(end_color, start_color, clamp(((min(max(1.0, tx), 3.0) - 1) * 0.5) * 2, 0.0, 1.0)); - e_color = lerp(start_color, middle_color, clamp(((min(max(1.0, tx), 3.0) - 1) * 0.5) * 2, 0.0, 1.0)); - } - if (tx >= 2.0) - { - s_color = lerp(end_color, start_color, clamp(((min(2.0, tx) - 2) * 0.5) * 2, 0.0, 1.0)); - m_color = lerp(start_color, middle_color, clamp(((min(2.0, tx) - 2) * 0.5) * 2, 0.0, 1.0)); - e_color = lerp(middle_color, end_color, clamp(((min(2.0, tx) - 2) * 0.5) * 2, 0.0, 1.0)); - } +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSourceFilterName')] +[Alias('obs.powershell.websocket.SetSourceFilterName')] +param( - if (tx < 0) - { - s_color = lerp(end_color, start_color, clamp(abs(max(1.0, tx)) * 2, 0.0, 1.0)); - m_color = lerp(start_color, middle_color, clamp(abs(max(1.0, tx)) * 2, 0.0, 1.0)); - e_color = lerp(middle_color, end_color, clamp(abs(max(1.0, tx)) * 2, 0.0, 1.0)); - } - } +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sourceName')] +[string] +$SourceName, - float4 colors[no_colors]; - colors[0] =s_color; - colors[1] = m_color; - colors[2] = e_color; - float step[no_colors]; - step[0] = start_step; - step[1] = middle_step; - step[2] = end_step; +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('sourceUuid')] +[string] +$SourceUuid, - float redness = max(min(color.r - color.g, color.r - color.b) / color.r, 0); - float greenness = max(min(color.g - color.r, color.g - color.b) / color.g, 0); - float blueness = max(min(color.b - color.r, color.b - color.g) / color.b, 0); +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('filterName')] +[string] +$FilterName, - float dist = distance(v_in.uv, gradient_center); - if (horizontal && (vertical == false)) - { - dist = distance(v_in.uv.y, gradient_center.y); - } - if (vertical && (horizontal == false)) - { - dist = distance(v_in.uv.x, gradient_center.x); - } +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('newFilterName')] +[string] +$NewFilterName, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - float4 col = colors[0]; - for (int i = 1; i < no_colors; ++i) { - col = lerp(col, colors[i], smoothstep(step[i - 1], step[i], dist)); - } - col.a = clamp(alpha, 0.0, 1.0); - if (Apply_To_Alpha_Layer == false) - color.a = alpha; - if (Apply_To_Specific_Color) - { - col.a = alpha; - float4 original_color = image.Sample(textureSampler, v_in.uv); - col.rgb = (distance(color.rgb, Color_To_Replace.rgb) <= 0.075) ? col.rgb : original_color.rgb; - } - // result = float4(redness, greenness,blueness,1); - //color *= float4(col.r, col.g, col.b, clamp(dot(color, luminance)* alpha, 0.0, 1.0)); - //color.rgb += col * alpha; - //color.a += clamp(1.0 - alpha, 0.0,1.0); - ///color.rgb *= (color.rgb * clamp(1.0- alpha, 0.0, 1.0)) + (col.rgb * clamp(alpha, 0.0, 1.0)); - //color = float4(max(color.r, col.r), max(color.g, col.g), max(color.b, col.b), clamp(dot(color, luminance) * alpha, 0.0, 1.0)); - color.rgb = lerp(color.rgb, col.rgb, clamp(alpha, 0.0, 1.0)); - } - return color; +process { - -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -25104,191 +16440,125 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSHalftoneShader { +function Set-OBSSourceFilterSettings { -[Alias('Set-OBSHalftoneShader','Add-OBSHalftoneShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSourceFilterSettings')] +[Alias('obs.powershell.websocket.SetSourceFilterSettings')] param( -# Set the threshold of OBSHalftoneShader -[ComponentModel.DefaultBindingProperty('threshold')] -[Single] -$Threshold, -# The name of the source. This must be provided when adding an item for the first time + [Parameter(ValueFromPipelineByPropertyName)] -[Alias('SceneItemName')] -[String] +[ComponentModel.DefaultBindingProperty('sourceName')] +[string] $SourceName, -# The name of the filter. If this is not provided, this will default to the shader name. + [Parameter(ValueFromPipelineByPropertyName)] -[String] +[ComponentModel.DefaultBindingProperty('sourceUuid')] +[string] +$SourceUuid, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('filterName')] +[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] + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('filterSettings')] +[PSObject] +$FilterSettings, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('overlay')] +[switch] +$Overlay, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'halftone' -$ShaderNoun = 'OBSHalftoneShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -#define PI 3.1415926535897932384626433832795 -#define PI180 float(PI / 180.0) -uniform float threshold< - string label = "Threshold"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.6; -float sind(float a) -{ - return sin(a * PI180); -} - -float cosd(float a) -{ - return cos(a * PI180); -} - -float added(float2 sh, float sa, float ca, float2 c, float d) -{ - return 0.5 + 0.25 * cos((sh.x * sa + sh.y * ca + c.x) * d) + 0.25 * cos((sh.x * ca - sh.y * sa + c.y) * d); -} - -float4 mainImage(VertData v_in) : TARGET -{ - // Halftone dot matrix shader - // @author Tomek Augustyn 2010 - - // Ported from my old PixelBender experiment - // https://github.com/og2t/HiSlope/blob/master/src/hislope/pbk/fx/halftone/Halftone.pbk - - float coordX = v_in.uv.x; - float coordY = v_in.uv.y; - float2 dstCoord = float2(coordX, coordY); - float2 rotationCenter = float2(0.5, 0.5); - float2 shift = dstCoord - rotationCenter; - - float dotSize = 3.0; - float angle = 45.0; - - float rasterPattern = added(shift, sind(angle), cosd(angle), rotationCenter, PI / dotSize * 680.0); - float4 srcPixel = image.Sample(textureSampler, dstCoord); - - float avg = 0.2125 * srcPixel.r + 0.7154 * srcPixel.g + 0.0721 * srcPixel.b; - float gray = (rasterPattern * threshold + avg - threshold) / (1.0 - threshold); - - // uncomment to see how the raster pattern looks - // gray = rasterPattern; - - return float4(gray, gray, gray, 1.0); -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -25297,212 +16567,217 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSHeatWaveSimpleShader { +function Set-OBSStreamServiceSettings { -[Alias('Set-OBSHeatWaveSimpleShader','Add-OBSHeatWaveSimpleShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetStreamServiceSettings')] +[Alias('obs.powershell.websocket.SetStreamServiceSettings')] param( -# Set the Rate of OBSHeatWaveSimpleShader -[ComponentModel.DefaultBindingProperty('Rate')] -[Single] -$Rate, -# Set the Strength of OBSHeatWaveSimpleShader -[ComponentModel.DefaultBindingProperty('Strength')] -[Single] -$Strength, -# Set the Distortion of OBSHeatWaveSimpleShader -[ComponentModel.DefaultBindingProperty('Distortion')] -[Single] -$Distortion, -# Set the Opacity of OBSHeatWaveSimpleShader -[ComponentModel.DefaultBindingProperty('Opacity')] -[Single] -$Opacity, -# 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(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('streamServiceType')] +[string] +$StreamServiceType, + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('streamServiceSettings')] +[PSObject] +$StreamServiceSettings, +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'heat-wave-simple' -$ShaderNoun = 'OBSHeatWaveSimpleShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Heat Wave Simple, Version 0.03, for OBS Shaderfilter -// Copyright ©️ 2022 by SkeletonBow -// License: GNU General Public License, version 2 -// -// Contact info: -// Twitter: -// Twitch: -// -// Description: -// Generate a crude pseudo heat wave displacement on an image source. -// -// Based on: https://www.shadertoy.com/view/td3GRn by Dombass -// -// Changelog: -// 0.03 - Added Opacity control -// 0.02 - Added crude Rate, Strength, and Distortion controls -// 0.01 - Initial release -uniform float Rate< - string label = "Rate"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.1; -> = 5.0; -uniform float Strength< - string label = "Strength"; - string widget_type = "slider"; - float minimum = -25.0; - float maximum = 25.0; - float step = 0.01; -> = 1.0; -uniform float Distortion< - string label = "Distortion"; - string widget_type = "slider"; - float minimum = 3.0; - float maximum = 20.0; - float step = 0.01; -> = 10.0; -uniform float Opacity< - string label = "Opacity"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 100.00; -float4 mainImage( VertData v_in ) : TARGET -{ - float2 uv = v_in.uv; - float distort = clamp(Distortion, 3.0, 20.0); + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - // Time varying pixel color - float jacked_time = Rate*elapsed_time; - float2 scale = float2(0.5, 0.5); - float str = clamp(Strength, -25.0, 25.0) * 0.01; - - uv += str * sin(scale*jacked_time + length( uv ) * distort); - float4 c = image.Sample( textureSampler, uv); - c.a *= saturate(Opacity*0.01); - return c; -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -' -} -$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 '|' + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } - ))" - 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] + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam } - continue nextParameter - } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } +} - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Set-OBSStudioModeEnabled { + + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetStudioModeEnabled')] +[Alias('obs.powershell.websocket.SetStudioModeEnabled')] +param( + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('studioModeEnabled')] +[switch] +$StudioModeEnabled, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) + + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -25511,321 +16786,111 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSHexagonShader { +function Set-OBSTBarPosition { -[Alias('Set-OBSHexagonShader','Add-OBSHexagonShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetTBarPosition')] +[Alias('obs.powershell.websocket.SetTBarPosition')] param( -# Set the Hex_Color of OBSHexagonShader -[Alias('Hex_Color')] -[ComponentModel.DefaultBindingProperty('Hex_Color')] -[String] -$HexColor, -# Set the Alpha_Percent of OBSHexagonShader -[Alias('Alpha_Percent')] -[ComponentModel.DefaultBindingProperty('Alpha_Percent')] -[Int32] -$AlphaPercent, -# Set the Quantity of OBSHexagonShader -[ComponentModel.DefaultBindingProperty('Quantity')] -[Single] -$Quantity, -# Set the Border_Width of OBSHexagonShader -[Alias('Border_Width')] -[ComponentModel.DefaultBindingProperty('Border_Width')] -[Int32] -$BorderWidth, -# Set the Blend of OBSHexagonShader -[ComponentModel.DefaultBindingProperty('Blend')] -[Management.Automation.SwitchParameter] -$Blend, -# Set the Equilateral of OBSHexagonShader -[ComponentModel.DefaultBindingProperty('Equilateral')] -[Management.Automation.SwitchParameter] -$Equilateral, -# Set the Zoom_Animate of OBSHexagonShader -[Alias('Zoom_Animate')] -[ComponentModel.DefaultBindingProperty('Zoom_Animate')] -[Management.Automation.SwitchParameter] -$ZoomAnimate, -# Set the Speed_Percent of OBSHexagonShader -[Alias('Speed_Percent')] -[ComponentModel.DefaultBindingProperty('Speed_Percent')] -[Int32] -$SpeedPercent, -# Set the Glitch of OBSHexagonShader -[ComponentModel.DefaultBindingProperty('Glitch')] -[Management.Automation.SwitchParameter] -$Glitch, -# Set the Distort_X of OBSHexagonShader -[Alias('Distort_X')] -[ComponentModel.DefaultBindingProperty('Distort_X')] -[Single] -$DistortX, -# Set the Distort_Y of OBSHexagonShader -[Alias('Distort_Y')] -[ComponentModel.DefaultBindingProperty('Distort_Y')] -[Single] -$DistortY, -# Set the Offset_X of OBSHexagonShader -[Alias('Offset_X')] -[ComponentModel.DefaultBindingProperty('Offset_X')] -[Single] -$OffsetX, -# Set the Offset_Y of OBSHexagonShader -[Alias('Offset_Y')] -[ComponentModel.DefaultBindingProperty('Offset_Y')] -[Single] -$OffsetY, -# Set the notes of OBSHexagonShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# The name of the source. This must be provided when adding an item for the first time + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('position')] +[ValidateRange(0,1)] +[double] +$Position, + [Parameter(ValueFromPipelineByPropertyName)] -[Alias('SceneItemName')] -[String] -$SourceName, -# The name of the filter. If this is not provided, this will default to the shader name. +[ComponentModel.DefaultBindingProperty('release')] +[switch] +$Release, +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'hexagon' -$ShaderNoun = 'OBSHexagonShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Hexagon shader by Charles Fettinger for obs-shaderfilter plugin 4/2019 -//https://github.com/Oncorporation/obs-shaderfilter -//Converted to OpenGL by Q-mii & Exeldro February 25, 2022 -uniform float4 Hex_Color; -uniform int Alpha_Percent< - string label = "Alpha percent"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 100; -uniform float Quantity< - string label = "Quantity"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 25; -uniform int Border_Width< - string label = "Border Width"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 115; - int step = 1; -> = 15; // <- -15 to 85, -15 off top -uniform bool Blend; -uniform bool Equilateral; -uniform bool Zoom_Animate; -uniform int Speed_Percent< - string label = "Speed Percent"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 100; -uniform bool Glitch; -uniform float Distort_X< - string label = "Distort X"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.01; -> = 1.0; -uniform float Distort_Y< - string label = "Distort Y"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.01; -> = 1.0; -uniform float Offset_X< - string label = "Offset X"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; -uniform float Offset_Y< - string label = "Offset X"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; -uniform string notes< - string widget_type = "info"; ->= "Tiles:equilateral: around 12.33,nonequilateral: square rootable number. Distort of 1 is normal."; - -float mod(float x, float y) -{ - return x - y * floor(x/y); -} - -float2 mod2(float2 x, float2 y) -{ - return x - y * floor(x/y); -} -// 0 on edges, 1 in non_edge -float hex(float2 p) { - float xyratio = 1; - if (Equilateral) - xyratio = uv_size.x /uv_size.y; - - // calc p - p.x = mul(p.x,xyratio); - p.y += mod(floor(p.x) , 2.0)*0.5; - p = abs((mod2(p , float2(1.0, 1.0)) - 0.5)); - return abs(max(p.x*1.5 + p.y, p.y*2.0) -1); -} - -float4 mainImage(VertData v_in) : TARGET -{ - float4 rgba = image.Sample(textureSampler, v_in.uv * uv_scale + uv_offset); - float alpha = float(Alpha_Percent) * 0.01; - float quantity = sqrt(clamp(Quantity, 0.0, 100.0)); - float border_width = clamp(float(Border_Width - 15), -15, 100) * 0.01; - float speed = float(Speed_Percent) * 0.01; - float time = (1 + sin(elapsed_time * speed))*0.5; - if (Zoom_Animate) - quantity *= time; - - // create a (pos)ition reference, hex radius and smoothstep out the non_edge - float2 pos = float2(v_in.uv.x * max(0,Distort_X), (1 - v_in.uv.y) * max(0,Distort_Y)) * uv_scale + uv_offset + float2(Offset_X, Offset_Y); - if (Glitch) - quantity *= lerp(pos.x, pos.y, rand_f); - float2 p = (pos * quantity); // number of hexes to be created - float r = (1.0 -0.7)*0.5; // cell default radius - float non_edge = smoothstep(0.0, r + border_width, hex(p)); // approach border become edge - - // make the border colorable - non_edge is scaled - float4 c = float4(non_edge, non_edge,non_edge,1.0) ; - if (non_edge < 1) - { - c = Hex_Color; - c.a = alpha; - if (Blend) - c = lerp(rgba, c, 1 - non_edge); - return lerp(rgba,c,alpha); - } - return lerp(rgba, c * rgba, alpha); -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -25834,316 +16899,345 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSHslHsvSaturationShader { +function Set-OBSVideoSettings { -[Alias('Set-OBSHslHsvSaturationShader','Add-OBSHslHsvSaturationShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetVideoSettings')] +[Alias('obs.powershell.websocket.SetVideoSettings')] param( -# Set the hslSaturationFactor of OBSHslHsvSaturationShader -[ComponentModel.DefaultBindingProperty('hslSaturationFactor')] -[Single] -$HslSaturationFactor, -# Set the hslGamma of OBSHslHsvSaturationShader -[ComponentModel.DefaultBindingProperty('hslGamma')] -[Single] -$HslGamma, -# Set the hsvSaturationFactor of OBSHslHsvSaturationShader -[ComponentModel.DefaultBindingProperty('hsvSaturationFactor')] -[Single] -$HsvSaturationFactor, -# Set the hsvGamma of OBSHslHsvSaturationShader -[ComponentModel.DefaultBindingProperty('hsvGamma')] -[Single] -$HsvGamma, -# Set the adjustmentOrder of OBSHslHsvSaturationShader -[ComponentModel.DefaultBindingProperty('adjustmentOrder')] -[Int32] -$AdjustmentOrder, -# 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. +[ComponentModel.DefaultBindingProperty('fpsNumerator')] +[ValidateRange(1,[int]::MaxValue)] +[double] +$FpsNumerator, + [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] +[ComponentModel.DefaultBindingProperty('fpsDenominator')] +[ValidateRange(1,[int]::MaxValue)] +[double] +$FpsDenominator, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('baseWidth')] +[ValidateRange(1,4096)] +[double] +$BaseWidth, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('baseHeight')] +[ValidateRange(1,4096)] +[double] +$BaseHeight, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('outputWidth')] +[ValidateRange(1,4096)] +[double] +$OutputWidth, + +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('outputHeight')] +[ValidateRange(1,4096)] +[double] +$OutputHeight, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'hsl_hsv_saturation' -$ShaderNoun = 'OBSHslHsvSaturationShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' - -// Adjusted Saturation Shader for obs-shaderfilter using HLSL conventions - -uniform float hslSaturationFactor< - string label = "HSL Sat Gain"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 5.0; - float step = 0.01; -> = 1.0; -uniform float hslGamma< - string label = "HSL Sat Gamma"; - string widget_type = "slider"; - float minimum = 0.1; - float maximum = 10.0; - float step = 0.01; -> = 1.0; -uniform float hsvSaturationFactor< - string label = "HSV Sat Gain"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 5.0; - float step = 0.01; -> = 1.0; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -uniform float hsvGamma< - string label = "HSV Sat Gamma"; - string widget_type = "slider"; - float minimum = 0.1; - float maximum = 10.0; - float step = 0.01; -> = 1.0; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -uniform int adjustmentOrder< - string label = "Order"; - string widget_type = "select"; - int option_0_value = 1; - string option_0_label = "Parallel adjustment (both HSL and HSV operate on the original image and then blend)"; - int option_1_value = 2; - string option_1_label = "HSL first, then HSV"; - int option_2_value = 3; - string option_2_label = "HSV first, then HSL"; -> = 1; - -// HSV conversion + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -float3 rgb2hsv(float3 c) { - float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g)); - float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r)); + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} - -float3 hsv2rgb(float3 c) { - float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * lerp(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -// HSL conversion + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -float3 rgb2hsl(float3 c) { - float maxVal = max(c.r, max(c.g, c.b)); - float minVal = min(c.r, min(c.g, c.b)); - float delta = maxVal - minVal; - float h = 0.0; - float s = 0.0; - float l = (maxVal + minVal) / 2.0; +} - if(delta != 0) { - if(l < 0.5) s = delta / (maxVal + minVal); - else s = delta / (2.0 - maxVal - minVal); - if(c.r == maxVal) h = (c.g - c.b) / delta + (c.g < c.b ? 6.0 : 0.0); - else if(c.g == maxVal) h = (c.b - c.r) / delta + 2.0; - else h = (c.r - c.g) / delta + 4.0; +} - h /= 6.0; - } + +#.ExternalHelp obs-powershell-Help.xml +function Start-OBSOutput { - return float3(h, s, l); -} -float hue2rgb(float p, float q, float t) { - if(t < 0.0) t += 1.0; - if(t > 1.0) t -= 1.0; - if(t < 1.0/6.0) return p + (q - p) * 6.0 * t; - if(t < 1.0/2.0) return q; - if(t < 2.0/3.0) return p + (q - p) * (2.0/3.0 - t) * 6.0; - return p; -} +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StartOutput')] +[Alias('obs.powershell.websocket.StartOutput')] +param( -float3 hsl2rgb(float3 c) { - float r, g, b; +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('outputName')] +[string] +$OutputName, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - if(c.y == 0.0) { - r = g = b = c.z; - } else { - float q = c.z < 0.5 ? c.z * (1.0 + c.y) : c.z + c.y - c.z * c.y; - float p = 2.0 * c.z - q; - r = hue2rgb(p, q, c.x + 1.0/3.0); - g = hue2rgb(p, q, c.x); - b = hue2rgb(p, q, c.x - 1.0/3.0); - } - return float3(r, g, b); -} +process { -float3 adjustColorWithOrder(float3 originalColor) { - if (adjustmentOrder == 1) { - // Parallel adjustment (both HSL and HSV operate on the original image and then blend) - float3 hslAdjusted = rgb2hsl(originalColor); - hslAdjusted.y = pow(hslAdjusted.y, (1/hslGamma)); - hslAdjusted.y *= hslSaturationFactor; - float3 hslAdjustedColor = hsl2rgb(hslAdjusted); - - float3 hsvAdjusted = rgb2hsv(originalColor); - hsvAdjusted.y = pow(hsvAdjusted.y, (1/hsvGamma)); - hsvAdjusted.y *= hsvSaturationFactor; - float3 hsvAdjustedColor = hsv2rgb(hsvAdjusted); - - float3 finalColor = (hslAdjustedColor + hsvAdjustedColor) * 0.5; - return finalColor; - } - else if (adjustmentOrder == 2) { - // HSL first, then HSV - float3 hslAdjusted = rgb2hsl(originalColor); - hslAdjusted.y = pow(hslAdjusted.y, (1/hslGamma)); - hslAdjusted.y *= hslSaturationFactor; - float3 afterHSL = hsl2rgb(hslAdjusted); - float3 hsvAdjusted = rgb2hsv(afterHSL); - hsvAdjusted.y = pow(hsvAdjusted.y, (1/hsvGamma)); - hsvAdjusted.y *= hsvSaturationFactor; - return hsv2rgb(hsvAdjusted); - } - else if (adjustmentOrder == 3) { - // HSV first, then HSL - float3 hsvAdjusted = rgb2hsv(originalColor); - hsvAdjusted.y = pow(hsvAdjusted.y, (1/hsvGamma)); - hsvAdjusted.y *= hsvSaturationFactor; - float3 afterHSV = hsv2rgb(hsvAdjusted); - float3 hslAdjusted = rgb2hsl(afterHSV); - hslAdjusted.y = pow(hslAdjusted.y, (1/hslGamma)); - hslAdjusted.y *= hslSaturationFactor; - return hsl2rgb(hslAdjusted); - } - return originalColor; // Default to original color in case of unexpected values -} -// Final composite + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -float4 mainImage(VertData v_in) : TARGET -{ - float3 originalColor = image.Sample(textureSampler, v_in.uv).rgb; - float3 adjustedColor = adjustColorWithOrder(originalColor); - return float4(adjustedColor, 1.0); // preserving the original alpha -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -' -} -$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 '|' + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } - ))" - 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] + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam } - continue nextParameter - } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } +} - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Start-OBSRecord { + + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StartRecord')] +[Alias('obs.powershell.websocket.StartRecord')] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) + + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -26152,235 +17246,202 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSHueRotatonShader { +function Start-OBSReplayBuffer { -[Alias('Set-OBSHueRotatonShader','Add-OBSHueRotatonShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StartReplayBuffer')] +[Alias('obs.powershell.websocket.StartReplayBuffer')] param( -# Set the Speed of OBSHueRotatonShader -[ComponentModel.DefaultBindingProperty('Speed')] -[Single] -$Speed, -# Set the Hue_Override of OBSHueRotatonShader -[Alias('Hue_Override')] -[ComponentModel.DefaultBindingProperty('Hue_Override')] -[Management.Automation.SwitchParameter] -$HueOverride, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'hue-rotaton' -$ShaderNoun = 'OBSHueRotatonShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Hue Rotation shader, version 1.0 for OBS Shaderfilter -// Copyright ©️ 2023 by SkeletonBow -// License: GNU General Public License, version 2 -// -// Contact info: -// Twitter: -// Twitch: -// YouTube: -// Soundcloud: -// -// Description: -// Rotates hue of input at a user configurable speed. Negative speed values reverse rotation. A hue -// override option is provided to force a specific rotating hue instead of the original image''s hue. -// -// Changelog: -// 1.0 - Initial release -/* - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -uniform float Speed< - string label = "Speed"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.001; -> = 10.00; -uniform bool Hue_Override = false; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } + + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } + + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -float3 HUEtoRGB(in float H) -{ - float R = abs(H * 6 - 3) - 1; - float G = 2 - abs(H * 6 - 2); - float B = 2 - abs(H * 6 - 4); - return saturate(float3(R,G,B)); } -#define Epsilon 1e-10 + +} + -float3 RGBtoHCV(in float3 RGB) -{ - // Based on work by Sam Hocevar and Emil Persson - float4 P = (RGB.g < RGB.b) ? float4(RGB.bg, -1.0, 2.0/3.0) : float4(RGB.gb, 0.0, -1.0/3.0); - float4 Q = (RGB.r < P.x) ? float4(P.xyw, RGB.r) : float4(RGB.r, P.yzx); - float C = Q.x - min(Q.w, Q.y); - float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z); - return float3(H, C, Q.x); -} +#.ExternalHelp obs-powershell-Help.xml +function Start-OBSStream { -float3 HSVtoRGB(in float3 HSV) -{ - float3 RGB = HUEtoRGB(HSV.x); - return ((RGB - 1) * HSV.y + 1) * HSV.z; -} -float3 RGBtoHSV(in float3 RGB) -{ - float3 HCV = RGBtoHCV(RGB); - float S = HCV.y / (HCV.z + Epsilon); - return float3(HCV.x, S, HCV.z); -} +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StartStream')] +[Alias('obs.powershell.websocket.StartStream')] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) -float4 mainImage( VertData v_in ) : TARGET -{ - float2 uv = v_in.uv; - float4 col_in = image.Sample(textureSampler, uv); - float3 col_out; - float3 HSV = RGBtoHSV(col_in.rgb); - if(Hue_Override) - HSV.x = elapsed_time * Speed * 0.01; - else - HSV.x += elapsed_time * Speed * 0.01; +process { - // Normalize Hue - HSV.x = frac(HSV.x); - - col_out = HSVtoRGB(HSV); - return float4(col_out, col_in.a); -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -26389,192 +17450,100 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSIntensityScopeShader { +function Start-OBSVirtualCam { -[Alias('Set-OBSIntensityScopeShader','Add-OBSIntensityScopeShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StartVirtualCam')] +[Alias('obs.powershell.websocket.StartVirtualCam')] param( -# Set the gain of OBSIntensityScopeShader -[ComponentModel.DefaultBindingProperty('gain')] -[Single] -$Gain, -# Set the blend of OBSIntensityScopeShader -[ComponentModel.DefaultBindingProperty('blend')] -[Single] -$Blend, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'intensity-scope' -$ShaderNoun = 'OBSIntensityScopeShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Robin Green, Dec 2016 -// Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. -// https://www.shadertoy.com/view/XtcSRs adopted for OBS by Exeldro -uniform float gain< - string label = "Gain"; - string widget_type = "slider"; - float minimum = 0.01; - float maximum = 1.00; - float step = 0.01; -> = 0.3; -uniform float blend< - string label = "Blend"; - string widget_type = "slider"; - float minimum = 0.00; - float maximum = 1.00; - float step = 0.01; -> = 0.6; -float4 mainImage(VertData v_in) : TARGET -{ - float2 uv = v_in.uv; - uv.y = 1.0 - uv.y; - - // calculate the intensity bucket for this pixel based on column height (padded at the top) - const float max_value = 270.0; - const float buckets = 512.0; - float bucket_min = log( max_value * floor(uv.y * buckets) / buckets ); - float bucket_max = log( max_value * floor((uv.y * buckets) + 1.0) / buckets ); - - // count the count the r,g,b and luma in this column that match the bucket - float4 count = float4(0.0, 0.0, 0.0, 0.0); - for( int i=0; i < 512; ++i ) { - float j = float(i) / buckets; - float4 pixel = image.Sample(textureSampler, float2(uv.x, j )) * 256.0; - - // calculate the Rec.709 luma for this pixel - pixel.a = pixel.r * 0.2126 + pixel.g * 0.7152 + pixel.b * 0.0722; - float4 logpixel = log(pixel); - if( logpixel.r >= bucket_min && logpixel.r < bucket_max) count.r += 1.0; - if( logpixel.g >= bucket_min && logpixel.g < bucket_max) count.g += 1.0; - if( logpixel.b >= bucket_min && logpixel.b < bucket_max) count.b += 1.0; - if( logpixel.a >= bucket_min && logpixel.a < bucket_max) count.a += 1.0; - } - - // sum luma into RGB, tweak log intensity for readability - count.rgb = log(count.rgb * (1.0-blend) + count.aaa * blend) * gain; - - // output - return count; -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -26583,266 +17552,208 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSInvertLumaShader { +function Stop-OBSOutput { -[Alias('Set-OBSInvertLumaShader','Add-OBSInvertLumaShader')] -param( -# Set the Invert_Color of OBSInvertLumaShader -[Alias('Invert_Color')] -[ComponentModel.DefaultBindingProperty('Invert_Color')] -[Management.Automation.SwitchParameter] -$InvertColor, -# Set the Invert_Luma of OBSInvertLumaShader -[Alias('Invert_Luma')] -[ComponentModel.DefaultBindingProperty('Invert_Luma')] -[Management.Automation.SwitchParameter] -$InvertLuma, -# Set the Gamma_Correction of OBSInvertLumaShader -[Alias('Gamma_Correction')] -[ComponentModel.DefaultBindingProperty('Gamma_Correction')] -[Management.Automation.SwitchParameter] -$GammaCorrection, -# Set the Test_Ramp of OBSInvertLumaShader -[Alias('Test_Ramp')] -[ComponentModel.DefaultBindingProperty('Test_Ramp')] -[Management.Automation.SwitchParameter] -$TestRamp, -# 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. + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StopOutput')] +[Alias('obs.powershell.websocket.StopOutput')] +param( + +[Parameter(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('outputName')] +[string] +$OutputName, +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'invert-luma' -$ShaderNoun = 'OBSInvertLumaShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Invert shader 1.0 - for OBS Shaderfilter -// Copyright 2021 by SkeletonBow -// https://twitter.com/skeletonbowtv -// https://twitch.tv/skeletonbowtv -// Performs RGB color inversion or YUV luma inversion with optional sRGB gamma handling -uniform bool Invert_Color = false; -uniform bool Invert_Luma = true; -uniform bool Gamma_Correction = true; -uniform bool Test_Ramp = false; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -float3 encodeSRGB(float3 linearRGB) -{ - float3 a = float3(12.92,12.92,12.92) * linearRGB; - float3 b = float3(1.055,1.055,1.055) * pow(linearRGB, float3(1.0 / 2.4,1.0 / 2.4,1.0 / 2.4)) - float3(0.055,0.055,0.055); - float3 c = step(float3(0.0031308,0.0031308,0.0031308), linearRGB); - return float3(lerp(a, b, c)); -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -float3 decodeSRGB(float3 screenRGB) -{ - float3 a = screenRGB / float3(12.92,12.92,12.92); - float3 b = pow((screenRGB + float3(0.055,0.055,0.055)) / float3(1.055,1.055,1.055), float3(2.4,2.4,2.4)); - float3 c = step(float3(0.04045,0.04045,0.04045), screenRGB); - return float3(lerp(a, b, c)); -} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -float3 HUEtoRGB(in float H) -{ - float R = abs(H * 6 - 3) - 1; - float G = 2 - abs(H * 6 - 2); - float B = 2 - abs(H * 6 - 4); - return float3(clamp(float3(R,G,B), float3(0.0, 0.0, 0.0), float3(1.0, 1.0, 1.0))); -} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -float3 RGBtoYUV(float3 color) -{ - // YUV matriz (BT709 luma coefficients) -#ifdef OPENGL - float3x3 toYUV = float3x3( - float3(0.2126, -0.09991, 0.615), - float3(0.7152, -0.33609, -0.55861), - float3(0.0722, 0.436, -0.05639)); -#else - float3x3 toYUV = { - { 0.2126, -0.09991, 0.615 }, - { 0.7152, -0.33609, -0.55861 }, - { 0.0722, 0.436, -0.05639 }, - }; -#endif - return mul(color, toYUV); -} + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -float3 YUVtoRGB(float3 color) -{ - // YUV matriz (BT709) -#ifdef OPENGL - float3x3 fromYUV = float3x3( - float3(1.000, 1.000, 1.000), - float3(0.0, -0.21482, 2.12798), - float3(1.28033, -0.38059, 0.0)); -#else - float3x3 fromYUV = { - { 1.000, 1.000, 1.000 }, - { 0.0, -0.21482, 2.12798 }, - { 1.28033, -0.38059, 0.0 }, - }; -#endif - return mul(color, fromYUV); } -float3 generate_ramps(float3 color, float2 uv) -{ - float3 ramp = float3(0.0, 0.0, 0.0); - if(uv.y < 0.2) - ramp.r = uv.x; // Red ramp - else if(uv.y < 0.4) - ramp.g = uv.x; // Green ramp - else if(uv.y < 0.6) - ramp.b = uv.x; // Blue ramp - else if(uv.y < 0.8) - ramp = float3(uv.x, uv.x, uv.x); // Grey ramp - else - ramp = HUEtoRGB(uv.x); // Hue rainbow - - return ramp; -} -float4 mainImage( VertData v_in ) : TARGET -{ - float2 uv = v_in.uv; - float4 obstex = image.Sample( textureSampler, uv ); - float3 color = obstex.rgb; - // Apply sRGB gamma transfer encode - if(Gamma_Correction) color = encodeSRGB( color ); - // Override display with test patterns to visually see what is happening - if( Test_Ramp ) color = generate_ramps( obstex.rgb, uv ); - // RGB color invert - if( Invert_Color ) { - color = float3(1.0, 1.0, 1.0) - color; - } - // YUV luma invert - if( Invert_Luma ) { - float3 yuv = RGBtoYUV( color ); - yuv.x = 1.0 - yuv.x; - color = YUVtoRGB(yuv); - } - // Apply sRGB gamma transfer decode - if(Gamma_Correction) color = decodeSRGB( color ); - return float4(color, obstex.a); -} +} -' -} -$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 - } - } + +#.ExternalHelp obs-powershell-Help.xml +function Stop-OBSRecord { - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName - } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StopRecord')] +[Alias('obs.powershell.websocket.StopRecord')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -26851,240 +17762,202 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSLuminance2Shader { +function Stop-OBSReplayBuffer { -[Alias('Set-OBSLuminance2Shader','Add-OBSLuminance2Shader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StopReplayBuffer')] +[Alias('obs.powershell.websocket.StopReplayBuffer')] param( -# Set the color of OBSLuminance2Shader -[ComponentModel.DefaultBindingProperty('color')] -[String] -$Color, -# Set the lumaMax of OBSLuminance2Shader -[ComponentModel.DefaultBindingProperty('lumaMax')] -[Single] -$LumaMax, -# Set the lumaMin of OBSLuminance2Shader -[ComponentModel.DefaultBindingProperty('lumaMin')] -[Single] -$LumaMin, -# Set the lumaMaxSmooth of OBSLuminance2Shader -[ComponentModel.DefaultBindingProperty('lumaMaxSmooth')] -[Single] -$LumaMaxSmooth, -# Set the lumaMinSmooth of OBSLuminance2Shader -[ComponentModel.DefaultBindingProperty('lumaMinSmooth')] -[Single] -$LumaMinSmooth, -# Set the invertImageColor of OBSLuminance2Shader -[ComponentModel.DefaultBindingProperty('invertImageColor')] -[Management.Automation.SwitchParameter] -$InvertImageColor, -# Set the invertAlphaChannel of OBSLuminance2Shader -[ComponentModel.DefaultBindingProperty('invertAlphaChannel')] -[Management.Automation.SwitchParameter] -$InvertAlphaChannel, -# Set the notes of OBSLuminance2Shader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'luminance2' -$ShaderNoun = 'OBSLuminance2Shader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//Converted to OpenGL by Q-mii & Exeldro February 25, 2022 -uniform float4 color; -uniform float lumaMax< - string label = "Luma Max"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> = 1.05; -uniform float lumaMin< - string label = "Luma Min"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> = 0.01; -uniform float lumaMaxSmooth< - string label = "Luma Max Smooth"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> = 0.10; -uniform float lumaMinSmooth< - string label = "Luma Min Smooth"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> = 0.01; -uniform bool invertImageColor; -uniform bool invertAlphaChannel; -uniform string notes< - string widget_type = "info"; -> = "''luma max'' - anything above will be transparent. ''luma min'' - anything below will be transparent. ''luma(min or max)Smooth - make the transparency fade in or out by a distance. ''invert color'' - inverts the color of the screen. ''invert alpha channel'' - flips all settings on thier head, which is excellent for testing."; -float4 InvertColor(float4 rgba_in) -{ - rgba_in.r = 1.0 - rgba_in.r; - rgba_in.g = 1.0 - rgba_in.g; - rgba_in.b = 1.0 - rgba_in.b; - rgba_in.a = 1.0 - rgba_in.a; - return rgba_in; -} - -float4 mainImage(VertData v_in) : TARGET -{ - - float4 rgba = image.Sample(textureSampler, v_in.uv); - if (rgba.a > 0.0) - { - - if (invertImageColor) - { - rgba = InvertColor(rgba); - } - float luminance = rgba.r * color.r * 0.299 + rgba.g * color.g * 0.587 + rgba.b * color.b * 0.114; - - //intensity = min(max(intensity,minIntensity),maxIntensity); - float clo = smoothstep(lumaMin, lumaMin + lumaMinSmooth, luminance); - float chi = 1. - smoothstep(lumaMax - lumaMaxSmooth, lumaMax, luminance); - float amask = clo * chi; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (invertAlphaChannel) - { - amask = 1.0 - amask; - } - rgba *= color; - rgba.a = clamp(amask, 0.0, 1.0); - - } - return rgba; -} + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -' -} -$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 '|' + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } - ))" - 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] + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam } - continue nextParameter - } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } +} - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Stop-OBSStream { + + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StopStream')] +[Alias('obs.powershell.websocket.StopStream')] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) + + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -27093,298 +17966,213 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSLuminanceAlphaShader { +function Stop-OBSVirtualCam { -[Alias('Set-OBSLuminanceAlphaShader','Add-OBSLuminanceAlphaShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StopVirtualCam')] +[Alias('obs.powershell.websocket.StopVirtualCam')] param( -# Set the ViewProj of OBSLuminanceAlphaShader -[ComponentModel.DefaultBindingProperty('ViewProj')] -[Single[][]] -$ViewProj, -# Set the image of OBSLuminanceAlphaShader -[ComponentModel.DefaultBindingProperty('image')] -[String] -$Image, -# Set the elapsed_time of OBSLuminanceAlphaShader -[Alias('elapsed_time')] -[ComponentModel.DefaultBindingProperty('elapsed_time')] -[Single] -$ElapsedTime, -# Set the uv_offset of OBSLuminanceAlphaShader -[Alias('uv_offset')] -[ComponentModel.DefaultBindingProperty('uv_offset')] -[Single[]] -$UvOffset, -# Set the uv_scale of OBSLuminanceAlphaShader -[Alias('uv_scale')] -[ComponentModel.DefaultBindingProperty('uv_scale')] -[Single[]] -$UvScale, -# Set the uv_pixel_interval of OBSLuminanceAlphaShader -[Alias('uv_pixel_interval')] -[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] -[Single[]] -$UvPixelInterval, -# Set the rand_f of OBSLuminanceAlphaShader -[Alias('rand_f')] -[ComponentModel.DefaultBindingProperty('rand_f')] -[Single] -$RandF, -# Set the uv_size of OBSLuminanceAlphaShader -[Alias('uv_size')] -[ComponentModel.DefaultBindingProperty('uv_size')] -[Single[]] -$UvSize, -# Set the color_matrix of OBSLuminanceAlphaShader -[Alias('color_matrix')] -[ComponentModel.DefaultBindingProperty('color_matrix')] -[Single[][]] -$ColorMatrix, -# Set the color of OBSLuminanceAlphaShader -[ComponentModel.DefaultBindingProperty('color')] -[String] -$Color, -# Set the mul_val of OBSLuminanceAlphaShader -[Alias('mul_val')] -[ComponentModel.DefaultBindingProperty('mul_val')] -[Single] -$MulVal, -# Set the add_val of OBSLuminanceAlphaShader -[Alias('add_val')] -[ComponentModel.DefaultBindingProperty('add_val')] -[Single] -$AddVal, -# Set the level of OBSLuminanceAlphaShader -[ComponentModel.DefaultBindingProperty('level')] -[Single] -$Level, -# Set the invertAlphaChannel of OBSLuminanceAlphaShader -[ComponentModel.DefaultBindingProperty('invertAlphaChannel')] -[Management.Automation.SwitchParameter] -$InvertAlphaChannel, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'luminance_alpha' -$ShaderNoun = 'OBSLuminanceAlphaShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Luminance Alpha Effect By Charles Fettinger (https://github.com/Oncorporation) 2/2019 -//Converted to OpenGL by Q-mii & Exeldro February 22, 2022 -uniform float4x4 ViewProj; -uniform texture2d image; -uniform float elapsed_time; -uniform float2 uv_offset; -uniform float2 uv_scale; -uniform float2 uv_pixel_interval; -uniform float rand_f; -uniform float2 uv_size; -uniform float4x4 color_matrix; -uniform float4 color; -uniform float mul_val< - string label = "Mulitply"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> = 1.0; -uniform float add_val< - string label = "Add"; - string widget_type = "slider"; - float minimum = -10.0; - float maximum = 10.0; - float step = 0.001; -> = 0.0; -uniform float level< - string label = "Level"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> =1.0; -uniform bool invertAlphaChannel; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -sampler_state textureSampler { - Filter = Linear; - AddressU = Border; - AddressV = Border; - BorderColor = 00000000; -}; + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } -struct VertDataIn { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -struct VertDataOut { - float4 pos : POSITION; - float2 uv : TEXCOORD0; - float2 uv2 : TEXCOORD1; -}; + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } + + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } -VertDataOut mainTransform(VertDataIn v_in) -{ - VertDataOut vert_out; - vert_out.pos = mul(float4(v_in.pos.xyz, 1.0 ), ViewProj); - vert_out.uv = v_in.uv * mul_val + add_val; - vert_out.uv2 = v_in.uv ; - return vert_out; } -/*float3 GetLuminance(float4 rgba) -{ - float red = rbga.r; - float green = rgba.g; - float blue = rgba.b; - return (.299 * red) + (.587 * green) + (.114 * blue); -}*/ -float4 PSAlphaMaskRGBA(VertDataOut v_in) : TARGET -{ - float4 rgba = image.Sample(textureSampler, v_in.uv) ; - if (rgba.a > 0.0) - { - - float intensity = rgba.r * color.r * 0.299 + rgba.g * color.g * 0.587 + rgba.b * color.b * 0.114; - if (invertAlphaChannel) - { - intensity = 1.0 - intensity; - } - rgba *= color; - rgba.a = clamp((intensity * level), 0.0, 1.0); - - } - return rgba; -} +} -technique Draw -{ - pass - { - vertex_shader = mainTransform(v_in); - pixel_shader = PSAlphaMaskRGBA(v_in); - } -} + +#.ExternalHelp obs-powershell-Help.xml +function Switch-OBSInputMute { -' -} -$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 - } - } +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'ToggleInputMute')] +[Alias('obs.powershell.websocket.ToggleInputMute')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName - } +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputName')] +[string] +$InputName, - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } +[Parameter(ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('inputUuid')] +[string] +$InputUuid, +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } } - 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 + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -27393,205 +18181,106 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSLuminanceShader { +function Switch-OBSOutput { -[Alias('Set-OBSLuminanceShader','Add-OBSLuminanceShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'ToggleOutput')] +[Alias('obs.powershell.websocket.ToggleOutput')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the color of OBSLuminanceShader -[ComponentModel.DefaultBindingProperty('color')] -[String] -$Color, -# Set the level of OBSLuminanceShader -[ComponentModel.DefaultBindingProperty('level')] -[Single] -$Level, -# Set the invertImageColor of OBSLuminanceShader -[ComponentModel.DefaultBindingProperty('invertImageColor')] -[Management.Automation.SwitchParameter] -$InvertImageColor, -# Set the invertAlphaChannel of OBSLuminanceShader -[ComponentModel.DefaultBindingProperty('invertAlphaChannel')] -[Management.Automation.SwitchParameter] -$InvertAlphaChannel, -# Set the notes of OBSLuminanceShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# 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(Mandatory,ValueFromPipelineByPropertyName)] +[ComponentModel.DefaultBindingProperty('outputName')] +[string] +$OutputName, +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'Luminance' -$ShaderNoun = 'OBSLuminanceShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -//Converted to OpenGL by Exeldro February 22, 2022 -uniform float4 color; -uniform float level< - string label = "Level"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.01; -> = 1.0; -uniform bool invertImageColor; -uniform bool invertAlphaChannel; - -uniform string notes< - string widget_type = "info"; -> = "''color'' - the color to add to the original image. Multiplies the color against the original color giving it a tint. White represents no tint. ''invertImageColor'' - - inverts the color of the screen, great for testing and fine tuning. ''level'' - transparency amount modifier where 1.0 = base luminance (recommend 0.00 - 10.00). ''invertAlphaChannel'' - flip what is transparent from darks (default) to lights"; - -float4 InvertColor(float4 rgba_in) -{ - rgba_in.r = 1.0 - rgba_in.r; - rgba_in.g = 1.0 - rgba_in.g; - rgba_in.b = 1.0 - rgba_in.b; - rgba_in.a = 1.0 - rgba_in.a; - return rgba_in; -} - -float4 mainImage(VertData v_in) : TARGET -{ - - float4 rgba = image.Sample(textureSampler, v_in.uv); - if (rgba.a > 0.0) - { - - if (invertImageColor) - { - rgba = InvertColor(rgba); - } - float intensity = rgba.r * color.r * 0.299 + rgba.g * color.g * 0.587 + rgba.b * color.b * 0.114; - - //intensity = min(max(intensity,minIntensity),maxIntensity); - - if (invertAlphaChannel) - { - intensity = 1.0 - intensity; - } - rgba *= color; - rgba.a = clamp((intensity * level), 0.0, 1.0); - - } - return rgba; -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -27600,439 +18289,203 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSMatrixShader { +function Switch-OBSRecord { -[Alias('Set-OBSMatrixShader','Add-OBSMatrixShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'ToggleRecord')] +[Alias('obs.powershell.websocket.ToggleRecord')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the ViewProj of OBSMatrixShader -[ComponentModel.DefaultBindingProperty('ViewProj')] -[Single[][]] -$ViewProj, -# Set the image of OBSMatrixShader -[ComponentModel.DefaultBindingProperty('image')] -[String] -$Image, -# Set the elapsed_time of OBSMatrixShader -[Alias('elapsed_time')] -[ComponentModel.DefaultBindingProperty('elapsed_time')] -[Single] -$ElapsedTime, -# Set the uv_offset of OBSMatrixShader -[Alias('uv_offset')] -[ComponentModel.DefaultBindingProperty('uv_offset')] -[Single[]] -$UvOffset, -# Set the uv_scale of OBSMatrixShader -[Alias('uv_scale')] -[ComponentModel.DefaultBindingProperty('uv_scale')] -[Single[]] -$UvScale, -# Set the uv_size of OBSMatrixShader -[Alias('uv_size')] -[ComponentModel.DefaultBindingProperty('uv_size')] -[Single[]] -$UvSize, -# Set the uv_pixel_interval of OBSMatrixShader -[Alias('uv_pixel_interval')] -[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] -[Single[]] -$UvPixelInterval, -# Set the rand_f of OBSMatrixShader -[Alias('rand_f')] -[ComponentModel.DefaultBindingProperty('rand_f')] -[Single] -$RandF, -# Set the rand_instance_f of OBSMatrixShader -[Alias('rand_instance_f')] -[ComponentModel.DefaultBindingProperty('rand_instance_f')] -[Single] -$RandInstanceF, -# Set the rand_activation_f of OBSMatrixShader -[Alias('rand_activation_f')] -[ComponentModel.DefaultBindingProperty('rand_activation_f')] -[Single] -$RandActivationF, -# Set the loops of OBSMatrixShader -[ComponentModel.DefaultBindingProperty('loops')] -[Int32] -$Loops, -# Set the local_time of OBSMatrixShader -[Alias('local_time')] -[ComponentModel.DefaultBindingProperty('local_time')] -[Single] -$LocalTime, -# Set the mouse of OBSMatrixShader -[ComponentModel.DefaultBindingProperty('mouse')] -[Single[]] -$Mouse, -# Set the Invert_Direction of OBSMatrixShader -[Alias('Invert_Direction')] -[ComponentModel.DefaultBindingProperty('Invert_Direction')] -[Management.Automation.SwitchParameter] -$InvertDirection, -# Set the lumaMin of OBSMatrixShader -[ComponentModel.DefaultBindingProperty('lumaMin')] -[Single] -$LumaMin, -# Set the lumaMinSmooth of OBSMatrixShader -[ComponentModel.DefaultBindingProperty('lumaMinSmooth')] -[Single] -$LumaMinSmooth, -# Set the Ratio of OBSMatrixShader -[ComponentModel.DefaultBindingProperty('Ratio')] -[Single] -$Ratio, -# Set the Alpha_Percentage of OBSMatrixShader -[Alias('Alpha_Percentage')] -[ComponentModel.DefaultBindingProperty('Alpha_Percentage')] -[Single] -$AlphaPercentage, -# Set the Apply_To_Alpha_Layer of OBSMatrixShader -[Alias('Apply_To_Alpha_Layer')] -[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] -[Management.Automation.SwitchParameter] -$ApplyToAlphaLayer, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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] +[Alias('OutputRequest','OutputInput')] +[switch] $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 +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse ) process { -$shaderName = 'matrix' -$ShaderNoun = 'OBSMatrixShader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -// Matrix effect by Charles Fettinger for obs-shaderfilter plugin 7/2020 v.2 -// https://github.com/Oncorporation/obs-shaderfilter -// https://www.shadertoy.com/view/XljBW3 The cat is a glitch (Matrix) - coverted from and updated - -#define vec2 float2 -#define vec3 float3 -#define vec4 float4 -#define ivec2 int2 -#define ivec3 int3 -#define ivec4 int4 -#define mat2 float2x2 -#define mat3 float3x3 -#define mat4 float4x4 -#define fract frac -#define mix lerp -#define iTime float - -uniform float4x4 ViewProj; -uniform texture2d image; - -uniform float elapsed_time; -uniform float2 uv_offset; -uniform float2 uv_scale; -uniform float2 uv_size; -uniform float2 uv_pixel_interval; -uniform float rand_f; -uniform float rand_instance_f; -uniform float rand_activation_f; -uniform int loops; -uniform float local_time; - - -uniform float2 mouse< - string label = "Virtual Mouse Coordinates"; - string widget_type = "slider"; - float2 minimum = {0, 0}; - float2 maximum = {100., 100.}; - float2 scale = {.01, .01}; - float2 step = {.01, .01}; -> = {0., 0.}; - - -int2 iMouse() { - return int2(mouse.x * uv_size.x, mouse.y * uv_size.y); -} - -sampler_state textureSampler { - Filter = Linear; - AddressU = Clamp; - AddressV = Clamp; -}; - -/* ps start - -*/ -uniform bool Invert_Direction< - string label = "Invert Direction"; -> = true; -uniform float lumaMin< - string label = "Luma Min"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> = 0.01; -uniform float lumaMinSmooth< - string label = "Luma Min Smooth"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> = 0.01; -uniform float Ratio< - string label = "Ratio"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 4.0; -uniform float Alpha_Percentage< - string label = "Alpha Percentage"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 100; // -uniform bool Apply_To_Alpha_Layer = true; + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand -#define PI2 6.28318530718 -#define PI 3.1416 + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } -float vorocloud(float2 p){ - float f = 0.0; - float flow = 1.0; - float time = elapsed_time; - if(Invert_Direction){ - flow *= -1; - } - /* - //periodically stop - if (loops % 16 >= 8.0) - { - time = local_time - elapsed_time; - } - */ - - float r = clamp(Ratio,-50,50); - float2 pp = cos(float2(p.x * 14.0, (16.0 * p.y + cos(floor(p.x * 30.0)) + flow * time * PI2)) ); - p = cos(p * 12.1 + pp * r + sin(time/PI)*(r/PI) + 0.5 * cos(pp.x * r + sin(time/PI)*(r/PI))); - - float2 pts[4]; - - pts[0] = float2(0.5, 0.6); - pts[1] = float2(-0.4, 0.4); - pts[2] = float2(0.2, -0.7); - pts[3] = float2(-0.3, -0.4); - - float d = 5.0; - - for(int i = 0; i < 4; i++){ - pts[i].x += 0.03 * cos(float(i)) + p.x; - pts[i].y += 0.03 * sin(float(i)) + p.y; - d = min(d, distance(pts[i], pp)); - } - - f = 2.0 * pow(1.0 - 0.3 * d, 13.0); - - f = min(f, 1.0); + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" - return f; -} + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } -vec4 scene(float2 UV){ - float alpha = clamp(Alpha_Percentage *.01 ,0,1.0); + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } - float x = UV.x; - float y = UV.y; - - float2 p = float2(x, y) - 0.5; - - vec4 col = vec4(0.0,0.0,0.0,0.0); - col.g += 0.02; - - float v = vorocloud(p); - v = 0.2 * floor(v * 5.0); - - col.r += 0.1 * v; - col.g += 0.6 * v; - col.b += 0.5 * pow(v, 5.0); - - - v = vorocloud(p * 2.0); - v = 0.2 * floor(v * 5.0); - - col.r += 0.1 * v; - col.g += 0.2 * v; - col.b += 0.01 * pow(v, 5.0); - - col.a = 1.0; - float luma = dot(col.rgb,float3(0.299,0.587,0.114)); - float luma_min = smoothstep(lumaMin, lumaMin + lumaMinSmooth, luma); - col.a = clamp(luma_min,0.0,1.0); +} - float4 original_color = image.Sample(textureSampler, UV); - - // skip if (alpha is zero and only apply to alpha layer is true) - if (!(original_color.a <= 0.0 && Apply_To_Alpha_Layer == true)) - { - if (Apply_To_Alpha_Layer == false) - original_color.a = alpha; - - col.rgb = lerp(original_color.rgb, col.rgb, alpha); //apply alpha slider - col = lerp(original_color, col, col.a); //remove black background color - } - else - { - col.a = original_color.a; - } - return col; -} +} -void mainImage( out vec4 fragColor, in vec2 fragCoord ) -{ - vec2 uv = fragCoord.xy / uv_size; - fragColor = scene(uv); -} + +#.ExternalHelp obs-powershell-Help.xml +function Switch-OBSRecordPause { -/*ps end*/ -struct VertFragData { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'ToggleRecordPause')] +[Alias('obs.powershell.websocket.ToggleRecordPause')] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) -VertFragData VSDefault(VertFragData vtx) { - vtx.pos = mul(float4(vtx.pos.xyz, 1.0), ViewProj); - return vtx; -} -float4 PSDefault(VertFragData vtx) : TARGET { - float4 col = float4(1., 1., 1., 1.); - mainImage(col, vtx.uv * uv_size); - return col; -} +process { -technique Draw -{ - pass - { - vertex_shader = VSDefault(vtx); - pixel_shader = PSDefault(vtx); - } -} -' -} -$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 - } - } + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand - if (-not $PSBoundParameters['FilterName']) { - $filterName = $PSBoundParameters['FilterName'] = $shaderName + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} } - $ShaderFilterSplat = [Ordered]@{ - ShaderSetting = $ShaderSettings - FilterName = $FilterName - SourceName = $SourceName - } - - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } } } - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } } - - 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 + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy } - if ($script:CachedShaderFilesFromCommand[$shaderName]) { - $ShaderFilterSplat.ShaderFile = $script:CachedShaderFilesFromCommand[$shaderName].FullName - } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + if ($PassThru) { + [PSCustomObject]$requestPayload } else { - Set-OBSShaderFilter @ShaderFilterSplat + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse } - } -} } @@ -28041,25 +18494,389 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSMultiplyShader { +function Switch-OBSReplayBuffer { -[Alias('Set-OBSMultiplyShader','Add-OBSMultiplyShader')] + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'ToggleReplayBuffer')] +[Alias('obs.powershell.websocket.ToggleReplayBuffer')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] param( -# Set the other_image of OBSMultiplyShader -[Alias('other_image')] -[ComponentModel.DefaultBindingProperty('other_image')] -[String] -$OtherImage, -# 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. +# If set, will return the information that would otherwise be sent to OBS. [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('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) + + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } + + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } + + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Switch-OBSStream { + + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'ToggleStream')] +[Alias('obs.powershell.websocket.ToggleStream')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) + + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } + + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } + + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Switch-OBSVirtualCam { + + +[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'ToggleVirtualCam')] +[Alias('obs.powershell.websocket.ToggleVirtualCam')] +[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +param( +# If set, will return the information that would otherwise be sent to OBS. +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('OutputRequest','OutputInput')] +[switch] +$PassThru, +# If set, will not attempt to receive a response from OBS. +# This can increase performance, and also silently ignore critical errors +[Parameter(ValueFromPipelineByPropertyName)] +[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] +[switch] +$NoResponse +) + + +process { + + + # Create a copy of the parameters (that are part of the payload) + $paramCopy = [Ordered]@{} + # get a reference to this command + $myCmd = $MyInvocation.MyCommand + + # Keep track of how many requests we have done of a given type + # (this makes creating RequestIDs easy) + if (-not $script:ObsRequestsCounts) { + $script:ObsRequestsCounts = @{} + } + + # Set my requestType to blank + $myRequestType = '' + # and indicate we are not expecting a response + $responseExpected = $false + # Then walk over this commands' attributes, + foreach ($attr in $myCmd.ScriptBlock.Attributes) { + if ($attr -is [Reflection.AssemblyMetadataAttribute]) { + if ($attr.Key -eq 'OBS.WebSocket.RequestType') { + $myRequestType = $attr.Value # set the requestType, + } + elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { + # and determine if we are expecting a response. + $responseExpected = + if ($attr.Value -eq 'false') { + $false + } else { $true } + } + } + } + + # Walk over each parameter + :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { + # and walk over each of it's attributes to see if it part of the payload + foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { + # If the parameter is bound to part of the payload + if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { + # copy it into our payload dicitionary. + $paramCopy[$attr.Name] = $keyValue.Value + # (don't forget to turn switches into booleans) + if ($paramCopy[$attr.Name] -is [switch]) { + $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + if ($attr.Name -like '*path') { + $paramCopy[$attr.Name] = + "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + continue nextParam + } + } + } + + # and make a request ID from that. + $myRequestId = "$myRequestType.$([Guid]::newGuid())" + + # Construct the payload object + $requestPayload = [Ordered]@{ + # It must include a request ID + requestId = $myRequestId + # request type + requestType = $myRequestType + # and optional data + requestData = $paramCopy + } + + if ($PassThru) { + [PSCustomObject]$requestPayload + } else { + [PSCustomObject]$requestPayload | + Send-OBS -NoResponse:$NoResponse + } + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBS3dPanelShader { + +[Alias('Set-OBS3dPanelShader','Add-OBS3dPanelShader')] +param( +# Set the credits of OBS3dPanelShader +[ComponentModel.DefaultBindingProperty('credits')] +[String] +$Credits, +# Set the scale of OBS3dPanelShader +[ComponentModel.DefaultBindingProperty('scale')] +[Single] +$Scale, +# Set the tilt_x_deg of OBS3dPanelShader +[Alias('tilt_x_deg')] +[ComponentModel.DefaultBindingProperty('tilt_x_deg')] +[Single] +$TiltXDeg, +# Set the tilt_y_deg of OBS3dPanelShader +[Alias('tilt_y_deg')] +[ComponentModel.DefaultBindingProperty('tilt_y_deg')] +[Single] +$TiltYDeg, +# Set the tilt_z_deg of OBS3dPanelShader +[Alias('tilt_z_deg')] +[ComponentModel.DefaultBindingProperty('tilt_z_deg')] +[Single] +$TiltZDeg, +# Set the pos_x of OBS3dPanelShader +[Alias('pos_x')] +[ComponentModel.DefaultBindingProperty('pos_x')] +[Single] +$PosX, +# Set the pos_y of OBS3dPanelShader +[Alias('pos_y')] +[ComponentModel.DefaultBindingProperty('pos_y')] +[Single] +$PosY, +# Set the thickness of OBS3dPanelShader +[ComponentModel.DefaultBindingProperty('thickness')] +[Single] +$Thickness, +# Set the radius_fb of OBS3dPanelShader +[Alias('radius_fb')] +[ComponentModel.DefaultBindingProperty('radius_fb')] +[Single] +$RadiusFb, +# Set the brightness of OBS3dPanelShader +[ComponentModel.DefaultBindingProperty('brightness')] +[Single] +$Brightness, +# Set the light_position of OBS3dPanelShader +[Alias('light_position')] +[ComponentModel.DefaultBindingProperty('light_position')] +[Int32] +$LightPosition, +# Set the wiggle of OBS3dPanelShader +[ComponentModel.DefaultBindingProperty('wiggle')] +[Single] +$Wiggle, +# Set the wiggle_rot of OBS3dPanelShader +[Alias('wiggle_rot')] +[ComponentModel.DefaultBindingProperty('wiggle_rot')] +[Management.Automation.SwitchParameter] +$WiggleRot, +# 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, @@ -28080,17 +18897,265 @@ $UseShaderTime process { -$shaderName = 'multiply' -$ShaderNoun = 'OBSMultiplyShader' +$shaderName = '3d-panel' +$ShaderNoun = 'OBS3dPanelShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform texture2d other_image; +//based on https://x.com/HoraiChan/status/1986268258883010766 -float4 mainImage(VertData v_in) : TARGET -{ - float4 other = other_image.Sample(textureSampler, v_in.uv); - float4 base = image.Sample(textureSampler, v_in.uv); - return base * other; +uniform string credits< + string widget_type = "info"; +> = "Based on effect by Horaiken"; + +uniform float scale< + string label = "大きさ / Scale"; + string widget_type = "slider"; + float minimum = 0.25; + float maximum = 3.00; + float step = 0.001; +> = 1.0; +uniform float tilt_x_deg< + string label = "縦方向の傾き(X) / Tilt (X)"; + string widget_type = "slider"; + float minimum = -360.0; + float maximum = 360.00; + float step = 0.1; +> = 20.0; +uniform float tilt_y_deg< + string label = "横方向の傾き(Y) / Tilt (Y)"; + string widget_type = "slider"; + float minimum = -360.0; + float maximum = 360.00; + float step = 0.1; +> = 35.0; +uniform float tilt_z_deg< + string label = "回転(Z) / Roll (Z)"; + string widget_type = "slider"; + float minimum = -360.0; + float maximum = 360.00; + float step = 0.1; +> = 0.0; +uniform float pos_x< + string label = "横位置 / Horizontal Position"; + string widget_type = "slider"; + float minimum = -1.00; + float maximum = 1.00; + float step = 0.0001; +> = 0.0; +uniform float pos_y< + string label = "縦位置 / Vertical Position"; + string widget_type = "slider"; + float minimum = -1.00; + float maximum = 1.00; + float step = 0.0001; +> = 0.0; +uniform float thickness< + string label = "厚み / Thickness"; + string widget_type = "slider"; + float minimum = 0.00; + float maximum = 0.1; + float step = 0.001; +> = 0.03; +uniform float radius_fb< + string label = "角丸 / Corner Radius"; + string widget_type = "slider"; + float minimum = 0.00; + float maximum = 1.00; + float step = 0.01; +> = 0.2; +uniform float brightness< + string label = "明るさ / Brightness"; + string widget_type = "slider"; + float minimum = 0.00; + float maximum = 2.00; + float step = 0.01; +> = 1.2; +uniform int light_position < + string label = "照明の位置 / Light Direction"; + string widget_type = "select"; + int option_0_value = 0; + string option_0_label = "左側に光 / Light From Left"; + int option_1_value = 1; + string option_1_label = "右側に光 / Light From Right"; +> = 0; +uniform float wiggle < + string label = "ゆらゆら / Wiggle"; + string widget_type = "slider"; + float minimum = 0.00; + float maximum = 2.50; + float step = 0.01; +> = 0.0; +uniform bool wiggle_rot < + string label = "角度もゆらゆら / Wiggle Rotation"; +>; + +float hash1(float n){ return frac(sin(n)*43758.5453123); } + +float noise1D(float x) { + float i = floor(x); + float f = frac(x); + float u = f*f*(3.0 - 2.0*f); + return lerp(hash1(i), hash1(i+1.0), u); // 0..1 +} + +float fbm1D(float x) { + float v = 0.0; + float a = 0.5; + float f = 1.0; + for(int k=0;k<4;k++){ + v += a * noise1D(x * f); + f *= 2.0; + a *= 0.5; + } + return v; +} + +float saturate(float x) { return clamp(x, 0.0, 1.0); } + +float3 rotateX(float3 p, float a){ float c=cos(a), s=sin(a); return float3(p.x, c*p.y - s*p.z, s*p.y + c*p.z); } +float3 rotateY(float3 p, float a){ float c=cos(a), s=sin(a); return float3( c*p.x + s*p.z, p.y, -s*p.x + c*p.z); } +float3 rotateZ(float3 p, float a){ float c=cos(a), s=sin(a); return float3(c*p.x - s*p.y, s*p.x + c*p.y, p.z); } + +// 2D 角丸長方形 SDF(中心、半径 bxy, 角丸 r) +float sdRoundRect2D(float2 p, float2 bxy, float r) { + float2 q = abs(p) - bxy + r; + return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - r; +} + +// 正面シルエット角丸 + Z方向に押し出し +float sdFrontViewRoundedPrism(float3 p, float3 b, float r_fb_norm) { + float r_fb = saturate(r_fb_norm) * (0.999 * min(b.x, b.y)); + float a = sdRoundRect2D(p.xy, b.xy, r_fb); + float dz = abs(p.z) - b.z; + return max(a, dz); +} + +// 法線 +float3 calcNormal(float3 p, float3 b, float rfb) { + const float e = 0.001; + float3 ex=float3(e,0,0), ey=float3(0,e,0), ez=float3(0,0,e); + float dx = sdFrontViewRoundedPrism(p+ex,b,rfb) - sdFrontViewRoundedPrism(p-ex,b,rfb); + float dy = sdFrontViewRoundedPrism(p+ey,b,rfb) - sdFrontViewRoundedPrism(p-ey,b,rfb); + float dz = sdFrontViewRoundedPrism(p+ez,b,rfb) - sdFrontViewRoundedPrism(p-ez,b,rfb); + return normalize(float3(dx,dy,dz)); +} + +// 照明 +float3 shade(float3 n, float3 v) { + float3 l; + if (light_position == 0) { // 左から光 + l = normalize(float3(-1.0, -0.1, 1.0)); + } + else { // 右から光 + l = normalize(float3( 1.0, -0.1, 1.0)); + } + float diff = saturate(dot(n,l)); + float rim = pow(1.0 - saturate(dot(n,v)), 2.0); + float li = 0.25 + 0.75*diff + 0.08*rim; + return float3(li, li, li); +} + +float4 mainImage(VertData v_in) : TARGET { + float2 uv = v_in.uv; + + // 画面座標(短辺基準) + float aspect = uv_size.x / uv_size.y; + float2 ndc = uv * 2.0 - 1.0; + ndc += float2(pos_x, pos_y) * -1.0 * (scale + 1.0); + float2 p2 = ndc; + p2.x *= aspect; + + // カメラ設定 + float3 ro = float3(0.0, 0.0, 3.2); + float3 rd = normalize(float3(p2, -4.0)); + + // 回転(Z→Y→X の順に逆回転) + float ax=radians(tilt_x_deg), ay=radians(tilt_y_deg), az=radians(tilt_z_deg); + ro = rotateX(rotateY(rotateZ(ro, -az), -ay), -ax); + rd = normalize(rotateX(rotateY(rotateZ(rd, -az), -ay), -ax)); + + // 画面フィット(短辺基準)+ 厚み + float2 baseXY; + if (aspect > 1.0) { + baseXY = float2(1.0, 1.0 / aspect); + } else { + const float portraitMargin = 0.6; + baseXY = float2(aspect * portraitMargin, 1.0 * portraitMargin); + } + float3 b = float3(baseXY, thickness) * max(scale, 0.0001); + + // Wiggle + float diag = length(2.0 * b); + float amp = 0.05 * wiggle * diag; + const float WSPD = 0.1; + + // 各軸に独立ノイズ + float wx = (fbm1D(elapsed_time*WSPD + 13.37) * 2.0 - 1.0) * amp; + float wy = (fbm1D(elapsed_time*WSPD + 47.11) * 2.0 - 1.0) * amp; + float wz = (fbm1D(elapsed_time*WSPD + 91.73) * 2.0 - 1.0) * amp * 0.35; + float3 woff = float3(wx, wy, wz); + + float rotAmp = radians(12.0) * wiggle; + + float wobX = (fbm1D(elapsed_time*WSPD + 128.31) * 2.0 - 1.0) * rotAmp; + float wobY = (fbm1D(elapsed_time*WSPD + 299.91) * 2.0 - 1.0) * rotAmp; + + float3 ro2 = ro; + float3 rd2 = rd; + + if (wiggle_rot) { + ro2 = rotateX(ro2, wobX); + ro2 = rotateY(ro2, wobY); + rd2 = rotateX(rd2, wobX); + rd2 = rotateY(rd2, wobY); + } + + float t = 0.0; + float d = 0.0; + bool hit = false; + for (int i=0; i<64; i++) { + float3 pos = ro2 + rd2 * t; + d = sdFrontViewRoundedPrism(pos - woff, b, radius_fb); + if (d < 0.001) { hit = true; break; } + t += d; + if (t > 8.0) break; + } + + // ヒットしなければ完全透明(元ソースは非表示) + if (!hit) return float4(0.0, 0.0, 0.0, 0.0); + + float3 pos = ro2 + rd2 * t; + float3 pObj = pos - woff; + float3 n = calcNormal(pObj, b, radius_fb); + float3 vdir = normalize(-rd2); + + // テクスチャ貼り付け + float frontMask = smoothstep(0.5, 0.8, dot(n, float3(0.0, 0.0, 1.0))); + float2 uvTex = (pObj.xy / b.xy) * 0.5 + 0.5; + + // サンプル(Address Clamp なので側面/背面は端ピクセルが“引き伸ばし”) + float4 texFront = image.Sample(textureSampler, uvTex); + float4 texEdge = image.Sample(textureSampler, uvTex); + float4 tex = lerp(texEdge, texFront, frontMask); + + // フロント面エッジ・ハイライト(細い線) + float r_fb = saturate(radius_fb) * (0.999 * min(b.x, b.y)); + float a_xy = sdRoundRect2D(pObj.xy, b.xy, r_fb); // XY角丸SDF + float edgeWidth = 0.02 * min(b.x, b.y); + float edgeIntensity = 0.6; + float edgeProx = 1.0 - saturate(abs(a_xy) / edgeWidth); + float edgeMask = frontMask * edgeProx; + tex.rgb *= (1.0 + edgeMask * edgeIntensity); + + // 照明 + float3 lightTerm = shade(n, vdir); + tex.rgb *= lightTerm; + + // 明るさスライダ + tex.rgb *= brightness; + + // 出力 + return float4(tex.rgb, 1.0); } ' @@ -28190,99 +19255,47 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSNightSkyShader { +function Get-OBS3dSwapTransitionShader { -[Alias('Set-OBSNightSkyShader','Add-OBSNightSkyShader')] +[Alias('Set-OBS3dSwapTransitionShader','Add-OBS3dSwapTransitionShader')] param( -# Set the speed of OBSNightSkyShader -[ComponentModel.DefaultBindingProperty('speed')] +# Set the image_a of OBS3dSwapTransitionShader +[Alias('image_a')] +[ComponentModel.DefaultBindingProperty('image_a')] +[String] +$ImageA, +# Set the image_b of OBS3dSwapTransitionShader +[Alias('image_b')] +[ComponentModel.DefaultBindingProperty('image_b')] +[String] +$ImageB, +# Set the transition_time of OBS3dSwapTransitionShader +[Alias('transition_time')] +[ComponentModel.DefaultBindingProperty('transition_time')] [Single] -$Speed, -# Set the Include_Clouds of OBSNightSkyShader -[Alias('Include_Clouds')] -[ComponentModel.DefaultBindingProperty('Include_Clouds')] -[Management.Automation.SwitchParameter] -$IncludeClouds, -# Set the Include_Moon of OBSNightSkyShader -[Alias('Include_Moon')] -[ComponentModel.DefaultBindingProperty('Include_Moon')] +$TransitionTime, +# Set the convert_linear of OBS3dSwapTransitionShader +[Alias('convert_linear')] +[ComponentModel.DefaultBindingProperty('convert_linear')] [Management.Automation.SwitchParameter] -$IncludeMoon, -# Set the center_width_percentage of OBSNightSkyShader -[Alias('center_width_percentage')] -[ComponentModel.DefaultBindingProperty('center_width_percentage')] -[Int32] -$CenterWidthPercentage, -# Set the center_height_percentage of OBSNightSkyShader -[Alias('center_height_percentage')] -[ComponentModel.DefaultBindingProperty('center_height_percentage')] -[Int32] -$CenterHeightPercentage, -# Set the Alpha_Percentage of OBSNightSkyShader -[Alias('Alpha_Percentage')] -[ComponentModel.DefaultBindingProperty('Alpha_Percentage')] +$ConvertLinear, +# Set the reflection of OBS3dSwapTransitionShader +[ComponentModel.DefaultBindingProperty('reflection')] [Single] -$AlphaPercentage, -# Set the Apply_To_Image of OBSNightSkyShader -[Alias('Apply_To_Image')] -[ComponentModel.DefaultBindingProperty('Apply_To_Image')] -[Management.Automation.SwitchParameter] -$ApplyToImage, -# Set the Replace_Image_Color of OBSNightSkyShader -[Alias('Replace_Image_Color')] -[ComponentModel.DefaultBindingProperty('Replace_Image_Color')] -[Management.Automation.SwitchParameter] -$ReplaceImageColor, -# Set the number_stars of OBSNightSkyShader -[Alias('number_stars')] -[ComponentModel.DefaultBindingProperty('number_stars')] -[Int32] -$NumberStars, -# Set the SKY_COLOR of OBSNightSkyShader -[Alias('SKY_COLOR')] -[ComponentModel.DefaultBindingProperty('SKY_COLOR')] -[String] -$SKYCOLOR, -# Set the STAR_COLOR of OBSNightSkyShader -[Alias('STAR_COLOR')] -[ComponentModel.DefaultBindingProperty('STAR_COLOR')] +$Reflection, +# Set the perspective of OBS3dSwapTransitionShader +[ComponentModel.DefaultBindingProperty('perspective')] +[Single] +$Perspective, +# Set the depth of OBS3dSwapTransitionShader +[ComponentModel.DefaultBindingProperty('depth')] +[Single] +$Depth, +# Set the background_color of OBS3dSwapTransitionShader +[Alias('background_color')] +[ComponentModel.DefaultBindingProperty('background_color')] [String] -$STARCOLOR, -# Set the LIGHT_SKY of OBSNightSkyShader -[Alias('LIGHT_SKY')] -[ComponentModel.DefaultBindingProperty('LIGHT_SKY')] -[String] -$LIGHTSKY, -# Set the SKY_LIGHTNESS of OBSNightSkyShader -[Alias('SKY_LIGHTNESS')] -[ComponentModel.DefaultBindingProperty('SKY_LIGHTNESS')] -[Single] -$SKYLIGHTNESS, -# Set the MOON_COLOR of OBSNightSkyShader -[Alias('MOON_COLOR')] -[ComponentModel.DefaultBindingProperty('MOON_COLOR')] -[String] -$MOONCOLOR, -# Set the moon_size of OBSNightSkyShader -[Alias('moon_size')] -[ComponentModel.DefaultBindingProperty('moon_size')] -[Single] -$MoonSize, -# Set the moon_bump_size of OBSNightSkyShader -[Alias('moon_bump_size')] -[ComponentModel.DefaultBindingProperty('moon_bump_size')] -[Single] -$MoonBumpSize, -# Set the Moon_Position_x of OBSNightSkyShader -[Alias('Moon_Position_x')] -[ComponentModel.DefaultBindingProperty('Moon_Position_x')] -[Single] -$MoonPositionX, -# Set the Moon_Position_y of OBSNightSkyShader -[Alias('Moon_Position_y')] -[ComponentModel.DefaultBindingProperty('Moon_Position_y')] -[Single] -$MoonPositionY, +$BackgroundColor, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -28313,299 +19326,109 @@ $UseShaderTime process { -$shaderName = 'night_sky' -$ShaderNoun = 'OBSNightSkyShader' +$shaderName = '3d_swap_transition' +$ShaderNoun = 'OBS3dSwapTransitionShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Night Sky shader by Charles Fettinger for obs-shaderfilter plugin 6/2020 v.65 -// https://github.com/Oncorporation/obs-shaderfilter -//https://www.shadertoy.com/view/3tfXRM Simple Night Sky - converted from and updated -//Converted to OpenGL by Q-mii & Exeldro February 22, 2022 -uniform float speed< - string label = "Speed"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 20.0; -uniform bool Include_Clouds = true; -uniform bool Include_Moon = true; -uniform int center_width_percentage< - string label = "Center width percentage"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; -uniform int center_height_percentage< - string label = "Center width percentage"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; -uniform float Alpha_Percentage< - string label = "Alpha Percentage"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 95.0; // -uniform bool Apply_To_Image = false; -uniform bool Replace_Image_Color = false; -uniform int number_stars< - string label = "Number stars"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 20; // +//based on https://www.shadertoy.com/view/MlXGzf -uniform float4 SKY_COLOR = { 0.027, 0.151, 0.354, 1.0 }; -uniform float4 STAR_COLOR = { 0.92, 0.92, 0.14, 1.0 }; -uniform float4 LIGHT_SKY = { 0.45, 0.61, 0.98, 1.0 }; -uniform float SKY_LIGHTNESS< - string label = "SKY LIGHTNESS"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = .3; +uniform texture2d image_a; +uniform texture2d image_b; +uniform float transition_time = 0.5; +uniform bool convert_linear = true; - // Moon -uniform float4 MOON_COLOR = { .4, .25, 0.25, 1.0 }; -uniform float moon_size< - string label = "Moon size"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.18; -uniform float moon_bump_size< - string label = "Moon bump size"; +uniform float reflection< + string label = "Reflection (0.4)"; string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.14; -uniform float Moon_Position_x< - string label = "Moon Position x"; + float minimum = 0.00; + float maximum = 1.00; + float step = 0.01; +> = 0.4; +uniform float perspective< + string label = "Perspective (0.2)"; string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = -0.6; -uniform float Moon_Position_y< - string label = "Moon Position y"; + float minimum = 0.00; + float maximum = 1.00; + float step = 0.01; +> = .2; +uniform float depth< + string label = "Depth (3.0)"; string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = -0.3; - -#define PI 3.1416 - -//Noise functions from https://www.youtube.com/watch?v=zXsWftRdsvU -float noise11(float p) { - return frac(sin(p*633.1847) * 9827.95); -} - -float noise21(float2 p) { - return frac(sin(p.x*827.221 + p.y*3228.8275) * 878.121); -} - -float2 noise22(float2 p) { - return frac(float2(sin(p.x*9378.35), sin(p.y*75.589)) * 556.89); -} - -//From https://codepen.io/Tobsta/post/procedural-generation-part-1-1d-perlin-noise -float cosineInterpolation(float a, float b, float x) { - float ft = x * PI; - float f = (1. - cos(ft)) * .5; - return a * (1. - f) + b * f; -} - -float smoothNoise11(float p, float dist) { - float prev = noise11(p-dist); - float next = noise11(p+dist); - - return cosineInterpolation(prev, next, .5); -} - -float smoothNoise21(float2 uv, float cells) { - float2 lv = frac(uv*cells); - float2 id = floor(uv*cells); - - //smoothstep function: maybe change it later! - lv = lv*lv*(3.-2.*lv); - - float bl = noise21(id); - float br = noise21(id+float2(1.,0.)); - float b = lerp(bl, br, lv.x); - - float tl = noise21(id+float2(0.,1.)); - float tr = noise21(id+float2(1.,1.)); - float t = lerp(tl, tr, lv.x); - - return lerp(b, t, lv.y); -} - -float2 smoothNoise22(float2 uv, float cells) { - float2 lv = frac(uv*cells); - float2 id = floor(uv*cells); - - lv = lv*lv*(3.-2.*lv); - - float2 bl = noise22(id); - float2 br = noise22(id+float2(1.,0.)); - float2 b = lerp(bl, br, lv.x); - - float2 tl = noise22(id+float2(0.,1.)); - float2 tr = noise22(id+float2(1.,1.)); - float2 t = lerp(tl, tr, lv.x); - - return lerp(b, t, lv.y); -} + float minimum = 1.00; + float maximum = 10.00; + float step = 0.1; +> = 3.; -float valueNoise11(float p) { - float c = smoothNoise11(p, 0.5); - c += smoothNoise11(p, 0.25)*.5; - c += smoothNoise11(p, 0.125)*.25; - c += smoothNoise11(p, 0.0625)*.125; - - return c /= .875; -} +#ifndef OPENGL +#define lessThan(a,b) (a < b) +#endif -float valueNoise21(float2 uv) { - float c = smoothNoise21(uv, 4.); - c += smoothNoise21(uv, 8.)*.5; - c += smoothNoise21(uv, 16.)*.25; - c += smoothNoise21(uv, 32.)*.125; - c += smoothNoise21(uv, 64.)*.0625; - - return c /= .9375; -} -float2 valueNoise22(float2 uv) { - float2 c = smoothNoise22(uv, 4.); - c += smoothNoise22(uv, 8.)*.5; - c += smoothNoise22(uv, 16.)*.25; - c += smoothNoise22(uv, 32.)*.125; - c += smoothNoise22(uv, 64.)*.0625; - - return c /= .9375; +uniform float4 background_color = {0.0, 0.0, 0.0, 1.0}; + +bool inBounds (float2 p) { + return all(lessThan(float2(0.0,0.0), p)) && all(lessThan(p, float2(1.0,1.0))); } - -float3 points(float2 p, float2 uv, float3 color, float size, float blur) { - float dist = distance(p, uv); - return color*smoothstep(size, size*(0.999-blur), dist); + +float2 project (float2 p) { + return p * float2(1.0, -1.2) + float2(0.0, 2.22); } - -float mapInterval(float x, float a, float b, float c, float d) { - return (x-a)/(b-a) * (d-c) + c; + +float4 bgColor (float2 p, float2 pfr, float2 pto) { + float4 c = background_color; + pfr = project(pfr); + if (inBounds(pfr)) { + c += lerp(background_color, image_a.Sample(textureSampler, pfr), reflection * lerp(0.0, 1.0, pfr.y)); + } + pto = project(pto); + if (inBounds(pto)) { + c += lerp(background_color, image_b.Sample(textureSampler, pto), reflection * lerp(0.0, 1.0, pto.y)); + } + return c; } - -float blink(float time, float timeInterval) { - float halfInterval = timeInterval / 2.0; - //Get relative position in the bucket - float p = fmod(time, timeInterval); - - - if (p <= timeInterval / 2.) { - return smoothstep(0., 1., p/halfInterval); - } else { - return smoothstep(1., 0., (p-halfInterval)/halfInterval); + +float4 mainImage(VertData v_in) : TARGET { + float2 p = v_in.uv; + float2 pfr = float2(-1.,-1.); + float2 pto = float2(-1.,-1.); + + float progress = transition_time; + float size = lerp(1.0, depth, progress); + float persp = perspective * progress; + pfr = (p + float2(-0.0, -0.5)) * float2(size/(1.0-perspective*progress), size/(1.0-size*persp*p.x)) + float2(0.0, 0.5); + + size = lerp(1.0, depth, 1.-progress); + persp = perspective * (1.-progress); + pto = (p + float2(-1.0, -0.5)) * float2(size/(1.0-perspective*(1.0-progress)), size/(1.0-size*persp*(0.5-p.x))) + float2(1.0, 0.5); + + bool fromOver = progress < 0.5; + float4 rgba = background_color; + if (fromOver) { + if (inBounds(pfr)) { + rgba = image_a.Sample(textureSampler, pfr); } -} - -float3 sampleBumps(float2 p, float2 uv, float radius, float spin) { - float dist = distance(p, uv); - float3 BumpSamples = float3(0.,0.,0.); - - if (dist < radius) { - float bumps = (1.-valueNoise21(uv*spin))*.1; - BumpSamples = float3(bumps, bumps, bumps); + else if (inBounds(pto)) { + rgba = image_b.Sample(textureSampler, pto); } - return BumpSamples; -} - -float4 mainImage(VertData v_in) : TARGET -{ - float4 rgba;// = image.Sample(textureSampler, v_in.uv); - float alpha = clamp(Alpha_Percentage *.01 ,0,1.0); - float2 center_pixel_coordinates = float2((center_width_percentage * 0.01), (center_height_percentage * 0.01)); - float2 st = v_in.uv* uv_scale; - float2 toCenter = center_pixel_coordinates - st; - - // Normalized pixel coordinates (from 0 to 1) - float2 uv = v_in.uv; - float2 ouv = uv; - uv -= .5; - uv.x *= uv_size.x/uv_size.y; - - float2 seed = toCenter / uv_size.xy; - - float time = elapsed_time + seed.x*speed; - - //float3 col = float3(0.0); - //float m = valueNoise21(uv); - float3 col = lerp(SKY_COLOR.rgb, LIGHT_SKY.rgb, ouv.y-SKY_LIGHTNESS); - - col *= SKY_LIGHTNESS - (1.-ouv.y); - - //Add clouds - if (Include_Clouds) - { - float2 timeUv = uv; - timeUv.x += time*.1; - timeUv.y += valueNoise11(timeUv.x+.352)*.01; - float cloud = valueNoise21(timeUv); - col += cloud*.1; + else { + rgba = bgColor(p, pfr, pto); } - - //Add stars in the top part of the scene - float timeInterval = speed *.5; //5.0 - float timeBucket = floor(time / timeInterval); - - float2 moonPosition = float2(-1000, -1000); - if (Include_Moon) - { - moonPosition = float2(Moon_Position_x, Moon_Position_y); - col += points(moonPosition, uv, MOON_COLOR.rgb,moon_size, 0.3); - // Moon bumps - col += sampleBumps(moonPosition, uv, moon_bump_size, 9. + fmod(time*.1,9)); + } + else { + if (inBounds(pto)) { + rgba = image_b.Sample(textureSampler, pto); } - - for (float i = 0.; i < clamp(number_stars,0,100); i++) { - float2 starPosition = float2(i/10., i/10.); - - starPosition.x = mapInterval(valueNoise11(timeBucket + i*827.913)-.4, 0., 1., 0.825, -0.825); - starPosition.y = mapInterval(valueNoise11(starPosition.x)-.3, 0., 1., 0.445, -0.445); - - float starIntensity = blink(time+ (rand_f * i), timeInterval ); - //Hide stars that are behind the moon - if (distance(starPosition, moonPosition) > moon_size) { - col += points(starPosition, uv, STAR_COLOR.rgb, 0.001, 0.0)*clamp(starIntensity-.1, 0.0, 1.0)*10.0; - col += points(starPosition, uv, STAR_COLOR.rgb, 0.009, 3.5)*starIntensity*3.0; - } + else if (inBounds(pfr)) { + rgba = image_a.Sample(textureSampler, pfr); } - //col = float3(blink(time, timeInterval)); - rgba = float4(col,alpha); - - // Output to screen - if (Apply_To_Image) - { - float4 color = image.Sample(textureSampler, v_in.uv); - float4 original_color = color; - float luma = color.r * 0.299 + color.g * 0.587 + color.b * 0.114; - if (Replace_Image_Color) - color = float4(luma, luma, luma, luma); - rgba = lerp(original_color, rgba * color,alpha); - - } + else { + rgba = bgColor(p, pfr, pto); + } + } + if (convert_linear) + rgba.rgb = srgb_nonlinear_to_linear(rgba.rgb); return rgba; } - ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -28703,14 +19526,15 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSOpacityShader { +function Get-OBSAddShader { -[Alias('Set-OBSOpacityShader','Add-OBSOpacityShader')] +[Alias('Set-OBSAddShader','Add-OBSAddShader')] param( -# Set the Opacity of OBSOpacityShader -[ComponentModel.DefaultBindingProperty('Opacity')] -[Single] -$Opacity, +# Set the other_image of OBSAddShader +[Alias('other_image')] +[ComponentModel.DefaultBindingProperty('other_image')] +[String] +$OtherImage, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -28741,28 +19565,19 @@ $UseShaderTime process { -$shaderName = 'opacity' -$ShaderNoun = 'OBSOpacityShader' +$shaderName = 'Add' +$ShaderNoun = 'OBSAddShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Opacity shader - for OBS Shaderfilter -// Copyright 2021 by SkeltonBowTV -// https://twitter.com/skeletonbowtv -// https://twitch.tv/skeletonbowtv - -uniform float Opacity< - string label = "Opacity"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 200.0; - float step = 0.01; -> = 100.00; // 0.00 - 100.00 percent +uniform texture2d other_image; -float4 mainImage( VertData v_in ) : TARGET +float4 mainImage(VertData v_in) : TARGET { - float4 color = image.Sample( textureSampler, v_in.uv ); - return float4( color.rgb, color.a * Opacity * 0.01 ); + float4 other = other_image.Sample(textureSampler, v_in.uv); + float4 base = image.Sample(textureSampler, v_in.uv); + return clamp(base + other, 0.0, 1.0); } + ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -28860,18 +19675,25 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSPagePeelShader { +function Get-OBSAlphaBorderShader { -[Alias('Set-OBSPagePeelShader','Add-OBSPagePeelShader')] +[Alias('Set-OBSAlphaBorderShader','Add-OBSAlphaBorderShader')] param( -# Set the Speed of OBSPagePeelShader -[ComponentModel.DefaultBindingProperty('Speed')] -[Single] -$Speed, -# Set the Position of OBSPagePeelShader -[ComponentModel.DefaultBindingProperty('Position')] +# Set the border_color of OBSAlphaBorderShader +[Alias('border_color')] +[ComponentModel.DefaultBindingProperty('border_color')] +[String] +$BorderColor, +# Set the border_thickness of OBSAlphaBorderShader +[Alias('border_thickness')] +[ComponentModel.DefaultBindingProperty('border_thickness')] +[Int32] +$BorderThickness, +# Set the alpha_cut_off of OBSAlphaBorderShader +[Alias('alpha_cut_off')] +[ComponentModel.DefaultBindingProperty('alpha_cut_off')] [Single] -$Position, +$AlphaCutOff, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -28902,86 +19724,44 @@ $UseShaderTime process { -$shaderName = 'page-peel' -$ShaderNoun = 'OBSPagePeelShader' +$shaderName = 'alpha_border' +$ShaderNoun = 'OBSAlphaBorderShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Simple Page Peel, Version 0.01, for OBS Shaderfilter -// Copyright ©️ 2023 by SkeletonBow -// License: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License -// Contact info: -// Twitter: -// Twitch: -// YouTube: -// Soundcloud: -// -// Based on Shadertoy shader by droozle -// -// Description: -// -// -// Changelog: -// 0.01 - Initial release - -uniform float Speed< - string label = "Speed"; +uniform float4 border_color< + string label = "Border color"; +> = {0.0,0.0,0.0,1.0}; +uniform int border_thickness< + string label = "Border thickness"; string widget_type = "slider"; - float minimum = 0.0; - float maximum = 50.0; - float step = 0.001; -> = 1.00; -uniform float Position< - string label = "Position"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 0; +uniform float alpha_cut_off< + string label = "Alpha cut off"; string widget_type = "slider"; float minimum = 0.0; - float maximum = 100.0; - float step = 0.001; -> = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.5; -float4 mainImage( VertData v_in ) : TARGET +float4 mainImage(VertData v_in) : TARGET { - // Normalized pixel coordinates (from 0 to 1) - float2 aspect = float2( uv_size.x / uv_size.y, 1.0 ); - float2 uv = v_in.uv; - - float t = Position + elapsed_time * Speed; - // Define the fold. - float2 origin = float2( 0.6 + 0.4 * sin( t * 0.2 ), 0.5 + 0.5 * cos( t * 0.13 ) ) * aspect; - float2 normal = normalize( float2( 1.0, 2.0 * sin( t * 0.3 ) ) * aspect ); - - // Sample texture. - float3 col = image.Sample( textureSampler, uv ).rgb; // Front color. - - // Check on which side the pixel lies. - float2 pt = uv * aspect - origin; - float side = dot( pt, normal ); - if( side > 0.0 ) { - col *= 0.25; // Background color (peeled off). - - float shadow = smoothstep( 0.0, 0.05, side ); - col = lerp( col * 0.6, col, shadow ); - } - else { - // Find the mirror pixel. - pt = ( uv * aspect - 2.0 * side * normal ) / aspect; - - // Check if we''re still inside the image bounds. - if( pt.x >= 0.0 && pt.x < 1.0 && pt.y >= 0.0 && pt.y < 1.0 ) { - float4 back = image.Sample( textureSampler, pt ); // Back color. - back.rgb = back.rgb * 0.25 + 0.75; - - float shadow = smoothstep( 0.0, 0.2, -side ); - back.rgb = lerp( back.rgb * 0.2, back.rgb, shadow ); - - // Support for transparency. - col = lerp( col, back.rgb, back.a ); - } + float4 pix = image.Sample(textureSampler, v_in.uv); + if (pix.a > alpha_cut_off) + return pix; + [loop] for(int x = -border_thickness;x alpha_cut_off) + return border_color; + } + } } - - // Output to screen - return float4(col,1.0); + return pix; } - ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -29079,40 +19859,60 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSPagePeelTransitionShader { +function Get-OBSAlphaGamingBentCameraShader { -[Alias('Set-OBSPagePeelTransitionShader','Add-OBSPagePeelTransitionShader')] +[Alias('Set-OBSAlphaGamingBentCameraShader','Add-OBSAlphaGamingBentCameraShader')] param( -# Set the image_a of OBSPagePeelTransitionShader -[Alias('image_a')] -[ComponentModel.DefaultBindingProperty('image_a')] -[String] -$ImageA, -# Set the image_b of OBSPagePeelTransitionShader -[Alias('image_b')] -[ComponentModel.DefaultBindingProperty('image_b')] -[String] -$ImageB, -# Set the transition_time of OBSPagePeelTransitionShader -[Alias('transition_time')] -[ComponentModel.DefaultBindingProperty('transition_time')] +# Set the left_side_width of OBSAlphaGamingBentCameraShader +[Alias('left_side_width')] +[ComponentModel.DefaultBindingProperty('left_side_width')] [Single] -$TransitionTime, -# Set the convert_linear of OBSPagePeelTransitionShader -[Alias('convert_linear')] -[ComponentModel.DefaultBindingProperty('convert_linear')] -[Management.Automation.SwitchParameter] -$ConvertLinear, -# Set the page_color of OBSPagePeelTransitionShader -[Alias('page_color')] -[ComponentModel.DefaultBindingProperty('page_color')] -[String] -$PageColor, -# Set the page_transparency of OBSPagePeelTransitionShader -[Alias('page_transparency')] -[ComponentModel.DefaultBindingProperty('page_transparency')] +$LeftSideWidth, +# Set the left_side_size of OBSAlphaGamingBentCameraShader +[Alias('left_side_size')] +[ComponentModel.DefaultBindingProperty('left_side_size')] [Single] -$PageTransparency, +$LeftSideSize, +# Set the left_side_shadow of OBSAlphaGamingBentCameraShader +[Alias('left_side_shadow')] +[ComponentModel.DefaultBindingProperty('left_side_shadow')] +[Single] +$LeftSideShadow, +# Set the left_flip_width of OBSAlphaGamingBentCameraShader +[Alias('left_flip_width')] +[ComponentModel.DefaultBindingProperty('left_flip_width')] +[Single] +$LeftFlipWidth, +# Set the left_flip_shadow of OBSAlphaGamingBentCameraShader +[Alias('left_flip_shadow')] +[ComponentModel.DefaultBindingProperty('left_flip_shadow')] +[Single] +$LeftFlipShadow, +# Set the right_side_width of OBSAlphaGamingBentCameraShader +[Alias('right_side_width')] +[ComponentModel.DefaultBindingProperty('right_side_width')] +[Single] +$RightSideWidth, +# Set the right_side_size of OBSAlphaGamingBentCameraShader +[Alias('right_side_size')] +[ComponentModel.DefaultBindingProperty('right_side_size')] +[Single] +$RightSideSize, +# Set the right_side_shadow of OBSAlphaGamingBentCameraShader +[Alias('right_side_shadow')] +[ComponentModel.DefaultBindingProperty('right_side_shadow')] +[Single] +$RightSideShadow, +# Set the right_flip_width of OBSAlphaGamingBentCameraShader +[Alias('right_flip_width')] +[ComponentModel.DefaultBindingProperty('right_flip_width')] +[Single] +$RightFlipWidth, +# Set the right_flip_shadow of OBSAlphaGamingBentCameraShader +[Alias('right_flip_shadow')] +[ComponentModel.DefaultBindingProperty('right_flip_shadow')] +[Single] +$RightFlipShadow, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -29143,77 +19943,127 @@ $UseShaderTime process { -$shaderName = 'page-peel-transition' -$ShaderNoun = 'OBSPagePeelTransitionShader' +$shaderName = 'alpha-gaming-bent-camera' +$ShaderNoun = 'OBSAlphaGamingBentCameraShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform texture2d image_a; -uniform texture2d image_b; -uniform float transition_time< - string label = "Transittion Time"; +uniform float left_side_width< + string label = "Left side width"; string widget_type = "slider"; float minimum = 0.0; float maximum = 1.0; - float step = 0.001; -> = 0.5; -uniform bool convert_linear = true; -uniform float4 page_color = {1.0, 1.0, 1.0, 1.0}; -uniform float page_transparency< - string label = "Page Transparency"; + float step = 0.01; +> = 0.1; +uniform float left_side_size< + string label = "Left side size"; string widget_type = "slider"; float minimum = 0.0; float maximum = 1.0; - float step = 0.001; -> = 0.5; + float step = 0.01; +> = 0.9; +uniform float left_side_shadow< + string label = "Left side shadow"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.8; +uniform float left_flip_width< + string label = "Left flip width"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.05; +uniform float left_flip_shadow< + string label = "Left flip shadow"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.6; + +uniform float right_side_width< + string label = "Right side width"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.1; +uniform float right_side_size< + string label = "Right side size"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.9; +uniform float right_side_shadow< + string label = "Right side shadow"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.8; +uniform float right_flip_width< + string label = "Right flip width"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.05; +uniform float right_flip_shadow< + string label = "Right flip shadow"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.6; float4 mainImage(VertData v_in) : TARGET { - // Normalized pixel coordinates (from 0 to 1) - float2 aspect = float2( uv_size.x / uv_size.y, 1.0 ); - float2 uv = v_in.uv; - - float t = transition_time * 12.0 + 11.0; - // Define the fold. - float2 origin = float2( 0.6 + 0.6 * sin( t * 0.2 ), 0.5 + 0.5 * cos( t * 0.13 ) ) * aspect; - float2 normal = normalize( float2( 1.0, 2.0 * sin( t * 0.3 ) ) * aspect ); - - // Sample texture. - float3 col = float3(1.0,0.0,0.0); - - // Check on which side the pixel lies. - float2 pt = uv * aspect - origin; - float side = dot( pt, normal ); - if( side > 0.0 ) { - // Next page - col = image_b.Sample( textureSampler, uv ).rgb; - - float shadow = smoothstep( 0.0, 0.05, side ); - col = lerp( col * 0.6, col, shadow ); + float2 pos=v_in.uv; + float shadow = 1.0; + if(pos.x < left_side_width){ + pos.y -= 0.5; + pos.y /= left_side_size; + pos.y += 0.5; + pos.x -= left_side_width + left_flip_width; + pos.x /= left_side_size; + pos.x += left_side_width + left_flip_width; + shadow = left_side_shadow; + }else if(pos.x < left_side_width + left_flip_width){ + float factor = 1.0 - ((left_side_width + left_flip_width)-pos.x)/left_flip_width*(1.0 - left_side_size); + pos.y -= 0.5; + pos.y /= factor; + pos.y += 0.5; + pos.x -= left_side_width + left_flip_width; + pos.x /= factor; + pos.x += left_side_width + left_flip_width; + shadow = left_flip_shadow; } - else { - - // Find the mirror pixel. - pt = ( uv * aspect - 2.0 * side * normal ) / aspect; - - // Check if we''re still inside the image bounds. - if( pt.x >= 0.0 && pt.x < 1.0 && pt.y >= 0.0 && pt.y < 1.0 ) { - col = image_a.Sample( textureSampler, pt ).rgb; // Back color. - col = lerp(page_color.rgb, col, page_transparency); - - float shadow = smoothstep( 0.0, 0.2, -side ); - col = lerp( col * 0.2, col, shadow ); - }else{ - col = image_a.Sample( textureSampler, uv ).rgb; - } + if(1.0 - pos.x < right_side_width){ + pos.y -= 0.5; + pos.y /= right_side_size; + pos.y += 0.5; + pos.x -= 1.0 - (right_side_width + right_flip_width); + pos.x /= right_side_size; + pos.x += 1.0 - (right_side_width + right_flip_width); + shadow = right_side_shadow; + }else if(1.0 - pos.x < right_side_width + right_flip_width){ + float factor = 1.0 - ((right_side_width + right_flip_width) - (1.0 - pos.x))/right_flip_width*(1.0 - right_side_size); + pos.y -= 0.5; + pos.y /= factor; + pos.y += 0.5; + pos.x -= 1.0 - (right_side_width + right_flip_width); + pos.x /= factor; + pos.x += 1.0 -(right_side_width + right_flip_width); + shadow = right_flip_shadow; } - - // Output to screen - if(convert_linear) - col = srgb_nonlinear_to_linear(col); - return float4(col,1.0); + float4 p_color = image.Sample(textureSampler, pos); + p_color.rgb *= shadow; + return p_color; } - ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -29311,59 +20161,57 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSPerlinNoiseShader { +function Get-OBSAnimatedPathShader { -[Alias('Set-OBSPerlinNoiseShader','Add-OBSPerlinNoiseShader')] +[Alias('Set-OBSAnimatedPathShader','Add-OBSAnimatedPathShader')] param( -# Set the speed of OBSPerlinNoiseShader -[ComponentModel.DefaultBindingProperty('speed')] -[Single] -$Speed, -# Set the animated of OBSPerlinNoiseShader -[ComponentModel.DefaultBindingProperty('animated')] -[Management.Automation.SwitchParameter] -$Animated, -# Set the apply_to_channel of OBSPerlinNoiseShader -[Alias('apply_to_channel')] -[ComponentModel.DefaultBindingProperty('apply_to_channel')] -[Management.Automation.SwitchParameter] -$ApplyToChannel, -# Set the inverted of OBSPerlinNoiseShader -[ComponentModel.DefaultBindingProperty('inverted')] -[Management.Automation.SwitchParameter] -$Inverted, -# Set the multiply of OBSPerlinNoiseShader -[ComponentModel.DefaultBindingProperty('multiply')] -[Management.Automation.SwitchParameter] -$Multiply, -# Set the speed_horizonal of OBSPerlinNoiseShader -[Alias('speed_horizonal')] -[ComponentModel.DefaultBindingProperty('speed_horizonal')] +# Set the ViewProj of OBSAnimatedPathShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the image of OBSAnimatedPathShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the elapsed_time of OBSAnimatedPathShader +[Alias('elapsed_time')] +[ComponentModel.DefaultBindingProperty('elapsed_time')] [Single] -$SpeedHorizonal, -# Set the speed_vertical of OBSPerlinNoiseShader -[Alias('speed_vertical')] -[ComponentModel.DefaultBindingProperty('speed_vertical')] +$ElapsedTime, +# Set the uv_offset of OBSAnimatedPathShader +[Alias('uv_offset')] +[ComponentModel.DefaultBindingProperty('uv_offset')] +[Single[]] +$UvOffset, +# Set the uv_scale of OBSAnimatedPathShader +[Alias('uv_scale')] +[ComponentModel.DefaultBindingProperty('uv_scale')] +[Single[]] +$UvScale, +# Set the uv_pixel_interval of OBSAnimatedPathShader +[Alias('uv_pixel_interval')] +[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +[Single[]] +$UvPixelInterval, +# Set the rand_f of OBSAnimatedPathShader +[Alias('rand_f')] +[ComponentModel.DefaultBindingProperty('rand_f')] [Single] -$SpeedVertical, -# Set the iterations of OBSPerlinNoiseShader -[ComponentModel.DefaultBindingProperty('iterations')] +$RandF, +# Set the speed_percent of OBSAnimatedPathShader +[Alias('speed_percent')] +[ComponentModel.DefaultBindingProperty('speed_percent')] [Int32] -$Iterations, -# Set the white_noise of OBSPerlinNoiseShader -[Alias('white_noise')] -[ComponentModel.DefaultBindingProperty('white_noise')] -[Single] -$WhiteNoise, -# Set the black_noise of OBSPerlinNoiseShader -[Alias('black_noise')] -[ComponentModel.DefaultBindingProperty('black_noise')] -[Single] -$BlackNoise, -# Set the notes of OBSPerlinNoiseShader -[ComponentModel.DefaultBindingProperty('notes')] +$SpeedPercent, +# Set the path_map of OBSAnimatedPathShader +[Alias('path_map')] +[ComponentModel.DefaultBindingProperty('path_map')] [String] -$Notes, +$PathMap, +# Set the reverse of OBSAnimatedPathShader +[ComponentModel.DefaultBindingProperty('reverse')] +[Management.Automation.SwitchParameter] +$Reverse, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -29394,258 +20242,101 @@ $UseShaderTime process { -$shaderName = 'perlin_noise' -$ShaderNoun = 'OBSPerlinNoiseShader' +$shaderName = 'animated_path' +$ShaderNoun = 'OBSAnimatedPathShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// -// Noise Shader Library for Unity - https://github.com/keijiro/NoiseShader -// Modified and improved my Charles Fettinger (https://github.com/Oncorporation) 1/2019 -// -// Original work (webgl-noise) Copyright (C) 2011 Stefan Gustavson -// Translation and modification was made by Keijiro Takahashi. -// Conversion for OBS by Charles Fettinger. -// -// This shader is based on the webgl-noise GLSL shader. For further details -// of the original shader, please see the following description from the -// original source code. -// - // -// GLSL textureless classic 2D noise "cnoise", (white_noise) -// with an RSL-style periodic variant "pnoise" (black_noise). -// Author: Stefan Gustavson (stefan.gustavson@liu.se) -// Version: 2011-08-22 -// -// Many thanks to Ian McEwan of Ashima Arts for the -// ideas for permutation and gradient selection. -// -// Copyright (c) 2011 Stefan Gustavson. All rights reserved. -// Distributed under the MIT license. See LICENSE file. -// https://github.com/ashima/webgl-noise -//Converted to OpenGL by Q-mii & Exeldro March 8, 2022 - float4 mod(float4 x, float4 y) +// Path effect By Charles Fettinger (https://github.com/Oncorporation) 3/2019 +//Converted to OpenGL by Q-mii & Exeldro February 24, 2022 +uniform float4x4 ViewProj; +uniform texture2d image; + +uniform float elapsed_time; +uniform float2 uv_offset; +uniform float2 uv_scale; +uniform float2 uv_pixel_interval; +uniform float rand_f; + +uniform int speed_percent = 100; +uniform texture2d path_map; +uniform bool reverse = false; + +sampler_state textureSampler { + Filter = Linear; + AddressU = Border; + AddressV = Border; + BorderColor = 00000000; +}; + +struct VertData { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; + +float4 convert_pmalpha(float4 c) { - return x - y * floor(x / y); + float4 ret = c; + if (c.a >= 0.001) + ret.xyz /= c.a; + else + ret = float4(0.0, 0.0, 0.0, 0.0); + return ret; } - float4 mod289(float4 x) + +VertData mainTransform(VertData v_in) { - return x - floor(x / 289.0) * 289.0; + VertData vert_out; + float3 pos = v_in.pos.xyz; + float3 current_pos; + float speed = speed_percent * 0.01; + //vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); + float t = 1.0 + sin(elapsed_time * speed) ; + // combine luma texture and user defined shine color + float luma = path_map.Sample(textureSampler, v_in.uv).x; + if (reverse) + { + luma = 1.0 - luma; + } + + float time = lerp(0.0f, 1.0f , t - 1.0); + + // set current position in time + current_pos.x = 0; + current_pos.y = 0; + + + float2 offset = uv_offset; + if (speed == 0.0f) + { + offset.x = 0.0f; + offset.y = 0.0f; + } + else + { + offset.x = uv_offset.x + time * luma; + offset.y = uv_offset.y + time * luma; + } + + vert_out.pos = mul(float4(current_pos, 1), ViewProj); + vert_out.uv = v_in.uv * uv_scale + offset; + return vert_out; } - float4 permute(float4 x) + +float4 mainImage(VertData v_in) : TARGET { - return mod289(((x*34.0)+1.0)*x); + return image.Sample(textureSampler, v_in.uv); } - float4 taylorInvSqrt(float4 r) + +technique Draw { - return 1.79284291400159 - r * 0.85373472095314; + pass + { + vertex_shader = mainTransform(v_in); + pixel_shader = mainImage(v_in); + } } - float2 fade(float2 t) { - return t*t*t*(t*(t*6.0-15.0)+10.0); -} - // Classic Perlin noise -float cnoise(float2 P) -{ - float4 Pi = floor(P.xyxy) + float4(0.0, 0.0, 1.0, 1.0); - float4 Pf = frac (P.xyxy) - float4(0.0, 0.0, 1.0, 1.0); - Pi = mod289(Pi); // To avoid truncation effects in permutation - float4 ix = Pi.xzxz; - float4 iy = Pi.yyww; - float4 fx = Pf.xzxz; - float4 fy = Pf.yyww; - float4 i = permute(permute(ix) + iy); - float4 gx = frac(i / 41.0) * 2.0 - 1.0 ; - float4 gy = abs(gx) - 0.5 ; - float4 tx = floor(gx + 0.5); - gx = gx - tx; - float2 g00 = float2(gx.x,gy.x); - float2 g10 = float2(gx.y,gy.y); - float2 g01 = float2(gx.z,gy.z); - float2 g11 = float2(gx.w,gy.w); - float4 norm = taylorInvSqrt(float4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); - g00 *= norm.x; - g01 *= norm.y; - g10 *= norm.z; - g11 *= norm.w; - float n00 = dot(g00, float2(fx.x, fy.x)); - float n10 = dot(g10, float2(fx.y, fy.y)); - float n01 = dot(g01, float2(fx.z, fy.z)); - float n11 = dot(g11, float2(fx.w, fy.w)); - float2 fade_xy = fade(Pf.xy); - float2 n_x = lerp(float2(n00, n01), float2(n10, n11), fade_xy.x); - float n_xy = lerp(n_x.x, n_x.y, fade_xy.y); - return 2.3 * n_xy; -} - // Classic Perlin noise, periodic variant -float pnoise(float2 P, float2 rep) -{ - float4 Pi = floor(P.xyxy) + float4(0.0, 0.0, 1.0, 1.0); - float4 Pf = frac (P.xyxy) - float4(0.0, 0.0, 1.0, 1.0); - Pi = mod(Pi, rep.xyxy); // To create noise with explicit period - Pi = mod289(Pi); // To avoid truncation effects in permutation - float4 ix = Pi.xzxz; - float4 iy = Pi.yyww; - float4 fx = Pf.xzxz; - float4 fy = Pf.yyww; - float4 i = permute(permute(ix) + iy); - float4 gx = frac(i / 41.0) * 2.0 - 1.0 ; - float4 gy = abs(gx) - 0.5 ; - float4 tx = floor(gx + 0.5); - gx = gx - tx; - float2 g00 = float2(gx.x,gy.x); - float2 g10 = float2(gx.y,gy.y); - float2 g01 = float2(gx.z,gy.z); - float2 g11 = float2(gx.w,gy.w); - float4 norm = taylorInvSqrt(float4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); - g00 *= norm.x; - g01 *= norm.y; - g10 *= norm.z; - g11 *= norm.w; - float n00 = dot(g00, float2(fx.x, fy.x)); - float n10 = dot(g10, float2(fx.y, fy.y)); - float n01 = dot(g01, float2(fx.z, fy.z)); - float n11 = dot(g11, float2(fx.w, fy.w)); - float2 fade_xy = fade(Pf.xy); - float2 n_x = lerp(float2(n00, n01), float2(n10, n11), fade_xy.x); - float n_xy = lerp(n_x.x, n_x.y, fade_xy.y); - return 2.3 * n_xy; -} - //The good bits~ adapting the noise generator for the plugin and giving some control over the shader - //todo: pseudorandom number generator w/ seed -uniform float speed< - string label = "Speed"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> = 0.5; -uniform bool animated; -uniform bool apply_to_channel; -uniform bool inverted; -uniform bool multiply; -uniform float speed_horizonal< - string label = "Speed horizontal"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> = 0.5; -uniform float speed_vertical< - string label = "Speed vertical"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> = 0; -uniform int iterations< - string label = "Iterations"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 20; - int step = 1; -> = 4; -//how much c_noise do we want? white -uniform float white_noise< - string label = "White noise"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> = 0.5; -//how much p_noise do we want? black -uniform float black_noise< - string label = "Black noise"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> = 0.5; -uniform string notes< - string widget_type = "info"; -> = "white noise and black noise and iterations.. enjoy!"; - - float2 noisePosition(float t){ - return float2(sin(2.2 * t) - cos(1.4 * t), cos(1.3 * t) + sin(-1.9 *t)); -} - float4 mainImage(VertData v_in) : TARGET -{ - float4 color = image.Sample(textureSampler, v_in.uv); - float t = elapsed_time * speed; - float2 dir = float2(speed_horizonal,speed_vertical); - - if(!animated){ - float o = 0.5; - float scale = 1.0; - float w = 0.5; - for(int i = 0; i < iterations; i++){ - float2 coord = v_in.uv * scale; - float2 period = float2(scale * 2.0, scale * 2.0); - - if(white_noise == 0.0 && black_noise == 0.0){ - o += pnoise(coord, period) * w; - } else { - if(white_noise != 0.0){ - o += cnoise(coord) * w * white_noise; - } - if(black_noise != 0.0){ - o += pnoise(coord, period) * w * black_noise; - } - } - - //o += pnoise(coord, period) * w; - - scale *= 2.0; - w *= 0.5; - } - if(inverted){ - o = 1 - o; - } - if(apply_to_channel){ - if(multiply){ - return float4(color.r,color.g,color.b,color.a*o); - } else { - return float4(color.r,color.g,color.b,o); - } - } else { - return float4(o,o,o,1.0); - } - } else { - float o = 0.5; - float scale = 1.0; - float w = 0.5; - for(int i = 0; i < iterations; i++){ - float2 coord = (v_in.uv + t*dir) * scale; - float2 period = float2(scale * 2.0, scale * 2.0); - - if(white_noise == 0.0 && black_noise == 0.0){ - o += pnoise(coord, period) * w; - } else { - if(white_noise != 0.0){ - o += cnoise(coord) * w * white_noise; - } - if(black_noise != 0.0){ - o += pnoise(coord, period) * w * black_noise; - } - } - - scale *= 2.0; - w *= 0.5; - } - if(inverted){ - o = 1 - o; - } - if(apply_to_channel){ - if(multiply){ - return float4(color.r,color.g,color.b,color.a*o); - } else { - return float4(color.r,color.g,color.b,o); - } - } else { - return float4(o,o,o,1.0); - } - } -} - -' + +' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 if (-not $myNoun) { @@ -29742,129 +20433,119 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSPieChartShader { +function Get-OBSAnimatedTextureShader { -[Alias('Set-OBSPieChartShader','Add-OBSPieChartShader')] +[Alias('Set-OBSAnimatedTextureShader','Add-OBSAnimatedTextureShader')] param( -# Set the inner_radius of OBSPieChartShader -[Alias('inner_radius')] -[ComponentModel.DefaultBindingProperty('inner_radius')] -[Single] -$InnerRadius, -# Set the outer_radius of OBSPieChartShader -[Alias('outer_radius')] -[ComponentModel.DefaultBindingProperty('outer_radius')] +# Set the ViewProj of OBSAnimatedTextureShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the image of OBSAnimatedTextureShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the elapsed_time of OBSAnimatedTextureShader +[Alias('elapsed_time')] +[ComponentModel.DefaultBindingProperty('elapsed_time')] [Single] -$OuterRadius, -# Set the start_angle of OBSPieChartShader -[Alias('start_angle')] -[ComponentModel.DefaultBindingProperty('start_angle')] +$ElapsedTime, +# Set the uv_offset of OBSAnimatedTextureShader +[Alias('uv_offset')] +[ComponentModel.DefaultBindingProperty('uv_offset')] +[Single[]] +$UvOffset, +# Set the uv_scale of OBSAnimatedTextureShader +[Alias('uv_scale')] +[ComponentModel.DefaultBindingProperty('uv_scale')] +[Single[]] +$UvScale, +# Set the uv_pixel_interval of OBSAnimatedTextureShader +[Alias('uv_pixel_interval')] +[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +[Single[]] +$UvPixelInterval, +# Set the rand_f of OBSAnimatedTextureShader +[Alias('rand_f')] +[ComponentModel.DefaultBindingProperty('rand_f')] [Single] -$StartAngle, -# Set the total of OBSPieChartShader -[ComponentModel.DefaultBindingProperty('total')] -[Int32] -$Total, -# Set the part_1 of OBSPieChartShader -[Alias('part_1')] -[ComponentModel.DefaultBindingProperty('part_1')] -[Int32] -$Part1, -# Set the color_1 of OBSPieChartShader -[Alias('color_1')] -[ComponentModel.DefaultBindingProperty('color_1')] -[String] -$Color1, -# Set the part_2 of OBSPieChartShader -[Alias('part_2')] -[ComponentModel.DefaultBindingProperty('part_2')] -[Int32] -$Part2, -# Set the color_2 of OBSPieChartShader -[Alias('color_2')] -[ComponentModel.DefaultBindingProperty('color_2')] -[String] -$Color2, -# Set the part_3 of OBSPieChartShader -[Alias('part_3')] -[ComponentModel.DefaultBindingProperty('part_3')] -[Int32] -$Part3, -# Set the color_3 of OBSPieChartShader -[Alias('color_3')] -[ComponentModel.DefaultBindingProperty('color_3')] -[String] -$Color3, -# Set the part_4 of OBSPieChartShader -[Alias('part_4')] -[ComponentModel.DefaultBindingProperty('part_4')] -[Int32] -$Part4, -# Set the color_4 of OBSPieChartShader -[Alias('color_4')] -[ComponentModel.DefaultBindingProperty('color_4')] -[String] -$Color4, -# Set the part_5 of OBSPieChartShader -[Alias('part_5')] -[ComponentModel.DefaultBindingProperty('part_5')] -[Int32] -$Part5, -# Set the color_5 of OBSPieChartShader -[Alias('color_5')] -[ComponentModel.DefaultBindingProperty('color_5')] -[String] -$Color5, -# Set the part_6 of OBSPieChartShader -[Alias('part_6')] -[ComponentModel.DefaultBindingProperty('part_6')] -[Int32] -$Part6, -# Set the color_6 of OBSPieChartShader -[Alias('color_6')] -[ComponentModel.DefaultBindingProperty('color_6')] -[String] -$Color6, -# Set the part_7 of OBSPieChartShader -[Alias('part_7')] -[ComponentModel.DefaultBindingProperty('part_7')] -[Int32] -$Part7, -# Set the color_7 of OBSPieChartShader -[Alias('color_7')] -[ComponentModel.DefaultBindingProperty('color_7')] -[String] -$Color7, -# Set the part_8 of OBSPieChartShader -[Alias('part_8')] -[ComponentModel.DefaultBindingProperty('part_8')] -[Int32] -$Part8, -# Set the color_8 of OBSPieChartShader -[Alias('color_8')] -[ComponentModel.DefaultBindingProperty('color_8')] +$RandF, +# Set the uv_size of OBSAnimatedTextureShader +[Alias('uv_size')] +[ComponentModel.DefaultBindingProperty('uv_size')] +[Single[]] +$UvSize, +# Set the notes of OBSAnimatedTextureShader +[ComponentModel.DefaultBindingProperty('notes')] [String] -$Color8, -# Set the part_9 of OBSPieChartShader -[Alias('part_9')] -[ComponentModel.DefaultBindingProperty('part_9')] -[Int32] -$Part9, -# Set the color_9 of OBSPieChartShader -[Alias('color_9')] -[ComponentModel.DefaultBindingProperty('color_9')] +$Notes, +# Set the Animation_Image of OBSAnimatedTextureShader +[Alias('Animation_Image')] +[ComponentModel.DefaultBindingProperty('Animation_Image')] [String] -$Color9, -# Set the part_10 of OBSPieChartShader -[Alias('part_10')] -[ComponentModel.DefaultBindingProperty('part_10')] -[Int32] -$Part10, -# Set the color_10 of OBSPieChartShader -[Alias('color_10')] -[ComponentModel.DefaultBindingProperty('color_10')] +$AnimationImage, +# Set the Colorization_Image of OBSAnimatedTextureShader +[Alias('Colorization_Image')] +[ComponentModel.DefaultBindingProperty('Colorization_Image')] [String] -$Color10, +$ColorizationImage, +# Set the reverse of OBSAnimatedTextureShader +[ComponentModel.DefaultBindingProperty('reverse')] +[Management.Automation.SwitchParameter] +$Reverse, +# Set the bounce of OBSAnimatedTextureShader +[ComponentModel.DefaultBindingProperty('bounce')] +[Management.Automation.SwitchParameter] +$Bounce, +# Set the center_animation of OBSAnimatedTextureShader +[Alias('center_animation')] +[ComponentModel.DefaultBindingProperty('center_animation')] +[Management.Automation.SwitchParameter] +$CenterAnimation, +# Set the polar_animation of OBSAnimatedTextureShader +[Alias('polar_animation')] +[ComponentModel.DefaultBindingProperty('polar_animation')] +[Management.Automation.SwitchParameter] +$PolarAnimation, +# Set the polar_angle of OBSAnimatedTextureShader +[Alias('polar_angle')] +[ComponentModel.DefaultBindingProperty('polar_angle')] +[Single] +$PolarAngle, +# Set the polar_height of OBSAnimatedTextureShader +[Alias('polar_height')] +[ComponentModel.DefaultBindingProperty('polar_height')] +[Single] +$PolarHeight, +# Set the speed_horizontal_percent of OBSAnimatedTextureShader +[Alias('speed_horizontal_percent')] +[ComponentModel.DefaultBindingProperty('speed_horizontal_percent')] +[Single] +$SpeedHorizontalPercent, +# Set the speed_vertical_percent of OBSAnimatedTextureShader +[Alias('speed_vertical_percent')] +[ComponentModel.DefaultBindingProperty('speed_vertical_percent')] +[Single] +$SpeedVerticalPercent, +# Set the tint_speed_horizontal_percent of OBSAnimatedTextureShader +[Alias('tint_speed_horizontal_percent')] +[ComponentModel.DefaultBindingProperty('tint_speed_horizontal_percent')] +[Single] +$TintSpeedHorizontalPercent, +# Set the tint_speed_vertical_percent of OBSAnimatedTextureShader +[Alias('tint_speed_vertical_percent')] +[ComponentModel.DefaultBindingProperty('tint_speed_vertical_percent')] +[Single] +$TintSpeedVerticalPercent, +# Set the Alpha of OBSAnimatedTextureShader +[ComponentModel.DefaultBindingProperty('Alpha')] +[Single] +$Alpha, +# Set the Use_Animation_Image_Color of OBSAnimatedTextureShader +[Alias('Use_Animation_Image_Color')] +[ComponentModel.DefaultBindingProperty('Use_Animation_Image_Color')] +[Management.Automation.SwitchParameter] +$UseAnimationImageColor, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -29895,160 +20576,171 @@ $UseShaderTime process { -$shaderName = 'pie-chart' -$ShaderNoun = 'OBSPieChartShader' +$shaderName = 'animated_texture' +$ShaderNoun = 'OBSAnimatedTextureShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform float inner_radius< - string label = "inner radius"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.1; -> = 32.0; -uniform float outer_radius< - string label = "outer radius"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.1; -> = 50.0; -uniform float start_angle< - string label = "Start angle"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 360.0; - float step = 0.1; -> = 90.0; +// Animated Texture By Charles Fettinger (https://github.com/Oncorporation) 3/2020 +// Animates a texture with polar sizing and color options +// for use with obs-shaderfilter 1.0 +//Converted to OpenGL by Q-mii & Exeldro February 24, 2022 +uniform float4x4 ViewProj; +uniform texture2d image; + +uniform float elapsed_time; +uniform float2 uv_offset; +uniform float2 uv_scale; +uniform float2 uv_pixel_interval; +uniform float rand_f; +uniform float2 uv_size; +uniform string notes; + +uniform texture2d Animation_Image; +uniform texture2d Colorization_Image; +uniform bool reverse = false; +uniform bool bounce = false; +uniform bool center_animation = true; +uniform bool polar_animation = true; +uniform float polar_angle = 90.0; +uniform float polar_height = 1.0; +uniform float speed_horizontal_percent = 50; +uniform float speed_vertical_percent = 5; +uniform float tint_speed_horizontal_percent = 50; +uniform float tint_speed_vertical_percent = 5; +uniform float Alpha = 1.0; +uniform bool Use_Animation_Image_Color = true; + +sampler_state textureSampler { + Filter = Linear; + AddressU = Border; + AddressV = Border; + BorderColor = 00000000; +}; + +struct VertData { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; + +float4 convert_pmalpha(float4 color) +{ + float4 ret = color; + if (color.a >= 0.001) + ret.xyz /= color.a; + else + ret = float4(0.0, 0.0, 0.0, 0.0); + return ret; +} + +float2 time(float2 speed_dir) +{ + float PI = 3.1415926535897932384626433832795; //acos(-1); + + float2 t = (elapsed_time * speed_dir) ; + if (bounce) + { + // coordinates moved from -1.0 to 1.0 to 0.0 to 2.0 then modified to fit screen + t.x = sin(elapsed_time * speed_dir.x * PI * 0.6667) + 1.0; + t.y = cos(elapsed_time * speed_dir.y * PI) + 1.0; + t *= -0.5; + } + + if (reverse) + t = t * -1; + return t; +} + +VertData mainTransform(VertData v_in) +{ + float2 speed_dir = float2(speed_horizontal_percent * 0.01, speed_vertical_percent * 0.01); + + VertData vert_out; + //float2 direction = abs(sin((elapsed_time - 0.001) * speed_dir)); + + float2 offset = uv_offset; + + if (center_animation) + { + vert_out.uv = v_in.uv - 0.5f; + } + else + { + offset += time(speed_dir); + vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); + vert_out.uv = v_in.uv * uv_scale + offset; + } + + return vert_out; +} -uniform int total< - string label = "Total"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 1000; - int step = 1; -> = 100; -uniform int part_1< - string label = "Part 1"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 1000; - int step = 1; -> = 50; -uniform float4 color_1 = {0.0,0.26,0.62,1.0}; -uniform int part_2< - string label = "Part 2"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 1000; - int step = 1; -> = 25; -uniform float4 color_2 = {0.24,0.40,0.68,1.0}; -uniform int part_3< - string label = "Part 3"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 1000; - int step = 1; -> = 10; -uniform float4 color_3 = {0.38,0.56,0.75,1.0}; -uniform int part_4< - string label = "Part 4"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 1000; - int step = 1; -> = 5; -uniform float4 color_4 = {0.52,0.72,0.81,1.0}; -uniform int part_5< - string label = "Part 5"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 1000; - int step = 1; -> = 3; -uniform float4 color_5 = {0.69,0.87,0.86,1.0}; -uniform int part_6< - string label = "Part 6"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 1000; - int step = 1; -> = 2; -uniform float4 color_6 = {1.0,0.79,0.73,1.0}; -uniform int part_7< - string label = "Part 7"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 1000; - int step = 1; -> = 1; -uniform float4 color_7 = {0.99,0.57,0.57,1.0}; -uniform int part_8< - string label = "Part 8"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 1000; - int step = 1; -> = 1; -uniform float4 color_8 = {0.91,0.36,0.44,1.0}; -uniform int part_9< - string label = "Part 9"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 1000; - int step = 1; -> = 1; -uniform float4 color_9 = {0.77,0.16,0.32,1.0}; -uniform int part_10< - string label = "Part 10"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 1000; - int step = 1; -> = 0; -uniform float4 color_10 = {0.58,0.0,0.23,1.0}; float4 mainImage(VertData v_in) : TARGET { - const float pi = 3.14159265358979323846; -#ifdef OPENGL - float[10] parts = float[10](part_1, part_2, part_3, part_4, part_5, part_6, part_7, part_8, part_9, part_10); - float4[10] colors = float4[10](color_1, color_2, color_3, color_4, color_5, color_6, color_7, color_8, color_9, color_10); -#else - float parts[] = {part_1, part_2, part_3, part_4, part_5, part_6, part_7, part_8, part_9, part_10}; - float4 colors[] = {color_1, color_2, color_3, color_4, color_5, color_6, color_7, color_8, color_9, color_10}; -#endif - float2 center = float2(0.5, 0.5); - float2 factor; - if(uv_size.x < uv_size.y){ - factor = float2(1.0, uv_size.y/uv_size.x); - }else{ - factor = float2(uv_size.x/uv_size.y, 1.0); - } - center = center * factor; - float d = distance(center, v_in.uv * factor); - if(d > outer_radius/100.0 || d < inner_radius/100.0){ - return image.Sample(textureSampler, v_in.uv); - } - float2 toCenter = center - v_in.uv*factor; - float angle = atan2(toCenter.y ,toCenter.x); - angle = angle - (start_angle / 180.0 * pi); - if(angle < 0.0) - angle = pi + pi + angle; - if(angle < 0.0) - angle = pi + pi + angle; - angle = angle / (pi + pi); - float t = 0.0; - for(int i = 0; i < 10; i+=1) { - float part = parts[i]/total; - if(angle > t && angle <= t+part){ - return colors[i]; - } - t = t + part; - } - return image.Sample(textureSampler, v_in.uv); + float PI = 3.1415926535897932384626433832795; //acos(-1); + float PI180th = 0.0174532925; //PI divided by 180 + + float2 speed_dir = float2(speed_horizontal_percent * 0.01, speed_vertical_percent * 0.01); + float2 tint_speed_dir = float2(tint_speed_horizontal_percent * 0.01, tint_speed_vertical_percent * 0.01); + + //compensate for background vertex shader values + float2 background_offset = float2(-.5,-.5); + if (!center_animation) + background_offset = time(speed_dir); + float4 rgba = image.Sample(textureSampler, v_in.uv - background_offset); //float4(0.0,0.0,0.0,0.01); + + // Convert our texture coordinates to polar form: + if (polar_animation) { + + float2 polar = float2( + atan2(v_in.uv.y, v_in.uv.x) / (polar_angle * PI180th * 4), // angle + log(dot(v_in.uv, v_in.uv)) * -1 * (polar_height * PI180th * PI) // log-radius + ); + + // Check how much our texture sampling point changes between + // neighbouring pixels to the sides (ddx) and above/below (ddy) + ///float4 gradient = float4(ddx(polar), ddy(polar)); + + // If our angle wraps around between adjacent samples, + // discard one full rotation from its value and keep the fraction. + ///gradient.xz = frac(gradient.xz + 1.5f) - 0.5f; + + float2 tintUVs = polar * 4; + tintUVs += time(tint_speed_dir); + + // Apply texture scale + polar *= 4; + // Scroll the texture over time. + polar += time(speed_dir); + float4 animation = Animation_Image.Sample(textureSampler, frac(polar)); + + + float keyAmount = distance(animation.rgb,float3(0.0,0.0,0.0)); + float intensity = dot(animation.rgb ,float3(0.299,0.587,0.114)); + //animation.a = clamp((intensity),0.0,1.0); + if (Use_Animation_Image_Color) + { + animation.rgb *= Colorization_Image.Sample(textureSampler, frac(tintUVs)).rgb; + } + else + { + animation.rgb = Colorization_Image.Sample(textureSampler, frac(tintUVs)).rgb; + } + //if (keyAmount > 0.5f) + rgba = lerp(rgba, animation, animation.a * Alpha); + } + + return rgba; +} + +technique Draw +{ + pass + { + vertex_shader = mainTransform(v_in); + pixel_shader = mainImage(v_in); + } } + ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -30146,24 +20838,32 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSPixelationShader { +function Get-OBSAsciiShader { -[Alias('Set-OBSPixelationShader','Add-OBSPixelationShader')] +[Alias('Set-OBSAsciiShader','Add-OBSAsciiShader')] param( -# Set the Target_Width of OBSPixelationShader -[Alias('Target_Width')] -[ComponentModel.DefaultBindingProperty('Target_Width')] -[Single] -$TargetWidth, -# Set the Target_Height of OBSPixelationShader -[Alias('Target_Height')] -[ComponentModel.DefaultBindingProperty('Target_Height')] -[Single] -$TargetHeight, -# Set the notes of OBSPixelationShader -[ComponentModel.DefaultBindingProperty('notes')] +# Set the scale of OBSAsciiShader +[ComponentModel.DefaultBindingProperty('scale')] +[Int32] +$Scale, +# Set the base_color of OBSAsciiShader +[Alias('base_color')] +[ComponentModel.DefaultBindingProperty('base_color')] [String] -$Notes, +$BaseColor, +# Set the monochrome of OBSAsciiShader +[ComponentModel.DefaultBindingProperty('monochrome')] +[Management.Automation.SwitchParameter] +$Monochrome, +# Set the character_set of OBSAsciiShader +[Alias('character_set')] +[ComponentModel.DefaultBindingProperty('character_set')] +[Int32] +$CharacterSet, +# Set the note of OBSAsciiShader +[ComponentModel.DefaultBindingProperty('note')] +[String] +$Note, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -30194,53 +20894,109 @@ $UseShaderTime process { -$shaderName = 'pixelation' -$ShaderNoun = 'OBSPixelationShader' +$shaderName = 'ascii' +$ShaderNoun = 'OBSAsciiShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// pixelation shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 -// with help from SkeltonBowTV +// ASCII shader for use with obs-shaderfilter 7/2020 v1.0 // https://github.com/Oncorporation/obs-shaderfilter -//Converted to OpenGL by Exeldro February 15, 2022 -uniform float Target_Width< - string label = "Target Width"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2000.0; - float step = 0.1; -> = 320.0; -uniform float Target_Height< - string label = "Target Height"; +// Based on the following shaders: +// https://www.shadertoy.com/view/3dtXD8 - Created by DSWebber in 2019-10-24 +// https://www.shadertoy.com/view/lssGDj - Created by movAX13h in 2013-09-22 + +// Modifications of original shaders include: +// - Porting from GLSL to HLSL +// - Combining characters sets from both source shaders +// - Adding support for parameters from OBS for monochrome rendering, scaling and dynamic character set +// +// Add Additional Characters with this tool: http://thrill-project.com/archiv/coding/bitmap/ +// converts a bitmap into int then decodes it to look like text + +uniform int scale< + string label = "Scale"; string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2000.0; - float step = 0.1; -> = 180.0; -uniform string notes< + int minimum = 1; + int maximum = 20; + int step = 1; +> = 1; // Size of characters +uniform float4 base_color< + string label = "Base color"; +> = {0.0,1.0,0.0,1.0}; // Monochrome base color +uniform bool monochrome< + string label = "Monochrome"; +> = false; +uniform int character_set< + string label = "Character set"; + string widget_type = "select"; + int option_0_value = 0; + string option_0_label = "Large set of non-letters"; + int option_1_value = 1; + string option_1_label = "Small set of capital letters"; +> = 0; +uniform string note< string widget_type = "info"; -> = "adjust width and height to your screen dimension"; +> = "Base color is used as monochrome base color."; -float4 mainImage(VertData v_in) : TARGET +float character(int n, float2 p) { - float targetWidth = Target_Width; - if(targetWidth < 2.0) - targetWidth = 2.0; - float targetHeight = Target_Height; - if(targetHeight < 2.0) - targetHeight = 2.0; - float2 tex1; - int pixelSizeX = int(uv_size.x / targetWidth); - int pixelSizeY = int(uv_size.y / targetHeight); + p = floor(p*float2(4.0, 4.0) + 2.5); + if (clamp(p.x, 0.0, 4.0) == p.x) + { + if (clamp(p.y, 0.0, 4.0) == p.y) + { + int a = int(round(p.x) + 5.0 * round(p.y)); + if (((n >> a) & 1) == 1) return 1.0; + } + } + return 0.0; +} - int pixelX = int(v_in.uv.x * uv_size.x); - int pixelY = int(v_in.uv.y * uv_size.y); +float2 mod(float2 x, float2 y) +{ + return x - y * floor(x/y); +} - tex1.x = ((float(pixelX / pixelSizeX)*float(pixelSizeX)) / uv_size.x) + (float(pixelSizeX) / uv_size.x)/2.0; - tex1.y = ((float(pixelY / pixelSizeY)*float(pixelSizeY)) / uv_size.y) + (float(pixelSizeY) / uv_size.y)/2.0; +float4 mainImage( VertData v_in ) : TARGET +{ + float2 iResolution = uv_size; + float2 pix = v_in.uv * iResolution; + float4 c = image.Sample(textureSampler, floor(pix/float2(scale*8.0,scale*8.0))*float2(scale*8.0,scale*8.0)/iResolution.xy); - float4 c1 = image.Sample(textureSampler, tex1 ); + float gray = 0.3 * c.r + 0.59 * c.g + 0.11 * c.b; + + int n; + int charset = clamp(character_set, 0, 1); - return c1; + if (charset==0) + { + if (gray <= 0.2) n = 4096; // . + if (gray > 0.2) n = 65600; // : + if (gray > 0.3) n = 332772; // * + if (gray > 0.4) n = 15255086; // o + if (gray > 0.5) n = 23385164; // & + if (gray > 0.6) n = 15252014; // 8 + if (gray > 0.7) n = 13199452; // @ + if (gray > 0.8) n = 11512810; // # + } + else if (charset==1) + { + if (gray <= 0.1) n = 0; + if (gray > 0.1) n = 9616687; // R + if (gray > 0.3) n = 32012382; // S + if (gray > 0.5) n = 16303663; // D + if (gray > 0.7) n = 15255086; // O + if (gray > 0.8) n = 16301615; // B + } + + float2 p = mod(pix/float2(scale*4.0,scale*4.0),float2(2.0,2.0)) - float2(1.0,1.0); + + if (monochrome) + { + c.rgb = base_color.rgb; + } + c = c*character(n, p); + + return c; } ' @@ -30340,34 +21096,56 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSPixelationTransitionShader { +function Get-OBSAspectRatioShader { -[Alias('Set-OBSPixelationTransitionShader','Add-OBSPixelationTransitionShader')] +[Alias('Set-OBSAspectRatioShader','Add-OBSAspectRatioShader')] param( -# Set the transition_time of OBSPixelationTransitionShader -[Alias('transition_time')] -[ComponentModel.DefaultBindingProperty('transition_time')] -[Single] -$TransitionTime, -# Set the convert_linear of OBSPixelationTransitionShader -[Alias('convert_linear')] -[ComponentModel.DefaultBindingProperty('convert_linear')] -[Management.Automation.SwitchParameter] -$ConvertLinear, -# Set the power of OBSPixelationTransitionShader -[ComponentModel.DefaultBindingProperty('power')] -[Single] -$Power, -# Set the center_x of OBSPixelationTransitionShader -[Alias('center_x')] -[ComponentModel.DefaultBindingProperty('center_x')] +# Set the ViewProj of OBSAspectRatioShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the image of OBSAspectRatioShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the elapsed_time of OBSAspectRatioShader +[Alias('elapsed_time')] +[ComponentModel.DefaultBindingProperty('elapsed_time')] [Single] -$CenterX, -# Set the center_y of OBSPixelationTransitionShader -[Alias('center_y')] -[ComponentModel.DefaultBindingProperty('center_y')] +$ElapsedTime, +# Set the uv_offset of OBSAspectRatioShader +[Alias('uv_offset')] +[ComponentModel.DefaultBindingProperty('uv_offset')] +[Single[]] +$UvOffset, +# Set the uv_scale of OBSAspectRatioShader +[Alias('uv_scale')] +[ComponentModel.DefaultBindingProperty('uv_scale')] +[Single[]] +$UvScale, +# Set the uv_pixel_interval of OBSAspectRatioShader +[Alias('uv_pixel_interval')] +[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +[Single[]] +$UvPixelInterval, +# Set the rand_f of OBSAspectRatioShader +[Alias('rand_f')] +[ComponentModel.DefaultBindingProperty('rand_f')] [Single] -$CenterY, +$RandF, +# Set the uv_size of OBSAspectRatioShader +[Alias('uv_size')] +[ComponentModel.DefaultBindingProperty('uv_size')] +[Single[]] +$UvSize, +# Set the borderColor of OBSAspectRatioShader +[ComponentModel.DefaultBindingProperty('borderColor')] +[String] +$BorderColor, +# Set the notes of OBSAspectRatioShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -30398,70 +21176,110 @@ $UseShaderTime process { -$shaderName = 'pixelation-transition' -$ShaderNoun = 'OBSPixelationTransitionShader' +$shaderName = 'aspect_ratio' +$ShaderNoun = 'OBSAspectRatioShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform float transition_time< - string label = "Transittion Time"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.5; -uniform bool convert_linear = true; -uniform float power< - string label = "Power"; - string widget_type = "slider"; - float minimum = 0.5; - float maximum = 8.0; - float step = 0.01; -> = 3.0; -uniform float center_x< - string label = "X"; - string widget_type = "slider"; - string group = "Center"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.5; -uniform float center_y< - string label = "Y"; - string widget_type = "slider"; - string group = "Center"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.5; +//Converted to OpenGL by Q-mii & Exeldro March 8, 2022 - DO NOT USE THIS IT WAS NEVER COMPLETED +uniform float4x4 ViewProj; +uniform texture2d image; -float4 mainImage(VertData v_in) : TARGET -{ - //1..0..1 - float scale = abs(transition_time - 0.5) * 2.0; - scale = pow(scale, power); +uniform float elapsed_time; +uniform float2 uv_offset; +uniform float2 uv_scale; +uniform float2 uv_pixel_interval; +uniform float rand_f; +uniform float2 uv_size; - float2 uv = v_in.uv; - uv -= float2(center_x, center_y); - uv *= uv_size; - uv *= scale; - uv = floor(uv); - uv /= scale; - uv /= uv_size; - uv += float2(center_x, center_y); - uv = clamp(uv, 1.0/uv_size, 1.0); - float4 rgba = image.Sample(textureSampler, uv); - if(convert_linear) - rgba.rgb = srgb_nonlinear_to_linear(rgba.rgb); - return rgba; -} -' -} -$MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 -if (-not $myNoun) { - $myNoun = $myVerb - $myVerb = 'Get' -} +// variables +uniform float4 borderColor = {0,0,0,0}; +float targetaspect = 1.7777777777777777777777f; //16.0f / 9.0f; +uniform string notes; + +sampler_state textureSampler { + Filter = Linear; + AddressU = Border; + AddressV = Border; + BorderColor = 00000000; +}; + +struct VertData { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; + +VertData mainTransform(VertData v_in) +{ + VertData vert_out; + + vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); + vert_out.uv = v_in.uv * uv_scale + uv_offset; + + float2 hw = uv_scale; + // determine the game window''s current aspect ratio + float windowaspect = hw.x / hw.y; + + // current viewport height should be scaled by this amount + float scaleheight = windowaspect / targetaspect; + + + // if scaled height is less than current height, add letterbox + if (scaleheight < 1.0f) + { + Rect rect = camera.rect; + + rect.width = 1.0f; + rect.height = scaleheight; + rect.x = 0; + rect.y = (1.0f - scaleheight) / 2.0f; + + camera.rect = rect; + } + else // add pillarbox + { + float scalewidth = 1.0f / scaleheight; + + Rect rect = camera.rect; + + rect.width = scalewidth; + rect.height = 1.0f; + rect.x = (1.0f - scalewidth) / 2.0f; + rect.y = 0; + + camera.rect = rect; + } + return vert_out; +} + +float4 mainImage(VertData v_in) : TARGET +{ + if (v_in.uv.x < 0 || v_in.uv.x > 1 || v_in.uv.y < 0 || v_in.uv.y > 1) + { + return borderColor; + } + else + { + return image.Sample(textureSampler, v_in.uv); + } +} + +technique Draw +{ + pass + { + vertex_shader = mainTransform(v_in); + pixel_shader = mainImage(v_in); + } +} + +' +} +$MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 +if (-not $myNoun) { + $myNoun = $myVerb + $myVerb = 'Get' +} switch -regex ($myVerb) { Get { $FilterNamePattern = "(?>$( @@ -30552,41 +21370,24 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSPolarShader { +function Get-OBSAudioShader { -[Alias('Set-OBSPolarShader','Add-OBSPolarShader')] +[Alias('Set-OBSAudioShader','Add-OBSAudioShader')] param( -# Set the center_x of OBSPolarShader -[Alias('center_x')] -[ComponentModel.DefaultBindingProperty('center_x')] -[Single] -$CenterX, -# Set the center_y of OBSPolarShader -[Alias('center_y')] -[ComponentModel.DefaultBindingProperty('center_y')] -[Single] -$CenterY, -# Set the point_y of OBSPolarShader -[Alias('point_y')] -[ComponentModel.DefaultBindingProperty('point_y')] -[Single] -$PointY, -# Set the flip of OBSPolarShader -[ComponentModel.DefaultBindingProperty('flip')] -[Management.Automation.SwitchParameter] -$Flip, -# Set the rotate of OBSPolarShader -[ComponentModel.DefaultBindingProperty('rotate')] +# Set the audio_peak of OBSAudioShader +[Alias('audio_peak')] +[ComponentModel.DefaultBindingProperty('audio_peak')] [Single] -$Rotate, -# Set the repeat of OBSPolarShader -[ComponentModel.DefaultBindingProperty('repeat')] +$AudioPeak, +# Set the audio_magnitude of OBSAudioShader +[Alias('audio_magnitude')] +[ComponentModel.DefaultBindingProperty('audio_magnitude')] [Single] -$Repeat, -# Set the scale of OBSPolarShader -[ComponentModel.DefaultBindingProperty('scale')] +$AudioMagnitude, +# Set the intensity of OBSAudioShader +[ComponentModel.DefaultBindingProperty('intensity')] [Single] -$Scale, +$Intensity, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -30617,84 +21418,53 @@ $UseShaderTime process { -$shaderName = 'polar' -$ShaderNoun = 'OBSPolarShader' +$shaderName = 'audio' +$ShaderNoun = 'OBSAudioShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -#define PI 3.14159265359 -#define PI_2 6.2831 -#define mod(x,y) (x - y * floor(x / y)) - -uniform float center_x< - string label = "Center x"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.5; -uniform float center_y< - string label = "Center y"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.5; - -uniform float point_y< - string label = "Point y"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; - -uniform bool flip; - -uniform float rotate< - string label = "Rotate"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; - -uniform float repeat< - string label = "Repeat"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 20.0; - float step = 0.001; +// Audio shader example showing the difference between audio_peak and audio_magnitude. +// Left half uses audio_peak (red), right half uses audio_magnitude (blue). +uniform float audio_peak; +uniform float audio_magnitude; + +uniform float intensity < + string label = "Audio intensity"; + string widget_type = "slider"; + float minimum = 0.1; + float maximum = 3.0; + float step = 0.1; > = 1.0; -uniform float scale< - string label = "Scale"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2.0; - float step = 0.001; -> = 0.5; - -float4 mainImage(VertData v_in) : TARGET -{ - float2 uv = v_in.uv; - uv.x -= center_x ; - uv.y -= center_y ; - uv.x = uv.x * ( uv_size.x / uv_size.y); - float pixel_angle = atan2(uv.x,uv.y)/PI_2+0.5; - if(repeat < 1.0){ - pixel_angle = mod(pixel_angle+rotate,1.0); - if(pixel_angle > repeat) - return float4(0,0,0,0); - pixel_angle = mod(pixel_angle/repeat,1.0); - } else { - pixel_angle = mod(pixel_angle*repeat+rotate, 1.0); - } - float pixel_distance = length(uv)/ scale - point_y; - float2 uv2 = float2(pixel_angle , pixel_distance); - if(flip) - uv2 = float2(1.0,1.0) - uv2; - return image.Sample(textureSampler,uv2); +float4 mainImage(VertData v_in) : TARGET { + float4 color = image.Sample(textureSampler, v_in.uv); + + // Split screen based on UV coordinate + if (v_in.uv.x < 0.5) { + // Left half: audio_peak (instantaneous spikes, more reactive) + // Tint with red to show peak activity. + float peak_strength = audio_peak * intensity; + float3 peak_color = color.rgb + float3(peak_strength, 0, 0); + return float4(peak_color, color.a); + } else { + // Right half: audio_magnitude (RMS/averaged levels, smoother) + // Tint with blue to show magnitude activity. + float mag_strength = audio_magnitude * intensity; + float3 mag_color = color.rgb + float3(0, 0, mag_strength); + return float4(mag_color, color.a); + } } + +/* +EXPLANATION: +- audio_peak: Shows instantaneous maximum levels, very responsive to drums/percussion. +- audio_magnitude: Shows RMS (Root Mean Square) levels, smoother and represents sustained audio. + +TYPICAL BEHAVIOR: +- With music containing drums: Left side (peak) will flash more dramatically on beats. +- With sustained tones: Right side (magnitude) will show more consistent levels. +- Peak reacts faster to sudden sounds, magnitude is more stable for smooth effects. +*/ + ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -30792,62 +21562,78 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSPulseShader { +function Get-OBSBackgroundRemovalShader { -[Alias('Set-OBSPulseShader','Add-OBSPulseShader')] +[Alias('Set-OBSBackgroundRemovalShader','Add-OBSBackgroundRemovalShader')] param( -# Set the ViewProj of OBSPulseShader +# Set the ViewProj of OBSBackgroundRemovalShader [ComponentModel.DefaultBindingProperty('ViewProj')] [Single[][]] $ViewProj, -# Set the image of OBSPulseShader +# Set the image of OBSBackgroundRemovalShader [ComponentModel.DefaultBindingProperty('image')] [String] $Image, -# Set the elapsed_time of OBSPulseShader +# Set the elapsed_time of OBSBackgroundRemovalShader [Alias('elapsed_time')] [ComponentModel.DefaultBindingProperty('elapsed_time')] [Single] $ElapsedTime, -# Set the uv_offset of OBSPulseShader +# Set the uv_offset of OBSBackgroundRemovalShader [Alias('uv_offset')] [ComponentModel.DefaultBindingProperty('uv_offset')] [Single[]] $UvOffset, -# Set the uv_scale of OBSPulseShader +# Set the uv_scale of OBSBackgroundRemovalShader [Alias('uv_scale')] [ComponentModel.DefaultBindingProperty('uv_scale')] [Single[]] $UvScale, -# Set the uv_pixel_interval of OBSPulseShader +# Set the uv_pixel_interval of OBSBackgroundRemovalShader [Alias('uv_pixel_interval')] [ComponentModel.DefaultBindingProperty('uv_pixel_interval')] [Single[]] $UvPixelInterval, -# Set the rand_f of OBSPulseShader +# Set the rand_f of OBSBackgroundRemovalShader [Alias('rand_f')] [ComponentModel.DefaultBindingProperty('rand_f')] [Single] $RandF, -# Set the uv_size of OBSPulseShader +# Set the uv_size of OBSBackgroundRemovalShader [Alias('uv_size')] [ComponentModel.DefaultBindingProperty('uv_size')] [Single[]] $UvSize, -# Set the speed of OBSPulseShader -[ComponentModel.DefaultBindingProperty('speed')] -[Single] -$Speed, -# Set the min_growth_pixels of OBSPulseShader -[Alias('min_growth_pixels')] -[ComponentModel.DefaultBindingProperty('min_growth_pixels')] -[Single] -$MinGrowthPixels, -# Set the max_growth_pixels of OBSPulseShader -[Alias('max_growth_pixels')] -[ComponentModel.DefaultBindingProperty('max_growth_pixels')] +# Set the notes of OBSBackgroundRemovalShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# Set the target of OBSBackgroundRemovalShader +[ComponentModel.DefaultBindingProperty('target')] +[String] +$Target, +# Set the color of OBSBackgroundRemovalShader +[ComponentModel.DefaultBindingProperty('color')] +[String] +$Color, +# Set the opacity of OBSBackgroundRemovalShader +[ComponentModel.DefaultBindingProperty('opacity')] [Single] -$MaxGrowthPixels, +$Opacity, +# Set the invert of OBSBackgroundRemovalShader +[ComponentModel.DefaultBindingProperty('invert')] +[Management.Automation.SwitchParameter] +$Invert, +# Set the Convert_709to601 of OBSBackgroundRemovalShader +[Alias('Convert_709to601')] +[ComponentModel.DefaultBindingProperty('Convert_709to601')] +[Management.Automation.SwitchParameter] +$Convert709to601, +# Set the Convert_601to709 of OBSBackgroundRemovalShader +[Alias('Convert_601to709')] +[ComponentModel.DefaultBindingProperty('Convert_601to709')] +[Management.Automation.SwitchParameter] +$Convert601to709, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -30878,10 +21664,12 @@ $UseShaderTime process { -$shaderName = 'pulse' -$ShaderNoun = 'OBSPulseShader' +$shaderName = 'background_removal' +$ShaderNoun = 'OBSBackgroundRemovalShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' +// background removal effect By Charles Fettinger (https://github.com/Oncorporation) 4/2019 +//Converted to OpenGL by Exeldro February 19, 2022 uniform float4x4 ViewProj; uniform texture2d image; @@ -30891,71 +21679,109 @@ uniform float2 uv_scale; uniform float2 uv_pixel_interval; uniform float rand_f; uniform float2 uv_size; +uniform string notes = "Opacity between 10 and 20 works. Adjust `Color` from white to fix environmental changes.\r\r\nUsage:\r\n1) Disable `Auto` settings like focus, white balance, etc.\r\n2) Take a video of just the background. \r\n3) Take a frame and use it as the background image. Windows Snipping Tool (%windir%\\system32\\SnippingTool.exe). \r\r\nThis eliminates differences based upon camera/video settings."; + +uniform texture2d target; +uniform float4 color; +uniform float opacity = 15.0; +uniform bool invert; +uniform bool Convert_709to601; +uniform bool Convert_601to709; -uniform float speed< - string label = "Speed"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.1; -> = 1.0; -uniform float min_growth_pixels< - string label = "min growth pixels"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1000.0; - float step = 0.1; -> = 0.0; -uniform float max_growth_pixels< - string label = "max growth pixels"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1000.0; - float step = 0.1; -> = 200.0; sampler_state textureSampler { Filter = Linear; - AddressU = Border; - AddressV = Border; - BorderColor = 00000000; + AddressU = Clamp; + AddressV = Clamp; }; -struct VertData { +struct VertDataIn { float4 pos : POSITION; float2 uv : TEXCOORD0; }; -VertData mainTransform(VertData v_in) -{ - VertData vert_out; +struct VertDataOut { + float4 pos : POSITION; + float2 uv : TEXCOORD0; + float2 uv2 : TEXCOORD1; +}; - float3 pos = v_in.pos.xyz; - float3 direction_from_center = float3((v_in.uv.x - 0.5) * uv_pixel_interval.y / uv_pixel_interval.x, v_in.uv.y - 0.5, 0); - float3 min_pos = pos + direction_from_center * min_growth_pixels / 2; - float3 max_pos = pos + direction_from_center * max_growth_pixels / 2; +float dot(float3 a,float3 b){ + return a.x*b.x+a.y*b.y+a.z*b.z; +} - float t = (1 + sin(elapsed_time * speed)) / 2; - float3 current_pos = min_pos * (1 - t) + max_pos * t; +//BT.601 to BT.709 +// Correct video colorspace BT.601 [SD] to BT.709 [HD] for HD video input +// Use this shader only if BT.709 [HD] encoded video is incorrectly matrixed to full range RGB with the BT.601 [SD] colorspace. +float4 Convert601to709(float4 rgba) +{ + float3 s1 = rgba.rgb; + s1 = s1.rrr * float3(0.299, -0.1495 / 0.886, 0.5) + s1.ggg * float3(0.587, -0.2935 / 0.886, -0.2935 / 0.701) + s1.bbb * float3(0.114, 0.5, -0.057 / 0.701); // RGB to Y''CbCr, BT.601 [SD] colorspace + return (s1.rrr + float3(0, -0.1674679 / 0.894, 1.8556) * s1.ggg + float3(1.5748, -0.4185031 / 0.894, 0) * s1.bbb).rgbb; // Y''CbCr to RGB output, BT.709 [HD] colorspace +} - vert_out.pos = mul(float4(current_pos, 1.0), ViewProj); - vert_out.uv = v_in.uv * uv_scale + uv_offset; +//BT.709 to BT.601 +float4 Convert709to601(float4 rgba) +{ + float3 s1 = rgba.rgb; + s1 = float3(dot(float3(.2126, .7152, .0722), s1), dot(float3(-.1063 / .9278, -.3576 / .9278, .5), s1), dot(float3(.5, -.3576 / .7874, -.0361 / .7874), s1)); + return float3(s1.x + 1.402*s1.z, dot(s1, float3(1, -.202008 / .587, -.419198 / .587)), s1.x + 1.772*s1.y).rgbb; +} + +VertDataOut VSDefault(VertDataIn v_in) +{ + VertDataOut vert_out; + vert_out.pos = mul(float4(v_in.pos.x, v_in.pos.y, v_in.pos.z, 1.0), ViewProj); + vert_out.uv = v_in.uv; + vert_out.uv2 = v_in.uv * uv_scale + uv_offset; return vert_out; } -float4 mainImage(VertData v_in) : TARGET +float4 PSColorMaskRGBA(VertDataOut v_in) : TARGET { - return image.Sample(textureSampler, v_in.uv); + float Tolerance = opacity * 0.01; + float4 rgba = image.Sample(textureSampler, v_in.uv); + + float4 targetRGB = target.Sample(textureSampler, v_in.uv2) * color; + if (invert){ + targetRGB.rgb = 1.0 - targetRGB.rgb; + } + if (Convert_709to601) + { + rgba.rgb = Convert709to601(rgba).rgb; + targetRGB.rgb = Convert709to601(targetRGB).rgb; + } + + if (Convert_601to709) + { + rgba.rgb = Convert601to709(rgba).rgb; + targetRGB.rbg = Convert601to709(targetRGB).rgb; + } + + float4 shadowRGB = targetRGB * targetRGB; + + if ((abs(targetRGB.r - rgba.r) <= Tolerance && + abs(targetRGB.g - rgba.g) <= Tolerance && + abs(targetRGB.b - rgba.b) <= Tolerance) + || (abs(shadowRGB.r - rgba.r) <= Tolerance && + abs(shadowRGB.g - rgba.g) <= Tolerance && + abs(shadowRGB.b - rgba.b) <= Tolerance)) + { + rgba.rgba = float4(0,0,0,0); + } + return rgba; } technique Draw { pass { - vertex_shader = mainTransform(v_in); - pixel_shader = mainImage(v_in); + vertex_shader = VSDefault(v_in); + pixel_shader = PSColorMaskRGBA(v_in); } } + + ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -31053,65 +21879,47 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSRainbowShader { +function Get-OBSBlendOpacityShader { -[Alias('Set-OBSRainbowShader','Add-OBSRainbowShader')] +[Alias('Set-OBSBlendOpacityShader','Add-OBSBlendOpacityShader')] param( -# Set the Saturation of OBSRainbowShader -[ComponentModel.DefaultBindingProperty('Saturation')] -[Single] -$Saturation, -# Set the Luminosity of OBSRainbowShader -[ComponentModel.DefaultBindingProperty('Luminosity')] -[Single] -$Luminosity, -# Set the Spread of OBSRainbowShader -[ComponentModel.DefaultBindingProperty('Spread')] -[Single] -$Spread, -# Set the Speed of OBSRainbowShader -[ComponentModel.DefaultBindingProperty('Speed')] -[Single] -$Speed, -# Set the Alpha_Percentage of OBSRainbowShader -[Alias('Alpha_Percentage')] -[ComponentModel.DefaultBindingProperty('Alpha_Percentage')] -[Single] -$AlphaPercentage, -# Set the Vertical of OBSRainbowShader +# Set the Vertical of OBSBlendOpacityShader [ComponentModel.DefaultBindingProperty('Vertical')] [Management.Automation.SwitchParameter] $Vertical, -# Set the Rotational of OBSRainbowShader +# Set the Rotational of OBSBlendOpacityShader [ComponentModel.DefaultBindingProperty('Rotational')] [Management.Automation.SwitchParameter] $Rotational, -# Set the Rotation_Offset of OBSRainbowShader +# Set the Rotation_Offset of OBSBlendOpacityShader [Alias('Rotation_Offset')] [ComponentModel.DefaultBindingProperty('Rotation_Offset')] [Single] $RotationOffset, -# Set the Apply_To_Image of OBSRainbowShader -[Alias('Apply_To_Image')] -[ComponentModel.DefaultBindingProperty('Apply_To_Image')] -[Management.Automation.SwitchParameter] -$ApplyToImage, -# Set the Replace_Image_Color of OBSRainbowShader -[Alias('Replace_Image_Color')] -[ComponentModel.DefaultBindingProperty('Replace_Image_Color')] -[Management.Automation.SwitchParameter] -$ReplaceImageColor, -# Set the Apply_To_Specific_Color of OBSRainbowShader -[Alias('Apply_To_Specific_Color')] -[ComponentModel.DefaultBindingProperty('Apply_To_Specific_Color')] +# Set the Opacity_Start_Percent of OBSBlendOpacityShader +[Alias('Opacity_Start_Percent')] +[ComponentModel.DefaultBindingProperty('Opacity_Start_Percent')] +[Single] +$OpacityStartPercent, +# Set the Opacity_End_Percent of OBSBlendOpacityShader +[Alias('Opacity_End_Percent')] +[ComponentModel.DefaultBindingProperty('Opacity_End_Percent')] +[Single] +$OpacityEndPercent, +# Set the Spread of OBSBlendOpacityShader +[ComponentModel.DefaultBindingProperty('Spread')] +[Single] +$Spread, +# Set the Speed of OBSBlendOpacityShader +[ComponentModel.DefaultBindingProperty('Speed')] +[Single] +$Speed, +# Set the Apply_To_Alpha_Layer of OBSBlendOpacityShader +[Alias('Apply_To_Alpha_Layer')] +[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] [Management.Automation.SwitchParameter] -$ApplyToSpecificColor, -# Set the Color_To_Replace of OBSRainbowShader -[Alias('Color_To_Replace')] -[ComponentModel.DefaultBindingProperty('Color_To_Replace')] -[String] -$ColorToReplace, -# Set the Notes of OBSRainbowShader +$ApplyToAlphaLayer, +# Set the Notes of OBSBlendOpacityShader [ComponentModel.DefaultBindingProperty('Notes')] [String] $Notes, @@ -31145,150 +21953,92 @@ $UseShaderTime process { -$shaderName = 'rainbow' -$ShaderNoun = 'OBSRainbowShader' +$shaderName = 'blend_opacity' +$ShaderNoun = 'OBSBlendOpacityShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Rainbow shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 -// https://github.com/Oncorporation/obs-shaderfilter -//Converted to OpenGL by Exeldro February 13, 2022 -uniform float Saturation< - string label = "Saturation"; +// opacity blend shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 +//https://github.com/Oncorporation/obs-shaderfilter +//Converted to OpenGL by Exeldro February 14, 2022 +uniform bool Vertical; +uniform bool Rotational; +uniform float Rotation_Offset< + string label = "Rotation Offset"; string widget_type = "slider"; float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.8; // -uniform float Luminosity< - string label = "Luminosity"; + float maximum = 6.28318531; + float step = 0.01; +> = 0.0; +uniform float Opacity_Start_Percent< + string label = "Opacity Start Percent"; string widget_type = "slider"; float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.5; // + float maximum = 100.0; + float step = 1.0; +> = 0.0; +uniform float Opacity_End_Percent< + string label = "Opacity End Percent"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 1.0; +> = 100.0; uniform float Spread< string label = "Spread"; string widget_type = "slider"; - float minimum = 0.5; + float minimum = 0.25; float maximum = 10.0; float step = 0.01; -> = 3.8; // +> = 0.5; uniform float Speed< string label = "Speed"; string widget_type = "slider"; float minimum = -10.0; float maximum = 10.0; float step = 0.01; -> = 2.4; // -uniform float Alpha_Percentage< - string label = "Rotation Offset"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.1; -> = 100.0; // -uniform bool Vertical; -uniform bool Rotational; -uniform float Rotation_Offset< - string label = "Rotation Offset"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 6.28318531; - float step = 0.001; -> = 0.0; // -uniform bool Apply_To_Image; -uniform bool Replace_Image_Color; -uniform bool Apply_To_Specific_Color; -uniform float4 Color_To_Replace; +> = 0.0; +uniform bool Apply_To_Alpha_Layer = true; uniform string Notes< string widget_type = "info"; -> = "Spread is wideness of color and is limited between .25 and 10. Edit at your own risk"; - -float hueToRGB(float v1, float v2, float vH) { - vH = frac(vH); - if ((6.0 * vH) < 1.0) return (v1 + (v2 - v1) * 6.0 * vH); - if ((2.0 * vH) < 1.0) return (v2); - if ((3.0 * vH) < 2.0) return (v1 + (v2 - v1) * ((0.6666666666666667) - vH) * 6.0); - return clamp(v1, 0.0, 1.0); -} - -float4 HSLtoRGB(float4 hsl) { - float4 rgb = float4(0.0, 0.0, 0.0, hsl.w); - float v1 = 0.0; - float v2 = 0.0; - - if (hsl.y == 0) { - rgb.xyz = hsl.zzz; - } - else { - - if (hsl.z < 0.5) { - v2 = hsl.z * (1 + hsl.y); - } - else { - v2 = (hsl.z + hsl.y) - (hsl.y * hsl.z); - } - - v1 = 2.0 * hsl.z - v2; - - rgb.x = hueToRGB(v1, v2, hsl.x + (0.3333333333333333)); - rgb.y = hueToRGB(v1, v2, hsl.x); - rgb.z = hueToRGB(v1, v2, hsl.x - (0.3333333333333333)); - - } - - return rgb; -} +> = "Spread is wideness of opacity blend and is limited between .25 and 10. Edit at your own risk. Invert Start and End to Reverse effect."; float4 mainImage(VertData v_in) : TARGET { - float2 lPos = (v_in.uv * uv_scale + uv_offset)/ clamp(Spread, 0.25, 10.0); - float time = (elapsed_time * clamp(Speed, -5.0, 5.0)) / clamp(Spread, 0.25, 10.0); + float4 point_color = image.Sample(textureSampler, v_in.uv); + float luminance = 0.299*point_color.r+0.587*point_color.g+0.114*point_color.b; + float4 gray = float4(luminance,luminance,luminance, 1); - //set colors and direction - float hue = (-1 * lPos.x) / 2.0; + float2 lPos = (v_in.uv * uv_scale + uv_offset) / clamp(Spread, 0.25, 10.0); + float time = (elapsed_time * clamp(Speed, -5.0, 5.0)) / clamp(Spread, 0.25, 10.0); + float dist = distance(v_in.uv , (float2(0.99, 0.99) * uv_scale + uv_offset)); - if (Rotational && (Vertical == false)) + if (point_color.a > 0.0 || Apply_To_Alpha_Layer == false) { - float timeWithOffset = time + Rotation_Offset; - float sine = sin(timeWithOffset); - float cosine = cos(timeWithOffset); - hue = (lPos.x * cosine + lPos.y * sine) * 0.5; - } + //set opacity and direction + float opacity = (-1 * lPos.x) * 0.5; - if (Vertical && (Rotational == false)) - { - hue = (-1 * lPos.y) * 0.5; - } + if (Rotational && (Vertical == false)) + { + float timeWithOffset = time + Rotation_Offset; + float sine = sin(timeWithOffset); + float cosine = cos(timeWithOffset); + opacity = (lPos.x * cosine + lPos.y * sine) * 0.5; + } - hue += time; - hue = frac(hue); - float4 hsl = float4(hue, clamp(Saturation, 0.0, 1.0), clamp(Luminosity, 0.0, 1.0), 1.0); - float4 rgba = HSLtoRGB(hsl); - - float4 color; - float4 original_color; - if (Apply_To_Image) - { - color = image.Sample(textureSampler, v_in.uv); - original_color = color; - float luma = 0.30*color.r+0.59*color.g+0.11*color.b+1.0*color.a; - float4 luma_color = float4(luma, luma, luma, luma); - if (Replace_Image_Color) - color = luma_color; - rgba = lerp(original_color, rgba * color,clamp(Alpha_Percentage *.01 ,0,1.0)); - + if (Vertical && (Rotational == false)) + { + opacity = (-1 * lPos.y) * 0.5; + } + + opacity += time; + opacity = frac(opacity); + point_color.a = lerp(Opacity_Start_Percent * 0.01, Opacity_End_Percent * 0.01, clamp(opacity, 0.0, 1.0)); } - if (Apply_To_Specific_Color) - { - color = image.Sample(textureSampler, v_in.uv); - original_color = color; - color = (distance(color.rgb, Color_To_Replace.rgb) <= 0.075) ? rgba : color; - rgba = lerp(original_color, color, clamp(Alpha_Percentage * .01, 0, 1.0)); - } - return rgba; + return point_color; } + + ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -31386,36 +22136,14 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSRainWindowShader { +function Get-OBSBlinkShader { -[Alias('Set-OBSRainWindowShader','Add-OBSRainWindowShader')] +[Alias('Set-OBSBlinkShader','Add-OBSBlinkShader')] param( -# Set the size of OBSRainWindowShader -[ComponentModel.DefaultBindingProperty('size')] -[Single] -$Size, -# Set the blurSize of OBSRainWindowShader -[ComponentModel.DefaultBindingProperty('blurSize')] -[Single] -$BlurSize, -# Set the trail_strength of OBSRainWindowShader -[Alias('trail_strength')] -[ComponentModel.DefaultBindingProperty('trail_strength')] -[Single] -$TrailStrength, -# Set the trail_color of OBSRainWindowShader -[Alias('trail_color')] -[ComponentModel.DefaultBindingProperty('trail_color')] -[Single] -$TrailColor, -# Set the speed of OBSRainWindowShader +# Set the speed of OBSBlinkShader [ComponentModel.DefaultBindingProperty('speed')] [Single] $Speed, -# Set the debug of OBSRainWindowShader -[ComponentModel.DefaultBindingProperty('debug')] -[Management.Automation.SwitchParameter] -$DebugShader, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -31446,247 +22174,25 @@ $UseShaderTime process { -$shaderName = 'rain-window' -$ShaderNoun = 'OBSRainWindowShader' +$shaderName = 'blink' +$ShaderNoun = 'OBSBlinkShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// https://www.shadertoy.com/view/slfSzS adopted for OBS by Exeldro -// shader derived from Heartfelt - by Martijn Steinrucken aka BigWings - 2017 -// https://www.shadertoy.com/view/ltffzl -// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. - -uniform float size< - string label = "Rain Drop Size"; - string widget_type = "slider"; - float minimum = 0.001; - float maximum = 0.5; - float step = 0.01; -> = 0.2; -uniform float blurSize< - string label = "Blur Radius"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 32.0; // BLUR SIZE (Radius) -uniform float trail_strength< - string label = "Trail Strength"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 100.0; -uniform float trail_color< - string label = "Trail Color"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 40.0; uniform float speed< string label = "Speed"; string widget_type = "slider"; float minimum = 0.0; - float maximum = 200.0; + float maximum = 100.0; float step = 0.01; -> = 100.0; -uniform bool debug = false; - - -float fract(float v){ - return v - floor(v); -} - -float2 fract2(float2 v){ - return float2(v.x - floor(v.x), v.y - floor(v.y)); -} - -float3 fract3(float3 v){ - return float3(v.x - floor(v.x), v.y - floor(v.y), v.z - floor(v.z)); -} - -float3 fract4(float4 v){ - return float4(v.x - floor(v.x), v.y - floor(v.y), v.z - floor(v.z), v.w - floor(v.w)); -} - - -float3 N13(float p) { - // from DAVE HOSKINS - float3 p3 = fract3(float3(p, p, p) * float3(.1031,.11369,.13787)); - p3 += dot(p3, p3.yzx + 19.19); - return fract3(float3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x)); -} - -float4 N14(float t) { - return fract4(sin(t*float4(123., 1024., 1456., 264.))*float4(6547., 345., 8799., 1564.)); -} -float N(float t) { - return fract(sin(t*12345.564)*7658.76); -} - -float Saw(float b, float t) { - return smoothstep(0., b, t)*smoothstep(1., b, t); -} - -float2 Drops(float2 uv, float t) { - - float2 UV = uv; - - // DEFINE GRID - uv.y += t*0.8; - float2 a = float2(6., 1.); - float2 grid = a*2.; - float2 id = floor(uv*grid); - - // RANDOM SHIFT Y - float colShift = N(id.x); - uv.y += colShift; - - // DEFINE SPACES - id = floor(uv*grid); - float3 n = N13(id.x*35.2+id.y*2376.1); - float2 st = fract2(uv*grid)-float2(.5, 0); - - // POSITION DROPS - //clamp(2*x,0,2)+clamp(1-x*.5, -1.5, .5)+1.5-2 - float x = n.x-.5; - - float y = UV.y*20.; - - float distort = sin(y+sin(y)); - x += distort*(.5-abs(x))*(n.z-.5); - x *= .7; - float ti = fract(t+n.z); - y = (Saw(.85, ti)-.5)*.9+.5; - float2 p = float2(x, y); - - // DROPS - float d = length((st-p)*a.yx); - - float dSize = size; - - float Drop = smoothstep(dSize, .0, d); - - - float r = sqrt(smoothstep(1., y, st.y)); - float cd = abs(st.x-x); - - // TRAILS - float trail = smoothstep((dSize*.5+.03)*r, (dSize*.5-.05)*r, cd); - float trailFront = smoothstep(-.02, .02, st.y-y); - trail *= trailFront; - - - // DROPLETS - y = UV.y; - y += N(id.x); - float trail2 = smoothstep(dSize*r, .0, cd); - float droplets = max(0., (sin(y*(1.-y)*120.)-st.y))*trail2*trailFront*n.z; - y = fract(y*10.)+(st.y-.5); - float dd = length(st-float2(x, y)); - droplets = smoothstep(dSize*N(id.x), 0., dd); - float m = Drop+droplets*r*trailFront; - if(debug){ - m += st.x>a.y*.45 || st.y>a.x*.165 ? 1.2 : 0.; //DEBUG SPACES - } - - - return float2(m, trail); -} - -float StaticDrops(float2 uv, float t) { - uv *= 30.; - - float2 id = floor(uv); - uv = fract2(uv)-.5; - float3 n = N13(id.x*107.45+id.y*3543.654); - float2 p = (n.xy-.5)*0.5; - float d = length(uv-p); - - float fade = Saw(.025, fract(t+n.z)); - float c = smoothstep(size, 0., d)*fract(n.z*10.)*fade; - - return c; -} - -float2 Rain(float2 uv, float t) { - //float s = StaticDrops(uv, t); - float2 r1 = Drops(uv, t); - float2 r2 = Drops(uv*1.8, t); - float c; - if(debug){ - c = r1.x; - }else{ - c = r1.x+r2.x;//s+r1.x+r2.x; - } - - c = smoothstep(.3, 1., c); - - if(debug){ - return float2(c, r1.y); - }else{ - return float2(c, max(r1.y, r2.y)); - } -} +> = 0.5; float4 mainImage(VertData v_in) : TARGET { - float2 uv = v_in.uv;//(fragCoord.xy-.5*iResolution.xy) / iResolution.y; - uv.y = 1.0 - uv.y; - uv = uv * uv_scale; - float2 UV = v_in.uv; - float T = elapsed_time * speed / 100.0; - - float t = T*.2; - - UV = (UV-.5)*(.9)+.5; - - float2 c = Rain(uv, t); - - float2 e = float2(.001, 0.); //pixel offset - float cx = Rain(uv+e, t).x; - float cy = Rain(uv+e.yx, t).x; - float2 n = float2(cx-c.x, cy-c.x); //normals - - // BLUR derived from existical https://www.shadertoy.com/view/Xltfzj - float Pi = 6.28318530718; // Pi*2 - - // GAUSSIAN BLUR SETTINGS {{{ - float Directions = 32.0; // BLUR DIRECTIONS (Default 16.0 - More is better but slower) - float Quality = 8.0; // BLUR QUALITY (Default 4.0 - More is better but slower) - // GAUSSIAN BLUR SETTINGS }}} - float2 Radius = blurSize/uv_size; - float3 col = image.Sample(textureSampler, UV).rgb; - - if(blurSize > 0.0){ - // Blur calculations - for(float d=0.0; d; -uniform int shadow_offset_y< - string label = "shadow offset y"; +> = 5; // +uniform int Radius_Steps< + string label = "Radius Steps"; string widget_type = "slider"; - int minimum = -100; - int maximum = 100; + int minimum = 0; + int maximum = 20; int step = 1; ->; -uniform int shadow_blur_size< - string label = "shadow blur size"; +> = 9; // +uniform float ampFactor< + string label = "amp Factor"; string widget_type = "slider"; - int minimum = 1; - int maximum = 100; - int step = 1; -> = 1; - -uniform float4 shadow_color; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.01; +> = 2.0; +uniform string notes< + string widget_type = "info"; +> = "Steps limited in range from 0 to 20. Edit bloom.shader to remove limits at your own risk."; float4 mainImage(VertData v_in) : TARGET { - int shadow_blur_samples = int(pow(shadow_blur_size * 2 + 1, 2)); - - float4 color = image.Sample(textureSampler, v_in.uv); - float2 shadow_uv = float2(v_in.uv.x - uv_pixel_interval.x * int(shadow_offset_x), - v_in.uv.y - uv_pixel_interval.y * int(shadow_offset_y)); - - float start_of_overlap_x = max(0, shadow_uv.x - shadow_blur_size * uv_pixel_interval.x); - float end_of_overlap_x = min(1, shadow_uv.x + shadow_blur_size * uv_pixel_interval.x); - float x_proportion = (end_of_overlap_x - start_of_overlap_x) / (2 * shadow_blur_size * uv_pixel_interval.x); - - float start_of_overlap_y = max(0, shadow_uv.y - shadow_blur_size * uv_pixel_interval.y); - float end_of_overlap_y = min(1, shadow_uv.y + shadow_blur_size * uv_pixel_interval.y); - float y_proportion = (end_of_overlap_y - start_of_overlap_y) / (2 * shadow_blur_size * uv_pixel_interval.y); - - float4 final_shadow_color = float4(shadow_color.r, shadow_color.g, shadow_color.b, shadow_color.a * x_proportion * y_proportion); - - return final_shadow_color * (1-color.a) + color; -} + int radiusSteps = clamp(Radius_Steps, 0, 20); + int angleSteps = clamp(Angle_Steps, 1, 20); + float PI = 3.1415926535897932384626433832795;//acos(-1); + float minRadius = (0.0 * uv_pixel_interval.y); + float maxRadius = (10.0 * uv_pixel_interval.y); -' -} -$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 - } + float4 c0 = image.Sample(textureSampler, v_in.uv); + float4 outputPixel = c0; + float4 accumulatedColor = float4(0,0,0,0); + + int totalSteps = radiusSteps * angleSteps; + float angleDelta = (2.0 * PI) / float(angleSteps); + float radiusDelta = (maxRadius - minRadius) / float(radiusSteps); + + for (int radiusStep = 0; radiusStep < radiusSteps; radiusStep++) { + float radius = minRadius + float(radiusStep) * radiusDelta; + + for (float angle=0.0; angle <(2.0*PI); angle += angleDelta) { + float2 currentCoord; + + float xDiff = radius * cos(angle); + float yDiff = radius * sin(angle); + + currentCoord = v_in.uv + float2(xDiff, yDiff); + float4 currentColor =image.Sample(textureSampler, currentCoord); + float currentFraction = float(radiusSteps+1 - radiusStep) / float(radiusSteps + 1); + + accumulatedColor += currentFraction * currentColor / float(totalSteps); + + } + } + + outputPixel += accumulatedColor * ampFactor; + + return outputPixel; +} + +' +} +$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) { @@ -31985,28 +22510,14 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSReflectShader { +function Get-OBSBorderShader { -[Alias('Set-OBSReflectShader','Add-OBSReflectShader')] +[Alias('Set-OBSBorderShader','Add-OBSBorderShader')] param( -# Set the Horizontal of OBSReflectShader -[ComponentModel.DefaultBindingProperty('Horizontal')] -[Management.Automation.SwitchParameter] -$Horizontal, -# Set the Vertical of OBSReflectShader -[ComponentModel.DefaultBindingProperty('Vertical')] -[Management.Automation.SwitchParameter] -$Vertical, -# Set the center_x_percent of OBSReflectShader -[Alias('center_x_percent')] -[ComponentModel.DefaultBindingProperty('center_x_percent')] -[Int32] -$CenterXPercent, -# Set the center_y_percent of OBSReflectShader -[Alias('center_y_percent')] -[ComponentModel.DefaultBindingProperty('center_y_percent')] -[Int32] -$CenterYPercent, +# Set the borderColor of OBSBorderShader +[ComponentModel.DefaultBindingProperty('borderColor')] +[String] +$BorderColor, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -32037,63 +22548,24 @@ $UseShaderTime process { -$shaderName = 'Reflect' -$ShaderNoun = 'OBSReflectShader' +$shaderName = 'border' +$ShaderNoun = 'OBSBorderShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Simple Reflect Shader - -// Reflects horizontally and/or vertically. - -uniform bool Horizontal< - string label = "Reflect horizontally"; -> = false; -uniform bool Vertical< - string label = "Reflect vertically"; -> = true; - -uniform int center_x_percent< - string label = "center x percentage"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; -uniform int center_y_percent< - string label = "center y percentage"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; - +uniform float4 borderColor; float4 mainImage(VertData v_in) : TARGET { - float2 pos = v_in.uv; - float2 center_pos = float2(center_x_percent * .01, center_y_percent * .01); - - if (Horizontal == true) { - if (pos.x < center_pos.x) { - pos.x = center_pos.x - pos.x; - } else if (pos.x == center_pos.x) { - pos.x = pos.x; - } else { - pos.x = pos.x - center_pos.x; - } + if (v_in.uv.x < 0 || v_in.uv.x > 1 || v_in.uv.y < 0 || v_in.uv.y > 1) + { + return borderColor; } - if (Vertical == true) { - if (pos.y < center_pos.y) { - pos.y = center_pos.y - pos.y; - } else if (pos.y == center_pos.y) { - pos.y = pos.y; - } else { - pos.y = pos.y - center_pos.y; - } + else + { + return image.Sample(textureSampler, v_in.uv); } - - return image.Sample(textureSampler, pos); } + ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -32191,19 +22663,34 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSRemovePartialPixelsShader { +function Get-OBSBoxBlurShader { -[Alias('Set-OBSRemovePartialPixelsShader','Add-OBSRemovePartialPixelsShader')] +[Alias('Set-OBSBoxBlurShader','Add-OBSBoxBlurShader')] param( -# Set the minimum_alpha_percent of OBSRemovePartialPixelsShader -[Alias('minimum_alpha_percent')] -[ComponentModel.DefaultBindingProperty('minimum_alpha_percent')] +# Set the Strength of OBSBoxBlurShader +[ComponentModel.DefaultBindingProperty('Strength')] [Int32] -$MinimumAlphaPercent, -# Set the notes of OBSRemovePartialPixelsShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, +$Strength, +# Set the Mask_Left of OBSBoxBlurShader +[Alias('Mask_Left')] +[ComponentModel.DefaultBindingProperty('Mask_Left')] +[Single] +$MaskLeft, +# Set the Mask_Right of OBSBoxBlurShader +[Alias('Mask_Right')] +[ComponentModel.DefaultBindingProperty('Mask_Right')] +[Single] +$MaskRight, +# Set the Mask_Top of OBSBoxBlurShader +[Alias('Mask_Top')] +[ComponentModel.DefaultBindingProperty('Mask_Top')] +[Single] +$MaskTop, +# Set the Mask_Bottom of OBSBoxBlurShader +[Alias('Mask_Bottom')] +[ComponentModel.DefaultBindingProperty('Mask_Bottom')] +[Single] +$MaskBottom, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -32234,36 +22721,89 @@ $UseShaderTime process { -$shaderName = 'remove_partial_pixels' -$ShaderNoun = 'OBSRemovePartialPixelsShader' +$shaderName = 'box-blur' +$ShaderNoun = 'OBSBoxBlurShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Remove Partial Pixels shader by Charles Fettinger for obs-shaderfilter plugin 8/2020 -// https://github.com/Oncorporation/obs-shaderfilter -//Converted to OpenGL by Exeldro February 21, 2022 -uniform int minimum_alpha_percent< - string label = "minimum alpha percent"; +uniform int Strength< + string label = "Strength (1)"; string widget_type = "slider"; int minimum = 0; - int maximum = 100; + int maximum = 25; int step = 1; -> = 50; -uniform string notes< - string widget_type = "info"; -> = "Removes partial pixels, excellent for cleaning greenscreen. Default Minimum Alpha Percent is 50%, lowering will reveal more pixels"; +> = 1; +uniform float Mask_Left< + string label = "Mask left (1.0)"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 1.0; +uniform float Mask_Right< + string label = "Mask right (1.0)"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 1.0; +uniform float Mask_Top< + string label = "Mask top (1.0)"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 1.0; +uniform float Mask_Bottom< + string label = "Mask bottom (1.0)"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 1.0; float4 mainImage(VertData v_in) : TARGET { - float min_alpha = clamp(minimum_alpha_percent * .01, -1.0, 101.0); - float4 output_color = image.Sample(textureSampler, v_in.uv); - if (output_color.a < min_alpha) - { - return float4(0.0, 0.0, 0.0, 0.0); - } - else - { - return float4(output_color); + if(Strength <= 0) + return image.Sample(textureSampler, v_in.uv); + + if(Mask_Left + Mask_Right > 1.0){ + if(v_in.uv.x > Mask_Left || 1.0 - v_in.uv.x > Mask_Right ){ + return image.Sample(textureSampler, v_in.uv); + } + }else{ + if((v_in.uv.x > Mask_Left) && (1.0-v_in.uv.x > Mask_Right)){ + return image.Sample(textureSampler, v_in.uv); + } + } + if(Mask_Top + Mask_Bottom > 1.0){ + if(v_in.uv.y > Mask_Top || 1.0 - v_in.uv.y > Mask_Bottom){ + return image.Sample(textureSampler, v_in.uv); + } + }else { + if((v_in.uv.y > Mask_Top) && (1.0-v_in.uv.y > Mask_Bottom)){ + return image.Sample(textureSampler, v_in.uv); + } + } + float transparent = 0.0; + int count = 1; + float samples = 0.0; + float4 c = float4(0.0, 0.0, 0.0, 0.0); + float Steps = float(Strength); + + [loop] for (int i = -Strength; i <= Strength; i++) { + [loop] for (int k = -Strength; k <= Strength; k++) { + float4 sc = image.Sample(textureSampler, v_in.uv+float2(float(i), float(k))/uv_size*Steps); + transparent += sc.a; + count++; + c += sc * sc.a; + samples += sc.a; + } } + if(samples > 0.0) + c /= samples; + + c.a = transparent / float(count); + return c; } ' } @@ -32362,72 +22902,33 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSRepeatShader { +function Get-OBSBulgePinchShader { -[Alias('Set-OBSRepeatShader','Add-OBSRepeatShader')] +[Alias('Set-OBSBulgePinchShader','Add-OBSBulgePinchShader')] param( -# Set the ViewProj of OBSRepeatShader -[ComponentModel.DefaultBindingProperty('ViewProj')] -[Single[][]] -$ViewProj, -# Set the color_matrix of OBSRepeatShader -[Alias('color_matrix')] -[ComponentModel.DefaultBindingProperty('color_matrix')] -[Single[][]] -$ColorMatrix, -# Set the color_range_min of OBSRepeatShader -[Alias('color_range_min')] -[ComponentModel.DefaultBindingProperty('color_range_min')] -[Single[]] -$ColorRangeMin, -# Set the color_range_max of OBSRepeatShader -[Alias('color_range_max')] -[ComponentModel.DefaultBindingProperty('color_range_max')] -[Single[]] -$ColorRangeMax, -# Set the image of OBSRepeatShader -[ComponentModel.DefaultBindingProperty('image')] -[String] -$Image, -# Set the elapsed_time of OBSRepeatShader -[Alias('elapsed_time')] -[ComponentModel.DefaultBindingProperty('elapsed_time')] +# Set the radius of OBSBulgePinchShader +[ComponentModel.DefaultBindingProperty('radius')] [Single] -$ElapsedTime, -# Set the uv_offset of OBSRepeatShader -[Alias('uv_offset')] -[ComponentModel.DefaultBindingProperty('uv_offset')] -[Single[]] -$UvOffset, -# Set the uv_scale of OBSRepeatShader -[Alias('uv_scale')] -[ComponentModel.DefaultBindingProperty('uv_scale')] -[Single[]] -$UvScale, -# Set the uv_pixel_interval of OBSRepeatShader -[Alias('uv_pixel_interval')] -[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] -[Single[]] -$UvPixelInterval, -# Set the uv_size of OBSRepeatShader -[Alias('uv_size')] -[ComponentModel.DefaultBindingProperty('uv_size')] -[Single[]] -$UvSize, -# Set the rand_f of OBSRepeatShader -[Alias('rand_f')] -[ComponentModel.DefaultBindingProperty('rand_f')] +$Radius, +# Set the magnitude of OBSBulgePinchShader +[ComponentModel.DefaultBindingProperty('magnitude')] [Single] -$RandF, -# Set the alpha of OBSRepeatShader -[ComponentModel.DefaultBindingProperty('alpha')] +$Magnitude, +# Set the center_x of OBSBulgePinchShader +[Alias('center_x')] +[ComponentModel.DefaultBindingProperty('center_x')] [Single] -$Alpha, -# Set the copies of OBSRepeatShader -[ComponentModel.DefaultBindingProperty('copies')] +$CenterX, +# Set the center_y of OBSBulgePinchShader +[Alias('center_y')] +[ComponentModel.DefaultBindingProperty('center_y')] [Single] -$Copies, -# Set the notes of OBSRepeatShader +$CenterY, +# Set the animate of OBSBulgePinchShader +[ComponentModel.DefaultBindingProperty('animate')] +[Management.Automation.SwitchParameter] +$Animate, +# Set the notes of OBSBulgePinchShader [ComponentModel.DefaultBindingProperty('notes')] [String] $Notes, @@ -32461,79 +22962,78 @@ $UseShaderTime process { -$shaderName = 'repeat' -$ShaderNoun = 'OBSRepeatShader' +$shaderName = 'BulgePinch' +$ShaderNoun = 'OBSBulgePinchShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Repeat Effect By Charles Fettinger (https://github.com/Oncorporation) 2/2019 - -uniform float4x4 ViewProj; -uniform float4x4 color_matrix; -uniform float3 color_range_min = {0.0, 0.0, 0.0}; -uniform float3 color_range_max = {1.0, 1.0, 1.0}; -uniform texture2d image; - -uniform float elapsed_time; -uniform float2 uv_offset; -uniform float2 uv_scale; -uniform float2 uv_pixel_interval; -uniform float2 uv_size; -uniform float rand_f; - -uniform float alpha< - string label = "Alpha"; +//Created by Radegast Stravinsky for obs-shaderfilter 9/2020 +uniform float radius< + string label = "Radius"; string widget_type = "slider"; float minimum = 0.0; - float maximum = 3.0; - float step = 0.001; -> = 1.0; -uniform float copies< - string label = "Copies"; + float maximum = 2.0; + float step = 0.01; +> = 0.0; +uniform float magnitude< + string label = "Magnitude"; + string widget_type = "slider"; + float minimum = -1.3333; + float maximum = 1.3333; + float step = 0.01; +> = 0.0; +uniform float center_x< + string label = "Center x"; string widget_type = "slider"; float minimum = 0.0; - float maximum = 100.0; - float step = 0.1; -> = 4.0; + float maximum = 0.5; + float step = 0.01; +> = 0.25; +uniform float center_y< + string label = "Center y"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 0.5; + float step = 0.01; +> = 0.25; +uniform bool animate = false; + uniform string notes< string widget_type = "info"; -> = ''copies, use a number that has a square root. Alpha adjusts the alpha level of the copies (recommend 0.5-2.0 recommend)''; - -sampler_state def_sampler { - Filter = Linear; - AddressU = Repeat; - AddressV = Repeat; -}; +> = "Distorts the screen, expanding or drawing in pixels around a point." -struct VertInOut { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; -VertInOut VSDefault(VertInOut vert_in) +float4 mainImage(VertData v_in) : TARGET { - VertInOut vert_out; - vert_out.pos = mul(float4(vert_in.pos.xyz, 1 ), ViewProj); - vert_out.uv = vert_in.uv * sqrt(copies); - return vert_out; -} + float2 center = float2(center_x, center_y); + VertData v_out; + v_out.pos = v_in.pos; + float2 hw = uv_size; + float ar = 1. * hw.y/hw.x; + v_out.uv = 1. * v_in.uv - center; -float4 PSDrawBare(VertInOut vert_in) : TARGET -{ - float4 rgba = image.Sample(def_sampler, vert_in.uv); - rgba.a *= alpha; - return rgba; -} + center.x /= ar; + v_out.uv.x /= ar; -technique Draw -{ - pass - { - vertex_shader = VSDefault(vert_in); - pixel_shader = PSDrawBare(vert_in); - } -} + float dist = distance(v_out.uv, center); + if (dist < radius) + { + float anim_mag = (animate ? magnitude * sin(radians(elapsed_time * 20)) : magnitude); + float percent = dist/radius; + if(anim_mag > 0) + v_out.uv = (v_out.uv - center) * lerp(1.0, smoothstep(0.0, radius/dist, percent), anim_mag * 0.75); + else + v_out.uv = (v_out.uv-center) * lerp(1.0, pow(percent, 1.0 + anim_mag * 0.75) * radius/dist, 1.0 - percent); + v_out.uv += (2 * center); + v_out.uv.x *= ar; + return image.Sample(textureSampler, v_out.uv); + } + else + { + return image.Sample(textureSampler, v_in.uv); + } +} ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -32631,85 +23131,61 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSRepeatTextureShader { +function Get-OBSBurnShader { -[Alias('Set-OBSRepeatTextureShader','Add-OBSRepeatTextureShader')] +[Alias('Set-OBSBurnShader','Add-OBSBurnShader')] param( -# Set the ViewProj of OBSRepeatTextureShader -[ComponentModel.DefaultBindingProperty('ViewProj')] -[Single[][]] -$ViewProj, -# Set the color_matrix of OBSRepeatTextureShader -[Alias('color_matrix')] -[ComponentModel.DefaultBindingProperty('color_matrix')] -[Single[][]] -$ColorMatrix, -# Set the color_range_min of OBSRepeatTextureShader -[Alias('color_range_min')] -[ComponentModel.DefaultBindingProperty('color_range_min')] -[Single[]] -$ColorRangeMin, -# Set the color_range_max of OBSRepeatTextureShader -[Alias('color_range_max')] -[ComponentModel.DefaultBindingProperty('color_range_max')] -[Single[]] -$ColorRangeMax, -# Set the image of OBSRepeatTextureShader -[ComponentModel.DefaultBindingProperty('image')] -[String] -$Image, -# Set the tex_image of OBSRepeatTextureShader -[Alias('tex_image')] -[ComponentModel.DefaultBindingProperty('tex_image')] +# Set the Burn_Gradient of OBSBurnShader +[Alias('Burn_Gradient')] +[ComponentModel.DefaultBindingProperty('Burn_Gradient')] [String] -$TexImage, -# Set the elapsed_time of OBSRepeatTextureShader -[Alias('elapsed_time')] -[ComponentModel.DefaultBindingProperty('elapsed_time')] +$BurnGradient, +# Set the Speed of OBSBurnShader +[ComponentModel.DefaultBindingProperty('Speed')] [Single] -$ElapsedTime, -# Set the uv_offset of OBSRepeatTextureShader -[Alias('uv_offset')] -[ComponentModel.DefaultBindingProperty('uv_offset')] -[Single[]] -$UvOffset, -# Set the uv_scale of OBSRepeatTextureShader -[Alias('uv_scale')] -[ComponentModel.DefaultBindingProperty('uv_scale')] -[Single[]] -$UvScale, -# Set the uv_pixel_interval of OBSRepeatTextureShader -[Alias('uv_pixel_interval')] -[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] -[Single[]] -$UvPixelInterval, -# Set the uv_size of OBSRepeatTextureShader -[Alias('uv_size')] -[ComponentModel.DefaultBindingProperty('uv_size')] -[Single[]] -$UvSize, -# Set the rand_f of OBSRepeatTextureShader -[Alias('rand_f')] -[ComponentModel.DefaultBindingProperty('rand_f')] +$Speed, +# Set the Gradient_Adjust of OBSBurnShader +[Alias('Gradient_Adjust')] +[ComponentModel.DefaultBindingProperty('Gradient_Adjust')] [Single] -$RandF, -# Set the blend of OBSRepeatTextureShader -[ComponentModel.DefaultBindingProperty('blend')] +$GradientAdjust, +# Set the Dissolve_Value of OBSBurnShader +[Alias('Dissolve_Value')] +[ComponentModel.DefaultBindingProperty('Dissolve_Value')] [Single] -$Blend, -# Set the copies of OBSRepeatTextureShader -[ComponentModel.DefaultBindingProperty('copies')] +$DissolveValue, +# Set the Animated of OBSBurnShader +[ComponentModel.DefaultBindingProperty('Animated')] +[Management.Automation.SwitchParameter] +$Animated, +# Set the Apply_to_Channel of OBSBurnShader +[Alias('Apply_to_Channel')] +[ComponentModel.DefaultBindingProperty('Apply_to_Channel')] +[Management.Automation.SwitchParameter] +$ApplyToChannel, +# Set the Apply_Smoke of OBSBurnShader +[Alias('Apply_Smoke')] +[ComponentModel.DefaultBindingProperty('Apply_Smoke')] +[Management.Automation.SwitchParameter] +$ApplySmoke, +# Set the Smoke_Horizonal_Speed of OBSBurnShader +[Alias('Smoke_Horizonal_Speed')] +[ComponentModel.DefaultBindingProperty('Smoke_Horizonal_Speed')] [Single] -$Copies, -# Set the notes of OBSRepeatTextureShader -[ComponentModel.DefaultBindingProperty('notes')] +$SmokeHorizonalSpeed, +# Set the Smoke_Vertical_Speed of OBSBurnShader +[Alias('Smoke_Vertical_Speed')] +[ComponentModel.DefaultBindingProperty('Smoke_Vertical_Speed')] +[Single] +$SmokeVerticalSpeed, +# Set the Iterations of OBSBurnShader +[ComponentModel.DefaultBindingProperty('Iterations')] +[Int32] +$Iterations, +# Set the Notes of OBSBurnShader +[ComponentModel.DefaultBindingProperty('Notes')] [String] $Notes, -# Set the alpha_percentage of OBSRepeatTextureShader -[Alias('alpha_percentage')] -[ComponentModel.DefaultBindingProperty('alpha_percentage')] -[Single] -$AlphaPercentage, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -32740,102 +23216,169 @@ $UseShaderTime process { -$shaderName = 'repeat_texture' -$ShaderNoun = 'OBSRepeatTextureShader' +$shaderName = 'burn' +$ShaderNoun = 'OBSBurnShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Repeat Effect By Charles Fettinger (https://github.com/Oncorporation) 2/2019 +//Burn shader by Charles Fettinger (https://github.com/Oncorporation) 4/2019 +//for use with obs-shaderfilter 1.0 +//Converted to OpenGL by Exeldro February 17, 2022 +float4 mod(float4 x, float4 y) +{ + return x - y * floor(x / y); +} +float4 mod289(float4 x) +{ + return x - floor(x / 289.0) * 289.0; +} +float4 permute(float4 x) +{ + return mod289(((x * 34.0) + 1.0) * x); +} +float4 taylorInvSqrt(float4 r) +{ + return 1.79284291400159 - r * 0.85373472095314; +} +float2 fade(float2 t) { + return t * t* t* (t * (t * 6.0 - 15.0) + 10.0); +} -uniform float4x4 ViewProj; -uniform float4x4 color_matrix; -uniform float3 color_range_min = {0.0, 0.0, 0.0}; -uniform float3 color_range_max = {1.0, 1.0, 1.0}; -uniform texture2d image; -uniform texture2d tex_image; +float dot(float2 a,float2 b){ + return a.x*b.x+a.y*b.y; +} -uniform float elapsed_time; -uniform float2 uv_offset; -uniform float2 uv_scale; -uniform float2 uv_pixel_interval; -uniform float2 uv_size; -uniform float rand_f; +// Classic Perlin noise +float cnoise(float2 P) +{ + float4 Pi = floor(P.xyxy) + float4(0.0, 0.0, 1.0, 1.0); + float4 Pf = frac(P.xyxy) - float4(0.0, 0.0, 1.0, 1.0); + Pi = mod289(Pi); // To avoid truncation effects in permutation + float4 ix = Pi.xzxz; + float4 iy = Pi.yyww; + float4 fx = Pf.xzxz; + float4 fy = Pf.yyww; + float4 i = permute(permute(ix) + iy); + float4 gx = frac(i / 41.0) * 2.0 - 1.0; + float4 gy = abs(gx) - 0.5; + float4 tx = floor(gx + 0.5); + gx = gx - tx; + float2 g00 = float2(gx.x, gy.x); + float2 g10 = float2(gx.y, gy.y); + float2 g01 = float2(gx.z, gy.z); + float2 g11 = float2(gx.w, gy.w); + float4 norm = taylorInvSqrt(float4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); + g00 *= norm.x; + g01 *= norm.y; + g10 *= norm.z; + g11 *= norm.w; + float n00 = dot(g00, float2(fx.x, fy.x)); + float n10 = dot(g10, float2(fx.y, fy.y)); + float n01 = dot(g01, float2(fx.z, fy.z)); + float n11 = dot(g11, float2(fx.w, fy.w)); + float2 fade_xy = fade(Pf.xy); + float2 n_x = lerp(float2(n00, n01), float2(n10, n11), fade_xy.x); + float n_xy = lerp(n_x.x, n_x.y, fade_xy.y); + return 2.3 * n_xy; +} +// Classic Perlin noise, periodic variant +float pnoise(float2 P, float2 rep) +{ + float4 Pi = floor(P.xyxy) + float4(0.0, 0.0, 1.0, 1.0); + float4 Pf = frac(P.xyxy) - float4(0.0, 0.0, 1.0, 1.0); + Pi = mod(Pi, rep.xyxy); // To create noise with explicit period + Pi = mod289(Pi); // To avoid truncation effects in permutation + float4 ix = Pi.xzxz; + float4 iy = Pi.yyww; + float4 fx = Pf.xzxz; + float4 fy = Pf.yyww; + float4 i = permute(permute(ix) + iy); + float4 gx = frac(i / 41.0) * 2.0 - 1.0; + float4 gy = abs(gx) - 0.5; + float4 tx = floor(gx + 0.5); + gx = gx - tx; + float2 g00 = float2(gx.x, gy.x); + float2 g10 = float2(gx.y, gy.y); + float2 g01 = float2(gx.z, gy.z); + float2 g11 = float2(gx.w, gy.w); + float4 norm = taylorInvSqrt(float4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); + g00 *= norm.x; + g01 *= norm.y; + g10 *= norm.z; + g11 *= norm.w; + float n00 = dot(g00, float2(fx.x, fy.x)); + float n10 = dot(g10, float2(fx.y, fy.y)); + float n01 = dot(g01, float2(fx.z, fy.z)); + float n11 = dot(g11, float2(fx.w, fy.w)); + float2 fade_xy = fade(Pf.xy); + float2 n_x = lerp(float2(n00, n01), float2(n10, n11), fade_xy.x); + float n_xy = lerp(n_x.x, n_x.y, fade_xy.y); + return 2.3 * n_xy; +} -uniform float blend< - string label = "Blend"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 3.0; - float step = 0.001; -> = 1.0; -uniform float copies< - string label = "Copies"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.1; -> = 4.0; -uniform string notes< +uniform texture2d Burn_Gradient = "burngradient.png"; +uniform float Speed = 0.33; +uniform float Gradient_Adjust = 0.85; +uniform float Dissolve_Value = 1.43; +uniform bool Animated; +uniform bool Apply_to_Channel; +uniform bool Apply_Smoke = true; +uniform float Smoke_Horizonal_Speed = 0.3; +uniform float Smoke_Vertical_Speed = 0.17; +uniform int Iterations = 4; +uniform string Notes< string widget_type = "info"; -> = ''copies, use a number that has a square root. Blend adjusts the ratio of source and texture''; -uniform float alpha_percentage< - string label = "alpha percentage"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.1; -> = 100.0; - -sampler_state tex_sampler { - Filter = Linear; - AddressU = Repeat; - AddressV = Repeat; -}; +> = "Animate refers to the burn effect. Speed is general and is reversed with negative numbers. Gradient Adjust is the width of the burn gradient. Use the burngradient.png. Dissolve Value is important. Apply Smoke adds the scrolling smoke."; -sampler_state base_sampler { - Filter = Linear; - AddressU = Clamp; - AddressV = Clamp; -}; +float4 mainImage(VertData v_in) : TARGET +{ + float4 c = image.Sample(textureSampler, v_in.uv); + float4 smoke = float4(1.0,1.0,1.0,1.0); + float4 result = smoke; + float t = elapsed_time * Speed; + float cycle = 1 - max((sin(t) * 2) - 1, 0); //create a negative cycle time as a delay + float2 dir = float2(Smoke_Horizonal_Speed, Smoke_Vertical_Speed); + //float largestDistance = sqrt(pow(uv_size.x, 2) + pow(uv_size.y, 2)); -struct VertIn { - float4 pos : POSITION; - float2 uv_0 : TEXCOORD0; - float2 uv_1 : TEXCOORD1; -}; + float perlin = 0.5; + float smoke_perlin = 0; + float scale = 1; + float w = 0.5; -struct VertOut { - float4 pos : POSITION; - float2 uv_0 : TEXCOORD0; - float2 uv_1 : TEXCOORD1; -}; + for (int i = 0; i < Iterations; i++) { + //float2 coord = v_in.uv * scale;// (v_in.uv + t * dir)* scale; + float2 coord = (v_in.uv + t * (dir * .1)) * scale; + float2 period = scale * dir; + perlin += pnoise(coord, period) * w; + if (Apply_Smoke) + smoke_perlin += cnoise((v_in.uv + t * dir) * scale) * w * .5; -VertOut VSDefault(VertIn vert_in) -{ - VertOut vert_out; - vert_out.pos = mul(float4(vert_in.pos.xyz, 1 ), ViewProj); - vert_out.uv_1 = vert_in.uv_0; - vert_out.uv_0 = vert_in.uv_0 * sqrt(copies); - return vert_out; -} + scale *= 2.0; + w *= 0.5; + } -float4 PSDrawBare(VertOut vert_in) : TARGET -{ - float alpha = clamp(alpha_percentage * 0.01 ,-1.0,2.0); - float4 tex = tex_image.Sample(tex_sampler, vert_in.uv_0); - float4 base = image.Sample(base_sampler, vert_in.uv_1); + //float toPoint = abs(length(v_in.uv - (v_in.uv * .5)) / ((1.0001 - t) * largestDistance)); + if (!Animated) + cycle = 1; + float d = clamp(((Dissolve_Value * cycle + perlin) ) - 1.0, -.01, 0.99); + float overOne = saturate(d * Gradient_Adjust); + float4 burn = Burn_Gradient.Sample(textureSampler, float2(overOne, 0.5)); - return (1 - alpha) * base + (alpha) * tex; -} + if (Apply_to_Channel) { + result = c * burn; + } + else { + result = float4(perlin, perlin, perlin, 1.0) * burn; + } -technique Draw -{ - pass - { - vertex_shader = VSDefault(vert_in); - pixel_shader = PSDrawBare(vert_in); + if (smoke_perlin > 0) { + smoke *= smoke_perlin; + if (result.a <= 0.04) + result = float4(smoke.rgb, smoke_perlin); + result += smoke; } -} + return result; +} ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -32933,26 +23476,67 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSRGBAPercentShader { +function Get-OBSCartoonShader { -[Alias('Set-OBSRGBAPercentShader','Add-OBSRGBAPercentShader')] +[Alias('Set-OBSCartoonShader','Add-OBSCartoonShader')] param( -# Set the RedPercent of OBSRGBAPercentShader -[ComponentModel.DefaultBindingProperty('RedPercent')] -[Single] -$RedPercent, -# Set the GreenPercent of OBSRGBAPercentShader -[ComponentModel.DefaultBindingProperty('GreenPercent')] -[Single] -$GreenPercent, -# Set the BluePercent of OBSRGBAPercentShader -[ComponentModel.DefaultBindingProperty('BluePercent')] +# Set the ViewProj of OBSCartoonShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the image of OBSCartoonShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the elapsed_time of OBSCartoonShader +[Alias('elapsed_time')] +[ComponentModel.DefaultBindingProperty('elapsed_time')] [Single] -$BluePercent, -# Set the AlphaPercent of OBSRGBAPercentShader -[ComponentModel.DefaultBindingProperty('AlphaPercent')] +$ElapsedTime, +# Set the uv_offset of OBSCartoonShader +[Alias('uv_offset')] +[ComponentModel.DefaultBindingProperty('uv_offset')] +[Single[]] +$UvOffset, +# Set the uv_scale of OBSCartoonShader +[Alias('uv_scale')] +[ComponentModel.DefaultBindingProperty('uv_scale')] +[Single[]] +$UvScale, +# Set the uv_pixel_interval of OBSCartoonShader +[Alias('uv_pixel_interval')] +[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +[Single[]] +$UvPixelInterval, +# Set the rand_f of OBSCartoonShader +[Alias('rand_f')] +[ComponentModel.DefaultBindingProperty('rand_f')] [Single] -$AlphaPercent, +$RandF, +# Set the uv_size of OBSCartoonShader +[Alias('uv_size')] +[ComponentModel.DefaultBindingProperty('uv_size')] +[Single[]] +$UvSize, +# Set the notes of OBSCartoonShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# Set the hue_steps of OBSCartoonShader +[Alias('hue_steps')] +[ComponentModel.DefaultBindingProperty('hue_steps')] +[Int32] +$HueSteps, +# Set the value_steps of OBSCartoonShader +[Alias('value_steps')] +[ComponentModel.DefaultBindingProperty('value_steps')] +[Int32] +$ValueSteps, +# Set the Apply_To_Alpha_Layer of OBSCartoonShader +[Alias('Apply_To_Alpha_Layer')] +[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] +[Management.Automation.SwitchParameter] +$ApplyToAlphaLayer, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -32983,58 +23567,104 @@ $UseShaderTime process { -$shaderName = 'RGBA_Percent' -$ShaderNoun = 'OBSRGBAPercentShader' +$shaderName = 'cartoon' +$ShaderNoun = 'OBSCartoonShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Simple RGBA Percent Shader -// Allows Red, Green, or Blue to be adjusted between 0-200% -// Allows Alpha to be adjusted between 0/100% -uniform float RedPercent< - string label = "Red percentage"; - string widget_type = "slider"; - float minimum = 0; - float maximum = 200; - float step = 1.0; -> = 100; +//Darklink''s shader modified to by Charles ''Surn'' Fettinger for use with obs-shaderfilter 3/2019 +uniform float4x4 ViewProj; +uniform texture2d image; -uniform float GreenPercent< - string label = "Green percentage"; - string widget_type = "slider"; - float minimum = 0; - float maximum = 200; - float step = 1.0; -> = 100; +uniform float elapsed_time; +uniform float2 uv_offset; +uniform float2 uv_scale; +uniform float2 uv_pixel_interval; +uniform float rand_f; +uniform float2 uv_size; +uniform string notes = "5/2 seems reasonable"; -uniform float BluePercent< - string label = "Blue percentage"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 200; - float step = 1.0; -> = 100.0; +uniform int hue_steps = 5; +uniform int value_steps = 2; +uniform bool Apply_To_Alpha_Layer = true; +sampler_state textureSampler { + Filter = Linear; + AddressU = Clamp; + AddressV = Clamp; +}; -uniform float AlphaPercent< - string label = "Alpha percentage"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 1.0; -> = 100.0; +struct VertDataIn { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; -float4 mainImage(VertData v_in) : TARGET +struct VertDataOut { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; + +VertDataOut VSDefault(VertDataIn v_in) { - float2 pos = v_in.uv; - - float4 imageColors = image.Sample(textureSampler, v_in.uv); - float4 adjustedColor = float4( - imageColors.r * (RedPercent * 0.01), - imageColors.g * (GreenPercent * 0.01), - imageColors.b * (BluePercent * 0.01), - imageColors.a * (AlphaPercent * 0.01) - ); - return adjustedColor; + VertDataOut vert_out; + vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); + vert_out.uv = v_in.uv; + return vert_out; +} + +float3 rgb2hsv(float3 c) +{ + float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g)); + float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +float3 hsv2rgb(float3 c) +{ + float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y); +} + +float fit(float v, int factor) +{ + return round(v * factor) / factor; +} + +float hue_wrap(float h) +{ + return fmod(h + 1, 2) - 1; + if(h > 1) + return h - 2; + if(h < -1) + return h + 2; + return h; +} + +float4 PassThrough(VertDataOut v_in) : TARGET +{ + float4 rgba = image.Sample(textureSampler, v_in.uv); + if (rgba.a > 0.0 || Apply_To_Alpha_Layer == false) + { + float3 hsv = rgb2hsv(rgba.rgb); + hsv = float3(fit(hsv.x, hue_steps), hsv.y, fit(hsv.z, value_steps)); + //hsv = float3(hue_wrap(hsv.x + 0.5), 1, hsv.z); + rgba = float4(hsv2rgb(hsv), rgba.a); + //return float4(fit(rgba.r), fit(rgba.g), fit(rgba.b), rgba.a); + } + return rgba; +} + +technique Draw +{ + pass + { + vertex_shader = VSDefault(v_in); + pixel_shader = PassThrough(v_in); + } } ' @@ -33134,54 +23764,28 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSRgbColorWheelShader { +function Get-OBSCellShadedShader { -[Alias('Set-OBSRgbColorWheelShader','Add-OBSRgbColorWheelShader')] +[Alias('Set-OBSCellShadedShader','Add-OBSCellShadedShader')] param( -# Set the speed of OBSRgbColorWheelShader -[ComponentModel.DefaultBindingProperty('speed')] -[Single] -$Speed, -# Set the color_depth of OBSRgbColorWheelShader -[Alias('color_depth')] -[ComponentModel.DefaultBindingProperty('color_depth')] -[Single] -$ColorDepth, -# Set the Apply_To_Image of OBSRgbColorWheelShader -[Alias('Apply_To_Image')] -[ComponentModel.DefaultBindingProperty('Apply_To_Image')] -[Management.Automation.SwitchParameter] -$ApplyToImage, -# Set the Replace_Image_Color of OBSRgbColorWheelShader -[Alias('Replace_Image_Color')] -[ComponentModel.DefaultBindingProperty('Replace_Image_Color')] -[Management.Automation.SwitchParameter] -$ReplaceImageColor, -# Set the Apply_To_Specific_Color of OBSRgbColorWheelShader -[Alias('Apply_To_Specific_Color')] -[ComponentModel.DefaultBindingProperty('Apply_To_Specific_Color')] -[Management.Automation.SwitchParameter] -$ApplyToSpecificColor, -# Set the Color_To_Replace of OBSRgbColorWheelShader -[Alias('Color_To_Replace')] -[ComponentModel.DefaultBindingProperty('Color_To_Replace')] -[String] -$ColorToReplace, -# Set the Alpha_Percentage of OBSRgbColorWheelShader -[Alias('Alpha_Percentage')] -[ComponentModel.DefaultBindingProperty('Alpha_Percentage')] -[Single] -$AlphaPercentage, -# Set the center_width_percentage of OBSRgbColorWheelShader -[Alias('center_width_percentage')] -[ComponentModel.DefaultBindingProperty('center_width_percentage')] +# Set the Angle_Steps of OBSCellShadedShader +[Alias('Angle_Steps')] +[ComponentModel.DefaultBindingProperty('Angle_Steps')] [Int32] -$CenterWidthPercentage, -# Set the center_height_percentage of OBSRgbColorWheelShader -[Alias('center_height_percentage')] -[ComponentModel.DefaultBindingProperty('center_height_percentage')] +$AngleSteps, +# Set the Radius_Steps of OBSCellShadedShader +[Alias('Radius_Steps')] +[ComponentModel.DefaultBindingProperty('Radius_Steps')] [Int32] -$CenterHeightPercentage, +$RadiusSteps, +# Set the ampFactor of OBSCellShadedShader +[ComponentModel.DefaultBindingProperty('ampFactor')] +[Single] +$AmpFactor, +# Set the notes of OBSCellShadedShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -33212,101 +23816,76 @@ $UseShaderTime process { -$shaderName = 'rgb_color_wheel' -$ShaderNoun = 'OBSRgbColorWheelShader' +$shaderName = 'cell_shaded' +$ShaderNoun = 'OBSCellShadedShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// RGB Color Wheel shader by Charles Fettinger for obs-shaderfilter plugin 5/2020 -// https://github.com/Oncorporation/obs-shaderfilter -//Converted to OpenGl by Q-mii & Exeldro February 25, 2022 -uniform float speed< - string label = "Speed"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 15.0; - float step = 0.1; -> = 2.0; -uniform float color_depth< - string label = "Color Depth"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.1; -> = 2.10; -uniform bool Apply_To_Image; -uniform bool Replace_Image_Color; -uniform bool Apply_To_Specific_Color; -uniform float4 Color_To_Replace; -uniform float Alpha_Percentage< - string label = "Alpha Percentage"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.1; -> = 100; // -uniform int center_width_percentage< - string label = "center width percentage"; +// Cell Shaded shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 +//https://github.com/Oncorporation/obs-shaderfilter +//Converted to OpenGL by Q-mii & Exeldro February 18, 2022 +uniform int Angle_Steps< + string label = "Angle Steps"; string widget_type = "slider"; - int minimum = 0; - int maximum = 100; + int minimum = 1; + int maximum = 20; int step = 1; -> = 50; -uniform int center_height_percentage< - string label = "center height percentage"; +> = 5; +uniform int Radius_Steps< + string label = "Radius Steps"; string widget_type = "slider"; int minimum = 0; - int maximum = 100; + int maximum = 20; int step = 1; -> = 50; +> = 9; +uniform float ampFactor< + string label = "amp Factor"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 2.0; +uniform string notes< + string widget_type = "info"; +> = "Steps limited in range from 0 to 20. Edit cell_shaded.shader to remove limits at your own risk."; -float3 hsv2rgb(float3 c) +float4 mainImage(VertData v_in) : TARGET { - float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y); -} + float radiusSteps = clamp(Radius_Steps, 0, 20); + float angleSteps = clamp(Angle_Steps, 1, 20); + float PI = 3.1415926535897932384626433832795;//acos(-1); + int totalSteps = int(radiusSteps * angleSteps); + float minRadius = (3 * uv_pixel_interval.y); + float maxRadius = (24 * uv_pixel_interval.y); -float mod(float x, float y) -{ - return x - y * floor(x / y); -} + float angleDelta = ((2 * PI) / angleSteps); + float radiusDelta = ((maxRadius - minRadius) / radiusSteps); -float4 mainImage(VertData v_in) : TARGET -{ - const float PI = 3.14159265f;//acos(-1); - float PI180th = 0.0174532925; //PI divided by 180 - float4 rgba = image.Sample(textureSampler, v_in.uv); - float2 center_pixel_coordinates = float2((center_width_percentage * 0.01), (center_height_percentage * 0.01) ); - float2 st = v_in.uv* uv_scale; - float2 toCenter = center_pixel_coordinates - st ; - float r = length(toCenter) * color_depth; - float angle = atan2(toCenter.y ,toCenter.x ); - float angleMod = (elapsed_time * mod(speed ,18)) / 18; + float4 c0 = image.Sample(textureSampler, v_in.uv); + float4 origColor = c0; + float4 accumulatedColor = float4(0,0,0,0); - rgba.rgb = hsv2rgb(float3((angle / PI*0.5) + angleMod,r,1.0)); + for (int radiusStep = 0; radiusStep < radiusSteps; radiusStep++) { + float radius = minRadius + radiusStep * radiusDelta; - float4 color; - float4 original_color; - if (Apply_To_Image) - { - color = image.Sample(textureSampler, v_in.uv); - original_color = color; - float luma = color.r * 0.299 + color.g * 0.587 + color.b * 0.114; - if (Replace_Image_Color) - color = float4(luma, luma, luma, luma); - rgba = lerp(original_color, rgba * color,clamp(Alpha_Percentage *.01 ,0,1.0)); - + for (float angle=0; angle <(2*PI); angle += angleDelta) { + float2 currentCoord; + + float xDiff = radius * cos(angle); + float yDiff = radius * sin(angle); + + currentCoord = v_in.uv + float2(xDiff, yDiff); + float4 currentColor = image.Sample(textureSampler, currentCoord); + float4 colorDiff = abs(c0 - currentColor); + float currentFraction = (radiusSteps + 1 - radiusStep) / (radiusSteps + 1); + accumulatedColor += currentFraction * colorDiff / totalSteps; + + } } - if (Apply_To_Specific_Color) - { - color = image.Sample(textureSampler, v_in.uv); - original_color = color; - color = (distance(color.rgb, Color_To_Replace.rgb) <= 0.075) ? rgba : color; - rgba = lerp(original_color, color, clamp(Alpha_Percentage * .01, 0, 1.0)); - } + accumulatedColor *= ampFactor; - return rgba; + return c0 - accumulatedColor; // Cell shaded style } + ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -33404,34 +23983,48 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSRgbSplitShader { +function Get-OBSChromaticAberrationShader { -[Alias('Set-OBSRgbSplitShader','Add-OBSRgbSplitShader')] +[Alias('Set-OBSChromaticAberrationShader','Add-OBSChromaticAberrationShader')] param( -# Set the redx of OBSRgbSplitShader -[ComponentModel.DefaultBindingProperty('redx')] -[Single] -$Redx, -# Set the redy of OBSRgbSplitShader -[ComponentModel.DefaultBindingProperty('redy')] -[Single] -$Redy, -# Set the greenx of OBSRgbSplitShader -[ComponentModel.DefaultBindingProperty('greenx')] -[Single] -$Greenx, -# Set the greeny of OBSRgbSplitShader -[ComponentModel.DefaultBindingProperty('greeny')] -[Single] -$Greeny, -# Set the bluex of OBSRgbSplitShader -[ComponentModel.DefaultBindingProperty('bluex')] +# Set the power of OBSChromaticAberrationShader +[ComponentModel.DefaultBindingProperty('power')] [Single] -$Bluex, -# Set the bluey of OBSRgbSplitShader -[ComponentModel.DefaultBindingProperty('bluey')] +$Power, +# Set the gamma of OBSChromaticAberrationShader +[ComponentModel.DefaultBindingProperty('gamma')] [Single] -$Bluey, +$Gamma, +# Set the num_iter of OBSChromaticAberrationShader +[Alias('num_iter')] +[ComponentModel.DefaultBindingProperty('num_iter')] +[Int32] +$NumIter, +# Set the distort_radial of OBSChromaticAberrationShader +[Alias('distort_radial')] +[ComponentModel.DefaultBindingProperty('distort_radial')] +[Management.Automation.SwitchParameter] +$DistortRadial, +# Set the distort_barrel of OBSChromaticAberrationShader +[Alias('distort_barrel')] +[ComponentModel.DefaultBindingProperty('distort_barrel')] +[Management.Automation.SwitchParameter] +$DistortBarrel, +# Set the offset_spectrum_ycgco of OBSChromaticAberrationShader +[Alias('offset_spectrum_ycgco')] +[ComponentModel.DefaultBindingProperty('offset_spectrum_ycgco')] +[Management.Automation.SwitchParameter] +$OffsetSpectrumYcgco, +# Set the offset_spectrum_yuv of OBSChromaticAberrationShader +[Alias('offset_spectrum_yuv')] +[ComponentModel.DefaultBindingProperty('offset_spectrum_yuv')] +[Management.Automation.SwitchParameter] +$OffsetSpectrumYuv, +# Set the use_random of OBSChromaticAberrationShader +[Alias('use_random')] +[ComponentModel.DefaultBindingProperty('use_random')] +[Management.Automation.SwitchParameter] +$UseRandom, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -33462,64 +24055,214 @@ $UseShaderTime process { -$shaderName = 'rgb_split' -$ShaderNoun = 'OBSRgbSplitShader' +$shaderName = 'chromatic-aberration' +$ShaderNoun = 'OBSChromaticAberrationShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform float redx< - string label = "Red X"; - string widget_type = "slider"; - float minimum = -10.0; - float maximum = 10.0; - float step = 0.01; -> = 2.00; -uniform float redy< - string label = "Red Y"; - string widget_type = "slider"; - float minimum = -10.0; - float maximum = 10.0; - float step = 0.01; -> = 0.00; -uniform float greenx< - string label = "Green X"; - string widget_type = "slider"; - float minimum = -10.0; - float maximum = 10.0; - float step = 0.01; -> = 0.00; -uniform float greeny< - string label = "Green Y"; +//based on https://www.shadertoy.com/view/XssGz8 +//Converted to OpenGL by Exeldro February 14, 2022 + black background removed February 23, 2022 +uniform float power< + string label = "Power"; string widget_type = "slider"; - float minimum = -10.0; - float maximum = 10.0; + float minimum = 0.0; + float maximum = 2.0; float step = 0.01; -> = 0.00; -uniform float bluex< - string label = "Blue X"; +> = 0.01; +uniform float gamma< + string label = "Gamma"; string widget_type = "slider"; - float minimum = -10.0; - float maximum = 10.0; + float minimum = 0.01; + float maximum = 3.0; float step = 0.01; -> = -2.00; -uniform float bluey< - string label = "Blue Y"; +> = 2.2; +uniform int num_iter< + string label = "Number iterations"; string widget_type = "slider"; - float minimum = -10.0; - float maximum = 10.0; - float step = 0.01; -> = 0.00; + int minimum = 3; + int maximum = 25; + int step = 1; +> = 7; +uniform bool distort_radial = false; +uniform bool distort_barrel = false; +uniform bool offset_spectrum_ycgco = false; +uniform bool offset_spectrum_yuv = false; +uniform bool use_random = true; + +float2 remap( float2 t, float2 a, float2 b ) { + return clamp( (t - a) / (b - a), 0.0, 1.0 ); +} + +float3 spectrum_offset_rgb( float t ) +{ + float t0 = 3.0 * t - 1.5; + float3 ret = clamp( float3( -t0, 1.0-abs(t0), t0), 0.0, 1.0); + return ret; +} + + +float3 lin2srgb( float3 c ) +{ + return pow( c, float3(gamma, gamma, gamma) ); +} +float3 srgb2lin( float3 c ) +{ + return pow( c, float3(1.0/gamma, 1.0/gamma, 1.0/gamma)); +} + +float3 yCgCo2rgb(float3 ycc) +{ + float R = ycc.x - ycc.y + ycc.z; + float G = ycc.x + ycc.y; + float B = ycc.x - ycc.y - ycc.z; + return float3(R,G,B); +} + +float3 spectrum_offset_ycgco( float t ) +{ + //float3 ygo = float3( 1.0, 1.5*t, 0.0 ); //green-pink + //float3 ygo = float3( 1.0, -1.5*t, 0.0 ); //green-purple + float3 ygo = float3( 1.0, 0.0, -1.25*t ); //cyan-orange + //float3 ygo = float3( 1.0, 0.0, 1.5*t ); //brownyello-blue + return yCgCo2rgb( ygo ); +} + +float3 yuv2rgb( float3 yuv ) +{ + float3 rgb; + rgb.r = yuv.x + yuv.z * 1.13983; + rgb.g = yuv.x + dot( float2(-0.39465, -0.58060), yuv.yz ); + rgb.b = yuv.x + yuv.y * 2.03211; + return rgb; +} + +float2 radialdistort(float2 coord, float2 amt) +{ + float2 cc = coord - 0.5; + return coord + 2.0 * cc * amt; +} + +float2 barrelDistortion( float2 p, float2 amt ) +{ + p = 2.0 * p - 1.0; + + /* + const float maxBarrelPower = 5.0; + //note: http://glsl.heroku.com/e#3290.7 , copied from Little Grasshopper + float theta = atan(p.y, p.x); + float2 radius = float2( length(p) ); + radius = pow(radius, 1.0 + maxBarrelPower * amt); + p.x = radius.x * cos(theta); + p.y = radius.y * sin(theta); + /*/ + // much faster version + //const float maxBarrelPower = 5.0; + //float radius = length(p); + float maxBarrelPower = sqrt(5.0); + float radius = dot(p,p); //faster but doesn''t match above accurately + p *= pow(float2(radius, radius), maxBarrelPower * amt); + /* */ + + return p * 0.5 + 0.5; +} + +float2 brownConradyDistortion(float2 uv, float dist) +{ + uv = uv * 2.0 - 1.0; + // positive values of K1 give barrel distortion, negative give pincushion + float barrelDistortion1 = 0.1 * dist; // K1 in text books + float barrelDistortion2 = -0.025 * dist; // K2 in text books + + float r2 = dot(uv,uv); + uv *= 1.0 + barrelDistortion1 * r2 + barrelDistortion2 * r2 * r2; + //uv *= 1.0 + barrelDistortion1 * r2; + + // tangential distortion (due to off center lens elements) + // is not modeled in this function, but if it was, the terms would go here + return uv * 0.5 + 0.5; +} + +float2 distort( float2 uv, float t, float2 min_distort, float2 max_distort ) +{ + float2 dist = float2(min_distort.x * (1.0-t) +max_distort.x * t, min_distort.y * (1.0-t) +max_distort.y * t); + //float2 dist = mix( min_distort, max_distort, t ); + if (distort_radial) + return radialdistort( uv, 2.0 * dist ); + + if(distort_barrel) + return barrelDistortion( uv, 1.75 * dist ); //distortion at center + return brownConradyDistortion( uv, 75.0 * dist.x ); +} + +// ==== + +float3 spectrum_offset_yuv( float t ) +{ + //float3 yuv = float3( 1.0, 3.0*t, 0.0 ); //purple-green + //float3 yuv = float3( 1.0, 0.0, 2.0*t ); //purple-green + float3 yuv = float3( 1.0, 0.0, -1.0*t ); //cyan-orange + //float3 yuv = float3( 1.0, -0.75*t, 0.0 ); //brownyello-blue + return yuv2rgb( yuv ); +} + +float3 spectrum_offset( float t ) +{ + if(offset_spectrum_ycgco) + return spectrum_offset_ycgco( t ); + if(offset_spectrum_yuv) + return spectrum_offset_yuv( t ); + return spectrum_offset_rgb( t ); + //return srgb2lin( spectrum_offset_rgb( t ) ); + //return lin2srgb( spectrum_offset_rgb( t ) ); +} float4 mainImage(VertData v_in) : TARGET { - float4 c = image.Sample(textureSampler, v_in.uv); - if(redx != 0.0 || redy != 0.0) - c.r = image.Sample(textureSampler, v_in.uv + float2(redx/100.0, redy/100.0)).r; - if(greenx != 0.0 || greeny != 0.0) - c.g = image.Sample(textureSampler, v_in.uv + float2(greenx/100.0, greeny/100.0)).g; - if(bluex != 0.0 || bluey != 0.0) - c.b = image.Sample(textureSampler, v_in.uv + float2(bluex/100.0, bluey/100.0)).b; - return c; + float2 max_distort = float2(power, power); + float2 min_distort = 0.5 * max_distort; + + float2 oversiz = distort(float2(1.0, 1.0), 1.0, min_distort, max_distort); + + float2 uv = remap( v_in.uv, 1.0-oversiz, oversiz ); + + //debug oversiz + //float2 distuv = distort( uv, 1.0, max_distort ); + //if ( abs(distuv.x-0.5)>0.5 || abs(distuv.y-0.5)>0.5) + //{ + // fragColor = float4( 1.0, 0.0, 0.0, 1.0 ); return; + //} + + + float stepsiz = 1.0 / (float(num_iter)-1.0); + float rnd = 0.0; + if(use_random) + rnd = rand_f; + + float t = rnd * stepsiz; + + float3 sumcol = float3(0.0, 0.0, 0.0); + float3 sumw = float3(0.0, 0.0, 0.0); + float colA = 0.0; + + for ( int i=0; i = 2.2; - -uniform float Green< - string label = "Green"; - string widget_type = "slider"; - float minimum = 0.1; - float maximum = 10.0; - float step = 0.01; -> = 2.2; - -uniform float Blue< - string label = "Blue"; - string widget_type = "slider"; - float minimum = 0.1; - float maximum = 10.0; - float step = 0.01; -> = 2.2; +//based on https://www.shadertoy.com/view/WsdyRN -uniform float RedVisibility< - string label = "Red Visibility"; +//Higher values = less distortion +uniform float distortion< + string label = "Distortion"; string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; + float minimum = 5.0; + float maximum = 1000.0; float step = 0.01; -> = 1.0; - -uniform float GreenVisibility< - string label = "Green Visibility"; +> = 75.; +//Higher values = tighter distortion +uniform float amplitude< + string label = "Amplitude"; string widget_type = "slider"; float minimum = 0.0; - float maximum = 1.0; + float maximum = 100.0; float step = 0.01; -> = 1.0; - -uniform float BlueVisibility< - string label = "Blue Visibility"; +> = 10.; +//Higher values = more color distortion +uniform float chroma< + string label = "Chroma"; string widget_type = "slider"; float minimum = 0.0; - float maximum = 1.0; + float maximum = 6.28318531; float step = 0.01; -> = 1.0; +> = .5; -uniform string notes< - string widget_type = "info"; -> = "Modify Colors to correct for gamma, use equal values for general correction."; +float2 zoomUv(float2 uv, float zoom) { + float2 uv1 = uv; + uv1 += .5; + uv1 += zoom/2.-1.; + uv1 /= zoom; + return uv1; +} float4 mainImage(VertData v_in) : TARGET { - float4 c = image.Sample(textureSampler, v_in.uv); - float redChannel = pow(c.r, Red) * RedVisibility; - float greenChannel = pow(c.g, Green) * GreenVisibility; - float blueChannel = pow(c.b, Blue) * BlueVisibility; + float2 uvt = v_in.uv; - return float4(redChannel, greenChannel, blueChannel, c.a); -} + float2 uvtR = uvt; + float2 uvtG = uvt; + float2 uvtB = uvt; + + //Uncomment the following line to get varying chroma distortion + //chroma = sin(elapsed_time)/2.+.5; + + uvtR += float2(sin(uvt.y*amplitude+elapsed_time)/distortion, cos(uvt.x*amplitude+elapsed_time)/distortion); + uvtG += float2(sin(uvt.y*amplitude+elapsed_time+chroma)/distortion, cos(uvt.x*amplitude+elapsed_time+chroma)/distortion); + uvtB += float2(sin(uvt.y*amplitude+elapsed_time+(chroma*2.))/distortion, cos(uvt.x*amplitude+elapsed_time+(chroma*2.))/distortion); + + float2 uvR = zoomUv(uvtR, 1.1); + float2 uvG = zoomUv(uvtG, 1.1); + float2 uvB = zoomUv(uvtB, 1.1); + + float4 colR = image.Sample(textureSampler, uvR); + float4 colG = image.Sample(textureSampler, uvG); + float4 colB = image.Sample(textureSampler, uvB); + return float4(colR.r, colG.g, colB.b, (colR.a + colG.a + colB.a) / 3.0); +} ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -33845,22 +24568,38 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSRGSSAAShader { +function Get-OBSCircleMaskFilterShader { -[Alias('Set-OBSRGSSAAShader','Add-OBSRGSSAAShader')] +[Alias('Set-OBSCircleMaskFilterShader','Add-OBSCircleMaskFilterShader')] param( -# Set the ColorSigma of OBSRGSSAAShader -[ComponentModel.DefaultBindingProperty('ColorSigma')] -[Single] -$ColorSigma, -# Set the SpatialSigma of OBSRGSSAAShader -[ComponentModel.DefaultBindingProperty('SpatialSigma')] +# Set the Radius of OBSCircleMaskFilterShader +[ComponentModel.DefaultBindingProperty('Radius')] [Single] -$SpatialSigma, -# Set the notes of OBSRGSSAAShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, +$Radius, +# Set the Circle_Offset_X of OBSCircleMaskFilterShader +[Alias('Circle_Offset_X')] +[ComponentModel.DefaultBindingProperty('Circle_Offset_X')] +[Int32] +$CircleOffsetX, +# Set the Circle_Offset_Y of OBSCircleMaskFilterShader +[Alias('Circle_Offset_Y')] +[ComponentModel.DefaultBindingProperty('Circle_Offset_Y')] +[Int32] +$CircleOffsetY, +# Set the Source_Offset_X of OBSCircleMaskFilterShader +[Alias('Source_Offset_X')] +[ComponentModel.DefaultBindingProperty('Source_Offset_X')] +[Int32] +$SourceOffsetX, +# Set the Source_Offset_Y of OBSCircleMaskFilterShader +[Alias('Source_Offset_Y')] +[ComponentModel.DefaultBindingProperty('Source_Offset_Y')] +[Int32] +$SourceOffsetY, +# Set the Antialiasing of OBSCircleMaskFilterShader +[ComponentModel.DefaultBindingProperty('Antialiasing')] +[Management.Automation.SwitchParameter] +$Antialiasing, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -33891,154 +24630,85 @@ $UseShaderTime process { -$shaderName = 'RGSSAA' -$ShaderNoun = 'OBSRGSSAAShader' +$shaderName = 'circle-mask-filter' +$ShaderNoun = 'OBSCircleMaskFilterShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// RGSSAA shader by Eliseu Amaro for obs-shaderfilter plugin 2/2024 -// https://github.com/exeldro/obs-shaderfilter/tree/master -// Using edge detection shader as a base, created by Hallatore -// https://forums.unrealengine.com/t/sharper-image-without-the-edge-artifacts/108461 +// Circle Mask Filter version 1.01, for OBS Shaderfilter +// Copyright 2022 by SkeletonBow +// Twitter: +// Twitch: +// License: GNU GPLv2 +// +// Changelog: +// 1.01 - Don''t saturate() Radius parameter to allow oversizing to cover entire input texture. +// 1.0 - Initial release -uniform float ColorSigma< - string label = "Color Sigma"; +uniform float Radius< + string label = "Radius"; string widget_type = "slider"; - float minimum = 0.1; - float maximum = 1.0; - float step = 0.1; -> = 1.0; - -uniform float SpatialSigma< - string label = "Spatial Sigma"; + float minimum = 0; + float maximum = 100.0; + float step = 0.01; +> = 50.0; +uniform int Circle_Offset_X< + string label = "Circle Offset X"; string widget_type = "slider"; - float minimum = 0.1; - float maximum = 1.0; - float step = 0.1; -> = 1.0; + int minimum = -1000; + int maximum = 1000; + int step = 1; +> = 0; +uniform int Circle_Offset_Y< + string label = "Circle Offset X"; + string widget_type = "slider"; + int minimum = -1000; + int maximum = 1000; + int step = 1; +> = 0; +uniform int Source_Offset_X< + string label = "Source Offset X"; + string widget_type = "slider"; + int minimum = -1000; + int maximum = 1000; + int step = 1; +> = 0.0; +uniform int Source_Offset_Y< + string label = "Source Offset Y"; + string widget_type = "slider"; + int minimum = -1000; + int maximum = 1000; + int step = 1; +> = 0.0; -uniform string notes< - string widget_type = "info"; -> = "Performs RGSSAA, a form of anti-aliasing. Implementation roughly follows the original with color and spatial sigma (or strengths) parameters. Useful to apply before a sharpen pass (e.g on a webcam feed)." +uniform bool Antialiasing = true; +#define Smoothness 100.00 +#define AAwidth 4 -float Luminance(float3 rgb) -{ - return rgb.r * 0.299 + rgb.g * 0.587 + rgb.b * 0.114; -} +#define uv_pi uv_pixel_interval -float4 mainImage(VertData v_in) : TARGET +float4 mainImage( VertData v_in ) : TARGET { - float3 SceneColor = image.Sample(textureSampler, v_in.uv).rgb; - float2 SceneUV = v_in.uv; - float2 TexelScale = 1.0f/uv_size; - - const float SQRT2 = 1.4142135624; - const float PI = 3.141592654; - const float angle = PI / 8.0; - const float cs = cos(angle); - const float sn = sin(angle); - - // Rotated grid samples - float3 C1 = - image.Sample(textureSampler, SceneUV + float2(cs, -sn) * TexelScale).rgb; - float3 C2 = - image.Sample(textureSampler, SceneUV + float2(-cs, -sn) * TexelScale).rgb; - float3 C3 = - image.Sample(textureSampler, SceneUV + float2(-sn, cs) * TexelScale).rgb; - float3 C4 = - image.Sample(textureSampler, SceneUV + float2(sn, cs) * TexelScale).rgb; - float3 C5 = - image.Sample(textureSampler, SceneUV + float2(cs * SQRT2, 0) * TexelScale).rgb; - float3 C6 = - image.Sample(textureSampler, SceneUV + float2(0, sn *SQRT2) * TexelScale).rgb; - float3 C7 = - image.Sample(textureSampler, SceneUV + float2(-cs * SQRT2, 0) * TexelScale).rgb; - float3 C8 = - image.Sample(textureSampler, SceneUV + float2(0, -sn *SQRT2) * TexelScale).rgb; - - // Luminance edge detection - float A0 = Luminance(SceneColor); - float CL1 = Luminance(C1); - float L1 = ((max(CL1, A0)) / (min(CL1, A0) + 0.001) - 1); - float CL2 = Luminance(C2); - float L2 = ((max(CL2, A0)) / (min(CL2, A0) + 0.001) - 1); - float CL3 = Luminance(C3); - float L3 = ((max(CL3, A0)) / (min(CL3, A0) + 0.001) - 1); - float CL4 = Luminance(C4); - float L4 = ((max(CL4, A0)) / (min(CL4, A0) + 0.001) - 1); - float CL5 = Luminance(C5); - float L5 = ((max(CL5, A0)) / (min(CL5, A0) + 0.001) - 1); - float CL6 = Luminance(C6); - float L6 = ((max(CL6, A0)) / (min(CL6, A0) + 0.001) - 1); - float CL7 = Luminance(C7); - float L7 = ((max(CL7, A0)) / (min(CL7, A0) + 0.001) - 1); - float CL8 = Luminance(C8); - float L8 = ((max(CL8, A0)) / (min(CL8, A0) + 0.001) - 1); - float NeighborDifference = max(max(max(L1, L2), max(L3, L4)), max(max(L5, L6), max(L7, L8))); - - // Calculate distance-based weights - float2 Dist1 = float2(cs, -sn); - float2 Dist2 = float2(-cs, -sn); - float2 Dist3 = float2(-sn, cs); - float2 Dist4 = float2(sn, cs); - float2 Dist5 = float2(cs * SQRT2, 0); - float2 Dist6 = float2(0, sn * SQRT2); - float2 Dist7 = float2(-cs * SQRT2, 0); - float2 Dist8 = float2(0, -sn * SQRT2); - float SW1 = exp(-dot(Dist1, Dist1) / (2.0 * SpatialSigma * SpatialSigma)); - float SW2 = exp(-dot(Dist2, Dist2) / (2.0 * SpatialSigma * SpatialSigma)); - float SW3 = exp(-dot(Dist3, Dist3) / (2.0 * SpatialSigma * SpatialSigma)); - float SW4 = exp(-dot(Dist4, Dist4) / (2.0 * SpatialSigma * SpatialSigma)); - float SW5 = exp(-dot(Dist5, Dist5) / (2.0 * SpatialSigma * SpatialSigma)); - float SW6 = exp(-dot(Dist6, Dist6) / (2.0 * SpatialSigma * SpatialSigma)); - float SW7 = exp(-dot(Dist7, Dist7) / (2.0 * SpatialSigma * SpatialSigma)); - float SW8 = exp(-dot(Dist8, Dist8) / (2.0 * SpatialSigma * SpatialSigma)); - - // Color weights - float3 ColorDiff1 = SceneColor.rgb - C1; - float3 ColorDiff2 = SceneColor.rgb - C2; - float3 ColorDiff3 = SceneColor.rgb - C3; - float3 ColorDiff4 = SceneColor.rgb - C4; - float3 ColorDiff5 = SceneColor.rgb - C5; - float3 ColorDiff6 = SceneColor.rgb - C6; - float3 ColorDiff7 = SceneColor.rgb - C7; - float3 ColorDiff8 = SceneColor.rgb - C8; - - float CW1 = exp(-dot(ColorDiff1, ColorDiff1) / (2.0 * ColorSigma * ColorSigma)); - float CW2 = exp(-dot(ColorDiff2, ColorDiff2) / (2.0 * ColorSigma * ColorSigma)); - float CW3 = exp(-dot(ColorDiff3, ColorDiff3) / (2.0 * ColorSigma * ColorSigma)); - float CW4 = exp(-dot(ColorDiff4, ColorDiff4) / (2.0 * ColorSigma * ColorSigma)); - float CW5 = exp(-dot(ColorDiff5, ColorDiff5) / (2.0 * ColorSigma * ColorSigma)); - float CW6 = exp(-dot(ColorDiff6, ColorDiff6) / (2.0 * ColorSigma * ColorSigma)); - float CW7 = exp(-dot(ColorDiff7, ColorDiff7) / (2.0 * ColorSigma * ColorSigma)); - float CW8 = exp(-dot(ColorDiff8, ColorDiff8) / (2.0 * ColorSigma * ColorSigma)); - - // Mixing weights - float W1 = SW1 * CW1; - float W2 = SW2 * CW2; - float W3 = SW3 * CW3; - float W4 = SW4 * CW4; - float W5 = SW5 * CW5; - float W6 = SW6 * CW6; - float W7 = SW7 * CW7; - float W8 = SW8 * CW8; - float TotalWeight = W1 + W2 + W3 + W4 + W5 + W6 + W7 + W8; - - // Weighted color - float3 AAResult = (C1 * W1 + C2 * W2 + C3 * W3 + C4 * W4 + C5 * W5 + C6 * W6 + - C7 * W7 + C8 * W8) / - max(TotalWeight, 0.0001); + float2 uv = v_in.uv; + float2 coffset = float2(Circle_Offset_X, Circle_Offset_Y)/uv_size; + float2 soffset = float2( Source_Offset_X, Source_Offset_Y )/uv_size; - // Blend it - float4 LuminanceNeightbors = float4(CL1, CL2, CL3, CL4); - float4 LuminanceNeightbors2 = float4(CL5, CL6, CL7, CL8); - float4 A0LuminanceNeightbors = abs(A0 - LuminanceNeightbors); - float4 A0LuminanceNeightbors2 = abs(A0 - LuminanceNeightbors2); - float A0Max = max(max(A0LuminanceNeightbors.r, A0LuminanceNeightbors.g), max(A0LuminanceNeightbors.b, A0LuminanceNeightbors.a)); - float A0Max2 = max(max(A0LuminanceNeightbors2.r, A0LuminanceNeightbors2.g), max(A0LuminanceNeightbors2.b, A0LuminanceNeightbors2.a)); - float HDREdge = max(A0Max, A0Max2); - float EdgeMask = saturate(1.0f - HDREdge); + float radius = Radius * 0.01; + float smwidth = radius * Smoothness * 0.01; + + float4 obstex = image.Sample( textureSampler, uv - soffset); + float4 color = obstex; + // Account for aspect ratio + uv.x = (uv.x - 0.5) * uv_size.x / uv_size.y + 0.5; + float2 cuv = 0.5 + coffset; + float dist = distance(cuv,uv); + // Anti-aliased or pixelated edge + if( Antialiasing ) { + color.a = smoothstep( radius, (radius+(uv_pi.x)) - (uv_pi.x * AAwidth), dist); + } else { + color.a = step( dist, radius ); + } - return float4(lerp(SceneColor.rgb, AAResult, EdgeMask), 1.0); + return float4(color.rgb, color.a); } ' @@ -34138,35 +24808,65 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSRippleShader { +function Get-OBSClockAnalogShader { -[Alias('Set-OBSRippleShader','Add-OBSRippleShader')] +[Alias('Set-OBSClockAnalogShader','Add-OBSClockAnalogShader')] param( -# Set the distance_factor of OBSRippleShader -[Alias('distance_factor')] -[ComponentModel.DefaultBindingProperty('distance_factor')] -[Single] -$DistanceFactor, -# Set the time_factor of OBSRippleShader -[Alias('time_factor')] -[ComponentModel.DefaultBindingProperty('time_factor')] -[Single] -$TimeFactor, -# Set the power_factor of OBSRippleShader -[Alias('power_factor')] -[ComponentModel.DefaultBindingProperty('power_factor')] -[Single] -$PowerFactor, -# Set the center_pos_x of OBSRippleShader -[Alias('center_pos_x')] -[ComponentModel.DefaultBindingProperty('center_pos_x')] -[Single] -$CenterPosX, -# Set the center_pos_y of OBSRippleShader -[Alias('center_pos_y')] -[ComponentModel.DefaultBindingProperty('center_pos_y')] -[Single] -$CenterPosY, +# Set the current_time_ms of OBSClockAnalogShader +[Alias('current_time_ms')] +[ComponentModel.DefaultBindingProperty('current_time_ms')] +[Int32] +$CurrentTimeMs, +# Set the current_time_sec of OBSClockAnalogShader +[Alias('current_time_sec')] +[ComponentModel.DefaultBindingProperty('current_time_sec')] +[Int32] +$CurrentTimeSec, +# Set the current_time_min of OBSClockAnalogShader +[Alias('current_time_min')] +[ComponentModel.DefaultBindingProperty('current_time_min')] +[Int32] +$CurrentTimeMin, +# Set the current_time_hour of OBSClockAnalogShader +[Alias('current_time_hour')] +[ComponentModel.DefaultBindingProperty('current_time_hour')] +[Int32] +$CurrentTimeHour, +# Set the hour_handle_color of OBSClockAnalogShader +[Alias('hour_handle_color')] +[ComponentModel.DefaultBindingProperty('hour_handle_color')] +[Single[]] +$HourHandleColor, +# Set the minute_handle_color of OBSClockAnalogShader +[Alias('minute_handle_color')] +[ComponentModel.DefaultBindingProperty('minute_handle_color')] +[Single[]] +$MinuteHandleColor, +# Set the second_handle_color of OBSClockAnalogShader +[Alias('second_handle_color')] +[ComponentModel.DefaultBindingProperty('second_handle_color')] +[Single[]] +$SecondHandleColor, +# Set the outline_color of OBSClockAnalogShader +[Alias('outline_color')] +[ComponentModel.DefaultBindingProperty('outline_color')] +[Single[]] +$OutlineColor, +# Set the top_line_color of OBSClockAnalogShader +[Alias('top_line_color')] +[ComponentModel.DefaultBindingProperty('top_line_color')] +[Single[]] +$TopLineColor, +# Set the background_color of OBSClockAnalogShader +[Alias('background_color')] +[ComponentModel.DefaultBindingProperty('background_color')] +[Single[]] +$BackgroundColor, +# Set the time_offset_hours of OBSClockAnalogShader +[Alias('time_offset_hours')] +[ComponentModel.DefaultBindingProperty('time_offset_hours')] +[Int32] +$TimeOffsetHours, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -34197,54 +24897,168 @@ $UseShaderTime process { -$shaderName = 'ripple' -$ShaderNoun = 'OBSRippleShader' +$shaderName = 'clock_analog' +$ShaderNoun = 'OBSClockAnalogShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform float distance_factor< - string label = "distance factor"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.001; -> = 12.0; -uniform float time_factor< - string label = "time factor"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> = 2.0; -uniform float power_factor< - string label = "power factor"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> = 3.0; -uniform float center_pos_x< - string label = "center pos x"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; -uniform float center_pos_y< - string label = "center pos y"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; +//Based on https://www.shadertoy.com/view/XdKXzy +uniform int current_time_ms; +uniform int current_time_sec; +uniform int current_time_min; +uniform int current_time_hour; +uniform float3 hour_handle_color = {1.0,1.0,1.0}; +uniform float3 minute_handle_color = {1.0,1.0,1.0}; +uniform float3 second_handle_color = {1.0,0.0,0.0}; +uniform float3 outline_color = {1.0,1.0,1.0}; +uniform float3 top_line_color = {1.0,0.0,0.0}; +uniform float3 background_color = {.5,.5,.5}; +uniform int time_offset_hours = 0; -float4 mainImage(VertData v_in) : TARGET -{ - float2 cPos = (v_in.uv * 2 ) -1; - float2 center_pos = float2(center_pos_x, center_pos_y); - float cLength = distance(cPos, center_pos); - float2 uv = v_in.uv+(cPos/cLength)*cos(cLength*distance_factor-elapsed_time*time_factor) * power_factor / 100.0; - return image.Sample(textureSampler, uv); -} +#ifndef OPENGL +#define mod(x,y) (x - y * floor(x / y)) +#endif +// this is my first try to actually use glsl almost from scratch +// so far all i''ve done is learning by doing / reading glsl docs. +// this is inspired by my non glsl „elapsed_time“ projects +// especially this one: https://www.gottz.de/analoguhr.htm + +// i will most likely use a buffer in future to calculate the elapsed_time +// aswell as to draw the background of the clock only once. +// tell me if thats a bad idea. + +// update: +// screenshot: http://i.imgur.com/dF0nHDk.png +// as soon as i think its in a usefull state i''ll release the source +// of that particular c++ application on github. +// i hope sommeone might find it usefull :D + +#define PI 3.141592653589793238462643383 + +// from https://www.shadertoy.com/view/4s3XDn <3 +float ln(float2 p, float2 a, float2 b) +{ + float2 pa = p - a; + float2 ba = b - a; + float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); + return length(pa - ba * h); +} + +// i think i should spend some elapsed_time reading docs in order to minimize this. +// hints apreciated +// (Rotated LiNe) +float rln(float2 uv, float start, float end, float perc) { + float inp = perc * PI * 2.0; + float2 coord = float2(sin(inp), cos(inp)); + return ln(uv, coord * start, coord * end); +} + +// i need this to have an alphachannel in the output +// i intend to use an optimized version of this shader for a transparent desktop widget experiment +float4 mixer(float4 c1, float4 c2) { + // please tell me if you think this would boost performance. + // the elapsed_time i implemented mix myself it sure did reduce + // the amount of operations but i''m not sure now + // if (c2.a <= 0.0) return c1; + // if (c2.a >= 1.0) return c2; + return float4(lerp(c1.rgb, c2.rgb, c2.a), c1.a + c2.a); + // in case you are curious how you could implement mix yourself: + // return float4(c2.rgb * c2.a + c1.rgb * (1.0-c2.a), c1.a+c2.a); +} + +float4 styleHandle(float4 color, float px, float dist, float3 handleColor, float width, float shadow) { + if (dist <= width + shadow) { + // lets draw the shadow + color = mixer(color, float4(0.0, 0.0, 0.0, + (1.0-pow(smoothstep(width, width + shadow, dist),0.2))*0.2)); + // now lets draw the antialiased handle + color = mixer(color, float4(handleColor, smoothstep(width, max(width - 3.0 * px, 0.0), dist))); + } + return color; +} + +float4 mainImage(VertData v_in) : TARGET +{ + float2 R = uv_size; + // calculate the size of a pixel + float px = 1.0 / R.y; + // create percentages of the coordinate system + float2 p = (v_in.uv * uv_size).xy / R; + // center the scene and add perspective + float2 uv = (2.0 * (float2(v_in.uv.x,1.0-v_in.uv.y) * uv_size) - R) / min(R.x, R.y); + + /*float2 uv = -1.0 + 2.0 * p.xy; + // lets add perspective for mobile device support + if (uv_size.x > uv_size.y) + uv.x *= uv_size.x / uv_size.y; + else + uv.y *= uv_size.y / uv_size.x;*/ + + // lets scale the scene a bit down: + uv *= 1.1; + px *= 0.9; + + float width = 0.015; + float dist = 1.0; + float centerdist = length(uv); + + float4 color = image.Sample(textureSampler, v_in.uv); + + // background of the clock + if (centerdist < 1.0 - width) color = mixer(color, float4(background_color, 0.4*(1.8-length(uv)))); + + float isRed = 1.0; + + if (centerdist > 1.0 - 12.0 * width && centerdist <= 1.1) { + // minute bars + for (float i = 0.0; i <= 15.0; i += 1.0) { + if (mod(i, 5.0) == 0.0) { + dist = min(dist, rln(abs(uv), 1.0 - 10.0 * width, 1.0 - 2.0 * width, i / 60.0)); + // draw first bar red + if (i == 0.0 && uv.y > 0.0) { + isRed = dist; + dist = smoothstep(width, max(width - 3.0 * px, 0.0), dist); + color = mixer(color, float4(top_line_color, dist)); + dist = 1.0; + } + } + else { + dist = min(dist, rln(abs(uv), 1.0 - 10.0 * width, 1.0 - 7.0 * width, i / 60.0)); + } + } + + // outline circle + dist = min(dist, abs(1.0-width-length(uv))); + // draw clock shadow + if (centerdist > 1.0) + color = mixer(color, float4(0.0,0.0,0.0, 0.3*smoothstep(1.0 + width*2.0, 1.0, centerdist))); + + // draw outline + minute bars in white + color = mixer(color, float4(0.0, 0.0, 0.0, + (1.0 - pow(smoothstep(width, width + 0.02, min(isRed, dist)), 0.4))*0.2)); + color = mixer(color, float4(outline_color, smoothstep(width, max(width - 3.0 * px, 0.0), dist))); + } + + if (centerdist < 1.0) { + float elapsed_time = float((time_offset_hours+current_time_hour)*3600+current_time_min*60+current_time_sec) + pow(float(current_time_ms)/1000.0,16.0); + // hour + color = styleHandle(color, px, + rln(uv, -0.05, 0.5, elapsed_time / 3600.0 / 12.0), + hour_handle_color, 0.03, 0.02); + + // minute + color = styleHandle(color, px, + rln(uv, -0.075, 0.7, elapsed_time / 3600.0), + minute_handle_color, 0.02, 0.02); + + // second + color = styleHandle(color, px, + min(rln(uv, -0.1, 0.9, elapsed_time / 60.0), length(uv)-0.01), + second_handle_color, 0.01, 0.02); + } + + + return color; +} ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -34342,38 +25156,53 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSRotatingSourceShader { +function Get-OBSClockDigitalLedShader { -[Alias('Set-OBSRotatingSourceShader','Add-OBSRotatingSourceShader')] +[Alias('Set-OBSClockDigitalLedShader','Add-OBSClockDigitalLedShader')] param( -# Set the spin_speed of OBSRotatingSourceShader -[Alias('spin_speed')] -[ComponentModel.DefaultBindingProperty('spin_speed')] -[Single] -$SpinSpeed, -# Set the rotation of OBSRotatingSourceShader -[ComponentModel.DefaultBindingProperty('rotation')] -[Single] -$Rotation, -# Set the zoomin of OBSRotatingSourceShader -[ComponentModel.DefaultBindingProperty('zoomin')] -[Single] -$Zoomin, -# Set the keep_aspectratio of OBSRotatingSourceShader -[Alias('keep_aspectratio')] -[ComponentModel.DefaultBindingProperty('keep_aspectratio')] +# Set the current_time_sec of OBSClockDigitalLedShader +[Alias('current_time_sec')] +[ComponentModel.DefaultBindingProperty('current_time_sec')] +[Int32] +$CurrentTimeSec, +# Set the current_time_min of OBSClockDigitalLedShader +[Alias('current_time_min')] +[ComponentModel.DefaultBindingProperty('current_time_min')] +[Int32] +$CurrentTimeMin, +# Set the current_time_hour of OBSClockDigitalLedShader +[Alias('current_time_hour')] +[ComponentModel.DefaultBindingProperty('current_time_hour')] +[Int32] +$CurrentTimeHour, +# Set the timeMode of OBSClockDigitalLedShader +[ComponentModel.DefaultBindingProperty('timeMode')] +[Int32] +$TimeMode, +# Set the showMatrix of OBSClockDigitalLedShader +[ComponentModel.DefaultBindingProperty('showMatrix')] [Management.Automation.SwitchParameter] -$KeepAspectratio, -# Set the x_center of OBSRotatingSourceShader -[Alias('x_center')] -[ComponentModel.DefaultBindingProperty('x_center')] -[Single] -$XCenter, -# Set the y_center of OBSRotatingSourceShader -[Alias('y_center')] -[ComponentModel.DefaultBindingProperty('y_center')] -[Single] -$YCenter, +$ShowMatrix, +# Set the showOff of OBSClockDigitalLedShader +[ComponentModel.DefaultBindingProperty('showOff')] +[Management.Automation.SwitchParameter] +$ShowOff, +# Set the ampm of OBSClockDigitalLedShader +[ComponentModel.DefaultBindingProperty('ampm')] +[Management.Automation.SwitchParameter] +$Ampm, +# Set the ledColor of OBSClockDigitalLedShader +[ComponentModel.DefaultBindingProperty('ledColor')] +[String] +$LedColor, +# Set the offsetHours of OBSClockDigitalLedShader +[ComponentModel.DefaultBindingProperty('offsetHours')] +[Int32] +$OffsetHours, +# Set the offsetSeconds of OBSClockDigitalLedShader +[ComponentModel.DefaultBindingProperty('offsetSeconds')] +[Int32] +$OffsetSeconds, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -34404,85 +25233,214 @@ $UseShaderTime process { -$shaderName = 'rotating-source' -$ShaderNoun = 'OBSRotatingSourceShader' +$shaderName = 'clock_digital_led' +$ShaderNoun = 'OBSClockDigitalLedShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -//spin speed higher the slower -uniform float spin_speed< - string label = "Spin Speed"; - string widget_type = "slider"; - float minimum = -10.0; - float maximum = 10.0; - float step = 0.001; -> = 1.0; -uniform float rotation< - string label = "Rotation"; - string widget_type = "slider"; - float minimum = -360.0; - float maximum = 360.0; - float step = 0.1; -> = 0.0; -uniform float zoomin< - string label = "Zoom"; - string widget_type = "slider"; - float minimum = 0.01; - float maximum = 10.0; - float step = 0.01; -> = 1.0; -uniform bool keep_aspectratio = true; -uniform float x_center< - string label = "Center x"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.5; -uniform float y_center< - string label = "Center y"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.5; +// based on https://www.shadertoy.com/view/MdfGzf +// cmarangu has linked all 7 segments in his comments +// https://www.shadertoy.com/view/3dtSRj + +#ifndef OPENGL +#define mod(x,y) (x - y * floor(x / y)) +#endif +uniform int current_time_sec; +uniform int current_time_min; +uniform int current_time_hour; + +uniform int timeMode< + string label = "Time mode"; + string widget_type = "select"; + int option_0_value = 0; + string option_0_label = "Time"; + int option_1_value = 1; + string option_1_label = "Enable duration"; + int option_2_value = 2; + string option_2_label = "Active duration"; + int option_3_value = 3; + string option_3_label = "Show duration"; + int option_4_value = 4; + string option_4_label = "Load duration"; +> = 0; + +uniform bool showMatrix = false; +uniform bool showOff = false; +uniform bool ampm = false; +uniform float4 ledColor = {1.0,0,0,1.0}; +uniform int offsetHours = 0; +uniform int offsetSeconds = 0; + +float segment(float2 uv, bool On) +{ + if (!On && !showOff) + return 0.0; + + float seg = (1.0-smoothstep(0.08,0.09+float(On)*0.02,abs(uv.x)))* + (1.0-smoothstep(0.46,0.47+float(On)*0.02,abs(uv.y)+abs(uv.x))); + + //Fiddle with lights and matrix + //uv.x += sin(elapsed_time*60.0*6.26)/14.0; + //uv.y += cos(elapsed_time*60.0*6.26)/14.0; + + //led like brightness + if (On){ + seg *= (1.0-length(uv*float2(3.8,0.9)));//-sin(elapsed_time*25.0*6.26)*0.04; + } else { + seg *= -(0.05+length(uv*float2(0.2,0.1))); + } + return seg; +} + +float sevenSegment(float2 uv,int num) +{ + float seg= 0.0; + seg += segment(uv.yx+float2(-1.0, 0.0),num!=-1 && num!=1 && num!=4 ); + seg += segment(uv.xy+float2(-0.5,-0.5),num!=-1 && num!=1 && num!=2 && num!=3 && num!=7); + seg += segment(uv.xy+float2( 0.5,-0.5),num!=-1 && num!=5 && num!=6 ); + seg += segment(uv.yx+float2( 0.0, 0.0),num!=-1 && num!=0 && num!=1 && num!=7 ); + seg += segment(uv.xy+float2(-0.5, 0.5),num==0 || num==2 || num==6 || num==8 ); + seg += segment(uv.xy+float2( 0.5, 0.5),num!=-1 && num!=2 ); + seg += segment(uv.yx+float2( 1.0, 0.0),num!=-1 && num!=1 && num!=4 && num!=7 ); + + return seg; +} + +float showNum(float2 uv,int nr, bool zeroTrim) +{ + //Speed optimization, leave if pixel is not in segment + if (abs(uv.x)>1.5 || abs(uv.y)>1.2) + return 0.0; + + float seg= 0.0; + if (uv.x>0.0) + { + nr /= 10; + if (nr==0 && zeroTrim) + nr = -1; + seg += sevenSegment(uv+float2(-0.75,0.0),nr); + } else { + seg += sevenSegment(uv+float2( 0.75,0.0),int(mod(float(nr),10.0))); + } + + return seg; +} + +float dots(float2 uv) +{ + float seg = 0.0; + uv.y -= 0.5; + seg += (1.0-smoothstep(0.11,0.13,length(uv))) * (1.0-length(uv)*2.0); + uv.y += 1.0; + seg += (1.0-smoothstep(0.11,0.13,length(uv))) * (1.0-length(uv)*2.0); + return seg; +} -//main fragment code -//from lioran to nutella with love float4 mainImage(VertData v_in) : TARGET { - float x_aspectratio = keep_aspectratio ? uv_size.x : 1.0; - float y_aspectratio = keep_aspectratio ? uv_size.y : 1.0; - //get position on of the texture and focus on the middle - float i_rotation; - if (spin_speed == 0){ - //turn angle number into pi number - i_rotation = rotation/57.295779513; - }else{ - //use elapsed time for spinning if spin speed is not 0 - i_rotation = elapsed_time * spin_speed; - } - float2 i_point; - i_point.x = (v_in.uv.x * x_aspectratio) - (x_aspectratio * x_center); - i_point.y = (v_in.uv.y * y_aspectratio) - (y_aspectratio * y_center); - - //get the angle from center , returns pi number - float i_dir = atan(i_point.y/i_point.x); - if(i_point.x < 0.0){ - i_dir += 3.14159265359; - } - - //get the distance from the centers - float i_distance = sqrt(pow(i_point.x,2) + pow(i_point.y,2)); - //multiple distance by the zoomin value - i_distance *= zoomin; - - //shift the texture position based on angle and distance from the middle - i_point.x = ((x_aspectratio*x_center)+cos(i_dir-i_rotation)*i_distance)/x_aspectratio; - i_point.y = ((y_aspectratio*y_center)+sin(i_dir-i_rotation)*i_distance)/y_aspectratio; - - //draw normally from new point - return image.Sample(textureSampler, i_point); + float2 uv = ((float2(v_in.uv.x, 1.0-v_in.uv.y) * uv_size).xy-0.5*uv_size) / + min(uv_size.x,uv_size.y); + + if (uv_size.x>uv_size.y) + { + uv *= 6.0; + } + else + { + uv *= 12.0; + } + + uv.x *= -1.0; + uv.x += uv.y/12.0; + //wobble + //uv.x += sin(uv.y*3.0+elapsed_time*14.0)/25.0; + //uv.y += cos(uv.x*3.0+elapsed_time*14.0)/25.0; + uv.x += 3.5; + float seg = 0.0; + + if(timeMode == 0){ + seg += showNum(uv,current_time_sec,false); + uv.x -= 1.75; + seg += dots(uv); + uv.x -= 1.75; + seg += showNum(uv,current_time_min,false); + uv.x -= 1.75; + seg += dots(uv); + uv.x -= 1.75; + if (ampm) { + if(current_time_hour == 0){ + seg += showNum(uv,12,true); + }else if(current_time_hour > 12){ + seg += showNum(uv,current_time_hour-12,true); + }else{ + seg += showNum(uv,current_time_hour,true); + } + } else { + seg += showNum(uv,current_time_hour,true); + } + }else{ + float timeSecs = 0.0; + if(timeMode == 1){ + timeSecs = elapsed_time_enable; + }else if(timeMode == 2){ + timeSecs = elapsed_time_active; + }else if(timeMode == 3){ + timeSecs = elapsed_time_show; + }else if(timeMode == 4){ + timeSecs = elapsed_time_start; + } + + timeSecs += offsetSeconds + offsetHours*3600; + if(timeSecs < 0) + timeSecs = 0.9999-timeSecs; + seg += showNum(uv,int(mod(timeSecs,60.0)),false); + + timeSecs = floor(timeSecs/60.0); + + uv.x -= 1.75; + + seg += dots(uv); + + uv.x -= 1.75; + + seg += showNum(uv,int(mod(timeSecs,60.0)),false); + + timeSecs = floor(timeSecs/60.0); + if (ampm) + { + if(timeSecs == 0.0){ + timeSecs = 12.0; + }else if (timeSecs > 12.0){ + timeSecs = mod(timeSecs,12.0); + } + }else if (timeSecs > 24.0) { + timeSecs = mod(timeSecs,24.0); + } + + uv.x -= 1.75; + + seg += dots(uv); + + uv.x -= 1.75; + seg += showNum(uv,int(mod(timeSecs,60.0)),true); + } + + + if (seg==0.0){ + return image.Sample(textureSampler, v_in.uv); + } + // matrix over segment + if (showMatrix) + { + seg *= 0.8+0.2*smoothstep(0.02,0.04,mod(uv.y+uv.x,0.06025)); + //seg *= 0.8+0.2*smoothstep(0.02,0.04,mod(uv.y-uv.x,0.06025)); + } + if (seg<0.0) + { + seg = -seg;; + return float4(seg,seg,seg,1.0); + } + return float4(ledColor.rgb * seg, ledColor.a); } ' } @@ -34581,102 +25539,62 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSRotatoeShader { +function Get-OBSClockDigitalNixieShader { -[Alias('Set-OBSRotatoeShader','Add-OBSRotatoeShader')] +[Alias('Set-OBSClockDigitalNixieShader','Add-OBSClockDigitalNixieShader')] param( -# Set the ViewProj of OBSRotatoeShader -[ComponentModel.DefaultBindingProperty('ViewProj')] -[Single[][]] -$ViewProj, -# Set the image of OBSRotatoeShader -[ComponentModel.DefaultBindingProperty('image')] -[String] -$Image, -# Set the elapsed_time of OBSRotatoeShader -[Alias('elapsed_time')] -[ComponentModel.DefaultBindingProperty('elapsed_time')] -[Single] -$ElapsedTime, -# Set the uv_offset of OBSRotatoeShader -[Alias('uv_offset')] -[ComponentModel.DefaultBindingProperty('uv_offset')] +# Set the current_time_ms of OBSClockDigitalNixieShader +[Alias('current_time_ms')] +[ComponentModel.DefaultBindingProperty('current_time_ms')] +[Int32] +$CurrentTimeMs, +# Set the current_time_sec of OBSClockDigitalNixieShader +[Alias('current_time_sec')] +[ComponentModel.DefaultBindingProperty('current_time_sec')] +[Int32] +$CurrentTimeSec, +# Set the current_time_min of OBSClockDigitalNixieShader +[Alias('current_time_min')] +[ComponentModel.DefaultBindingProperty('current_time_min')] +[Int32] +$CurrentTimeMin, +# Set the current_time_hour of OBSClockDigitalNixieShader +[Alias('current_time_hour')] +[ComponentModel.DefaultBindingProperty('current_time_hour')] +[Int32] +$CurrentTimeHour, +# Set the timeMode of OBSClockDigitalNixieShader +[ComponentModel.DefaultBindingProperty('timeMode')] +[Int32] +$TimeMode, +# Set the offsetHours of OBSClockDigitalNixieShader +[ComponentModel.DefaultBindingProperty('offsetHours')] +[Int32] +$OffsetHours, +# Set the offsetSeconds of OBSClockDigitalNixieShader +[ComponentModel.DefaultBindingProperty('offsetSeconds')] +[Int32] +$OffsetSeconds, +# Set the corecolor of OBSClockDigitalNixieShader +[ComponentModel.DefaultBindingProperty('corecolor')] [Single[]] -$UvOffset, -# Set the uv_scale of OBSRotatoeShader -[Alias('uv_scale')] -[ComponentModel.DefaultBindingProperty('uv_scale')] +$Corecolor, +# Set the halocolor of OBSClockDigitalNixieShader +[ComponentModel.DefaultBindingProperty('halocolor')] [Single[]] -$UvScale, -# Set the uv_pixel_interval of OBSRotatoeShader -[Alias('uv_pixel_interval')] -[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +$Halocolor, +# Set the flarecolor of OBSClockDigitalNixieShader +[ComponentModel.DefaultBindingProperty('flarecolor')] [Single[]] -$UvPixelInterval, -# Set the rand_f of OBSRotatoeShader -[Alias('rand_f')] -[ComponentModel.DefaultBindingProperty('rand_f')] -[Single] -$RandF, -# Set the uv_size of OBSRotatoeShader -[Alias('uv_size')] -[ComponentModel.DefaultBindingProperty('uv_size')] +$Flarecolor, +# Set the anodecolor of OBSClockDigitalNixieShader +[ComponentModel.DefaultBindingProperty('anodecolor')] [Single[]] -$UvSize, -# Set the speed_percent of OBSRotatoeShader -[Alias('speed_percent')] -[ComponentModel.DefaultBindingProperty('speed_percent')] -[Int32] -$SpeedPercent, -# Set the Axis_X of OBSRotatoeShader -[Alias('Axis_X')] -[ComponentModel.DefaultBindingProperty('Axis_X')] -[Single] -$AxisX, -# Set the Axis_Y of OBSRotatoeShader -[Alias('Axis_Y')] -[ComponentModel.DefaultBindingProperty('Axis_Y')] -[Single] -$AxisY, -# Set the Axis_Z of OBSRotatoeShader -[Alias('Axis_Z')] -[ComponentModel.DefaultBindingProperty('Axis_Z')] -[Single] -$AxisZ, -# Set the Angle_Degrees of OBSRotatoeShader -[Alias('Angle_Degrees')] -[ComponentModel.DefaultBindingProperty('Angle_Degrees')] -[Single] -$AngleDegrees, -# Set the Rotate_Transform of OBSRotatoeShader -[Alias('Rotate_Transform')] -[ComponentModel.DefaultBindingProperty('Rotate_Transform')] -[Management.Automation.SwitchParameter] -$RotateTransform, -# Set the Rotate_Pixels of OBSRotatoeShader -[Alias('Rotate_Pixels')] -[ComponentModel.DefaultBindingProperty('Rotate_Pixels')] -[Management.Automation.SwitchParameter] -$RotatePixels, -# Set the Rotate_Colors of OBSRotatoeShader -[Alias('Rotate_Colors')] -[ComponentModel.DefaultBindingProperty('Rotate_Colors')] -[Management.Automation.SwitchParameter] -$RotateColors, -# Set the center_width_percentage of OBSRotatoeShader -[Alias('center_width_percentage')] -[ComponentModel.DefaultBindingProperty('center_width_percentage')] -[Int32] -$CenterWidthPercentage, -# Set the center_height_percentage of OBSRotatoeShader -[Alias('center_height_percentage')] -[ComponentModel.DefaultBindingProperty('center_height_percentage')] -[Int32] -$CenterHeightPercentage, -# Set the notes of OBSRotatoeShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, +$Anodecolor, +# Set the anodehighlightscolor of OBSClockDigitalNixieShader +[ComponentModel.DefaultBindingProperty('anodehighlightscolor')] +[Single[]] +$Anodehighlightscolor, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -34707,491 +25625,483 @@ $UseShaderTime process { -$shaderName = 'rotatoe' -$ShaderNoun = 'OBSRotatoeShader' +$shaderName = 'clock_digital_nixie' +$ShaderNoun = 'OBSClockDigitalNixieShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Rotation Effect By Charles Fettinger (https://github.com/Oncorporation) 10/2019 -//Converted to OpenGL by Q-mii, Exeldro, & skeletonbow -uniform float4x4 ViewProj; -uniform texture2d image; - -uniform float elapsed_time; -uniform float2 uv_offset; -uniform float2 uv_scale; -uniform float2 uv_pixel_interval; -uniform float rand_f; -uniform float2 uv_size; - -uniform int speed_percent< - string label = "speed percentage"; - string widget_type = "slider"; - int minimum = -100; - int maximum = 100; - int step = 1; -> = 50; // -uniform float Axis_X< - string label = "Axis X"; - string widget_type = "slider"; - float minimum = -2.0; - float maximum = 2.0; - float step = 0.1; -> = 0.0; -uniform float Axis_Y< - string label = "Axis Y"; - string widget_type = "slider"; - float minimum = -2.0; - float maximum = 2.0; - float step = 0.01; -> = 0.0; -uniform float Axis_Z< - string label = "Axis Z"; - string widget_type = "slider"; - float minimum = -2.0; - float maximum = 2.0; - float step = 0.01; -> = 1.0; -uniform float Angle_Degrees< - string label = "Angle Degrees"; - string widget_type = "slider"; - float minimum = -180.0; - float maximum = 180.0; - float step = 0.01; -> = 45.0; -uniform bool Rotate_Transform = true; -uniform bool Rotate_Pixels = false; -uniform bool Rotate_Colors = false; -uniform int center_width_percentage< - string label = "center width percentage"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; -uniform int center_height_percentage< - string label = "center height percentage"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; - -uniform string notes< - string widget_type = "info"; -> = " Choose axis, angle and speed, then rotate away! center_width_percentage & center_height_percentage allow you to change the pixel spin axis"; - -sampler_state textureSampler { - Filter = Linear; - AddressU = Border; - AddressV = Border; - BorderColor = 00000000; -}; - -struct VertData { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; - -float3x3 rotAxis(float3 axis, float a) { - float s=sin(a); - float c=cos(a); - float oc=1.0-c; - - float3 as=axis*s; - - float3x3 p=float3x3(axis.x*axis,axis.y*axis,axis.z*axis); - float3x3 q=float3x3(c,-as.z,as.y,as.z,c,-as.x,-as.y,as.x,c); - return p*oc+q; -} - -VertData mainTransform(VertData v_in) -{ - VertData vert_out; - vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); - - float speed = speed_percent * 0.01; - // circular easing variable - float PI = 3.1415926535897932384626433832795; //acos(-1); - float PI180th = 0.0174532925; //PI divided by 180 - float direction = abs(sin((elapsed_time - 0.001) * speed)); - float t = sin(elapsed_time * speed); - float angle_degrees = PI180th * Angle_Degrees; +//based on https://www.shadertoy.com/view/fsBcRm +uniform int current_time_ms; +uniform int current_time_sec; +uniform int current_time_min; +uniform int current_time_hour; +uniform int timeMode< + string label = "Time mode"; + string widget_type = "select"; + int option_0_value = 0; + string option_0_label = "Time"; + int option_1_value = 1; + string option_1_label = "Enable duration"; + int option_2_value = 2; + string option_2_label = "Active duration"; + int option_3_value = 3; + string option_3_label = "Show duration"; + int option_4_value = 4; + string option_4_label = "Load duration"; +> = 0; - // use matrix to transform rotation - if (Rotate_Transform) - vert_out.pos.xyz = mul(vert_out.pos.xyz,rotAxis(float3(Axis_X,Axis_Y,Axis_Z), (angle_degrees * t))).xyz; +uniform int offsetHours = 0; +uniform int offsetSeconds = 0; - vert_out.uv = v_in.uv * uv_scale + uv_offset; +// Colors as named variables, if you want to tweak them +uniform float3 corecolor = {1.0,0.7,0.0}; +uniform float3 halocolor = {1.0,0.5,0.0}; +uniform float3 flarecolor = {1.0,0.3,0.0}; +uniform float3 anodecolor = {0.2,0.1,0.1}; +uniform float3 anodehighlightscolor = {1.0,0.5,0.0}; - return vert_out; -} +#ifndef OPENGL +#define mod(x,y) (x - y * floor(x / y)) +#define lessThan(a,b) (a < b) +#define greaterThan(a,b) (a > b) +#endif -float4 mainImage(VertData v_in) : TARGET +// psrdnoise (c) Stefan Gustavson and Ian McEwan, +// ver. 2021-12-02, published under the MIT license: +// https://github.com/stegu/psrdnoise/ +float psrdnoise(float2 x, float2 period, float alpha, out float2 gradient) { - float4 rgba = image.Sample(textureSampler, v_in.uv); - - float speed = speed_percent * 0.01; - // circular easing variable - float PI = 3.1415926535897932384626433832795; //acos(-1); - float PI180th = 0.0174532925; //PI divided by 180 - float direction = abs(sin((elapsed_time - 0.001) * speed)); - float t = sin(elapsed_time * speed); - float angle_degrees = PI180th * Angle_Degrees; - - - // use matrix to transform pixels - if (Rotate_Pixels) - { - float2 center_pixel_coordinates = float2((center_width_percentage * 0.01), (center_height_percentage * 0.01) ); - rgba = image.Sample(textureSampler, mul(float3(v_in.uv - center_pixel_coordinates, 1.0), rotAxis(float3(Axis_X ,Axis_Y, Axis_Z ), (angle_degrees * t))).xy + center_pixel_coordinates); + float2 uv = float2(x.x+x.y*0.5, x.y); + float2 i0 = floor(uv), f0 = frac(uv); + float cmp = step(f0.y, f0.x); + float2 o1 = float2(cmp, 1.0-cmp); + float2 i1 = i0 + o1, i2 = i0 + 1.0; + float2 v0 = float2(i0.x - i0.y*0.5, i0.y); + float2 v1 = float2(v0.x + o1.x - o1.y*0.5, v0.y + o1.y); + float2 v2 = float2(v0.x + 0.5, v0.y + 1.0); + float2 x0 = x - v0, x1 = x - v1, x2 = x - v2; + float3 iu, iv, xw, yw; + if(any(greaterThan(period, float2(0.0,0.0)))) { + xw = float3(v0.x, v1.x, v2.x); + yw = float3(v0.y, v1.y, v2.y); + if(period.x > 0.0) + xw = mod(float3(v0.x, v1.x, v2.x), period.x); + if(period.y > 0.0) + yw = mod(float3(v0.y, v1.y, v2.y), period.y); + iu = floor(xw + 0.5*yw + 0.5); iv = floor(yw + 0.5); + } else { + iu = float3(i0.x, i1.x, i2.x); iv = float3(i0.y, i1.y, i2.y); } - if (Rotate_Colors) - rgba.rgb = mul(rgba.rgb, rotAxis(float3(Axis_X,Axis_Y,Axis_Z), (angle_degrees * t))).xyz; - - return rgba; + float3 hash = mod(iu, 289.0); + hash = mod((hash*51.0 + 2.0)*hash + iv, 289.0); + hash = mod((hash*34.0 + 10.0)*hash, 289.0); + float3 psi = hash*0.07482 + alpha; + float3 gx = cos(psi); float3 gy = sin(psi); + float2 g0 = float2(gx.x, gy.x); + float2 g1 = float2(gx.y, gy.y); + float2 g2 = float2(gx.z, gy.z); + float3 w = 0.8 - float3(dot(x0, x0), dot(x1, x1), dot(x2, x2)); + w = max(w, 0.0); float3 w2 = w*w; float3 w4 = w2*w2; + float3 gdotx = float3(dot(g0, x0), dot(g1, x1), dot(g2, x2)); + float n = dot(w4, gdotx); + float3 w3 = w2*w; float3 dw = -8.0*w3*gdotx; + float2 dn0 = w4.x*g0 + dw.x*x0; + float2 dn1 = w4.y*g1 + dw.y*x1; + float2 dn2 = w4.z*g2 + dw.z*x2; + gradient = 10.9*(dn0 + dn1 + dn2); + return 10.9*n; } -technique Draw -{ - pass - { - vertex_shader = mainTransform(v_in); - pixel_shader = mainImage(v_in); - } +// Compute the shortest distance from p +// to a line segment from p1 to p2. +float lined(float2 p1, float2 p2, float2 p) { + float2 p1p2 = p2 - p1; + float2 v = normalize(p1p2); + float2 s = p - p1; + float t = dot(v, s); + if (t<0.0) return length(s); + if (t>length(p1p2)) return length(p - p2); + return length(s - t*v); } -' -} -$MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 -if (-not $myNoun) { - $myNoun = $myVerb - $myVerb = 'Get' +// Compute the shortest distance from p to a circle +// with center at c and radius r. (Extremely simple.) +float circled(float2 c, float r, float2 p) { + return abs(length(p - c) - r); } -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 - } +// Compute the shortest distance from p to a +// circular arc with center c from p1 to p2. +// p1, p2 are in the +angle direction (ccw), +// to resolve the major/minor arc ambiguity, so +// specifying p1, p2 in the wrong order will +// yield the complement to the arc you wanted. +// If p1 = p2, the entire circle is drawn, but +// you don''t want to use this function to draw +// a circle. Use the simple circled() instead. +// If p1 and p2 have different distances to c, +// the end of the arc will not look right. If +// this is inconvenient, uncomment the 3rd line. +float arcd(float2 c, float2 p1, float2 p2, float2 p) { - foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { - if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { - $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] - } - } + float2 v1 = p1 - c; + float2 v2 = p2 - c; + // Optional: make sure p1, p2 are both on the circle + // v2 = normalize(v2)*length(v1); + float2 v = p - c; - if (-not $script:CachedShaderFilesFromCommand) { - $script:CachedShaderFilesFromCommand = @{} - } + float2 w = float2(dot(v, -float2(-v1.y, v1.x)), dot(v, float2(-v2.y, v2.x))); - 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 + if(dot(v1, float2(-v2.y, v2.x)) >= 0.0) { // Arc angle <= pi + if(all(lessThan(float2(0.0,0.0), w))) { + return min(length(p1-p), length(p2-p)); // nearest end } else { - $ShaderFilterSplat.ShaderText = $shaderText - } - - if ($myVerb -eq 'Add') { - Add-OBSShaderFilter @ShaderFilterSplat + return abs(length(v) - length(v1)); // dist to arc + } + } else { // Arc angle > pi + if(any(lessThan(float2(0.0,0.0), w))) { + return min(length(p1-p), length(p2-p)); } else { - Set-OBSShaderFilter @ShaderFilterSplat + return abs(length(v) - length(v1)); } } } +// A convenient anti-aliased step() using auto derivatives +float aastep(float threshold, float value) { + float afwidth = 0.7 * length(float2(ddx(value), ddy(value))); + return smoothstep(threshold-afwidth, threshold+afwidth, value); } +// A smoothstep() that blends to an aastep() under minification +float aasmoothstep(float t1, float t2, float v) { + float aw = 0.7 * length(float2(ddx(v), ddy(v))); + float sw = max(0.5*(t2-t1), aw); + float st = 0.5*(t1+t2); + return smoothstep(st-sw, st+sw, v); +} -} +// Distance field of a hexagonal (simplex) grid +// The return vector contains the distances to the +// three closest points, sorted by magnitude. +float3 hexgrid(float2 p) { - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSRoundedRect2Shader { + const float stretch = 1.0/0.8660; + + // v.y = v.y + 0.0001; // needed if no stretching (rounding errors) + p.y = p.y * stretch; + // Transform to grid space (axis-aligned "simplex" grid) + float2 uv = float2(p.x + p.y*0.5, p.y); + // Determine which simplex we''re in, with i0 being the "base" + float2 i0 = floor(uv); + float2 f0 = frac(uv); + // o1 is the offset in simplex space to the second corner + float cmp = step(f0.y, f0.x); + float2 o1 = float2(cmp, 1.0-cmp); + // Enumerate the remaining simplex corners + float2 i1 = i0 + o1; + float2 i2 = i0 + float2(1.0, 1.0); + // Transform corners back to texture space + float2 p0 = float2(i0.x - i0.y * 0.5, i0.y); + float2 p1 = float2(p0.x + o1.x - o1.y * 0.5, p0.y + o1.y); + float2 p2 = float2(p0.x + 0.5, p0.y + 1.0); + float3 d = float3(length(p-p0), length(p-p1), length(p-p2)); + // Only three values - bubble sort is just fine. + d.yz = (d.y < d.z) ? d.yz : d.zy; + d.xy = (d.x < d.y) ? d.xy : d.yx; + d.yz = (d.y < d.z) ? d.yz : d.zy; + return d; +} -[Alias('Set-OBSRoundedRect2Shader','Add-OBSRoundedRect2Shader')] -param( -# Set the corner_radius of OBSRoundedRect2Shader -[Alias('corner_radius')] -[ComponentModel.DefaultBindingProperty('corner_radius')] -[Int32] -$CornerRadius, -# Set the border_thickness of OBSRoundedRect2Shader -[Alias('border_thickness')] -[ComponentModel.DefaultBindingProperty('border_thickness')] -[Int32] -$BorderThickness, -# Set the border_color of OBSRoundedRect2Shader -[Alias('border_color')] -[ComponentModel.DefaultBindingProperty('border_color')] -[String] -$BorderColor, -# Set the border_alpha_start of OBSRoundedRect2Shader -[Alias('border_alpha_start')] -[ComponentModel.DefaultBindingProperty('border_alpha_start')] -[Single] -$BorderAlphaStart, -# Set the border_alpha_end of OBSRoundedRect2Shader -[Alias('border_alpha_end')] -[ComponentModel.DefaultBindingProperty('border_alpha_end')] -[Single] -$BorderAlphaEnd, -# Set the alpha_cut_off of OBSRoundedRect2Shader -[Alias('alpha_cut_off')] -[ComponentModel.DefaultBindingProperty('alpha_cut_off')] -[Single] -$AlphaCutOff, -# Set the faster_scan of OBSRoundedRect2Shader -[Alias('faster_scan')] -[ComponentModel.DefaultBindingProperty('faster_scan')] -[Management.Automation.SwitchParameter] -$FasterScan, -# 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 -) +// The digits. Simple functions, only a lot of them. + +// These glyphs and their implementation as distance fields +// are the original work of me (stefan.gustavson@gmail.com), +// and the code below is released under the MIT license: +// https://opensource.org/licenses/MIT +// (If that is inconvenient for you, let me know. I''m reasonable.) +// +// Experts say mortals should not attempt to design character shapes. +// "It''s just ten simple digits", I thought, "How hard can it be?" +// A week later, after countless little tweaks to proportions and +// curvature, and with a notepad full of sketches and pen-and-paper +// math, some of it horribly wrong because it was decades since I +// solved this kind of equations by hand, I know the answer: +// It can be *really* hard. But also loads of fun! +// +float nixie0(float2 p) { + // Special hack instead of pasting together arcs and lines + float d = lined(float2(2.0,2.0), float2(2.0, 6.0), p); + return abs(d - 2.0); +} +float nixie1(float2 p) { + float d1 = lined(float2(2.0, 0.0), float2(2.0, 8.0), p); + float d2 = lined(float2(2.0, 8.0), float2(1.0, 6.0), p); + return min(d1, d2); +} -process { -$shaderName = 'rounded_rect2' -$ShaderNoun = 'OBSRoundedRect2Shader' -if (-not $psBoundParameters['ShaderText']) { - $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform int corner_radius< - string label = "Corner radius"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; ->; -uniform int border_thickness< - string label = "Border thickness"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; ->; -uniform float4 border_color; -uniform float border_alpha_start< - string label = "Border alpha start"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 1.0; -uniform float border_alpha_end< - string label = "Border alpha end"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.0; -uniform float alpha_cut_off< - string label = "Aplha cut off"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.5; -uniform bool faster_scan = true; +float nixie1alt(float2 p) { // Straight line + return lined(float2(2.0, 0.0), float2(2.0, 8.0), p); +} + +float nixie2(float2 p) { + const float x = 3.2368345; // Icky coordinates, + const float y = 4.4283002; // used twice below + float d1 = lined(float2(4.25, 0.0), float2(-0.25, 0.0), p); + float d2 = arcd(float2(10.657842, -5.001899), // Also icky + float2(x, y), float2(-0.25, 0.0), p); + float d3 = arcd(float2(2.0, 6.0), float2(x, y), float2(0.0, 6.0), p); + return min(min(d1, d2), d3); +} + +float nixie2alt(float2 p) { // Straight neck + float d1 = lined(float2(4.0, 0.0), float2(0.0,0.0), p); + float d2 = lined(float2(0.0,0.0), float2(3.6, 4.8), p); + float d3 = arcd(float2(2.0, 6.0), float2(3.6, 4.8), float2(0.0, 6.0), p); + return min(min(d1, d2), d3); +} + +float nixie3(float2 p) { + // Two round parts: + // float d1 = arcd(float2(2.0, 2.1), float2(-0.1, 2.1), float2(2.0, 4.2), p); + // float d2 = arcd(float2(2.0, 6.1), float2(2.0, 4.2), float2(0.1, 6.1), p); + // Angled top, more like classic Nixie tube digits: + float d1 = arcd(float2(2.0, 2.25), float2(-0.25, 2.25), float2(2.0, 4.5), p); + float d2 = lined(float2(2.0, 4.5), float2(4.0, 7.75), p); + float d3 = lined(float2(4.0, 7.75), float2(0.0, 7.75), p); + return min(min(d1, d2), d3); +} + +float nixie3alt(float2 p) { // Two round parts of the same size + float d1 = arcd(float2(2.0,2.0), float2(0.0, 2.0), float2(2.0, 4.0), p); + float d2 = arcd(float2(2.0, 6.0), float2(2.0, 4.0), float2(0.0, 6.0), p); + return min(d1, d2); +} + +float nixie4(float2 p) { + // This digit is 5.0 units wide, most others are 4.0 or 4.5 + float d1 = lined(float2(4.0, 0.0), float2(4.0, 8.0), p); + float d2 = lined(float2(4.0, 8.0), float2(0.0, 2.0), p); + float d3 = lined(float2(0.0, 2.0), float2(5.0, 2.0), p); + return min(min(d1, d2), d3); +} + +float nixie4alt(float2 p) { + // This digit is 4.0 units wide, but looks cropped + float d1 = lined(float2(4.0, 0.0), float2(4.0, 8.0), p); + float d2 = lined(float2(4.0, 8.0), float2(0.0, 2.0), p); + float d3 = lined(float2(0.0, 2.0), float2(4.0, 2.0), p); + return min(min(d1, d2), d3); +} + +float nixie5(float2 p) { + float d1 = lined(float2(4.0, 7.75), float2(0.5, 7.75), p); + float d2 = lined(float2(0.5, 7.75), float2(0.0, 4.5), p); + float d3 = lined(float2(0.0, 4.5), float2(2.0, 4.5), p); + float d4 = arcd(float2(2.0, 2.25), float2(-0.25, 2.25), float2(2.0, 4.5), p); + return min(min(d1, d2), min(d3, d4)); +} + +float nixie5alt(float2 p) { + float d1 = lined(float2(4.0, 8.0), float2(0.0, 8.0), p); + float d2 = lined(float2(0.0, 8.0), float2(0.0, 5.0), p); + float d3 = lined(float2(0.0, 5.0), float2(2.0, 5.0), p); + float d4 = arcd(float2(2.0, 3.0), float2(4.0, 3.0), float2(2.0, 5.0), p); + float d5 = lined(float2(4.0, 3.0), float2(4.0, 2.0), p); + float d6 = arcd(float2(2.0,2.0), float2(0.0, 2.0), float2(4.0, 2.0), p); + return min(min(min(d1, d2), min(d3, d4)), min(d5, d6)); +} + +float nixie6(float2 p) { + float d1 = arcd(float2(84.0/13.0, 2.25), float2(3.0, 8.0), float2(-0.25, 2.25), p); + float d2 = circled(float2(2.0, 2.25), 2.25, p); + return min(d1, d2); +} + +float nixie6alt(float2 p) { // Straight neck + float d1 = lined(float2(0.4, 3.2), float2(3.0, 8.0), p); + float d2 = circled(float2(2.0,2.0), 2.0, p); + return min(d1, d2); +} + +float nixie7(float2 p) { // Ugly coordinates, but these expressions are exact + float d1 = lined(float2(0.0, 7.75), float2(0.25*sqrt(2259.0)-8.0, 7.75), p); + float d2 = arcd(float2(-8.0, 12.0), float2(2.5, 5.0), float2(0.25*sqrt(2259.0)-8.0, 7.75), p); + float d3 = arcd(float2(10.0, 0.0), float2(2.5, 5.0), float2(10.0-2.5*sqrt(13.0), 0.0), p); + return min(min(d1, d2), d3); +} + +float nixie7alt(float2 p) { // Straight neck + float d1 = lined(float2(0.0, 8.0), float2(4.0, 8.0), p); + float d2 = lined(float2(4.0, 8.0), float2(1.0, 0.0), p); + return min(d1, d2); +} + +float nixie8(float2 p) { + float d1 = circled(float2(2.0, 2.2), 2.2, p); + float d2 = circled(float2(2.0, 6.2), 1.8, p); + return min(d1, d2); +} + +float nixie8alt(float2 p) { // Same size loops + float d1 = circled(float2(2.0,2.0), 2.0, p); + float d2 = circled(float2(2.0, 6.0), 2.0, p); + return min(d1, d2); +} + +float nixie9(float2 p) { + float d1 = arcd(float2(-32.0/13.0, 5.75), float2(1.0, 0.0), float2(4.25, 5.75), p); + float d2 = circled(float2(2.0, 5.75), 2.25, p); + return min(d1, d2); +} + +float nixie9alt(float2 p) { // Straight neck + float d1 = lined(float2(3.6, 4.8), float2(1.0, 0.0), p); + float d2 = circled(float2(2.0, 6.0), 2.0, p); + return min(d1, d2); +} + +float nixieminus(float2 p) { + return lined(float2(0.5, 4.0), float2(3.5, 4.0), p); +} + +float nixieequals(float2 p) { + float d1 = lined(float2(0.5, 3.0), float2(3.5, 3.0), p); + float d2 = lined(float2(0.5, 5.0), float2(3.5, 5.0), p); + return min(d1, d2); +} + +float nixieplus(float2 p) { + float d1 = lined(float2(0.0, 4.0), float2(4.0, 4.0), p); + float d2 = lined(float2(2.0, 2.0), float2(2.0, 6.0), p); + return min(d1, d2); +} + +float nixiedot(float2 p) { + // circled with r=0 yields a point, but with more work + return length(p - float2(2.0, 0.0)); +} + +float nixiecolon(float2 p) { + float d1 = length(p - float2(2.0,2.0)); + float d2 = length(p - float2(2.0, 5.0)); + return min(d1, d2); +} + +// End of MIT-licensed code +float number(int n, float2 p) { + switch(n) { + case 0: return nixie0(p); + case 1: return nixie1(p); + case 2: return nixie2(p); + case 3: return nixie3(p); + case 4: return nixie4(p); + case 5: return nixie5(p); + case 6: return nixie6(p); + case 7: return nixie7(p); + case 8: return nixie8(p); + case 9: return nixie9(p); + default: return 1e10; + } +} +// Display the current time with a retro Nixie-tube look +// Stefan Gustavson (stegu on shadertoy.com) 2022-01-26 +// All code in the "Image" tab is public domain. +// Functions in the "Common" tab are also public domain, +// except where a separate license is specified. float4 mainImage(VertData v_in) : TARGET { - float4 pixel = image.Sample(textureSampler, v_in.uv); - int closedEdgeX = 0; - int closedEdgeY = 0; - if(pixel.a < alpha_cut_off){ - return float4(1.0,0.0,0.0,0.0); - } - float check_dist = float(corner_radius); - if(border_thickness > check_dist) - check_dist = border_thickness; - if(image.Sample(textureSampler, v_in.uv + float2(check_dist*uv_pixel_interval.x,0)).a < alpha_cut_off){ - closedEdgeX = int(check_dist); - }else if(image.Sample(textureSampler, v_in.uv + float2(-check_dist*uv_pixel_interval.x,0)).a < alpha_cut_off){ - closedEdgeX = int(-check_dist); - } - if(image.Sample(textureSampler, v_in.uv + float2(0,check_dist*uv_pixel_interval.y)).a < alpha_cut_off){ - closedEdgeY = int(check_dist); - }else if(image.Sample(textureSampler, v_in.uv + float2(0,-check_dist*uv_pixel_interval.y)).a < alpha_cut_off){ - closedEdgeY = int(-check_dist); - } - if(closedEdgeX == 0 && closedEdgeY == 0){ - return pixel; - } - if(!faster_scan || closedEdgeX != 0){ - [loop] for(int x = 1;float(x) check_dist && border_thickness > corner_radius){ - if(closedEdgeXabs < corner_radius && closedEdgeYabs < corner_radius){ - float cd = distance(float2(closedEdgeXabs, closedEdgeYabs), float2(corner_radius,corner_radius)); - if(floor(cd) > corner_radius) - return float4(0.0,0.0,0.0,0.0); - if(cd > corner_radius){ - d = border_thickness + cd - corner_radius; - } else if(d > border_thickness){ - d = border_thickness; - } - }else if(d > border_thickness){ - d = border_thickness; - } - } - if(floor(d) <= check_dist){ - if(border_thickness > 0){ - if(ceil(check_dist-d) <= border_thickness){ - float4 fade_color = border_color; - fade_color.a = border_alpha_end + ((check_dist-d)/ float(border_thickness))*(border_alpha_start-border_alpha_end); - if(border_alpha_start < border_alpha_end){ - fade_color.rgb = pixel.rgb * (1.0 - fade_color.a) + fade_color.rgb * fade_color.a; - fade_color.a = border_alpha_end + ((check_dist-d) / float(border_thickness))*(pixel.a-border_alpha_end); - } - if(d > check_dist) - fade_color.a *= 1.0 -(d - check_dist); - return fade_color; - }else if(d >= 0 && floor(check_dist-d) <= border_thickness && border_alpha_start >= border_alpha_end){ - float4 fade_color = border_color; - float f; - if(border_thickness > (check_dist-d)) - f = border_thickness - (check_dist-d); - else - f = 1.0 -((check_dist-d) - border_thickness); - fade_color.rgb = pixel.rgb * (1.0 - f) + fade_color.rgb * f; - return fade_color; - } - } - if (d > check_dist) - pixel.a *= 1.0 - (d - check_dist); - return pixel; - + float bbox = 1.0-max(max(1.0-aastep(-3.0, p.x), aastep(47.0, p.x)), + max(1.0-aastep(-3.0, p.y), aastep(11.0, p.y))); + + // Some relief for the GPU: exit early if we''re in the black margins + if(bbox == 0.0) { + return float4(float3(0.0,0.0,0.0),1.0); } - return float4(0.0,0.0,0.0,0.0); + + // If not, well, let''s put that GPU to good use! + float secs = floor(mod(time, 60.0)); + float mins = floor(mod(time, 3600.0)/60.0); + float hrs = floor(time/3600.0); + int h10 = int(floor(hrs/10.0)); + int h1 = int(floor(mod(hrs, 10.0))); + int m10 = int(floor(mins/10.0)); + int m1 = int(floor(mod(mins, 10.0))); + int s10 = int(floor(secs/10.0)); + int s1 = int(floor(mod(secs, 10.0))); + + float2 wspace = float2(6.5, 0.0); + float2 nspace = float2(3.5, 0.0); + float d = 1e10; + d = min(d, number(h10, p)); + d = min(d, number(h1, p-wspace)); + d = min(d, nixiecolon(p-wspace-1.45*nspace)-0.2); + d = min(d, number(m10, p-2.0*wspace-nspace)); + d = min(d, number(m1, p-3.0*wspace-nspace)); + d = min(d, nixiecolon(p-3.0*wspace-2.4*nspace)-0.2); + d = min(d, number(s10, p-4.0*wspace-2.0*nspace)); + d = min(d, number(s1, p-5.0*wspace-2.0*nspace)); + + float2 g; // For gradients returned from psrdnoise() + + // Digit outlines + float core = 1.0-aastep(0.2, d); + // "flare" is a wide blurry region around the characters, and + // "flarenoise" is a spatio-temporal modulation of its extents + // (slight flickering, but not all characters at the same time) + float flarenoise = psrdnoise(float2(p.x*0.1,5.0*elapsed_time), float2(0.0,0.0), 0.0, g); + float flare = 1.0-smoothstep(0.0, 2.5, d + 0.05*flarenoise); + flare *= flare; // A more rapid decline towards the edge + // "glow" is a variation in the intensity of the glowy cathode (core) + float glow = 0.8+0.2*psrdnoise(p - float2(0.0, 2.0*elapsed_time), float2(0.0,0.0), 4.0*time, g); + // Now we mess up the distance field a little for the "halo" effect + d += 0.1*psrdnoise(p - float2(0.0, 2.0*elapsed_time), float2(0.0,0.0), 8.0*time, g); + d += 0.05*psrdnoise(2.0*p - float2(0.0, 4.0*elapsed_time) + 0.15*g, float2(0.0,0.0), -16.0*time, g); + // "halo" is a kind of flame/plasma cloud near the core. A real Nixie tube + // doesn''t have this, but it adds some appealing visual detail. + // Looks more like hot filaments than "cold cathodes", but... oh, well. + float halo = 1.0-smoothstep(-0.3, 0.3, d); + + // Brittle parameters! This scale/shift of p has a strong impact + // on the pattern at the edges of the grid through "anodefade". + float3 anodedists = hexgrid(1.7*p+float2(0.1,0.23)); + float anodedist = anodedists.y - anodedists.x; // Voronoi cell borders + // Fade the hexagonal holes in the anode towards the edges + float anodefade = max(max(1.0-aasmoothstep(-2.2, -1.5, p.x), aasmoothstep(45.5, 46.2, p.x)), + max(1.0-aasmoothstep(-2.0, -1.6, p.y), aasmoothstep(9.4, 10.0, p.y))); + float anode = 1.0 - aastep(0.1, anodedist - anodefade); + + float anodecolornoise = 0.02*psrdnoise(p*float2(0.2,2.0), float2(0.0,0.0), 0.0, g); + float3 anodecolorresult = anodecolor+ anodecolornoise*anodehighlightscolor; // Long variable names, I know + + float3 mixcolor = float3(0.0,0.0,0.0); // Mix additively from black + mixcolor = lerp(mixcolor, flarecolor, 0.5*flare); + mixcolor = lerp(mixcolor, halocolor, 0.9*halo); + mixcolor = lerp(mixcolor, corecolor, core*glow); + mixcolor = lerp(mixcolor, anodecolorresult, anode); + mixcolor *= bbox; // AA-mask to black at the very edge of the bounding box + return float4(mixcolor,1.0); } + ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -35289,55 +26199,18 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSRoundedRectPerCornerShader { +function Get-OBSColorDepthShader { -[Alias('Set-OBSRoundedRectPerCornerShader','Add-OBSRoundedRectPerCornerShader')] +[Alias('Set-OBSColorDepthShader','Add-OBSColorDepthShader')] param( -# Set the corner_radius_tl of OBSRoundedRectPerCornerShader -[Alias('corner_radius_tl')] -[ComponentModel.DefaultBindingProperty('corner_radius_tl')] -[Int32] -$CornerRadiusTl, -# Set the corner_radius_tr of OBSRoundedRectPerCornerShader -[Alias('corner_radius_tr')] -[ComponentModel.DefaultBindingProperty('corner_radius_tr')] -[Int32] -$CornerRadiusTr, -# Set the corner_radius_br of OBSRoundedRectPerCornerShader -[Alias('corner_radius_br')] -[ComponentModel.DefaultBindingProperty('corner_radius_br')] -[Int32] -$CornerRadiusBr, -# Set the corner_radius_bl of OBSRoundedRectPerCornerShader -[Alias('corner_radius_bl')] -[ComponentModel.DefaultBindingProperty('corner_radius_bl')] -[Int32] -$CornerRadiusBl, -# Set the border_thickness of OBSRoundedRectPerCornerShader -[Alias('border_thickness')] -[ComponentModel.DefaultBindingProperty('border_thickness')] -[Int32] -$BorderThickness, -# Set the border_color of OBSRoundedRectPerCornerShader -[Alias('border_color')] -[ComponentModel.DefaultBindingProperty('border_color')] -[String] -$BorderColor, -# Set the border_alpha_start of OBSRoundedRectPerCornerShader -[Alias('border_alpha_start')] -[ComponentModel.DefaultBindingProperty('border_alpha_start')] -[Single] -$BorderAlphaStart, -# Set the border_alpha_end of OBSRoundedRectPerCornerShader -[Alias('border_alpha_end')] -[ComponentModel.DefaultBindingProperty('border_alpha_end')] +# Set the colorDepth of OBSColorDepthShader +[ComponentModel.DefaultBindingProperty('colorDepth')] [Single] -$BorderAlphaEnd, -# Set the alpha_cut_off of OBSRoundedRectPerCornerShader -[Alias('alpha_cut_off')] -[ComponentModel.DefaultBindingProperty('alpha_cut_off')] +$ColorDepth, +# Set the pixelSize of OBSColorDepthShader +[ComponentModel.DefaultBindingProperty('pixelSize')] [Single] -$AlphaCutOff, +$PixelSize, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -35368,185 +26241,40 @@ $UseShaderTime process { -$shaderName = 'rounded_rect_per_corner' -$ShaderNoun = 'OBSRoundedRectPerCornerShader' +$shaderName = 'color-depth' +$ShaderNoun = 'OBSColorDepthShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -//Converted to OpenGL by Q-mii & Exeldro February 18, 2022 -uniform int corner_radius_tl< - string label = "Corner radius top left"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 200; - int step = 1; ->; -uniform int corner_radius_tr< - string label = "Corner radius top right"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 200; - int step = 1; ->; -uniform int corner_radius_br< - string label = "Corner radius bottom right"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 200; - int step = 1; ->; -uniform int corner_radius_bl< - string label = "Corner radius bottom left"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 200; - int step = 1; ->; -uniform int border_thickness< - string label = "Border thickness"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; ->; -uniform float4 border_color; -uniform float border_alpha_start< - string label = "border alpha start"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 1.0; -uniform float border_alpha_end< - string label = "border alpha end"; +//based on https://www.shadertoy.com/view/tscfWM +uniform float colorDepth< + string label = "Color depth"; string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; -uniform float alpha_cut_off< - string label = "alpha cut off"; + float minimum = 0.01; + float maximum = 100.0; + float step = 0.01; +> = 5.0; + +uniform float pixelSize< + string label = "Pixel Size"; string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.5; + float minimum = 1.0; + float maximum = 100.0; + float step = 0.01; +> = 5.0; + float4 mainImage(VertData v_in) : TARGET { - float4 pixel = image.Sample(textureSampler, v_in.uv); - int closedEdgeX = 0; - int closedEdgeY = 0; - if(pixel.a < alpha_cut_off){ - return float4(1.0,0.0,0.0,0.0); - } - int corner_radius_top = corner_radius_tl>corner_radius_tr?corner_radius_tl:corner_radius_tr; - int corner_radius_right = corner_radius_tr>corner_radius_br?corner_radius_tr:corner_radius_br; - int corner_radius_bottom = corner_radius_bl>corner_radius_br?corner_radius_bl:corner_radius_br; - int corner_radius_left = corner_radius_tl>corner_radius_bl?corner_radius_tl:corner_radius_bl; - - if(image.Sample(textureSampler, v_in.uv + float2(corner_radius_right*uv_pixel_interval.x,0)).a < alpha_cut_off){ - closedEdgeX = corner_radius_right; - }else if(image.Sample(textureSampler, v_in.uv + float2(-corner_radius_left*uv_pixel_interval.x,0)).a < alpha_cut_off){ - closedEdgeX = -corner_radius_left; - } - if(image.Sample(textureSampler, v_in.uv + float2(0,corner_radius_bottom*uv_pixel_interval.y)).a < alpha_cut_off){ - closedEdgeY = corner_radius_bottom; - }else if(image.Sample(textureSampler, v_in.uv + float2(0,-corner_radius_top*uv_pixel_interval.y)).a < alpha_cut_off){ - closedEdgeY = -corner_radius_top; - } - if(closedEdgeX == 0 && closedEdgeY == 0){ - return pixel; - } - if(closedEdgeX != 0){ - [loop] for(int x = 1;x 0 && closedEdgeY < 0){ - corner_radius = corner_radius_tr; - }else if(closedEdgeX > 0 && closedEdgeY > 0){ - corner_radius = corner_radius_br; - }else if(closedEdgeX < 0 && closedEdgeY > 0){ - corner_radius = corner_radius_bl; - } - if(closedEdgeXabs > corner_radius && closedEdgeYabs > corner_radius){ - return pixel; - } - if(closedEdgeXabs == 0){ - if(closedEdgeYabs <= border_thickness){ - float4 fade_color = border_color; - fade_color.a = border_alpha_end + (closedEdgeYabs / border_thickness)*(border_alpha_start-border_alpha_end); - return fade_color; - }else{ - return pixel; - } - } - if(closedEdgeYabs == 0){ - if(closedEdgeXabs <= border_thickness){ - float4 fade_color = border_color; - fade_color.a = border_alpha_end + (closedEdgeXabs / border_thickness)*(border_alpha_start-border_alpha_end); - return fade_color; - }else{ - return pixel; - } - } - if(closedEdgeXabs > corner_radius){ - if(closedEdgeYabs <= border_thickness){ - float4 fade_color = border_color; - fade_color.a = border_alpha_end + (closedEdgeYabs / border_thickness)*(border_alpha_start-border_alpha_end); - return fade_color; - }else{ - return pixel; - } - } - if(closedEdgeYabs > corner_radius){ - if(closedEdgeXabs <= border_thickness){ - float4 fade_color = border_color; - fade_color.a = border_alpha_end + (closedEdgeXabs / border_thickness)*(border_alpha_start-border_alpha_end); - return fade_color; - }else{ - return pixel; - } - } - float d = distance(float2(closedEdgeXabs, closedEdgeYabs), float2(corner_radius,corner_radius)); - if(d = "Choose LUT, Default LUT amount is 100, scale = 100, offset = 0. Valid values: -200 to 200"; + +uniform texture2d lut< + string label = "LUT"; >; -uniform int corner_radius_left< - string label = "Corner radius left"; +uniform int lut_amount_percent< + string label = "LUT amount percentage"; string widget_type = "slider"; - int minimum = 0; + int minimum = -200; int maximum = 200; int step = 1; ->; -uniform int corner_radius_top< - string label = "Corner radius top"; +> = 100; +uniform int lut_scale_percent< + string label = "LUT scale percentage"; string widget_type = "slider"; - int minimum = 0; + int minimum = -200; int maximum = 200; int step = 1; ->; -uniform int corner_radius_right< - string label = "Corner radius right"; +> = 100; +uniform int lut_offset_percent< + string label = "LUT offset percentage"; string widget_type = "slider"; - int minimum = 0; + int minimum = -200; int maximum = 200; int step = 1; ->; -uniform int border_thickness< - string label = "Border thickness"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; ->; -uniform float4 border_color; -uniform float border_alpha_start< - string label = "border alpha start"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 1.0; -uniform float border_alpha_end< - string label = "border alpha end"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; -uniform float alpha_cut_off< - string label = "alpha cut off"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.5; +> = 0; + float4 mainImage(VertData v_in) : TARGET { - float4 output_color = image.Sample(textureSampler, v_in.uv); - int closedEdgeX = 0; - int closedEdgeY = 0; - if(output_color.a < alpha_cut_off){ - return float4(1.0,0.0,0.0,0.0); - } - if(image.Sample(textureSampler, v_in.uv + float2(corner_radius_right*uv_pixel_interval.x,0)).a < alpha_cut_off){ - closedEdgeX = corner_radius_right; - }else if(image.Sample(textureSampler, v_in.uv + float2(-corner_radius_left*uv_pixel_interval.x,0)).a < alpha_cut_off){ - closedEdgeX = -corner_radius_left; - } - if(image.Sample(textureSampler, v_in.uv + float2(0,corner_radius_bottom*uv_pixel_interval.y)).a < alpha_cut_off){ - closedEdgeY = corner_radius_bottom; - }else if(image.Sample(textureSampler, v_in.uv + float2(0,-corner_radius_top*uv_pixel_interval.y)).a < alpha_cut_off){ - closedEdgeY = -corner_radius_top; - } - if(closedEdgeX == 0 && closedEdgeY == 0){ - return output_color; - } - if(closedEdgeX != 0){ - [loop] for(int x = 1;x corner_radius){ - closedEdgeXabs = 0; - } - if(closedEdgeYabs > corner_radius){ - closedEdgeYabs = 0; - } - if(closedEdgeXabs == 0 && closedEdgeYabs == 0){ - return output_color; - } - if(closedEdgeXabs == 0){ - if(closedEdgeYabs <= border_thickness){ - float4 fade_color = border_color; - fade_color.a = border_alpha_end + (float(closedEdgeYabs) / float(border_thickness))*(border_alpha_start-border_alpha_end); - return fade_color; - }else{ - return output_color; - } - } - if(closedEdgeYabs == 0){ - if(closedEdgeXabs <= border_thickness){ - float4 fade_color = border_color; - fade_color.a = border_alpha_end + (float(closedEdgeXabs) / float(border_thickness))*(border_alpha_start-border_alpha_end); - return fade_color; - }else{ - return output_color; - } - } + float lut_amount = clamp(lut_amount_percent *.01, -2.0, 2.0); + float lut_scale = clamp(lut_scale_percent *.01,-2.0, 2.0); + float lut_offset = clamp(lut_offset_percent *.01,-2.0, 2.0); - float closest = closedEdgeXabs +// Twitch: +// +// Based on: +// Original work by Inigo Quilez: https://www.iquilezles.org/www/articles/ibilinear/ibilinear.htm +// https://www.youtube.com/c/InigoQuilez +// https://iquilezles.org/ +// and the derivative StreamFX Corner Pin effect by Xaymar +// https://github.com/Xaymar/obs-StreamFX +// +// Description: +// Corner Pin allows you to pin the corners of an image onto the corners of an arbitrarily +// angled picture frame, TV screen or other rectangular surface in 3D space in an underlying +// image with proper perspective without distortion. +// +// TODO: +// - Add feature to automatically quantize corners to pixel centers +// +// Changelog: +// 0.1 - Initial release based on the StreamFX Corner Pin effect, as well as the original work by +// Inigo Quilez that it was based upon. + +uniform bool Antialias_Edges = true; + +uniform float Top_Left_X< + string label = "Top left x"; string widget_type = "slider"; - int minimum = 0; - int maximum = 200; - int step = 1; ->; -uniform int border_thickness< - string label = "border thickness"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.1; +> = -100.; +uniform float Top_Left_Y< + string label = "Top left y"; string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; ->; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.1; +> = -100.; +uniform float Top_Right_X< + string label = "Top right x"; + string widget_type = "slider"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.1; +> = 100.; +uniform float Top_Right_Y< + string label = "Top right y"; + string widget_type = "slider"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.1; +> = -100.; +uniform float Bottom_Left_X< + string label = "Bottom left x"; + string widget_type = "slider"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.1; +> = -100.; +uniform float Bottom_Left_Y< + string label = "Bottom left y"; + string widget_type = "slider"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.1; +> = 100.; +uniform float Bottom_Right_X< + string label = "Bottom right x"; + string widget_type = "slider"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.1; +> = 100.; +uniform float Bottom_Right_Y< + string label = "Bottom right y"; + string widget_type = "slider"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.1; +> = 100.; -uniform float4 border_color; +// DEVELOPMENTAL DEBUGGING OPTIONS +//uniform float AAstrength = 1.0; +//uniform float AAdist = 1.0; +//uniform float debug_psmult = 1.0; +//#define PIXEL_SIZE_MULT 2.0 -float4 mainImage(VertData v_in) : TARGET +float cross2d(in float2 a, in float2 b) { - float2 mirrored_tex_coord = float2(0.5, 0.5) - abs(v_in.uv - float2(0.5, 0.5)); - float4 output_color = image.Sample(textureSampler, v_in.uv); - - float2 pixel_position = float2(mirrored_tex_coord.x / uv_pixel_interval.x, mirrored_tex_coord.y / uv_pixel_interval.y); - float pixel_distance_from_center = distance(pixel_position, float2(corner_radius, corner_radius)); - - bool is_in_corner = pixel_position.x < corner_radius && pixel_position.y < corner_radius; - bool is_within_radius = pixel_distance_from_center <= corner_radius; - - bool is_within_edge_border = !is_in_corner && (pixel_position.x < 0 && pixel_position.x >= -border_thickness || pixel_position.y < 0 && pixel_position.y >= -border_thickness); - bool is_within_corner_border = is_in_corner && pixel_distance_from_center > corner_radius && pixel_distance_from_center <= (corner_radius + border_thickness); - - return ((!is_in_corner || is_within_radius)?output_color:float4(0,0,0,0)) + ((is_within_edge_border || is_within_corner_border)?border_color:float4(0,0,0,0)); + return (a.x * b.y) - (a.y * b.x); +} + +float2 inverse_bilinear(in float2 p, in float2 a, in float2 b, in float2 c, in float2 d) +{ + float2 result = float2(-1., -1.); + + float2 e = b - a; + float2 f = d - a; + float2 g = a-b+c-d; + float2 h = p-a; + + float k2 = cross2d(g, f); + float k1 = cross2d(e, f) + cross2d(h, g); + float k0 = cross2d(h, e); + + if (abs(k2) < .001) { // Edges are likely parallel, so this is a linear equation. + result = float2( + (h.x * k1 + f.x * k0) / (e.x * k1 - g.x * k0), + -k0 / k1 + ); + } else { // It''s a quadratic equation. + float w = k1 * k1 - 4.0 * k0 * k2; + if (w < 0.0) { // Prevent GPUs from going insane. + return result; + } + w = sqrt(w); + + float ik2 = 0.5/k2; + float v = (-k1 - w) * ik2; + float u = (h.x - f.x * v) / (e.x + g.x * v); + + if (u < 0.0 || u > 1.0 || v < 0.0 || v > 1.0) { + v = (-k1 + w) * ik2; + u = (h.x - f.x * v) / (e.x + g.x * v); + } + + result = float2(u, v); + } + + return result; +} + +// distance to a line segment +float sdSegment( in float2 p, in float2 a, in float2 b ) +{ + p -= a; b -= a; + return length( p-b*saturate(dot(p,b)/dot(b,b)) ); +} + +// Anti-alias edges - EXPERIMENTAL - (SkeletonBow) +float aastepEdgeAlpha(in float alpha, in float2 p, in float2 a, in float2 b) +{ + //float ps = 2.0 * (2.0/uv_size.y); // Original +// float ps = debug_psmult * (2.0/uv_size.y); + float ps = (2.0/uv_size.y); +// float ps = fwidth(p)*2.; // Try using fwidth() - goes haywire on AMD Radeon HD7850 at least, disable for now + return lerp( alpha, 0.0, 1.0 - smoothstep(0.0,ps,sdSegment(p,a,b))); +} + +float4 mainImage( VertData v_in ) : TARGET { + float2 p = 2.* v_in.uv - 1.; + + float2 Top_Left = float2(Top_Left_X, Top_Left_Y) * .01; + float2 Top_Right = float2(Top_Right_X, Top_Right_Y) * .01; + float2 Bottom_Left = float2(Bottom_Left_X, Bottom_Left_Y) * .01; + float2 Bottom_Right = float2(Bottom_Right_X, Bottom_Right_Y) * .01; + + // Convert from screen coords to potential Quad UV coordinates + float2 uv = inverse_bilinear(p, Top_Left, Top_Right, Bottom_Right, Bottom_Left); + + if (max(abs(uv.x - .5), abs(uv.y - .5)) >= .5) { + return float4(0.0, 0.0, 0.0, 0.0); + } + + float4 texel = image.Sample(textureSampler, uv); + + if ( Antialias_Edges ) { + // Anti-alias edges of texture + texel.a = aastepEdgeAlpha(texel.a, p, Top_Left, Top_Right); + texel.a = aastepEdgeAlpha(texel.a, p, Top_Right, Bottom_Right); + texel.a = aastepEdgeAlpha(texel.a, p, Bottom_Right, Bottom_Left); + texel.a = aastepEdgeAlpha(texel.a, p, Bottom_Left, Top_Left); + } + return texel; } ' @@ -36163,54 +26960,22 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSRoundedStrokeGradientShader { +function Get-OBSCrtCurvatureShader { -[Alias('Set-OBSRoundedStrokeGradientShader','Add-OBSRoundedStrokeGradientShader')] +[Alias('Set-OBSCrtCurvatureShader','Add-OBSCrtCurvatureShader')] param( -# Set the corner_radius of OBSRoundedStrokeGradientShader -[Alias('corner_radius')] -[ComponentModel.DefaultBindingProperty('corner_radius')] -[Int32] -$CornerRadius, -# Set the border_thickness of OBSRoundedStrokeGradientShader -[Alias('border_thickness')] -[ComponentModel.DefaultBindingProperty('border_thickness')] -[Int32] -$BorderThickness, -# Set the minimum_alpha_percent of OBSRoundedStrokeGradientShader -[Alias('minimum_alpha_percent')] -[ComponentModel.DefaultBindingProperty('minimum_alpha_percent')] -[Int32] -$MinimumAlphaPercent, -# Set the rotation_speed of OBSRoundedStrokeGradientShader -[Alias('rotation_speed')] -[ComponentModel.DefaultBindingProperty('rotation_speed')] -[Int32] -$RotationSpeed, -# Set the border_colorL of OBSRoundedStrokeGradientShader -[Alias('border_colorL')] -[ComponentModel.DefaultBindingProperty('border_colorL')] -[String] -$BorderColorL, -# Set the border_colorR of OBSRoundedStrokeGradientShader -[Alias('border_colorR')] -[ComponentModel.DefaultBindingProperty('border_colorR')] -[String] -$BorderColorR, -# Set the center_width of OBSRoundedStrokeGradientShader -[Alias('center_width')] -[ComponentModel.DefaultBindingProperty('center_width')] -[Int32] -$CenterWidth, -# Set the center_height of OBSRoundedStrokeGradientShader -[Alias('center_height')] -[ComponentModel.DefaultBindingProperty('center_height')] -[Int32] -$CenterHeight, -# Set the notes of OBSRoundedStrokeGradientShader -[ComponentModel.DefaultBindingProperty('notes')] +# Set the strength of OBSCrtCurvatureShader +[ComponentModel.DefaultBindingProperty('strength')] +[Single] +$Strength, +# Set the border of OBSCrtCurvatureShader +[ComponentModel.DefaultBindingProperty('border')] [String] -$Notes, +$Border, +# Set the feathering of OBSCrtCurvatureShader +[ComponentModel.DefaultBindingProperty('feathering')] +[Single] +$Feathering, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -36241,198 +27006,286 @@ $UseShaderTime process { -$shaderName = 'rounded_stroke_gradient' -$ShaderNoun = 'OBSRoundedStrokeGradientShader' +$shaderName = 'crt-curvature' +$ShaderNoun = 'OBSCrtCurvatureShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -//rounded rectange shader from https://raw.githubusercontent.com/exeldro/obs-lua/master/rounded_rect.shader -//modified slightly by Surn -uniform int corner_radius< - string label = "Corner radius"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 200; - int step = 1; ->; -uniform int border_thickness< - string label = "Border thickness"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; ->; -uniform int minimum_alpha_percent< - string label = "Minimum alpha percent"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; -uniform int rotation_speed< - string label = "rotation speed"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; ->; -uniform float4 border_colorL; -uniform float4 border_colorR; -//uniform float color_spread = 2.0; -uniform int center_width< - string label = "center width"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; -uniform int center_height< - string label = "center height"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; -uniform string notes< - string widget_type = "info"; -> = "Outlines the opaque areas with a rounded border. Default Minimum Alpha Percent is 50%, lowering will reveal more"; +uniform float strength< + string label = "Strength"; + string widget_type = "slider"; + float minimum = 0.; + float maximum = 200.; + float step = 0.01; +> = 33.33; -// float3 hsv2rgb(float3 c) -// { -// float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); -// float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www); -// return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y); -// } +uniform float4 border< + string label = "Border Color"; +> = {0., 0., 0., 1.}; -float mod(float x, float y) +uniform float feathering< + string label = "Feathering"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 33.33; + + +float4 mainImage(VertData v_in) : TARGET { - return x - y * floor(x/y); + float2 cc = v_in.uv - float2(0.5, 0.5); + float dist = dot(cc, cc) * strength / 100.0; + float2 bent = v_in.uv + cc * (1.0 + dist) * dist; + if ((bent.x <= 0.0 || bent.x >= 1.0) || (bent.y <= 0.0 || bent.y >= 1.0)) { + return border; + } + if (feathering >= .01) { + float2 borderArea = float2(0.5, 0.5) * feathering / 100.0; + float2 borderDistance = (float2(0.5, 0.5) - abs(bent - float2(0.5, 0.5))) / float2(0.5, 0.5); + borderDistance = (min(borderDistance - float2(0.5, 0.5) * feathering / 100.0, 0) + borderArea) / borderArea; + float borderFade = sin(borderDistance.x * 1.570796326) * sin(borderDistance.y * 1.570796326); + return lerp(border, image.Sample(textureSampler, bent), borderFade); + } + + return image.Sample(textureSampler, bent); } -float4 gradient(float c) { - c = mod(c , 2.0); - if(c < 0.0f){ - c = c * -1.0; +' +} +$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 + } } - if(c > 1.0){ - c = 1.0 - c; - if(c < 0.0f){ - c = c + 1.0; + '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 } } - return lerp(border_colorL, border_colorR, c); } -float4 getBorderColor(float2 toCenter){ - float angle = atan2(toCenter.y ,toCenter.x ); - float angleMod = (elapsed_time * mod(float(rotation_speed) , 18.0)) / 9; - return gradient((angle / 3.14159265f) + angleMod); } -float4 mainImage(VertData v_in) : TARGET -{ - float2 st = v_in.uv * uv_scale; - float2 center_pixel_coordinates = float2((float(center_width) * 0.01), (float(center_height) * 0.01) ); - float2 toCenter = center_pixel_coordinates - st; - float min_alpha = clamp(minimum_alpha_percent * .01, -1.0, 101.0); - float4 output_color = image.Sample(textureSampler, v_in.uv); - if (output_color.a < min_alpha) - { - return float4(0.0, 0.0, 0.0, 0.0); - } - int closedEdgeX = 0; - if (image.Sample(textureSampler, v_in.uv + float2(corner_radius * uv_pixel_interval.x, 0)).a < min_alpha) - { - closedEdgeX = corner_radius; - } - else if (image.Sample(textureSampler, v_in.uv + float2(-corner_radius * uv_pixel_interval.x, 0)).a < min_alpha) - { - closedEdgeX = corner_radius; - } - int closedEdgeY = 0; - if (image.Sample(textureSampler, v_in.uv + float2(0, corner_radius * uv_pixel_interval.y)).a < min_alpha) - { - closedEdgeY = corner_radius; - } - else if (image.Sample(textureSampler, v_in.uv + float2(0, -corner_radius * uv_pixel_interval.y)).a < min_alpha) - { - closedEdgeY = corner_radius; - } - if (closedEdgeX == 0 && closedEdgeY == 0) - { - return output_color; - } - if (closedEdgeX != 0) - { - [loop] - for (int x = 1; x < corner_radius; x++) - { - if (image.Sample(textureSampler, v_in.uv + float2(x * uv_pixel_interval.x, 0)).a < min_alpha) - { - closedEdgeX = x; - break; - } - if (image.Sample(textureSampler, v_in.uv + float2(-x * uv_pixel_interval.x, 0)).a < min_alpha) - { - closedEdgeX = x; - break; - } - } - } - if (closedEdgeY != 0) - { - [loop] - for (int y = 1; y < corner_radius; y++) - { - if (image.Sample(textureSampler, v_in.uv + float2(0, y * uv_pixel_interval.y)).a < min_alpha) - { - closedEdgeY = y; - break; - } - if (image.Sample(textureSampler, v_in.uv + float2(0, -y * uv_pixel_interval.y)).a < min_alpha) - { - closedEdgeY = y; - break; - } - } - } - if (closedEdgeX == 0) - { - if (closedEdgeY < border_thickness) - { - return getBorderColor(toCenter); - } - else - { - return output_color; - } - } - if (closedEdgeY == 0) - { - if (closedEdgeX < border_thickness) - { - return getBorderColor(toCenter); - } - else - { - return output_color; - } - } +} - float d = distance(float2(closedEdgeX, closedEdgeY), float2(corner_radius, corner_radius)); - if (d < corner_radius) - { - if (corner_radius - d < border_thickness) - { - return getBorderColor(toCenter); - } - else - { - return output_color; - } - } - return float4(0.0, 0.0, 0.0, 0.0); + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSCubeRotatingShader { + +[Alias('Set-OBSCubeRotatingShader','Add-OBSCubeRotatingShader')] +param( +# Set the images of OBSCubeRotatingShader +[ComponentModel.DefaultBindingProperty('images')] +[Int32] +$Images, +# Set the speed of OBSCubeRotatingShader +[ComponentModel.DefaultBindingProperty('speed')] +[Single] +$Speed, +# Set the shadow of OBSCubeRotatingShader +[ComponentModel.DefaultBindingProperty('shadow')] +[Single] +$Shadow, +# Set the other_image1 of OBSCubeRotatingShader +[Alias('other_image1')] +[ComponentModel.DefaultBindingProperty('other_image1')] +[String] +$OtherImage1, +# Set the other_image2 of OBSCubeRotatingShader +[Alias('other_image2')] +[ComponentModel.DefaultBindingProperty('other_image2')] +[String] +$OtherImage2, +# Set the other_image3 of OBSCubeRotatingShader +[Alias('other_image3')] +[ComponentModel.DefaultBindingProperty('other_image3')] +[String] +$OtherImage3, +# 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 = 'cube_rotating' +$ShaderNoun = 'OBSCubeRotatingShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform int images< + string label = "Images"; + string widget_type = "select"; + int option_0_value = 1; + string option_0_label = "1"; + int option_1_value = 2; + string option_1_label = "2"; + int option_2_value = 4; + string option_2_label = "4"; +> = 1; + +uniform float speed< + string label = "Speed"; + string widget_type = "slider"; + float minimum = -5.0; + float maximum = 5.0; + float step = 0.001; +> = 0.5; + +uniform float shadow< + string label = "Shadow"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 2.5; + float step = 0.001; +> = 1.0; + +uniform texture2d other_image1; +uniform texture2d other_image2; +uniform texture2d other_image3; + +#define PI 3.14159265359 +float4 mainImage(VertData v_in) : TARGET +{ + float t = elapsed_time * speed; + float4 c = float4(0,0,0,0); + for(float side = 0.0; side<4.0; side += 1.0){ + float left = cos(t+((side*0.5-0.25)*PI))/2+0.5; + float right = cos(t+((side*0.5+0.25)*PI))/2+0.5; + if(left < right){ + float2 uv; + uv.x = (v_in.uv.x-left)/(right-left); + float left_size = 1.0 +sin(t+((side*0.5-0.25)*PI))/2+0.5; + float right_size = 1.0 + sin(t+((side*0.5+0.25)*PI))/2+0.5; + float size = (uv.x * right_size) + ((1.0-uv.x) * left_size); + uv.y = (v_in.uv.y-0.5)*size+0.5; + float4 sample = float4(0,0,0,0); + if(images <= 1 || side == 0.0){ + sample = image.Sample(textureSampler, uv); + }else if(images == 2){ + if(side == 1.0 || side == 3.0){ + sample = other_image1.Sample(textureSampler, uv); + }else{ + sample = image.Sample(textureSampler, uv); + } + }else if(images == 4){ + if(side == 1.0){ + sample = other_image1.Sample(textureSampler, uv); + }else if(side == 2.0){ + sample = other_image2.Sample(textureSampler, uv); + }else if(side == 3.0){ + sample = other_image3.Sample(textureSampler, uv); + }else{ + sample = image.Sample(textureSampler, uv); + } + } + if(sample.a > 0.0){ + c += float4(sample.rgb*(1.0-abs((left+right)/2.0-0.5)*shadow),sample.a); + } + } + } + return c; } + ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -36530,34 +27383,23 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSRoundedStrokeShader { +function Get-OBSCurveShader { -[Alias('Set-OBSRoundedStrokeShader','Add-OBSRoundedStrokeShader')] +[Alias('Set-OBSCurveShader','Add-OBSCurveShader')] param( -# Set the corner_radius of OBSRoundedStrokeShader -[Alias('corner_radius')] -[ComponentModel.DefaultBindingProperty('corner_radius')] -[Int32] -$CornerRadius, -# Set the border_thickness of OBSRoundedStrokeShader -[Alias('border_thickness')] -[ComponentModel.DefaultBindingProperty('border_thickness')] -[Int32] -$BorderThickness, -# Set the minimum_alpha_percent of OBSRoundedStrokeShader -[Alias('minimum_alpha_percent')] -[ComponentModel.DefaultBindingProperty('minimum_alpha_percent')] -[Int32] -$MinimumAlphaPercent, -# Set the border_color of OBSRoundedStrokeShader -[Alias('border_color')] -[ComponentModel.DefaultBindingProperty('border_color')] -[String] -$BorderColor, -# Set the notes of OBSRoundedStrokeShader -[ComponentModel.DefaultBindingProperty('notes')] +# Set the strength of OBSCurveShader +[ComponentModel.DefaultBindingProperty('strength')] +[Single] +$Strength, +# Set the scale of OBSCurveShader +[ComponentModel.DefaultBindingProperty('scale')] +[Single] +$Scale, +# Set the curve_color of OBSCurveShader +[Alias('curve_color')] +[ComponentModel.DefaultBindingProperty('curve_color')] [String] -$Notes, +$CurveColor, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -36588,139 +27430,50 @@ $UseShaderTime process { -$shaderName = 'rounded_stroke' -$ShaderNoun = 'OBSRoundedStrokeShader' +$shaderName = 'curve' +$ShaderNoun = 'OBSCurveShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -//rounded rectange shader from https://raw.githubusercontent.com/exeldro/obs-lua/master/rounded_rect.shader -//modified slightly by Surn -//Converted to OpenGl by Q-mii & Exeldro February 21, 2022 -uniform int corner_radius< - string label = "Corner radius"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 200; - int step = 1; ->; -uniform int border_thickness< - string label = "border thickness"; +#define PI 3.14159265359 + +uniform float strength< + string label = "Strength"; string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; ->; -uniform int minimum_alpha_percent< - string label = "Minimum alpha percent"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.5; + +uniform float scale< + string label = "Scale"; string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; -uniform float4 border_color; -uniform string notes< - string widget_type = "info"; -> = "Outlines the opaque areas with a rounded border. Default Minimum Alpha Percent is 50%, lowering will reveal more"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 1.0; + +uniform float4 curve_color = {0,0,0,0}; float4 mainImage(VertData v_in) : TARGET { - float min_alpha = clamp(minimum_alpha_percent * .01, -1.0, 101.0); - float4 output_color = image.Sample(textureSampler, v_in.uv); - if (output_color.a < min_alpha) - { - return float4(0.0, 0.0, 0.0, 0.0); - } - int closedEdgeX = 0; - if (image.Sample(textureSampler, v_in.uv + float2(corner_radius * uv_pixel_interval.x, 0)).a < min_alpha) - { - closedEdgeX = corner_radius; - } - else if (image.Sample(textureSampler, v_in.uv + float2(-corner_radius * uv_pixel_interval.x, 0)).a < min_alpha) - { - closedEdgeX = corner_radius; - } - int closedEdgeY = 0; - if (image.Sample(textureSampler, v_in.uv + float2(0, corner_radius * uv_pixel_interval.y)).a < min_alpha) - { - closedEdgeY = corner_radius; - } - else if (image.Sample(textureSampler, v_in.uv + float2(0, -corner_radius * uv_pixel_interval.y)).a < min_alpha) - { - closedEdgeY = corner_radius; - } - if (closedEdgeX == 0 && closedEdgeY == 0) - { - return float4(output_color); - } - if (closedEdgeX != 0) - { - [loop] - for (int x = 1; x < corner_radius; x++) - { - if (image.Sample(textureSampler, v_in.uv + float2(x * uv_pixel_interval.x, 0)).a < min_alpha) - { - closedEdgeX = x; - break; - } - if (image.Sample(textureSampler, v_in.uv + float2(-x * uv_pixel_interval.x, 0)).a < min_alpha) - { - closedEdgeX = x; - break; - } - } - } - if (closedEdgeY != 0) - { - [loop] - for (int y = 1; y < corner_radius; y++) - { - if (image.Sample(textureSampler, v_in.uv + float2(0, y * uv_pixel_interval.y)).a < min_alpha) - { - closedEdgeY = y; - break; - } - if (image.Sample(textureSampler, v_in.uv + float2(0, -y * uv_pixel_interval.y)).a < min_alpha) - { - closedEdgeY = y; - break; - } - } - } - if (closedEdgeX == 0) - { - if (closedEdgeY < border_thickness) - { - return border_color; - } - else - { - return float4(output_color); - } - } - if (closedEdgeY == 0) - { - if (closedEdgeX < border_thickness) - { - return border_color; - } - else - { - return float4(output_color); - } - } - - float d = distance(float2(closedEdgeX, closedEdgeY), float2(corner_radius, corner_radius)); - if (d < corner_radius) - { - if (corner_radius - d < border_thickness) - { - return border_color; - } - else - { - return output_color; - } + float2 uv = v_in.uv; + const float ydiff = 1.0; + uv -= float2(0.5,ydiff); + uv.x *= ( uv_size.x / uv_size.y); + uv /= scale; + if(strength > 0.0){ + float d = tan((1.0-strength)*PI/2.0); + float r = length(float2(0.5*(uv_size.x / uv_size.y), d)); + float2 center = float2(0.0,(1.0-ydiff)+d); + float pd = distance(uv, center); + if(pd < r) + return curve_color; + float angle = atan2(center.x-uv.x,center.y-uv.y); + uv = float2(uv.x + sin(angle)*(pd-r),(1.0-ydiff)-(pd-r)); } - return float4(0.0, 0.0, 0.0, 0.0); + uv.x /= ( uv_size.x / uv_size.y); + uv += float2(0.5,ydiff); + return image.Sample(textureSampler,uv); } ' } @@ -36819,46 +27572,55 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSScanLineShader { +function Get-OBSCutRectPerCornerShader { -[Alias('Set-OBSScanLineShader','Add-OBSScanLineShader')] +[Alias('Set-OBSCutRectPerCornerShader','Add-OBSCutRectPerCornerShader')] param( -# Set the lengthwise of OBSScanLineShader -[ComponentModel.DefaultBindingProperty('lengthwise')] -[Management.Automation.SwitchParameter] -$Lengthwise, -# Set the animate of OBSScanLineShader -[ComponentModel.DefaultBindingProperty('animate')] -[Management.Automation.SwitchParameter] -$Animate, -# Set the speed of OBSScanLineShader -[ComponentModel.DefaultBindingProperty('speed')] -[Single] -$Speed, -# Set the angle of OBSScanLineShader -[ComponentModel.DefaultBindingProperty('angle')] +# Set the corner_tl of OBSCutRectPerCornerShader +[Alias('corner_tl')] +[ComponentModel.DefaultBindingProperty('corner_tl')] +[Int32] +$CornerTl, +# Set the corner_tr of OBSCutRectPerCornerShader +[Alias('corner_tr')] +[ComponentModel.DefaultBindingProperty('corner_tr')] +[Int32] +$CornerTr, +# Set the corner_br of OBSCutRectPerCornerShader +[Alias('corner_br')] +[ComponentModel.DefaultBindingProperty('corner_br')] +[Int32] +$CornerBr, +# Set the corner_bl of OBSCutRectPerCornerShader +[Alias('corner_bl')] +[ComponentModel.DefaultBindingProperty('corner_bl')] +[Int32] +$CornerBl, +# Set the border_thickness of OBSCutRectPerCornerShader +[Alias('border_thickness')] +[ComponentModel.DefaultBindingProperty('border_thickness')] +[Int32] +$BorderThickness, +# Set the border_color of OBSCutRectPerCornerShader +[Alias('border_color')] +[ComponentModel.DefaultBindingProperty('border_color')] +[String] +$BorderColor, +# Set the border_alpha_start of OBSCutRectPerCornerShader +[Alias('border_alpha_start')] +[ComponentModel.DefaultBindingProperty('border_alpha_start')] [Single] -$Angle, -# Set the shift of OBSScanLineShader -[ComponentModel.DefaultBindingProperty('shift')] -[Management.Automation.SwitchParameter] -$Shift, -# Set the boost of OBSScanLineShader -[ComponentModel.DefaultBindingProperty('boost')] -[Management.Automation.SwitchParameter] -$Boost, -# Set the floor of OBSScanLineShader -[ComponentModel.DefaultBindingProperty('floor')] +$BorderAlphaStart, +# Set the border_alpha_end of OBSCutRectPerCornerShader +[Alias('border_alpha_end')] +[ComponentModel.DefaultBindingProperty('border_alpha_end')] [Single] -$Floor, -# Set the period of OBSScanLineShader -[ComponentModel.DefaultBindingProperty('period')] +$BorderAlphaEnd, +# Set the alpha_cut_off of OBSCutRectPerCornerShader +[Alias('alpha_cut_off')] +[ComponentModel.DefaultBindingProperty('alpha_cut_off')] [Single] -$Period, -# Set the notes of OBSScanLineShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, +$AlphaCutOff, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -36889,106 +27651,186 @@ $UseShaderTime process { -$shaderName = 'scan_line' -$ShaderNoun = 'OBSScanLineShader' +$shaderName = 'cut_rect_per_corner' +$ShaderNoun = 'OBSCutRectPerCornerShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Scan Line Effect for OBS Studio -// originally from Andersama (https://github.com/Andersama) -// Modified and improved my Charles Fettinger (https://github.com/Oncorporation) 1/2019 -//Converted to OpenGL by Q-mii & Exeldro February 21, 2022 -//Count the number of scanlines we want via height or width, adjusts the sin wave period -uniform bool lengthwise; -//Do we want the scanlines to move? -uniform bool animate; -//How fast do we want those scanlines to move? -uniform float speed< - string label = "Speed"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10000.0; - float step = 1; -> = 1000; -//What angle should the scanlines come in at (based in degrees) -uniform float angle< - string label = "angle"; +//Converted to OpenGL by Q-mii & Exeldro February 18, 2022 +uniform int corner_tl< + string label = "Corner top left"; string widget_type = "slider"; - float minimum = 0.0; - float maximum = 360.0; - float step = 0.1; -> = 45; -//Turns on adjustment of the results, sin returns -1 -> 1 these settings will change the results a bit -//By default values for color range from 0 to 1 -//Boost centers the result of the sin wave on 1*, to help maintain the brightness of the screen -uniform bool shift = true; -uniform bool boost = true; -//Increases the minimum value of the sin wave -uniform float floor< - string label = "Floor"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 0; +uniform int corner_tr< + string label = "Corner top right"; string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.001; -> = 0.0; -//final adjustment to the period of the sin wave, we can''t / 0, need to be careful w/ user input -uniform float period< - string label = "Period"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 0; +uniform int corner_br< + string label = "Corner bottom right"; string widget_type = "slider"; - float minimum = 1.0; - float maximum = 1000.0; - float step = 1.0; -> = 10.0; -uniform string notes< - string widget_type = "info"; -> = "floor affects the minimum opacity of the scan line"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 0; +uniform int corner_bl< + string label = "Corner bottom left"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 0; +uniform int border_thickness< + string label = "Border thickness"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 0; +uniform float4 border_color; +uniform float border_alpha_start< + string label = "Border aplha start"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 1.0; +uniform float border_alpha_end< + string label = "Border aplha start"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.0; +uniform float alpha_cut_off< + string label = "Alpha cut off"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.5; + float4 mainImage(VertData v_in) : TARGET { - //3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481 3.141592653589793238462643383279502884197169399375105820974944592307816406286 - // float pix2 = 6.2831853071795864769252;//86766559005768394338798750211641949 - float nfloor = clamp(floor, 0.0, 100.0) * 0.01; - float nperiod = max(period, 1.0); - float gap = 1 - nfloor; - float pi = 3.1415926535897932384626; - float2 direction = float2( cos(angle * pi / 180.0) , sin(angle * pi / 180.0) ); - float nspeed = 0.0; - if(animate){ - nspeed = speed * 0.0001; - } - - float4 color = image.Sample(textureSampler, v_in.uv); - - float t = elapsed_time * nspeed; - - if(!lengthwise){ - float base_height = 1.0 / uv_pixel_interval.y; - float h_interval = pi * base_height; - - float rh_sin = sin(((v_in.uv.y * direction.y + v_in.uv.x * direction.x) + t) * (h_interval / nperiod)); - if(shift){ - rh_sin = ((1.0 + rh_sin) * 0.5) * gap + nfloor; - if(boost){ - rh_sin += gap * 0.5; - } - } - float4 s_mult = float4(rh_sin,rh_sin,rh_sin,1); - return s_mult * color; - } - else{ - float base_width = 1.0 / uv_pixel_interval.x; - float w_interval = pi * base_width; - - float rh_sin = sin(((v_in.uv.y * direction.y + v_in.uv.x * direction.x) + t) * (w_interval / nperiod)); - if(shift){ - rh_sin = ((1.0 + rh_sin) * 0.5) * gap + nfloor; - if(boost){ - rh_sin += gap * 0.5; - } - } - float4 s_mult = float4(rh_sin,rh_sin,rh_sin,1); - return s_mult * color; - } + float4 pixel = image.Sample(textureSampler, v_in.uv); + int closedEdgeX = 0; + int closedEdgeY = 0; + if(pixel.a < alpha_cut_off){ + return float4(1.0,0.0,0.0,0.0); + } + int corner_top = corner_tl>corner_tr?corner_tl:corner_tr; + int corner_right = corner_tr>corner_br?corner_tr:corner_br; + int corner_bottom = corner_bl>corner_br?corner_bl:corner_br; + int corner_left = corner_tl>corner_bl?corner_tl:corner_bl; + + if(image.Sample(textureSampler, v_in.uv + float2(corner_right*uv_pixel_interval.x,0)).a < alpha_cut_off){ + closedEdgeX = corner_right; + }else if(image.Sample(textureSampler, v_in.uv + float2(-corner_left*uv_pixel_interval.x,0)).a < alpha_cut_off){ + closedEdgeX = -corner_left; + } + if(image.Sample(textureSampler, v_in.uv + float2(0,corner_bottom*uv_pixel_interval.y)).a < alpha_cut_off){ + closedEdgeY = corner_bottom; + }else if(image.Sample(textureSampler, v_in.uv + float2(0,-corner_top*uv_pixel_interval.y)).a < alpha_cut_off){ + closedEdgeY = -corner_top; + } + if(closedEdgeX == 0 && closedEdgeY == 0){ + return pixel; + } + if(closedEdgeX != 0){ + [loop] for(int x = 1;x 0 && closedEdgeY < 0){ + corner_radius = corner_tr; + }else if(closedEdgeX > 0 && closedEdgeY > 0){ + corner_radius = corner_br; + }else if(closedEdgeX < 0 && closedEdgeY > 0){ + corner_radius = corner_bl; + } + if(closedEdgeXabs > corner_radius && closedEdgeYabs > corner_radius){ + return pixel; + } + if(closedEdgeXabs == 0){ + if(closedEdgeYabs <= border_thickness){ + float4 fade_color = border_color; + fade_color.a = border_alpha_end + (float(closedEdgeYabs) / float(border_thickness))*(border_alpha_start-border_alpha_end); + return fade_color; + }else{ + return pixel; + } + } + if(closedEdgeYabs == 0){ + if(closedEdgeXabs <= border_thickness){ + float4 fade_color = border_color; + fade_color.a = border_alpha_end + (float(closedEdgeXabs) / float(border_thickness))*(border_alpha_start-border_alpha_end); + return fade_color; + }else{ + return pixel; + } + } + if(closedEdgeXabs > corner_radius){ + if(closedEdgeYabs <= border_thickness){ + float4 fade_color = border_color; + fade_color.a = border_alpha_end + (float(closedEdgeYabs) / float(border_thickness))*(border_alpha_start-border_alpha_end); + return fade_color; + }else{ + return pixel; + } + } + if(closedEdgeYabs > corner_radius){ + if(closedEdgeXabs <= border_thickness){ + float4 fade_color = border_color; + fade_color.a = border_alpha_end + (float(closedEdgeXabs) / float(border_thickness))*(border_alpha_start-border_alpha_end); + return fade_color; + }else{ + return pixel; + } + } + float d = closedEdgeXabs+closedEdgeYabs; + if(d>corner_radius){ + if(d-corner_radius <= border_thickness){ + float4 fade_color = border_color; + fade_color.a = border_alpha_end + ((d-corner_radius)/ float(border_thickness))*(border_alpha_start-border_alpha_end); + return fade_color; + }else{ + return pixel; + } + } + return float4(0.0,0.0,0.0,0.0); } - ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -37086,54 +27928,20 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSeascapeShader { +function Get-OBSCylinderShader { -[Alias('Set-OBSSeascapeShader','Add-OBSSeascapeShader')] +[Alias('Set-OBSCylinderShader','Add-OBSCylinderShader')] param( -# Set the AA of OBSSeascapeShader -[ComponentModel.DefaultBindingProperty('AA')] -[Management.Automation.SwitchParameter] -$AA, -# Set the SEA_HEIGHT of OBSSeascapeShader -[Alias('SEA_HEIGHT')] -[ComponentModel.DefaultBindingProperty('SEA_HEIGHT')] -[Single] -$SEAHEIGHT, -# Set the SEA_CHOPPY of OBSSeascapeShader -[Alias('SEA_CHOPPY')] -[ComponentModel.DefaultBindingProperty('SEA_CHOPPY')] -[Single] -$SEACHOPPY, -# Set the SEA_SPEED of OBSSeascapeShader -[Alias('SEA_SPEED')] -[ComponentModel.DefaultBindingProperty('SEA_SPEED')] -[Single] -$SEASPEED, -# Set the SEA_FREQ of OBSSeascapeShader -[Alias('SEA_FREQ')] -[ComponentModel.DefaultBindingProperty('SEA_FREQ')] -[Single] -$SEAFREQ, -# Set the SEA_BASE of OBSSeascapeShader -[Alias('SEA_BASE')] -[ComponentModel.DefaultBindingProperty('SEA_BASE')] -[String] -$SEABASE, -# Set the SEA_WATER_COLOR of OBSSeascapeShader -[Alias('SEA_WATER_COLOR')] -[ComponentModel.DefaultBindingProperty('SEA_WATER_COLOR')] -[String] -$SEAWATERCOLOR, -# Set the CAMERA_SPEED of OBSSeascapeShader -[Alias('CAMERA_SPEED')] -[ComponentModel.DefaultBindingProperty('CAMERA_SPEED')] +# Set the cylinder_factor of OBSCylinderShader +[Alias('cylinder_factor')] +[ComponentModel.DefaultBindingProperty('cylinder_factor')] [Single] -$CAMERASPEED, -# Set the CAMERA_TURN_SPEED of OBSSeascapeShader -[Alias('CAMERA_TURN_SPEED')] -[ComponentModel.DefaultBindingProperty('CAMERA_TURN_SPEED')] +$CylinderFactor, +# Set the background_cut of OBSCylinderShader +[Alias('background_cut')] +[ComponentModel.DefaultBindingProperty('background_cut')] [Single] -$CAMERATURNSPEED, +$BackgroundCut, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -37164,282 +27972,222 @@ $UseShaderTime process { -$shaderName = 'seascape' -$ShaderNoun = 'OBSSeascapeShader' +$shaderName = 'cylinder' +$ShaderNoun = 'OBSCylinderShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -/* - * "Seascape" by Alexander Alekseev aka TDM - 2014 - * License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. - * Contact: tdmaav@gmail.com - * https://www.shadertoy.com/view/Ms2SD1 adapted by Exeldro - */ - -#define NUM_STEPS 8 -#define PI 3.141592 -#define EPSILON 0.001 -uniform bool AA< - string label = "Smooth (more resources)"; -> = false; - -#ifndef OPENGL -#define mat2 float2x2 -#define mat3 float3x3 -#define fract frac -#define mix lerp -#endif - -// sea -#define ITER_GEOMETRY 3 -#define ITER_FRAGMENT 5 -uniform float SEA_HEIGHT< - string label = "Sea Height"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.5; - float step = 0.001; -> = 0.6; -uniform float SEA_CHOPPY< - string label = "Sea Choppy"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> = 4.0; -uniform float SEA_SPEED< - string label = "Sea Speed"; +uniform float cylinder_factor< + string label = "Cylinder factor"; string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; + float minimum = -1.0; + float maximum = 1.0; float step = 0.001; -> = 0.8; -uniform float SEA_FREQ< - string label = "Sea Frequency"; +> = 0.2; +uniform float background_cut< + string label = "Background cut"; string widget_type = "slider"; float minimum = 0.0; - float maximum = 0.5; + float maximum = 1.0; float step = 0.001; -> = 0.16; -uniform float4 SEA_BASE< - string label = "Sea Base"; -> = {0.0,0.09,0.18,1.0}; -uniform float4 SEA_WATER_COLOR< - string label = "Sea Water"; -> = {0.48,0.54,0.36,1.0}; +> = 0.1; -uniform float CAMERA_SPEED< - string label = "Camera Speed"; - string widget_type = "slider"; - float minimum = -10.0; - float maximum = 10.0; - float step = 0.001; -> = 1.0; +float4 mainImage(VertData v_in) : TARGET +{ + float2 uv = v_in.uv; + uv.x -= 0.5; + float bend = sqrt(1.0 - uv.x*uv.x*4); + uv.y = uv.y/(1.0 - cylinder_factor)-bend*cylinder_factor; + uv.y-=cylinder_factor/2; + uv.x /= 2; + uv.x += 0.5; + float4 front_color = image.Sample(textureSampler, uv); + front_color.rgb *= bend/2+0.5; + if(front_color.a >= 1.0) + return front_color; + + uv = v_in.uv; + uv.x -= 0.5; + if(abs(uv.x) < background_cut) + return front_color; + uv.y = uv.y/(1.0 - cylinder_factor)+bend*cylinder_factor; + uv.y-=cylinder_factor/2; + uv.x /= 2; + if(uv.x > 0){ + uv.x = 1.0 - uv.x; + }else{ + uv.x = 0 - uv.x; + } -uniform float CAMERA_TURN_SPEED< - string label = "Camera Turn Speed"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> = 1.0; + float4 back_color = image.Sample(textureSampler, uv); + back_color.rgb *= 0.5-bend/2; + front_color.rgb *= front_color.a; + front_color.rgb += back_color.rgb * (1.0 - front_color.a) * back_color.a; + front_color.a = back_color.a * (1.0 - front_color.a) + front_color.a; + return front_color; +} +' +} +$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 + } -float SEA_TIME(){ - return 1.0 + elapsed_time * SEA_SPEED; -} + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } -// math -mat3 fromEuler(float3 ang) { - float2 a1 = float2(sin(ang.x),cos(ang.x)); - float2 a2 = float2(sin(ang.y),cos(ang.y)); - float2 a3 = float2(sin(ang.z),cos(ang.z)); - return mat3(float3(a1.y*a3.y+a1.x*a2.x*a3.x,a1.y*a2.x*a3.x+a3.y*a1.x,-a2.y*a3.x), - float3(-a2.y*a1.x,a1.y*a2.y,a2.x), - float3(a3.y*a1.x*a2.x+a1.y*a3.x,a1.x*a3.x-a1.y*a3.y*a2.x,a2.y*a3.y)); -} + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + } + } -float hash(float2 p) { - float h = dot(p,float2(127.1,311.7)); - return fract(sin(h)*43758.5453123); -} + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} + } -float noise(float2 p) { - float2 i = floor( p ); - float2 f = fract( p ); - float2 u = f*f*(3.0-2.0*f); - return -1.0+2.0*mix( mix( hash( i + float2(0.0,0.0) ), - hash( i + float2(1.0,0.0) ), u.x), - mix( hash( i + float2(0.0,1.0) ), - hash( i + float2(1.0,1.0) ), u.x), u.y); -} + 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 + } -// lighting -float diffuse(float3 n,float3 l,float p) { - return pow(dot(n,l) * 0.4 + 0.6,p); -} -float specular(float3 n,float3 l,float3 e,float s) { - float nrm = (s + 8.0) / (PI * 8.0); - return pow(max(dot(reflect(e,n),l),0.0),s) * nrm; + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat + } + } } -// sky -float3 getSkyColor(float3 e) { - e.y = (max(e.y,0.0)*0.8+0.2)*0.8; - return float3(pow(1.0-e.y,2.0), 1.0-e.y, 0.6+(1.0-e.y)*0.4) * 1.1; } -// sea -float sea_octave(float2 uv, float choppy) { - uv += noise(uv); - float2 wv = 1.0-abs(sin(uv)); - float2 swv = abs(cos(uv)); - wv = mix(wv,swv,wv); - return pow(1.0-pow(wv.x * wv.y,0.65),choppy); -} -float map(float3 p) { - float freq = SEA_FREQ; - float amp = SEA_HEIGHT; - float choppy = SEA_CHOPPY; - float2 uv = p.xz; - uv.x *= 0.75; - mat2 octave_m = mat2(1.6,1.2,-1.2,1.6); +} - float st = SEA_TIME(); - float d, h = 0.0; - for(int i = 0; i < ITER_GEOMETRY; i++) { - d = sea_octave((uv+float2(st,st))*freq,choppy); - d += sea_octave((uv-float2(st,st))*freq,choppy); - h += d * amp; - uv = mul(uv, octave_m); - freq *= 1.9; - amp *= 0.22; - choppy = mix(choppy,1.0,0.2); - } - return p.y - h; -} - -float map_detailed(float3 p) { - float freq = SEA_FREQ; - float amp = SEA_HEIGHT; - float choppy = SEA_CHOPPY; - float2 uv = p.xz; uv.x *= 0.75; - mat2 octave_m = mat2(1.6,1.2,-1.2,1.6); - float st = SEA_TIME(); - float d, h = 0.0; - for(int i = 0; i < ITER_FRAGMENT; i++) { - d = sea_octave((uv+float2(st,st))*freq,choppy); - d += sea_octave((uv-float2(st,st))*freq,choppy); - h += d * amp; - uv = mul(uv, octave_m); - freq *= 1.9; - amp *= 0.22; - choppy = mix(choppy,1.0,0.2); - } - return p.y - h; -} - -float3 getSeaColor(float3 p, float3 n, float3 l, float3 eye, float3 dist) { - float fresnel = clamp(1.0 - dot(n,-eye), 0.0, 1.0); - fresnel = min(pow(fresnel,3.0), 0.5); - - float3 reflected = getSkyColor(reflect(eye,n)); - float3 refracted = SEA_BASE.rgb + diffuse(n,l,80.0) * SEA_WATER_COLOR.rgb * 0.12; - - float3 color = mix(refracted,reflected,fresnel); - - float atten = max(1.0 - dot(dist,dist) * 0.001, 0.0); - color += SEA_WATER_COLOR.rgb * (p.y - SEA_HEIGHT) * 0.18 * atten; - - float s = specular(n,l,eye,60.0); - color += float3(s,s,s); - - return color; -} + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSDarkenShader { -// tracing -float3 getNormal(float3 p, float eps) { - float3 n; - n.y = map_detailed(p); - n.x = map_detailed(float3(p.x+eps,p.y,p.z)) - n.y; - n.z = map_detailed(float3(p.x,p.y,p.z+eps)) - n.y; - n.y = eps; - return normalize(n); -} +[Alias('Set-OBSDarkenShader','Add-OBSDarkenShader')] +param( +# Set the Opacity_Percentage of OBSDarkenShader +[Alias('Opacity_Percentage')] +[ComponentModel.DefaultBindingProperty('Opacity_Percentage')] +[Single] +$OpacityPercentage, +# Set the Fill_Percentage of OBSDarkenShader +[Alias('Fill_Percentage')] +[ComponentModel.DefaultBindingProperty('Fill_Percentage')] +[Single] +$FillPercentage, +# Set the Notes of OBSDarkenShader +[ComponentModel.DefaultBindingProperty('Notes')] +[String] +$Notes, +# 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 +) -float heightMapTracing(float3 ori, float3 dir, out float3 p) { - float tm = 0.0; - float tx = 1000.0; - float hx = map(ori + dir * tx); - if(hx > 0.0) { - p = ori + dir * tx; - return tx; - } - float hm = map(ori + dir * tm); - float tmid = 0.0; - for(int i = 0; i < NUM_STEPS; i++) { - tmid = mix(tm,tx, hm/(hm-hx)); - p = ori + dir * tmid; - float hmid = map(p); - if(hmid < 0.0) { - tx = tmid; - hx = hmid; - } else { - tm = tmid; - hm = hmid; - } - } - return tmid; -} -float3 getPixel(in float2 coord, float time) { - float2 uv = coord / uv_size.xy; - uv = uv * 2.0 - 1.0; - uv.x *= uv_size.x / uv_size.y; - - // ray - float3 ang = float3(sin(time*3.0*CAMERA_TURN_SPEED)*0.1,sin(time*CAMERA_TURN_SPEED)*0.2+0.3,time*CAMERA_TURN_SPEED); - float3 ori = float3(0.0,3.5,time*5.0*CAMERA_SPEED); - float3 dir = normalize(float3(uv.xy,-2.0)); - dir.z += length(uv) * 0.14; - dir = mul(normalize(dir), fromEuler(ang)); - - // tracing - float3 p; - heightMapTracing(ori,dir,p); - float3 dist = p - ori; - float3 n = getNormal(p, dot(dist,dist) * (0.1 / uv_size.x)); - float3 light = normalize(float3(0.0,1.0,0.8)); - - // color - return mix( - getSkyColor(dir), - getSeaColor(p,n,light,dir,dist), - pow(smoothstep(0.0,-0.02,dir.y),0.2)); -} +process { +$shaderName = 'darken' +$ShaderNoun = 'OBSDarkenShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform float Opacity_Percentage = 100.0; +uniform float Fill_Percentage = 100.0; +uniform string Notes = "Simulates a photo editing darken layer blending mode. Fill percentage is the interior alpha and Opacity is the layer alpha."; -// main float4 mainImage(VertData v_in) : TARGET { - float time = elapsed_time * 0.3; - float2 fragCoord = float2(v_in.uv.x * uv_size.x, (1.0 - v_in.uv.y) * uv_size.y); - - float3 color = float3(0.0,0.0,0.0);; - if (AA){ - for(int i = -1; i <= 1; i++) { - for(int j = -1; j <= 1; j++) { - float2 uv = fragCoord+float2(i,j)/3.0; - color += getPixel(uv, time); - } - } - color /= 9.0; - }else{ - color = getPixel(fragCoord, time); - } - - // post - return float4(pow(color,float3(0.65,0.65,0.65)), 1.0); + float4 other = float4(1.0, 1.0, 1.0, 1.0); + float4 base = image.Sample(textureSampler, v_in.uv); + float luminance = dot(base.rgb, float3(0.299, 0.587, 0.114)); + float4 gray = float4(luminance,luminance,luminance, 1.0); + + return min(base,other); } + ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -37537,30 +28285,20 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSeasickShader { +function Get-OBSDeadPixelFixerShader { -[Alias('Set-OBSSeasickShader','Add-OBSSeasickShader')] +[Alias('Set-OBSDeadPixelFixerShader','Add-OBSDeadPixelFixerShader')] param( -# Set the notes of OBSSeasickShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# Set the amplitude of OBSSeasickShader -[ComponentModel.DefaultBindingProperty('amplitude')] -[Single] -$Amplitude, -# Set the speed of OBSSeasickShader -[ComponentModel.DefaultBindingProperty('speed')] -[Single] -$Speed, -# Set the frequency of OBSSeasickShader -[ComponentModel.DefaultBindingProperty('frequency')] -[Single] -$Frequency, -# Set the opacity of OBSSeasickShader -[ComponentModel.DefaultBindingProperty('opacity')] -[Single] -$Opacity, +# Set the Dead_Pixel_X of OBSDeadPixelFixerShader +[Alias('Dead_Pixel_X')] +[ComponentModel.DefaultBindingProperty('Dead_Pixel_X')] +[Int32] +$DeadPixelX, +# Set the Dead_Pixel_Y of OBSDeadPixelFixerShader +[Alias('Dead_Pixel_Y')] +[ComponentModel.DefaultBindingProperty('Dead_Pixel_Y')] +[Int32] +$DeadPixelY, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -37591,49 +28329,63 @@ $UseShaderTime process { -$shaderName = 'seasick' -$ShaderNoun = 'OBSSeasickShader' +$shaderName = 'dead-pixel-fixer' +$ShaderNoun = 'OBSDeadPixelFixerShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Seasick - an effect for OBS Studio +// Dead Pixel Fixer, Version 0.01, for OBS Shaderfilter +// Copyright ©️ 2022 by SkeletonBow +// License: GNU General Public License, version 2 +// Contact info: +// Twitter: +// Twitch: // -uniform string notes< - string widget_type = "info"; -> = "Seasick - from the game Snavenger\n\n(available on Google Play/Amazon Fire)"; -uniform float amplitude< - string label = "amplitude"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.03; -uniform float speed< - string label = "speed"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.01; -> = 1.0; -uniform float frequency< - string label = "frequency"; +// Description: Intended for use with an input source that has a dead pixel on its sensor such as a webcam. +// The pixel located at the user configured offset will have its color overridden by taking the average of the +// color of the 8 pixels immediately surrounding it, effectively hiding the dead pixel. +// +// Changelog: +// 0.01 - Initial release + +uniform int Dead_Pixel_X< + string label = "Dead Pixel X"; string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 6.0; -uniform float opacity< - string label = "opacity"; + int minimum = 0; + int maximum = 2000; + int step = 1; +> = 0; +uniform int Dead_Pixel_Y< + string label = "Dead Pixel Y"; string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.5; + int minimum = 0; + int maximum = 2000; + int step = 1; +> = 0; -float4 mainImage(VertData v_in) : TARGET +float3 blur_dead_pixel(in float2 pos) { - float2 pulse = sin(elapsed_time*speed - frequency * v_in.uv); - float2 coord = v_in.uv + amplitude * float2(pulse.x, -pulse.y); - return image.Sample(textureSampler, coord) * opacity; + float3 color; + color = image.Sample(textureSampler, (pos + float2(-1.0, -0.5))/uv_size).rgb; + color += image.Sample(textureSampler, (pos + float2(0.5, -1.0))/uv_size).rgb; + color += image.Sample(textureSampler, (pos + float2(1.0, 0.5))/uv_size).rgb; + color += image.Sample(textureSampler, (pos + float2(-0.5, 1.0))/uv_size).rgb; + return color * 0.25; +} + +float4 mainImage( VertData v_in ) : TARGET +{ + float2 uv = v_in.uv; + float2 pos = v_in.pos.xy; + float2 dp_pos = clamp( float2(Dead_Pixel_X, Dead_Pixel_Y), float2(0.0,0.0), uv_size - 1); + float4 obstex = image.Sample(textureSampler, uv); + float3 color; + + if(floor(pos.x) == floor(dp_pos.x) && floor(pos.y) == floor(dp_pos.y) ) { + color = blur_dead_pixel(pos); + } else { + color.rgb = obstex.rgb; + } + return float4( color, obstex.a); } ' @@ -37733,64 +28485,114 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSelectiveColorShader { +function Get-OBSDensitySatHueShader { -[Alias('Set-OBSSelectiveColorShader','Add-OBSSelectiveColorShader')] +[Alias('Set-OBSDensitySatHueShader','Add-OBSDensitySatHueShader')] param( -# Set the cutoff_Red of OBSSelectiveColorShader -[Alias('cutoff_Red')] -[ComponentModel.DefaultBindingProperty('cutoff_Red')] +# Set the notes of OBSDensitySatHueShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# Set the density_r of OBSDensitySatHueShader +[Alias('density_r')] +[ComponentModel.DefaultBindingProperty('density_r')] [Single] -$CutoffRed, -# Set the cutoff_Green of OBSSelectiveColorShader -[Alias('cutoff_Green')] -[ComponentModel.DefaultBindingProperty('cutoff_Green')] +$DensityR, +# Set the saturation_r of OBSDensitySatHueShader +[Alias('saturation_r')] +[ComponentModel.DefaultBindingProperty('saturation_r')] [Single] -$CutoffGreen, -# Set the cutoff_Blue of OBSSelectiveColorShader -[Alias('cutoff_Blue')] -[ComponentModel.DefaultBindingProperty('cutoff_Blue')] +$SaturationR, +# Set the hueShift_r of OBSDensitySatHueShader +[Alias('hueShift_r')] +[ComponentModel.DefaultBindingProperty('hueShift_r')] [Single] -$CutoffBlue, -# Set the cutoff_Yellow of OBSSelectiveColorShader -[Alias('cutoff_Yellow')] -[ComponentModel.DefaultBindingProperty('cutoff_Yellow')] +$HueShiftR, +# Set the density_y of OBSDensitySatHueShader +[Alias('density_y')] +[ComponentModel.DefaultBindingProperty('density_y')] [Single] -$CutoffYellow, -# Set the acceptance_Amplifier of OBSSelectiveColorShader -[Alias('acceptance_Amplifier')] -[ComponentModel.DefaultBindingProperty('acceptance_Amplifier')] +$DensityY, +# Set the saturation_y of OBSDensitySatHueShader +[Alias('saturation_y')] +[ComponentModel.DefaultBindingProperty('saturation_y')] [Single] -$AcceptanceAmplifier, -# Set the show_Red of OBSSelectiveColorShader -[Alias('show_Red')] -[ComponentModel.DefaultBindingProperty('show_Red')] -[Management.Automation.SwitchParameter] -$ShowRed, -# Set the show_Green of OBSSelectiveColorShader -[Alias('show_Green')] -[ComponentModel.DefaultBindingProperty('show_Green')] -[Management.Automation.SwitchParameter] -$ShowGreen, -# Set the show_Blue of OBSSelectiveColorShader -[Alias('show_Blue')] -[ComponentModel.DefaultBindingProperty('show_Blue')] -[Management.Automation.SwitchParameter] -$ShowBlue, -# Set the show_Yellow of OBSSelectiveColorShader -[Alias('show_Yellow')] -[ComponentModel.DefaultBindingProperty('show_Yellow')] -[Management.Automation.SwitchParameter] -$ShowYellow, -# Set the notes of OBSSelectiveColorShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, -# Set the background_type of OBSSelectiveColorShader -[Alias('background_type')] -[ComponentModel.DefaultBindingProperty('background_type')] -[Int32] -$BackgroundType, +$SaturationY, +# Set the hueShift_y of OBSDensitySatHueShader +[Alias('hueShift_y')] +[ComponentModel.DefaultBindingProperty('hueShift_y')] +[Single] +$HueShiftY, +# Set the density_g of OBSDensitySatHueShader +[Alias('density_g')] +[ComponentModel.DefaultBindingProperty('density_g')] +[Single] +$DensityG, +# Set the saturation_g of OBSDensitySatHueShader +[Alias('saturation_g')] +[ComponentModel.DefaultBindingProperty('saturation_g')] +[Single] +$SaturationG, +# Set the hueShift_g of OBSDensitySatHueShader +[Alias('hueShift_g')] +[ComponentModel.DefaultBindingProperty('hueShift_g')] +[Single] +$HueShiftG, +# Set the density_c of OBSDensitySatHueShader +[Alias('density_c')] +[ComponentModel.DefaultBindingProperty('density_c')] +[Single] +$DensityC, +# Set the saturation_c of OBSDensitySatHueShader +[Alias('saturation_c')] +[ComponentModel.DefaultBindingProperty('saturation_c')] +[Single] +$SaturationC, +# Set the hueShift_c of OBSDensitySatHueShader +[Alias('hueShift_c')] +[ComponentModel.DefaultBindingProperty('hueShift_c')] +[Single] +$HueShiftC, +# Set the density_b of OBSDensitySatHueShader +[Alias('density_b')] +[ComponentModel.DefaultBindingProperty('density_b')] +[Single] +$DensityB, +# Set the saturation_b of OBSDensitySatHueShader +[Alias('saturation_b')] +[ComponentModel.DefaultBindingProperty('saturation_b')] +[Single] +$SaturationB, +# Set the hueShift_b of OBSDensitySatHueShader +[Alias('hueShift_b')] +[ComponentModel.DefaultBindingProperty('hueShift_b')] +[Single] +$HueShiftB, +# Set the density_m of OBSDensitySatHueShader +[Alias('density_m')] +[ComponentModel.DefaultBindingProperty('density_m')] +[Single] +$DensityM, +# Set the saturation_m of OBSDensitySatHueShader +[Alias('saturation_m')] +[ComponentModel.DefaultBindingProperty('saturation_m')] +[Single] +$SaturationM, +# Set the hueShift_m of OBSDensitySatHueShader +[Alias('hueShift_m')] +[ComponentModel.DefaultBindingProperty('hueShift_m')] +[Single] +$HueShiftM, +# Set the global_density of OBSDensitySatHueShader +[Alias('global_density')] +[ComponentModel.DefaultBindingProperty('global_density')] +[Single] +$GlobalDensity, +# Set the global_saturation of OBSDensitySatHueShader +[Alias('global_saturation')] +[ComponentModel.DefaultBindingProperty('global_saturation')] +[Single] +$GlobalSaturation, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -37821,126 +28623,259 @@ $UseShaderTime process { -$shaderName = 'selective_color' -$ShaderNoun = 'OBSSelectiveColorShader' +$shaderName = 'density_sat_hue' +$ShaderNoun = 'OBSDensitySatHueShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Selective Color shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 -//https://github.com/Oncorporation/obs-shaderfilter -//updated 4/13/2020: take into account the opacity/alpha of input image -thanks Skeletonbow for suggestion -//Converted to OpenGL by Q-mii February 25, 2020 -uniform float cutoff_Red< - string label = "cutoff Red"; +// Density-Saturation-Hue Shader for OBS Shaderfilter +// Modified by CameraTim for use with obs-shaderfilter 12/2024 v.12 + +uniform string notes< + string widget_type = "info"; +> = "Density adjustment shader: Density reduces luminance, while saturation is subtractively increased to avoid greyish colors."; + +uniform float density_r < + string label = "Red Density"; string widget_type = "slider"; - float minimum = 0.0; + float minimum = -1.0; float maximum = 1.0; float step = 0.001; -> = 0.40; -uniform float cutoff_Green< - string label = "cutoff Green"; +> = 0.0; + +uniform float saturation_r < + string label = "Red Sat"; string widget_type = "slider"; - float minimum = 0.0; + float minimum = -1.0; float maximum = 1.0; float step = 0.001; -> = 0.025; -uniform float cutoff_Blue< - string label = "cutoff Blue"; +> = 0.0; + +uniform float hueShift_r < + string label = "Red Hue Shift"; string widget_type = "slider"; - float minimum = 0.0; + float minimum = -1.0; float maximum = 1.0; float step = 0.001; -> = 0.25; -uniform float cutoff_Yellow< - string label = "cutoff Yellow"; +> = 0.0; + +uniform float density_y < + string label = "Yellow Density"; string widget_type = "slider"; - float minimum = 0.0; + float minimum = -1.0; float maximum = 1.0; float step = 0.001; -> = 0.25; -uniform float acceptance_Amplifier< - string label = "acceptance Amplifier"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 20.0; - float step = 0.001; -> = 5.0; +> = 0.0; -uniform bool show_Red = true; -uniform bool show_Green = true; -uniform bool show_Blue = true; -uniform bool show_Yellow = true; -uniform string notes< - string widget_type = "info"; -> = "defaults: .4,.03,.25,.25, 5.0, true,true, true, true. cuttoff higher = less color, 0 = all 1 = none."; -uniform int background_type< - string label = "background type"; - string widget_type = "select"; - int option_0_value = 0; - string option_0_label = "Grey"; - int option_1_value = 1; - string option_1_label = "Luma"; - int option_2_value = 2; - string option_2_label = "White"; - int option_3_value = 3; - string option_3_label = "Black"; - int option_4_value = 4; - string option_4_label = "Transparent"; - int option_5_value = 5; - string option_5_label = "Background Color"; -> = 0; +uniform float saturation_y < + string label = "Yellow Sat"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; -float4 mainImage(VertData v_in) : TARGET -{ - const float PI = 3.1415926535897932384626433832795;//acos(-1); - const float3 coefLuma = float3(0.2126, 0.7152, 0.0722); - float4 color = image.Sample(textureSampler, v_in.uv); +uniform float hueShift_y < + string label = "Yellow Hue Shift"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; - float luminance = dot(coefLuma, color.rgb); - float4 gray = float4(luminance, luminance, luminance, 1.0); +uniform float density_g < + string label = "Green Density"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; - if (background_type == 0) - { - luminance = (color.r + color.g + color.b) * 0.3333; - gray = float4(luminance,luminance,luminance, 1.0); - } - //if (background_type == 1) - //{ - // gray = float4(luminance,luminance,luminance, 1.0); - //} - if (background_type == 2) - gray = float4(1.0,1.0,1.0,1.0); - if (background_type == 3) - gray = float4(0.0,0.0,0.0,1.0); - if (background_type == 4) - gray.a = 0.01; - if (background_type == 5) - gray = color; +uniform float saturation_g < + string label = "Green Sat"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; - float redness = max ( min ( color.r - color.g , color.r - color.b ) / color.r , 0); - float greenness = max ( min ( color.g - color.r , color.g - color.b ) / color.g , 0); - float blueness = max ( min ( color.b - color.r , color.b - color.g ) / color.b , 0); - - float rgLuminance = (color.r*1.4 + color.g*0.6)/2; - float rgDiff = abs(color.r-color.g)*1.4; +uniform float hueShift_g < + string label = "Green Hue Shift"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; - float yellowness = 0.1 + rgLuminance * 1.2 - color.b - rgDiff; +uniform float density_c < + string label = "Cyan Density"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; - float4 accept; - accept.r = float(show_Red) * (redness - cutoff_Red); - accept.g = float(show_Green) * (greenness - cutoff_Green); - accept.b = float(show_Blue) * (blueness - cutoff_Blue); - accept[3] = float(show_Yellow) * (yellowness - cutoff_Yellow); +uniform float saturation_c < + string label = "Cyan Sat"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; - float acceptance = max (accept.r, max(accept.g, max(accept.b, max(accept[3],0)))); - float modAcceptance = min (acceptance * acceptance_Amplifier, 1); +uniform float hueShift_c < + string label = "Cyan Hue Shift"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; - float4 result = color; - if (result.a > 0) { - result = modAcceptance * color + (1.0 - modAcceptance) * gray; - //result.a *= gray.a; - } +uniform float density_b < + string label = "Blue Density"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; - return result; +uniform float saturation_b < + string label = "Blue Sat"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; + +uniform float hueShift_b < + string label = "Blue Hue Shift"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; + +uniform float density_m < + string label = "Magenta Density"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; + +uniform float saturation_m < + string label = "Magenta Sat"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; + +uniform float hueShift_m < + string label = "Magenta Hue Shift"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; + +uniform float global_density < + string label = "Global Density"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; + +uniform float global_saturation < + string label = "Global Sat"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; + +// Tetrahedral interpolation based on the ordering of the input color channels +float3 applyAdjustments(float3 p) { + // Pre-calculate the flipped density values for each channel: + float d_r = -(density_r + global_density); + float d_y = -(density_y + global_density); + float d_g = -(density_g + global_density); + float d_c = -(density_c + global_density); + float d_b = -(density_b + global_density); + float d_m = -(density_m + global_density); + + // Compute the color vectors for each hue region using the flipped densities: + float3 red = float3( + 1.0 + d_r, + d_r - (saturation_r + global_saturation), + d_r + hueShift_r - (saturation_r + global_saturation) + ); + + float3 yellow = float3( + 1.0 + hueShift_y + d_y, + 1.0 + d_y, + d_y - (saturation_y + global_saturation) + ); + + float3 green = float3( + d_g - (saturation_g + global_saturation), + 1.0 + d_g, + d_g + hueShift_g - (saturation_g + global_saturation) + ); + + float3 cyan = float3( + d_c - (saturation_c + global_saturation), + 1.0 + hueShift_c + d_c, + 1.0 + d_c + ); + + float3 blue = float3( + d_b + hueShift_b - (saturation_b + global_saturation), + d_b - (saturation_b + global_saturation), + 1.0 + d_b + ); + + float3 magenta = float3( + 1.0 + d_m, + d_m - (saturation_m + global_saturation), + 1.0 + hueShift_m + d_m + ); + + // Define the black and white endpoints: + float3 blk = float3(0.0, 0.0, 0.0); + float3 wht = float3(1.0, 1.0, 1.0); + + float3 rgb; + if (p.r > p.g) { + if (p.g > p.b) { + // p.r >= p.g >= p.b + rgb = p.r * (red - blk) + blk + p.g * (yellow - red) + p.b * (wht - yellow); + } else if (p.r > p.b) { + // p.r >= p.b > p.g + rgb = p.r * (red - blk) + blk + p.g * (wht - magenta) + p.b * (magenta - red); + } else { + // p.b >= p.r > p.g + rgb = p.r * (magenta - blue) + p.g * (wht - magenta) + p.b * (blue - blk) + blk; + } + } else { + if (p.b > p.g) { + // p.b >= p.g >= p.r + rgb = p.r * (wht - cyan) + p.g * (cyan - blue) + p.b * (blue - blk) + blk; + } else if (p.b > p.r) { + // p.g >= p.r and p.b > p.r + rgb = p.r * (wht - cyan) + p.g * (green - blk) + blk + p.b * (cyan - green); + } else { + // p.g >= p.b >= p.r + rgb = p.r * (yellow - green) + p.g * (green - blk) + blk + p.b * (wht - yellow); + } + } + return clamp(rgb, 0.0, 1.0); +} + +float4 mainImage(VertData v_in) : TARGET { + float4 inputColor = image.Sample(textureSampler, v_in.uv); + float3 adjustedColor = applyAdjustments(inputColor.rgb); + return float4(adjustedColor, inputColor.a); } ' @@ -38040,85 +28975,35 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSShakeShader { +function Get-OBSDiffuseTransitionShader { -[Alias('Set-OBSShakeShader','Add-OBSShakeShader')] +[Alias('Set-OBSDiffuseTransitionShader','Add-OBSDiffuseTransitionShader')] param( -# Set the ViewProj of OBSShakeShader -[ComponentModel.DefaultBindingProperty('ViewProj')] -[Single[][]] -$ViewProj, -# Set the image of OBSShakeShader -[ComponentModel.DefaultBindingProperty('image')] +# Set the image_a of OBSDiffuseTransitionShader +[Alias('image_a')] +[ComponentModel.DefaultBindingProperty('image_a')] [String] -$Image, -# Set the elapsed_time of OBSShakeShader -[Alias('elapsed_time')] -[ComponentModel.DefaultBindingProperty('elapsed_time')] -[Single] -$ElapsedTime, -# Set the uv_offset of OBSShakeShader -[Alias('uv_offset')] -[ComponentModel.DefaultBindingProperty('uv_offset')] -[Single[]] -$UvOffset, -# Set the uv_scale of OBSShakeShader -[Alias('uv_scale')] -[ComponentModel.DefaultBindingProperty('uv_scale')] -[Single[]] -$UvScale, -# Set the uv_pixel_interval of OBSShakeShader -[Alias('uv_pixel_interval')] -[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] -[Single[]] -$UvPixelInterval, -# Set the rand_f of OBSShakeShader -[Alias('rand_f')] -[ComponentModel.DefaultBindingProperty('rand_f')] -[Single] -$RandF, -# Set the uv_size of OBSShakeShader -[Alias('uv_size')] -[ComponentModel.DefaultBindingProperty('uv_size')] -[Single[]] -$UvSize, -# Set the local_time of OBSShakeShader -[Alias('local_time')] -[ComponentModel.DefaultBindingProperty('local_time')] -[Single] -$LocalTime, -# Set the random_scale of OBSShakeShader -[Alias('random_scale')] -[ComponentModel.DefaultBindingProperty('random_scale')] -[Single] -$RandomScale, -# Set the worble of OBSShakeShader -[ComponentModel.DefaultBindingProperty('worble')] -[Management.Automation.SwitchParameter] -$Worble, -# Set the speed of OBSShakeShader -[ComponentModel.DefaultBindingProperty('speed')] -[Single] -$Speed, -# Set the min_growth_pixels of OBSShakeShader -[Alias('min_growth_pixels')] -[ComponentModel.DefaultBindingProperty('min_growth_pixels')] -[Single] -$MinGrowthPixels, -# Set the max_growth_pixels of OBSShakeShader -[Alias('max_growth_pixels')] -[ComponentModel.DefaultBindingProperty('max_growth_pixels')] +$ImageA, +# Set the image_b of OBSDiffuseTransitionShader +[Alias('image_b')] +[ComponentModel.DefaultBindingProperty('image_b')] +[String] +$ImageB, +# Set the transition_time of OBSDiffuseTransitionShader +[Alias('transition_time')] +[ComponentModel.DefaultBindingProperty('transition_time')] [Single] -$MaxGrowthPixels, -# Set the randomize_movement of OBSShakeShader -[Alias('randomize_movement')] -[ComponentModel.DefaultBindingProperty('randomize_movement')] +$TransitionTime, +# Set the convert_linear of OBSDiffuseTransitionShader +[Alias('convert_linear')] +[ComponentModel.DefaultBindingProperty('convert_linear')] [Management.Automation.SwitchParameter] -$RandomizeMovement, -# Set the notes of OBSShakeShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, +$ConvertLinear, +# Set the num_samples of OBSDiffuseTransitionShader +[Alias('num_samples')] +[ComponentModel.DefaultBindingProperty('num_samples')] +[Int32] +$NumSamples, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -38149,146 +29034,92 @@ $UseShaderTime process { -$shaderName = 'shake' -$ShaderNoun = 'OBSShakeShader' +$shaderName = 'diffuse_transition' +$ShaderNoun = 'OBSDiffuseTransitionShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Shake Effect By Charles Fettinger (https://github.com/Oncorporation) 2/2019 -// Added some randomization based upon random_scale input -// updated for latest version of obs-shaderfilter - -uniform float4x4 ViewProj; -uniform texture2d image; - -uniform float elapsed_time; -uniform float2 uv_offset; -uniform float2 uv_scale; -uniform float2 uv_pixel_interval; -uniform float rand_f; -uniform float2 uv_size; -uniform float local_time; +//based on https://www.shadertoy.com/view/4cK3z1 +uniform texture2d image_a; +uniform texture2d image_b; +uniform float transition_time = 0.5; +uniform bool convert_linear = true; +// Diffuse (move pixels) between two 2D images +// Demo inspired by Iterative-(de)Blending (see Figure 9 in https://arxiv.org/pdf/2305.03486.pdf) +// Note: the approach in this demo is different - rather than randomising paths we use means -uniform float random_scale< - string label = "random scale"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> = 0.25; -uniform bool worble = false; -uniform float speed< - string label = "Speed"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.001; -> = 1.0; -uniform float min_growth_pixels< - string label = "min growth pixels"; - string widget_type = "slider"; - float minimum = -10.0; - float maximum = 10.0; - float step = 0.001; -> = -2.0; -uniform float max_growth_pixels< - string label = "max growth pixels"; +// increase for greater precision - this is O(n^2) :( +uniform int num_samples< + string label = "Number of samples (10)"; string widget_type = "slider"; - float minimum = -10.0; - float maximum = 10.0; - float step = 0.001; -> = 2.0; -uniform bool randomize_movement = false; + int minimum = 2; + int maximum = 100; + int step = 1; +> = 10; -uniform string notes< - string widget_type = "info"; -> =''keep the random_scale low for small (0.2-1) for small jerky movements and larger for less often big jumps''; +float4 mainImage(VertData v_in) : TARGET +{ + float2 uv = v_in.uv; -sampler_state textureSampler { - Filter = Linear; - AddressU = Border; - AddressV = Border; - BorderColor = 00000000; -}; + if (transition_time < 0.00001) { + return image_a.Sample(textureSampler, uv); + } + + // we need to normalise the distributions so just sum the samples for a division later + // note: could calculate this once per image in a buffer or something + float3 from_total = float3(0.0,0.0,0.0); + float3 to_total = float3(0.0,0.0,0.0); -struct VertData { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; + for (int i=0; i = 25; -uniform int gradient_percent< - string label = "gradient percent"; + float minimum = 0.001; + float maximum = 2.0; + float step = .001; +> = 1.0; + +uniform float char_speed< + string label = "Character Speed"; string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 20; -uniform int delay_percent< - string label = "delay percent"; + float minimum = 0.0; + float maximum = 2.0; + float step = .001; +> = 1.0; + +uniform float glow_contrast< + string label = "Glow contrast"; string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; -uniform bool Apply_To_Alpha_Layer = false; -uniform bool ease = false; -uniform bool hide = false; -uniform bool reverse = false; -uniform bool One_Direction = true; -uniform bool glitch = false; -uniform string notes< - string widget_type = "info"; -> = "Use Luma Wipes ( data/obs-plugins/obs-transitions/luma_wipes ) ''ease'' makes the animation pause at the begin and end for a moment, ''hide'' will make the image disappear, ''glitch'' is random and amazing, ''reverse'' quickly allows you to test settings, ''One Direction'' only shows the shine as it travels in one direction, ''delay percentage'' adds a delay between shines (requires adjustment to speed: https://www.desmos.com/calculator/wkgbndweyt )"; + float minimum = 0.0; + float maximum = 2.5; + float step = .001; +> = 1.0; -uniform float start_adjust; -uniform float stop_adjust; -float EaseInOutCircTimer(float t,float b,float c,float d){ - t /= d/2.0; - if (t < 1.0) return -c/2.0 * (sqrt(1.0 - t*t) - 1.0) + b; - t -= 2.0; - return c/2.0 * (sqrt(1.0 - t*t) + 1.0) + b; +float mod(float x, float y) +{ + return x - y * floor(x/y); } -float Styler(float t,float b,float c,float d,bool ease) +float2 mod2(float2 x, float2 y) { - if (ease) return EaseInOutCircTimer(t,0.0,c,d); - return t; + return x - y * floor(x/y); } -float4 convert_pmalpha(float4 c) +float text(float2 fragCoord) { - float4 ret = c; - if (c.a >= 0.001) - ret.xyz /= c.a; - else - ret = float4(0.0, 0.0, 0.0, 0.0); - return ret; + float2 uv = mod2(fragCoord, float2(16.0, 16.0) )/16.0; + float2 block = (fragCoord*.0625 - uv)/uv_size*16.0; + uv = uv*.8+.1; // scale the letters up a bit + block += elapsed_time*.002*char_speed; + uv += floor(noise.Sample(textureSampler, fract(block)).xy * 16.); // randomize letters + uv *= .0625; // bring back into 0-1 range + return font.Sample(textureSampler, uv).r; } -float4 slerp(float4 start, float4 end, float percent) +float3 rain(float2 fragCoord) { - // Dot product - the cosine of the angle between 2 vectors. - float dotf = start.r*end.r+start.g*end.g+start.b*end.b+start.a*end.a; - // Clamp it to be in the range of Acos() - // This may be unnecessary, but floating point - // precision can be a fickle mistress. - dotf = clamp(dotf, -1.0f, 1.0f); - // Acos(dot) returns the angle between start and end, - // And multiplying that by percent returns the angle between - // start and the final result. - float theta = acos(dotf)*percent; - float4 RelativeVec = normalize(end - start * dotf); - - // Orthonormal basis - // The final result. - return ((start*cos(theta)) + (RelativeVec*sin(theta))); + fragCoord.x -= mod(fragCoord.x, 16.); + float offset=sin(fragCoord.x*15.); + float speed=(cos(fragCoord.x*3.)*.3+.7)*rain_speed; + + float y = fract(fragCoord.y/uv_size.y + elapsed_time*speed + offset); + return base_color.rgb / pow(y*20.0, glow_contrast); } float4 mainImage(VertData v_in) : TARGET { - // convert input for vector math - float4 rgba = convert_pmalpha(image.Sample(textureSampler, v_in.uv)); - float speed = speed_percent * 0.01; - float softness = max(abs(gradient_percent * 0.01), 0.01) * sign(gradient_percent); - float delay = clamp(delay_percent * 0.01, 0.0, 1.0); - - - // circular easing variable - float direction = abs(sin((elapsed_time - 0.001) * speed)); - float t = abs(sin(elapsed_time * speed)); - - // if time is greater than direction, we are going up! - direction = t - direction; - - // split into segments with frac or mod. - // delay is the gap between starting and ending of the sine wave, use speed to compensate - t = (frac(t) - delay) * (1 / (1 - delay)); - t = 1 + max(t,0.0); - - float s = 0.0; //start value - float c = 2.0; //change value - float d = 2.0; //duration - - if (glitch) t = clamp(t + ((rand_f *2) - 1), 0.0,2.0); - - //if Unidirectional disable on return - if (One_Direction && (direction < 0.0)) - { - s = 0; - } - else - { - s = Styler(t, 0, c, d, ease); - } - - // combine luma texture and user defined shine color - float luma = l_tex.Sample(textureSampler, v_in.uv).x; - - // - adjust for min and max - if ((luma >= (start_adjust)) && (luma <= (1 - stop_adjust))) - { - - if (reverse) - { - luma = 1.0 - luma; - } - - // user color with luma - float4 output_color = float4(shine_color.rgb, luma); - - float time = lerp(0.0f, 1.0f + abs(2*softness), s - 1.0); - - // use luma texture to add alpha and shine - - // if behind glow, consider trailing gradient shine then show underlying image - if (luma <= time - softness) - { - float alpha_behind = clamp(1.0 - (time - softness - luma ) / softness, 0.00, 1.0); - if (Apply_To_Alpha_Layer) - alpha_behind *= rgba.a; - return lerp(rgba, rgba + output_color, alpha_behind); - } - - // if in front of glow, consider if the underlying image is hidden - if (luma >= time) - { - // if hide, make the transition better - if (hide) - { - return float4(rgba.rgb, lerp(0.0, rgba.a, (time + softness) / (1 + abs(2*softness)))); - } - else - { - return rgba; - } - } - - // else show the glow area, with luminance - float alpha_ = (time - luma) / softness; - if (Apply_To_Alpha_Layer) - alpha_ *= rgba.a; - return lerp(rgba, rgba + output_color, alpha_); - } - else - { - return rgba; - } + return mix(image.Sample(textureSampler, v_in.uv),float4(rain(float2(v_in.uv.x,1.0-v_in.uv.y)*uv_size),1.0), text(v_in.uv*uv_size)); } - ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -38761,49 +29453,110 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSimpleGradientShader { +function Get-OBSDisplacementMapAdvancedInvertShader { -[Alias('Set-OBSSimpleGradientShader','Add-OBSSimpleGradientShader')] +[Alias('Set-OBSDisplacementMapAdvancedInvertShader','Add-OBSDisplacementMapAdvancedInvertShader')] param( -# Set the speed_percentage of OBSSimpleGradientShader -[Alias('speed_percentage')] -[ComponentModel.DefaultBindingProperty('speed_percentage')] -[Int32] -$SpeedPercentage, -# Set the alpha_percentage of OBSSimpleGradientShader -[Alias('alpha_percentage')] -[ComponentModel.DefaultBindingProperty('alpha_percentage')] +# Set the displacement_info of OBSDisplacementMapAdvancedInvertShader +[Alias('displacement_info')] +[ComponentModel.DefaultBindingProperty('displacement_info')] +[String] +$DisplacementInfo, +# Set the displacement_x of OBSDisplacementMapAdvancedInvertShader +[Alias('displacement_x')] +[ComponentModel.DefaultBindingProperty('displacement_x')] +[Single] +$DisplacementX, +# Set the displacement_y of OBSDisplacementMapAdvancedInvertShader +[Alias('displacement_y')] +[ComponentModel.DefaultBindingProperty('displacement_y')] +[Single] +$DisplacementY, +# Set the displacement_curve of OBSDisplacementMapAdvancedInvertShader +[Alias('displacement_curve')] +[ComponentModel.DefaultBindingProperty('displacement_curve')] [Int32] -$AlphaPercentage, -# Set the Lens_Flair of OBSSimpleGradientShader -[Alias('Lens_Flair')] -[ComponentModel.DefaultBindingProperty('Lens_Flair')] -[Management.Automation.SwitchParameter] -$LensFlair, -# Set the Animate_Lens_Flair of OBSSimpleGradientShader -[Alias('Animate_Lens_Flair')] -[ComponentModel.DefaultBindingProperty('Animate_Lens_Flair')] -[Management.Automation.SwitchParameter] -$AnimateLensFlair, -# Set the Apply_To_Alpha_Layer of OBSSimpleGradientShader -[Alias('Apply_To_Alpha_Layer')] -[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] -[Management.Automation.SwitchParameter] -$ApplyToAlphaLayer, -# Set the Apply_To_Specific_Color of OBSSimpleGradientShader -[Alias('Apply_To_Specific_Color')] -[ComponentModel.DefaultBindingProperty('Apply_To_Specific_Color')] -[Management.Automation.SwitchParameter] -$ApplyToSpecificColor, -# Set the Color_To_Replace of OBSSimpleGradientShader -[Alias('Color_To_Replace')] -[ComponentModel.DefaultBindingProperty('Color_To_Replace')] -[String] -$ColorToReplace, -# Set the notes of OBSSimpleGradientShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, +$DisplacementCurve, +# Set the blur_info of OBSDisplacementMapAdvancedInvertShader +[Alias('blur_info')] +[ComponentModel.DefaultBindingProperty('blur_info')] +[String] +$BlurInfo, +# Set the blur_size of OBSDisplacementMapAdvancedInvertShader +[Alias('blur_size')] +[ComponentModel.DefaultBindingProperty('blur_size')] +[Single] +$BlurSize, +# Set the blur_quality of OBSDisplacementMapAdvancedInvertShader +[Alias('blur_quality')] +[ComponentModel.DefaultBindingProperty('blur_quality')] +[Single] +$BlurQuality, +# Set the blur_directions of OBSDisplacementMapAdvancedInvertShader +[Alias('blur_directions')] +[ComponentModel.DefaultBindingProperty('blur_directions')] +[Single] +$BlurDirections, +# Set the blur_angle of OBSDisplacementMapAdvancedInvertShader +[Alias('blur_angle')] +[ComponentModel.DefaultBindingProperty('blur_angle')] +[Single] +$BlurAngle, +# Set the chromatic_aberration_info of OBSDisplacementMapAdvancedInvertShader +[Alias('chromatic_aberration_info')] +[ComponentModel.DefaultBindingProperty('chromatic_aberration_info')] +[String] +$ChromaticAberrationInfo, +# Set the chromatic_aberration of OBSDisplacementMapAdvancedInvertShader +[Alias('chromatic_aberration')] +[ComponentModel.DefaultBindingProperty('chromatic_aberration')] +[Single] +$ChromaticAberration, +# Set the colorize_info of OBSDisplacementMapAdvancedInvertShader +[Alias('colorize_info')] +[ComponentModel.DefaultBindingProperty('colorize_info')] +[String] +$ColorizeInfo, +# Set the colorize_color of OBSDisplacementMapAdvancedInvertShader +[Alias('colorize_color')] +[ComponentModel.DefaultBindingProperty('colorize_color')] +[String] +$ColorizeColor, +# Set the flags_info of OBSDisplacementMapAdvancedInvertShader +[Alias('flags_info')] +[ComponentModel.DefaultBindingProperty('flags_info')] +[String] +$FlagsInfo, +# Set the blue_affects_strength of OBSDisplacementMapAdvancedInvertShader +[Alias('blue_affects_strength')] +[ComponentModel.DefaultBindingProperty('blue_affects_strength')] +[Management.Automation.SwitchParameter] +$BlueAffectsStrength, +# Set the blue_affects_colorize of OBSDisplacementMapAdvancedInvertShader +[Alias('blue_affects_colorize')] +[ComponentModel.DefaultBindingProperty('blue_affects_colorize')] +[Management.Automation.SwitchParameter] +$BlueAffectsColorize, +# Set the blue_affects_blur of OBSDisplacementMapAdvancedInvertShader +[Alias('blue_affects_blur')] +[ComponentModel.DefaultBindingProperty('blue_affects_blur')] +[Management.Automation.SwitchParameter] +$BlueAffectsBlur, +# Set the alpha_affects_strength of OBSDisplacementMapAdvancedInvertShader +[Alias('alpha_affects_strength')] +[ComponentModel.DefaultBindingProperty('alpha_affects_strength')] +[Management.Automation.SwitchParameter] +$AlphaAffectsStrength, +# Set the apply_alpha of OBSDisplacementMapAdvancedInvertShader +[Alias('apply_alpha')] +[ComponentModel.DefaultBindingProperty('apply_alpha')] +[Management.Automation.SwitchParameter] +$ApplyAlpha, +# Set the background_layer of OBSDisplacementMapAdvancedInvertShader +[Alias('background_layer')] +[ComponentModel.DefaultBindingProperty('background_layer')] +[String] +$BackgroundLayer, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -38834,126 +29587,210 @@ $UseShaderTime process { -$shaderName = 'simple_gradient' -$ShaderNoun = 'OBSSimpleGradientShader' +$shaderName = 'displacement_map_advanced_invert' +$ShaderNoun = 'OBSDisplacementMapAdvancedInvertShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Simple Gradient shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 -// https://github.com/Oncorporation/obs-shaderfilter +uniform string displacement_info< + string label = "Displacement"; + string widget_type = "info"; +> = "Displaces the Background Layer with the current image. Red channel is affected to X (horizontal) displacement and Green channel to Y (vertical). rgb(.5, .5, .5) is no displacement. You can choose the curve mapping to map values between -1 to 1 differently."; -//lots of room to play here -//Converted to OpenGL by Q-mii & Exeldro February 25, 2022 -uniform int speed_percentage< - string label = "speed percentage"; - string widget_type = "slider"; - int minimum = -500; - int maximum = 500; - int step = 1; -> = 240; // -uniform int alpha_percentage< - string label = "aplha percentage"; +uniform float displacement_x< + string label = "Displacement X (px)"; +> = 16.0; + +uniform float displacement_y< + string label = "Displacement Y (px)"; +> = 16.0; + +uniform int displacement_curve< + string label = "Displacement Curve"; + string widget_type = "select"; + int option_0_value = 1; + string option_0_label = "Linear"; + int option_1_value = 2; + string option_1_label = "Quadratic"; + int option_2_value = 3; + string option_2_label = "Cubic"; +> = 0; + +uniform string blur_info< + string label = "Blur"; + string widget_type = "info"; +> = "Imitates how light disperses through displacement. It can recreate refractions like effects. Blur size affects how much light disperses, quality is the number of samples, directions of those samples (around a circle). You can choose the starting angle (use directions 1 or 2 to have highly directional refractions)."; + +uniform float blur_size< + string label = "Blur Size (px)"; +> = 8.0; // BLUR SIZE (Radius) +uniform float blur_quality< + string label = "Blur Quality (4.0)"; + string widget_type = "slider"; + float minimum = 1.0; + float maximum = 16; + float step = 1.0; +> = 4.0; // BLUR QUALITY (Default 4.0 - More is better but slower) +uniform float blur_directions< + string label = "Blur Directions (16.0)"; + string widget_type = "slider"; + float minimum = 1.0; + float maximum = 24; + float step = 1.0; +> = 16.0; // BLUR DIRECTIONS (number of rays in sampling) +uniform float blur_angle< + string label = "Blur Angle (degrees)"; string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 90; -uniform bool Lens_Flair = false; -uniform bool Animate_Lens_Flair = false; -uniform bool Apply_To_Alpha_Layer = false; -uniform bool Apply_To_Specific_Color; -uniform float4 Color_To_Replace; -uniform string notes< - string widget_type = "info"; -> = "This gradient is very basic from the top left corner. Red on horizontal, Green vertical, Blue Diagonal. Apply To Alpha Layer will add the gradient colors to the background. Lens Flair will brighten the scene from the bottom right. There is also a lot of unused code to play with in the shader file, delimted by /* ... */"; + float minimum = 0; + float maximum = 360; + float step = 1.0; +> = 0; // BLUR Angle (starting angle of first sample) + +uniform string chromatic_aberration_info< + string label = "Chromatic Aberration"; + string widget_type = "info"; +> = "Imitates how colors diverge when light refracts. Value is between -1 and 1 as a multiplier of the displacement amount."; + +uniform float chromatic_aberration< + string label = "Chromatic Aberration (0.0)"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; + +uniform string colorize_info< + string label = "Color"; + string widget_type = "info"; +> = "Imitates how light change color (tinted glass for instance)"; + +uniform float4 colorize_color< + string label = "Colorize"; +> = {0.0, 0.0, 0.0, 0.0}; + +uniform string flags_info< + string label = "Additional Channels"; + string widget_type = "info"; +> = "You can affect Blue channel (Height / Z) to displacement strength, colorization or blur radius, and Alpha to displacement (can fix glitches on edges)."; + +uniform bool blue_affects_strength< + string label = "Blue channel affects displacement"; +> = false; +uniform bool blue_affects_colorize< + string label = "Blue channel affects colorize"; +> = false; +uniform bool blue_affects_blur< + string label = "Blue channel affects blur"; +> = false; +uniform bool alpha_affects_strength< + string label = "Alpha channel affects displacement"; +> = false; +uniform bool apply_alpha< + string label = "Apply alpha"; +> = false; + +uniform texture2d background_layer < + string label = "Background Layer"; +>; float4 mainImage(VertData v_in) : TARGET { + float Pi = 6.28318530718; // Pi*2 + float blurAngleRadians = (blur_angle / 360.) * Pi; - float4 background_color = image.Sample(textureSampler, v_in.uv); - int no_colors = 4; - float3 colors[4]; - colors[0] = float3(1.0,0.0,0.0); - colors[1] = float3(0.0,1.0,0.0); - colors[2] = float3(0.0,0.0,1.0); - colors[3] = float3(1.0,1.0,1.0); - float alpha = float(alpha_percentage) * 0.01; - float speed = float(speed_percentage) * 0.01; + float4 map_rgba = image.Sample(textureSampler, v_in.uv); - float mx = max(uv_size.x , uv_size.y); - //float2 uv = v_in.uv / mx; - float3 rgb = background_color.rgb; + float2 displace_strength = float2(displacement_x, displacement_y) / uv_size; + float4 displace = float4( + (map_rgba.r * 2) - 1, + (map_rgba.g * 2) - 1, + (map_rgba.b * 2) - 1, + map_rgba.a + ); - // skip if (alpha is zero and only apply to alpha layer is true) - if (!(background_color.a <= 0.0 && Apply_To_Alpha_Layer == true)) - { - rgb = float3(v_in.uv.x, v_in.uv.y, 0.10 + 0.85 * sin(elapsed_time * speed)); - } + float2 displace_uv = float2(displace.r, displace.g) * displace_strength; - //create lens flare like effect - if (Lens_Flair) - { - float2 lens_flair_coordinates = float2(0.95 ,0.95); - if (Animate_Lens_Flair) - lens_flair_coordinates *= float2(sin(elapsed_time * speed) ,cos(elapsed_time * speed)); + for(int p=1; p 0 && displace.a > 0) { + float4 oc = base_rgba; + float transparent = oc.a; + int count = 1; + float samples = oc.a; + + // Blur calculations + [loop] for( float d=blurAngleRadians; d < Pi + blurAngleRadians; d+=Pi/blur_directions) { + [loop] for(float i=1.0 / blur_quality; i <= 1.0; i += 1.0 / blur_quality) { + float size = blur_size; + float4 sc; - //try prepositioned colors with colors[] array timing - //creates an animated color spotlight -/* int color_index = int(sin(elapsed_time * speed) * no_colors); - float3 start_color = colors[color_index]; - float3 end_color; - if (color_index >= 0) - { - end_color = colors[color_index - 1]; - } - else - { - end_color = colors[no_colors - 1]; - } + if (blue_affects_blur) { + size *= displace.b; + } - rgb = smoothstep(start_color, end_color, distance(v_in.uv , sin(elapsed_time * speed * no_colors) * (float2(1.0,1.0) * uv_scale + uv_offset))); -*/ - float4 rgba; - if (Apply_To_Alpha_Layer == false) - { - rgba = lerp(background_color,float4(rgb, 1.0),alpha); - } - else - { - rgba = lerp(background_color,background_color * float4(rgb,1.0), alpha); - } - if (Apply_To_Specific_Color) - { - float4 original_color = background_color; - background_color = (distance(background_color.rgb, Color_To_Replace.rgb) <= 0.075) ? rgba : background_color; - rgba = lerp(original_color, background_color, clamp(alpha, 0, 1.0)); + if (chromatic_aberration) { + float4 sc_r = background_layer.Sample(textureSampler, v_in.uv + displace_uv - chromatic_aberration*displace_uv + float2(cos(d),sin(d)) * size * i / uv_size); + float4 sc_g = background_layer.Sample(textureSampler, v_in.uv + displace_uv + float2(cos(d),sin(d)) * size * i / uv_size); + float4 sc_b = background_layer.Sample(textureSampler, v_in.uv + displace_uv + chromatic_aberration*displace_uv + float2(cos(d),sin(d)) * size * i / uv_size); + + sc = float4(sc_r.r, sc_g.g, sc_b.b, sc_g.a); + } else { + sc = background_layer.Sample(textureSampler, v_in.uv + displace_uv + float2(cos(d),sin(d)) * size * i / uv_size); + } + + transparent += sc.a; + count++; + base_rgba += sc * sc.a; + samples += sc.a; + } } - return rgba; -} + //Calculate averages + if (samples > 0.0) + base_rgba /= samples; + + base_rgba.a = transparent / count; + } + + if (blue_affects_colorize) { + base_rgba = lerp(base_rgba, float4(colorize_color.r, colorize_color.g, colorize_color.b, 1.0), colorize_color.a * displace.b); + } else { + base_rgba = lerp(base_rgba, float4(colorize_color.r, colorize_color.g, colorize_color.b, 1.0), colorize_color.a); + } + + if (apply_alpha) { + float4 background_rgba = background_layer.Sample(textureSampler, v_in.uv); + return lerp( + float4(background_rgba.r, background_rgba.g, background_rgba.b, background_rgba.a), + float4(base_rgba.r, base_rgba.g, base_rgba.b, base_rgba.a * displace.a), + displace.a + ); + } + + return float4(base_rgba.r, base_rgba.g, base_rgba.b, base_rgba.a * displace.a); +} ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -39051,52 +29888,110 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSimplexNoiseShader { +function Get-OBSDisplacementMapAdvancedShader { -[Alias('Set-OBSSimplexNoiseShader','Add-OBSSimplexNoiseShader')] +[Alias('Set-OBSDisplacementMapAdvancedShader','Add-OBSDisplacementMapAdvancedShader')] param( -# Set the Snap_Percent of OBSSimplexNoiseShader -[Alias('Snap_Percent')] -[ComponentModel.DefaultBindingProperty('Snap_Percent')] +# Set the displacement_info of OBSDisplacementMapAdvancedShader +[Alias('displacement_info')] +[ComponentModel.DefaultBindingProperty('displacement_info')] +[String] +$DisplacementInfo, +# Set the displacement_x of OBSDisplacementMapAdvancedShader +[Alias('displacement_x')] +[ComponentModel.DefaultBindingProperty('displacement_x')] [Single] -$SnapPercent, -# Set the Speed_Percent of OBSSimplexNoiseShader -[Alias('Speed_Percent')] -[ComponentModel.DefaultBindingProperty('Speed_Percent')] +$DisplacementX, +# Set the displacement_y of OBSDisplacementMapAdvancedShader +[Alias('displacement_y')] +[ComponentModel.DefaultBindingProperty('displacement_y')] [Single] -$SpeedPercent, -# Set the Resolution of OBSSimplexNoiseShader -[ComponentModel.DefaultBindingProperty('Resolution')] +$DisplacementY, +# Set the displacement_curve of OBSDisplacementMapAdvancedShader +[Alias('displacement_curve')] +[ComponentModel.DefaultBindingProperty('displacement_curve')] +[Int32] +$DisplacementCurve, +# Set the blur_info of OBSDisplacementMapAdvancedShader +[Alias('blur_info')] +[ComponentModel.DefaultBindingProperty('blur_info')] +[String] +$BlurInfo, +# Set the blur_size of OBSDisplacementMapAdvancedShader +[Alias('blur_size')] +[ComponentModel.DefaultBindingProperty('blur_size')] [Single] -$Resolution, -# Set the Fractal of OBSSimplexNoiseShader -[ComponentModel.DefaultBindingProperty('Fractal')] -[Management.Automation.SwitchParameter] -$Fractal, -# Set the Use_Alpha_Layer of OBSSimplexNoiseShader -[Alias('Use_Alpha_Layer')] -[ComponentModel.DefaultBindingProperty('Use_Alpha_Layer')] -[Management.Automation.SwitchParameter] -$UseAlphaLayer, -# Set the Fore_Color of OBSSimplexNoiseShader -[Alias('Fore_Color')] -[ComponentModel.DefaultBindingProperty('Fore_Color')] -[String] -$ForeColor, -# Set the Back_Color of OBSSimplexNoiseShader -[Alias('Back_Color')] -[ComponentModel.DefaultBindingProperty('Back_Color')] -[String] -$BackColor, -# Set the Alpha_Percent of OBSSimplexNoiseShader -[Alias('Alpha_Percent')] -[ComponentModel.DefaultBindingProperty('Alpha_Percent')] +$BlurSize, +# Set the blur_quality of OBSDisplacementMapAdvancedShader +[Alias('blur_quality')] +[ComponentModel.DefaultBindingProperty('blur_quality')] [Single] -$AlphaPercent, -# Set the Notes of OBSSimplexNoiseShader -[ComponentModel.DefaultBindingProperty('Notes')] -[String] -$Notes, +$BlurQuality, +# Set the blur_directions of OBSDisplacementMapAdvancedShader +[Alias('blur_directions')] +[ComponentModel.DefaultBindingProperty('blur_directions')] +[Single] +$BlurDirections, +# Set the blur_angle of OBSDisplacementMapAdvancedShader +[Alias('blur_angle')] +[ComponentModel.DefaultBindingProperty('blur_angle')] +[Single] +$BlurAngle, +# Set the chromatic_aberration_info of OBSDisplacementMapAdvancedShader +[Alias('chromatic_aberration_info')] +[ComponentModel.DefaultBindingProperty('chromatic_aberration_info')] +[String] +$ChromaticAberrationInfo, +# Set the chromatic_aberration of OBSDisplacementMapAdvancedShader +[Alias('chromatic_aberration')] +[ComponentModel.DefaultBindingProperty('chromatic_aberration')] +[Single] +$ChromaticAberration, +# Set the colorize_info of OBSDisplacementMapAdvancedShader +[Alias('colorize_info')] +[ComponentModel.DefaultBindingProperty('colorize_info')] +[String] +$ColorizeInfo, +# Set the colorize_color of OBSDisplacementMapAdvancedShader +[Alias('colorize_color')] +[ComponentModel.DefaultBindingProperty('colorize_color')] +[String] +$ColorizeColor, +# Set the flags_info of OBSDisplacementMapAdvancedShader +[Alias('flags_info')] +[ComponentModel.DefaultBindingProperty('flags_info')] +[String] +$FlagsInfo, +# Set the blue_affects_strength of OBSDisplacementMapAdvancedShader +[Alias('blue_affects_strength')] +[ComponentModel.DefaultBindingProperty('blue_affects_strength')] +[Management.Automation.SwitchParameter] +$BlueAffectsStrength, +# Set the blue_affects_colorize of OBSDisplacementMapAdvancedShader +[Alias('blue_affects_colorize')] +[ComponentModel.DefaultBindingProperty('blue_affects_colorize')] +[Management.Automation.SwitchParameter] +$BlueAffectsColorize, +# Set the blue_affects_blur of OBSDisplacementMapAdvancedShader +[Alias('blue_affects_blur')] +[ComponentModel.DefaultBindingProperty('blue_affects_blur')] +[Management.Automation.SwitchParameter] +$BlueAffectsBlur, +# Set the alpha_affects_strength of OBSDisplacementMapAdvancedShader +[Alias('alpha_affects_strength')] +[ComponentModel.DefaultBindingProperty('alpha_affects_strength')] +[Management.Automation.SwitchParameter] +$AlphaAffectsStrength, +# Set the apply_alpha of OBSDisplacementMapAdvancedShader +[Alias('apply_alpha')] +[ComponentModel.DefaultBindingProperty('apply_alpha')] +[Management.Automation.SwitchParameter] +$ApplyAlpha, +# Set the mask_layer of OBSDisplacementMapAdvancedShader +[Alias('mask_layer')] +[ComponentModel.DefaultBindingProperty('mask_layer')] +[String] +$MaskLayer, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -39127,204 +30022,209 @@ $UseShaderTime process { -$shaderName = 'simplex_noise' -$ShaderNoun = 'OBSSimplexNoiseShader' +$shaderName = 'displacement_map_advanced' +$ShaderNoun = 'OBSDisplacementMapAdvancedShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Simplex Noise shader by Charles Fettinger (https://github.com/Oncorporation) 5/2019 -// for use with obs-shaderfilter 1.0 -//based upon: https://www.shadertoy.com/view/XsX3zB +uniform string displacement_info< + string label = "Displacement"; + string widget_type = "info"; +> = "Displaces the current image with the Mask Layer. Red channel is affected to X (horizontal) displacement and Green channel to Y (vertical). rgb(.5, .5, .5) is no displacement. You can choose the curve mapping to map values between -1 to 1 differently."; -#ifndef OPENGL -#define fract frac -#endif +uniform float displacement_x< + string label = "Displacement X (px)"; +> = 16.0; -uniform float Snap_Percent< - string label = "Snap Percent"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 7.5; -uniform float Speed_Percent< - string label = "Speed Percent"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 2.5; -uniform float Resolution< - string label = "Resolution"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; +uniform float displacement_y< + string label = "Displacement Y (px)"; > = 16.0; -uniform bool Fractal = false; -uniform bool Use_Alpha_Layer = false; -uniform float4 Fore_Color = {0.95,0.95,0.95, 1.0}; -uniform float4 Back_Color = {0.75, 0.75, 0.75, 1.0}; -uniform float Alpha_Percent< - string label = "Alpha Percent"; + +uniform int displacement_curve< + string label = "Displacement Curve"; + string widget_type = "select"; + int option_0_value = 1; + string option_0_label = "Linear"; + int option_1_value = 2; + string option_1_label = "Quadratic"; + int option_2_value = 3; + string option_2_label = "Cubic"; +> = 0; + +uniform string blur_info< + string label = "Blur"; + string widget_type = "info"; +> = "Imitates how light disperses through displacement. It can recreate refractions like effects. Blur size affects how much light disperses, quality is the number of samples, directions of those samples (around a circle). You can choose the starting angle (use directions 1 or 2 to have highly directional refractions)."; + +uniform float blur_size< + string label = "Blur Size (px)"; +> = 8.0; // BLUR SIZE (Radius) +uniform float blur_quality< + string label = "Blur Quality (4.0)"; + string widget_type = "slider"; + float minimum = 1.0; + float maximum = 16; + float step = 1.0; +> = 4.0; // BLUR QUALITY (Default 4.0 - More is better but slower) +uniform float blur_directions< + string label = "Blur Directions (16.0)"; + string widget_type = "slider"; + float minimum = 1.0; + float maximum = 24; + float step = 1.0; +> = 16.0; // BLUR DIRECTIONS (number of rays in sampling) +uniform float blur_angle< + string label = "Blur Angle (degrees)"; string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 100.0; -uniform string Notes< - string widget_type = "info"; -> = "Alpha Percentage applies to the shader, Use_Alpha_Layer applies effect with the image alpha layer, Resolution is the amount of detail of noise created.Fractal is a different algorithm. Snap Percent affects how many updates per second. Default values: 7.5%, 2.5%, 16.0, 100%"; + float minimum = 0; + float maximum = 360; + float step = 1.0; +> = 0; // BLUR Angle (starting angle of first sample) + +uniform string chromatic_aberration_info< + string label = "Chromatic Aberration"; + string widget_type = "info"; +> = "Imitates how colors diverge when light refracts. Value is between -1 and 1 as a multiplier of the displacement amount."; + +uniform float chromatic_aberration< + string label = "Chromatic Aberration (0.0)"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; -float dot(float3 a, float3 b){ - return a.r*b.r+a.g*b.g+a.b*b.b; -} +uniform string colorize_info< + string label = "Color"; + string widget_type = "info"; +> = "Imitates how light change color (tinted glass for instance)"; -float dot4(float4 a, float4 b){ - return a.r*b.r+a.g*b.g+a.b*b.b+a.a*b.a; -} -float snap(float x, float snap) -{ - return snap * round(x / max(0.01,snap)); -} +uniform float4 colorize_color< + string label = "Colorize"; +> = {0.0, 0.0, 0.0, 0.0}; -float3 random3(float3 co) -{ - float j = 4096.0 * sin(dot(co, float3(17.0, 59.4, 15.0))); - float3 result; - result.z = fract(512.0 * j); - j *= .125; - result.x = fract(512.0 * j); - j *= .125; - result.y = fract(512.0 * j); - return result - 0.5; -} +uniform string flags_info< + string label = "Additional Channels"; + string widget_type = "info"; +> = "You can affect Blue channel (Height / Z) to displacement strength, colorization or blur radius, and Alpha to displacement (can fix glitches on edges)."; -/* 3d simplex noise */ -float simplex3d(float3 p) { - /* 1. find current tetrahedron T and it''s four vertices */ - /* s, s+i1, s+i2, s+1.0 - absolute skewed (integer) coordinates of T vertices */ - /* x, x1, x2, x3 - unskewed coordinates of p relative to each of T vertices*/ - - /* skew constants for 3d simplex functions */ - float F3 = 0.3333333; - float G3 = 0.1666667; +uniform bool blue_affects_strength< + string label = "Blue channel affects displacement"; +> = false; +uniform bool blue_affects_colorize< + string label = "Blue channel affects colorize"; +> = false; +uniform bool blue_affects_blur< + string label = "Blue channel affects blur"; +> = false; +uniform bool alpha_affects_strength< + string label = "Alpha channel affects displacement"; +> = false; +uniform bool apply_alpha< + string label = "Apply alpha"; +> = false; - /* calculate s and x */ - float3 s = floor(p + dot(p, float3(F3,F3,F3))); - float3 x = p - s + dot(s, float3(G3,G3,G3)); +uniform texture2d mask_layer < + string label = "Mask Layer"; +>; - /* calculate i1 and i2 */ - float3 e = step(float3(0.0,0.0,0.0), x - x.yzx); - float3 i1 = e * (1.0 - e.zxy); - float3 i2 = 1.0 - e.zxy * (1.0 - e); +float4 mainImage(VertData v_in) : TARGET +{ + float Pi = 6.28318530718; // Pi*2 + float blurAngleRadians = (blur_angle / 360.) * Pi; - /* x1, x2, x3 */ - float3 x1 = x - i1 + G3; - float3 x2 = x - i2 + 2.0 * G3; - float3 x3 = x - 1.0 + 3.0 * G3; + float4 map_rgba = mask_layer.Sample(textureSampler, v_in.uv); - /* 2. find four surflets and store them in d */ - float4 w, d; + float2 displace_strength = float2(displacement_x, displacement_y) / uv_size; + float4 displace = float4( + (map_rgba.r * 2) - 1, + (map_rgba.g * 2) - 1, + (map_rgba.b * 2) - 1, + map_rgba.a + ); - /* calculate surflet weights */ - w.x = dot(x, x); - w.y = dot(x1, x1); - w.z = dot(x2, x2); - w.w = dot(x3, x3); + float2 displace_uv = float2(displace.r, displace.g) * displace_strength; - /* w fades from 0.6 at the center of the surflet to 0.0 at the margin */ - w = max(0.61 - w, 0.0); + for(int p=1; p 0 && displace.a > 0) { + float4 oc = base_rgba; + float transparent = oc.a; + int count = 1; + float samples = oc.a; + + // Blur calculations + [loop] for( float d=blurAngleRadians; d < Pi + blurAngleRadians; d+=Pi/blur_directions) { + [loop] for(float i=1.0 / blur_quality; i <= 1.0; i += 1.0 / blur_quality) { + float size = blur_size; + float4 sc; - float3 m = {m3.x, m3.y, m3.z}; -#endif + if (blue_affects_blur) { + size *= displace.b; + } - return 0.5333333* simplex3d(mul(m, rot1)) - + 0.2666667 * simplex3d(2.0 * mul(m, rot2)) - + 0.1333333 * simplex3d(4.0 * mul(m, rot3)) - + 0.0666667 * simplex3d(8.0 * m); -} + if (chromatic_aberration) { + float4 sc_r = image.Sample(textureSampler, v_in.uv + displace_uv - chromatic_aberration*displace_uv + float2(cos(d),sin(d)) * size * i / uv_size); + float4 sc_g = image.Sample(textureSampler, v_in.uv + displace_uv + float2(cos(d),sin(d)) * size * i / uv_size); + float4 sc_b = image.Sample(textureSampler, v_in.uv + displace_uv + chromatic_aberration*displace_uv + float2(cos(d),sin(d)) * size * i / uv_size); -float4 mainImage(VertData v_in) : TARGET -{ - float time = snap(elapsed_time, Snap_Percent * .01); - float4 rgba = image.Sample(textureSampler, v_in.uv); - float2 p = v_in.uv.xy + float2( 0, -0.5); - float3 p3 = float3(p, time * (Speed_Percent * 0.01)); - - float pixel_alpha = 1.0; - // apply to mainImage rgba - if (Use_Alpha_Layer) { - p3 *= rgba.rgb; - pixel_alpha = rgba.a; - } + sc = float4(sc_r.r, sc_g.g, sc_b.b, sc_g.a); + } else { + sc = image.Sample(textureSampler, v_in.uv + displace_uv + float2(cos(d),sin(d)) * size * i / uv_size); + } - float value; + transparent += sc.a; + count++; + base_rgba += sc * sc.a; + samples += sc.a; + } + } - if (Fractal) { - value = simplex3d_fractal(p3 * (Resolution * 0.5) + (Resolution * 0.5)); - } - else { - value = simplex3d(p3 * Resolution); - } + //Calculate averages + if (samples > 0.0) + base_rgba /= samples; - //soften color - value = 0.5 + (0.5 * value); - float intensity = dot(float3(value, value, value), float3(0.299, 0.587, 0.114)); + base_rgba.a = transparent / count; + } - //use intensity to apply foreground and background colors - float4 r = lerp(float4(float3(value, value, value), pixel_alpha), Fore_Color, saturate(intensity)); - r = lerp(Back_Color, r, saturate(intensity)); - r.a = pixel_alpha; + if (blue_affects_colorize) { + base_rgba = lerp(base_rgba, float4(colorize_color.r, colorize_color.g, colorize_color.b, 1.0), colorize_color.a * displace.b); + } else { + base_rgba = lerp(base_rgba, float4(colorize_color.r, colorize_color.g, colorize_color.b, 1.0), colorize_color.a); + } - return lerp(rgba, r, Alpha_Percent * 0.01); + if (apply_alpha) { + float4 background_rgba = image.Sample(textureSampler, v_in.uv); + + return lerp( + float4(background_rgba.r, background_rgba.g, background_rgba.b, background_rgba.a), + float4(base_rgba.r, base_rgba.g, base_rgba.b, base_rgba.a * displace.a), + displace.a + ); + } + + return float4(base_rgba.r, base_rgba.g, base_rgba.b, base_rgba.a * displace.a); } ' } @@ -39423,22 +30323,30 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSmartDenoiseShader { +function Get-OBSDisplacementMapInvertShader { -[Alias('Set-OBSSmartDenoiseShader','Add-OBSSmartDenoiseShader')] +[Alias('Set-OBSDisplacementMapInvertShader','Add-OBSDisplacementMapInvertShader')] param( -# Set the uSigma of OBSSmartDenoiseShader -[ComponentModel.DefaultBindingProperty('uSigma')] -[Single] -$USigma, -# Set the uKSigma of OBSSmartDenoiseShader -[ComponentModel.DefaultBindingProperty('uKSigma')] +# Set the displacement_info of OBSDisplacementMapInvertShader +[Alias('displacement_info')] +[ComponentModel.DefaultBindingProperty('displacement_info')] +[String] +$DisplacementInfo, +# Set the displacement_x of OBSDisplacementMapInvertShader +[Alias('displacement_x')] +[ComponentModel.DefaultBindingProperty('displacement_x')] [Single] -$UKSigma, -# Set the uThreshold of OBSSmartDenoiseShader -[ComponentModel.DefaultBindingProperty('uThreshold')] +$DisplacementX, +# Set the displacement_y of OBSDisplacementMapInvertShader +[Alias('displacement_y')] +[ComponentModel.DefaultBindingProperty('displacement_y')] [Single] -$UThreshold, +$DisplacementY, +# Set the background_layer of OBSDisplacementMapInvertShader +[Alias('background_layer')] +[ComponentModel.DefaultBindingProperty('background_layer')] +[String] +$BackgroundLayer, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -39469,85 +30377,42 @@ $UseShaderTime process { -$shaderName = 'smart_denoise' -$ShaderNoun = 'OBSSmartDenoiseShader' +$shaderName = 'displacement_map_invert' +$ShaderNoun = 'OBSDisplacementMapInvertShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Smart DeNoise By Michele Morrone (https://github.com/BrutPitt/glslSmartDeNoise) -// Converted to OBS version of HLSL by Euiko on February 10, 2025 - -#define INV_SQRT_OF_2PI 0.39894228040143267793994605993439 // 1.0/SQRT_OF_2PI -#define INV_PI 0.31830988618379067153776752674503 - -uniform float uSigma< - string label = "Sigma"; - string widget_type = "slider"; - float minimum = 0.01; - float maximum = 3; // max based on the webgl sample, which is 3 - float step = 0.01; -> = 5.0; // default value based on shadertoy -uniform float uKSigma< - string label = "K-Sigma"; - string widget_type = "slider"; - float minimum = 0.01; - float maximum = 24; // max based on the webgl sample, which is 24 - float step = 0.01; -> = 7.0; // the default value is based on the webgl sample -uniform float uThreshold< - string label = "Edge Threshold"; - string widget_type = "slider"; - float minimum = 0.01; - float maximum = 2; // max based on the webgl sample, which is 2 - float step = 0.01; -> = 0.190; // the default value is based on the webgl sample - -// smartDeNoise - parameters -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// float2 uv - actual fragment coord -// float2 size - window size -// float sigma > 0 - sigma Standard Deviation -// float kSigma >= 0 - sigma coefficient -// kSigma * sigma --> radius of the circular kernel -// float threshold - edge sharpening threshold -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// NOTE: image''s texture2d data will be supplied by the OBS shaderfilter by default -float4 smartDeNoise(float2 uv, float2 size, float sigma, float kSigma, float threshold) -{ - float radius = round(kSigma * sigma); - float radQ = radius * radius; - - float invSigmaQx2 = 0.5 / (sigma * sigma); // 1.0 / (sigma^2 * 2.0) - float invSigmaQx2PI = INV_PI * invSigmaQx2; // 1/(2 * PI * sigma^2) - - float invThresholdSqx2 = 0.5 / (threshold * threshold); // 1.0 / (sigma^2 * 2.0) - float invThresholdSqrt2PI = INV_SQRT_OF_2PI / threshold; // 1.0 / (sqrt(2*PI) * sigma^2) +uniform string displacement_info< + string label = "Displacement"; + string widget_type = "info"; +> = "Displaces the Background Layer with the current image. Red channel is affected to X (horizontal) displacement and Green channel to Y (vertical). rgb(.5, .5, .5) is no displacement."; - float4 centrPx = image.Sample(textureSampler, uv); +uniform float displacement_x< + string label = "Displacement X (px)"; +> = 16.0; - float zBuff = 0.0; - float4 aBuff = float4(0.0, 0.0, 0.0, 0.0); +uniform float displacement_y< + string label = "Displacement Y (px)"; +> = 16.0; - float2 d; - for (d.x = -radius; d.x <= radius; d.x += 1.0) - { - float pt = sqrt(radQ - (d.x * d.x)); // pt = yRadius: have circular trend - d.y = -pt; - for (; d.y <= pt; d.y += 1.0) - { - float blurFactor = exp((-dot(d, d)) * invSigmaQx2) * invSigmaQx2PI; - float4 walkPx = image.Sample(textureSampler, uv + (d / size)); - float4 dC = walkPx - centrPx; - float deltaFactor = (exp((-dot(dC.xyz, dC.xyz)) * invThresholdSqx2) * invThresholdSqrt2PI) * blurFactor; - zBuff += deltaFactor; - aBuff += (walkPx * deltaFactor); - } - } - return aBuff / float4(zBuff, zBuff, zBuff, zBuff); -} +uniform texture2d background_layer ; float4 mainImage(VertData v_in) : TARGET { - return smartDeNoise(v_in.uv, uv_size, uSigma, uKSigma, uThreshold); + float4 map = image.Sample(textureSampler, v_in.uv); + float4 base = background_layer.Sample(textureSampler, v_in.uv); + + float2 displace_strength = float2(displacement_x, displacement_y) / uv_size; + float4 displace = float4( + (map.r * 2) - 1, + (map.g * 2) - 1, + (map.b * 2) - 1, + map.a + ); + + float2 displace_uv = float2(displace.r, displace.g) * displace_strength; + float4 displaced = background_layer.Sample(textureSampler, v_in.uv + displace_uv); + + return float4(displaced.r, displaced.g, displaced.b, displaced.a * displace.a); } ' @@ -39647,47 +30512,30 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSpecularShineShader { +function Get-OBSDisplacementMapShader { -[Alias('Set-OBSSpecularShineShader','Add-OBSSpecularShineShader')] +[Alias('Set-OBSDisplacementMapShader','Add-OBSDisplacementMapShader')] param( -# Set the Hint of OBSSpecularShineShader -[ComponentModel.DefaultBindingProperty('Hint')] -[String] -$Hint, -# Set the roughness of OBSSpecularShineShader -[ComponentModel.DefaultBindingProperty('roughness')] -[Single] -$Roughness, -# Set the lightStrength of OBSSpecularShineShader -[ComponentModel.DefaultBindingProperty('lightStrength')] -[Single] -$LightStrength, -# Set the LightPositionX of OBSSpecularShineShader -[ComponentModel.DefaultBindingProperty('LightPositionX')] -[Single] -$LightPositionX, -# Set the LightPositionY of OBSSpecularShineShader -[ComponentModel.DefaultBindingProperty('LightPositionY')] -[Single] -$LightPositionY, -# Set the flattenNormal of OBSSpecularShineShader -[ComponentModel.DefaultBindingProperty('flattenNormal')] -[Single] -$FlattenNormal, -# Set the stretchNormalX of OBSSpecularShineShader -[ComponentModel.DefaultBindingProperty('stretchNormalX')] +# Set the displacement_info of OBSDisplacementMapShader +[Alias('displacement_info')] +[ComponentModel.DefaultBindingProperty('displacement_info')] +[String] +$DisplacementInfo, +# Set the displacement_x of OBSDisplacementMapShader +[Alias('displacement_x')] +[ComponentModel.DefaultBindingProperty('displacement_x')] [Single] -$StretchNormalX, -# Set the stretchNormalY of OBSSpecularShineShader -[ComponentModel.DefaultBindingProperty('stretchNormalY')] +$DisplacementX, +# Set the displacement_y of OBSDisplacementMapShader +[Alias('displacement_y')] +[ComponentModel.DefaultBindingProperty('displacement_y')] [Single] -$StretchNormalY, -# Set the Light_Color of OBSSpecularShineShader -[Alias('Light_Color')] -[ComponentModel.DefaultBindingProperty('Light_Color')] -[Single[]] -$LightColor, +$DisplacementY, +# Set the mask_layer of OBSDisplacementMapShader +[Alias('mask_layer')] +[ComponentModel.DefaultBindingProperty('mask_layer')] +[String] +$MaskLayer, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -39718,108 +30566,42 @@ $UseShaderTime process { -$shaderName = 'specular-shine' -$ShaderNoun = 'OBSSpecularShineShader' +$shaderName = 'displacement_map' +$ShaderNoun = 'OBSDisplacementMapShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Specular Shine shader by Andicraft / Andrea Jörgensen - https://github.com/Andicraft - -uniform string Hint< - string widget_type = "info"; -> = "Try using a black color source with the additive blend mode!"; - -uniform float roughness< - string label = "Roughness"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.25; - -uniform float lightStrength< - string label = "lightStrength"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2.0; - float step = 0.001; -> = 0.5; - -uniform float LightPositionX< - string label = "Light Position X"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; - -uniform float LightPositionY< - string label = "Light Position Y"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; - -uniform float flattenNormal< - string label = "Flatten Normal"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.01; -> = 0.1; - -uniform float stretchNormalX< - string label = "Stretch Normal X"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 4.0; - float step = 0.01; -> = 1; - -uniform float stretchNormalY< - string label = "Stretch Normal Y"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 4.0; - float step = 0.01; -> = 1; - -uniform float3 Light_Color = {1,1,1}; +uniform string displacement_info< + string label = "Displacement"; + string widget_type = "info"; +> = "Displaces the current image with the Mask Layer. Red channel is affected to X (horizontal) displacement and Green channel to Y (vertical). rgb(.5, .5, .5) is no displacement."; -float Square(float a) { return a * a; } +uniform float displacement_x< + string label = "Displacement X (px)"; +> = 16.0; -float CookTorrance(float3 lightDir, float3 normal, float roughness) { - float3 h = normalize(lightDir + float3(0,0,1)); - float nh2 = Square(saturate(dot(normal, h))); - float lh2 = Square(saturate(dot(lightDir, h))); - float r2 = Square(roughness); - float d2 = Square(nh2 * (r2 - 1.0) + 1.00001); - float normalization = roughness * 4.0 + 2.0; - return r2 / (d2 * max(0.1, lh2) * normalization); -} +uniform float displacement_y< + string label = "Displacement Y (px)"; +> = 16.0; -#define PI 3.14159265 +uniform texture2d mask_layer ; float4 mainImage(VertData v_in) : TARGET { + float4 map = mask_layer.Sample(textureSampler, v_in.uv); + float4 base = image.Sample(textureSampler, v_in.uv); + + float2 displace_strength = float2(displacement_x, displacement_y) / uv_size; + float4 displace = float4( + (map.r * 2) - 1, + (map.g * 2) - 1, + (map.b * 2) - 1, + map.a + ); - float4 c0 = image.Sample(textureSampler, v_in.uv); - - float3 lightDir = normalize(float3(-LightPositionX*5, -LightPositionY*5, 1)); - - float2 normalUV = v_in.uv - 0.5; - normalUV.x /= stretchNormalX; - normalUV.y /= stretchNormalY; - normalUV += 0.5; - - float3 normal = normalize(float3(normalUV.x * 2 - 1,normalUV.y * 2 - 1,-1)); - normal.z *= -1; - - normal = lerp(normal, float3(0,0,-1), flattenNormal); - - float3 light = CookTorrance(lightDir, normal, roughness)*float3(1,1,1)*lightStrength*Light_Color; + float2 displace_uv = float2(displace.r, displace.g) * displace_strength; + float4 displaced = image.Sample(textureSampler, v_in.uv + displace_uv); - return float4(c0 + light,c0.a); + return float4(displaced.r, displaced.g, displaced.b, displaced.a * displace.a); } ' @@ -39919,41 +30701,31 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSpotlightShader { +function Get-OBSDivideRotateShader { -[Alias('Set-OBSSpotlightShader','Add-OBSSpotlightShader')] +[Alias('Set-OBSDivideRotateShader','Add-OBSDivideRotateShader')] param( -# Set the Speed_Percent of OBSSpotlightShader -[Alias('Speed_Percent')] -[ComponentModel.DefaultBindingProperty('Speed_Percent')] -[Single] -$SpeedPercent, -# Set the Focus_Percent of OBSSpotlightShader -[Alias('Focus_Percent')] -[ComponentModel.DefaultBindingProperty('Focus_Percent')] -[Single] -$FocusPercent, -# Set the Glitch of OBSSpotlightShader -[ComponentModel.DefaultBindingProperty('Glitch')] -[Management.Automation.SwitchParameter] -$Glitch, -# Set the Spotlight_Color of OBSSpotlightShader -[Alias('Spotlight_Color')] -[ComponentModel.DefaultBindingProperty('Spotlight_Color')] +# Set the iChannel0 of OBSDivideRotateShader +[ComponentModel.DefaultBindingProperty('iChannel0')] [String] -$SpotlightColor, -# Set the Horizontal_Offset of OBSSpotlightShader -[Alias('Horizontal_Offset')] -[ComponentModel.DefaultBindingProperty('Horizontal_Offset')] -[Single] -$HorizontalOffset, -# Set the Vertical_Offset of OBSSpotlightShader -[Alias('Vertical_Offset')] -[ComponentModel.DefaultBindingProperty('Vertical_Offset')] -[Single] -$VerticalOffset, -# Set the Notes of OBSSpotlightShader -[ComponentModel.DefaultBindingProperty('Notes')] +$IChannel0, +# Set the speed_percentage of OBSDivideRotateShader +[Alias('speed_percentage')] +[ComponentModel.DefaultBindingProperty('speed_percentage')] +[Int32] +$SpeedPercentage, +# Set the alpha_percentage of OBSDivideRotateShader +[Alias('alpha_percentage')] +[ComponentModel.DefaultBindingProperty('alpha_percentage')] +[Int32] +$AlphaPercentage, +# Set the Apply_To_Alpha_Layer of OBSDivideRotateShader +[Alias('Apply_To_Alpha_Layer')] +[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] +[Management.Automation.SwitchParameter] +$ApplyToAlphaLayer, +# Set the notes of OBSDivideRotateShader +[ComponentModel.DefaultBindingProperty('notes')] [String] $Notes, # The name of the source. This must be provided when adding an item for the first time @@ -39986,62 +30758,89 @@ $UseShaderTime process { -$shaderName = 'spotlight' -$ShaderNoun = 'OBSSpotlightShader' +$shaderName = 'divide_rotate' +$ShaderNoun = 'OBSDivideRotateShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Spotlight By Charles Fettinger (https://github.com/Oncorporation) 4/2019 -uniform float Speed_Percent< - string label = "Speed Percent"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 100.0; -uniform float Focus_Percent< - string label = "Focus Percent"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 0.01; -> = 15.0; -uniform bool Glitch; -uniform float4 Spotlight_Color; -uniform float Horizontal_Offset< - string label = "Horizontal Offset"; +// divide and rotate shader for OBS Studio shaderfilter plugin +// originally from shadertoy (https://www.shadertoy.com/view/3sy3Dh) +// Modified by Charles Fettinger (https://github.com/Oncorporation) 10/2019 +//Converted to OpenGL by Q-mii & Exeldro February 18, 2022 +uniform texture2d iChannel0; +uniform int speed_percentage< + string label = "Speed"; string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = 0.0; -uniform float Vertical_Offset< - string label = "Vertical Offset"; + int minimum = -10; + int maximum = 10; + int step = 1; +> = 5; +uniform int alpha_percentage< + string label = "Opacity Percentage"; string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.001; -> = -0.5; -uniform string Notes< + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform bool Apply_To_Alpha_Layer = true; + +uniform string notes< string widget_type = "info"; -> = "use negative Focus Percent to create a shade effect, speed zero is a stationary spotlight"; +> = "add rotation and speed"; + + +float2 cm(float2 a, float2 b) { + return float2(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x); +} + +float2 iter(float2 uv, float2 rot, float scale) { + float2 gv = frac(cm(uv, rot) * scale); + float boundDist = 1. - max(abs(gv.x), abs(gv.y)); + float mask = step(.03, boundDist); + gv *= mask; + return gv; +} float4 mainImage(VertData v_in) : TARGET { - float speed = Speed_Percent * 0.01; - float focus = Focus_Percent; - if (Glitch) - { - speed *= ((rand_f * 2) - 1) * 0.01; - focus *= ((rand_f * 1.1) - 0.1); - } + float alpha = clamp(alpha_percentage * 0.01, 0.0, 1.0); + float speed = clamp(speed_percentage * 0.01, -10.0, 10.0); - float PI = 3.1415926535897932384626433832795;//acos(-1); - float4 c0 = image.Sample( textureSampler, v_in.uv); - float3 lightsrc = float3(sin(elapsed_time * speed * PI * 0.667) *.5 + .5 + Horizontal_Offset, cos(elapsed_time * speed * PI) *.5 + .5 + Vertical_Offset, 1); - float3 light = normalize(lightsrc - float3( v_in.uv.x + (Horizontal_Offset * speed), v_in.uv.y + (Vertical_Offset * speed), 0)); - c0 *= pow(dot(light, float3(0, 0, 1)), focus) * Spotlight_Color; + // Normalize coords + //float2 uv = (v_in.uv * uv_scale + uv_offset); + float2 uv = (float2(v_in.uv.x, (1 - v_in.uv.y)) * uv_scale + uv_offset) - .5 * (v_in.uv * uv_scale + uv_offset);// / v_in.uv.y; + float2 mouse = (v_in.uv.xy - .5 * v_in.uv.xy) / v_in.uv.y; - return c0; + // Add some time rotation and offset + float t = elapsed_time * speed; + float2 time = float2(sin(t), cos(t)); + uv += time; + + // Imaginary component has to be mirrored for natural feeling rotation + mouse.y *= -1.0; + + // Draw few layers of this to bend space + float2 rot = cm(mouse, time); + for (float i=1.0; i<=3.0; i++) { + uv = iter(uv, rot, 1.5); + } + + // Combine background with new image + float4 background_color = image.Sample(textureSampler, v_in.uv); + float4 col = iChannel0.Sample(textureSampler, uv); + + // Border + if (uv.x == 0.0 && uv.y == 0.0) { + col = float4(0,0,0,alpha); + } + + // if not appling to alpha layer, set output alpha + if (Apply_To_Alpha_Layer == false) + col.a = alpha; + + //output color is combined with background image + col.rgb = lerp(background_color.rgb,col.rgb,clamp(alpha, 0.0, 1.0)); + + return col; } ' } @@ -40140,38 +30939,60 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSwirlShader { +function Get-OBSDoodleShader { -[Alias('Set-OBSSwirlShader','Add-OBSSwirlShader')] +[Alias('Set-OBSDoodleShader','Add-OBSDoodleShader')] param( -# Set the radius of OBSSwirlShader -[ComponentModel.DefaultBindingProperty('radius')] +# Set the ViewProj of OBSDoodleShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the image of OBSDoodleShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the elapsed_time of OBSDoodleShader +[Alias('elapsed_time')] +[ComponentModel.DefaultBindingProperty('elapsed_time')] [Single] -$Radius, -# Set the angle of OBSSwirlShader -[ComponentModel.DefaultBindingProperty('angle')] +$ElapsedTime, +# Set the uv_offset of OBSDoodleShader +[Alias('uv_offset')] +[ComponentModel.DefaultBindingProperty('uv_offset')] +[Single[]] +$UvOffset, +# Set the uv_scale of OBSDoodleShader +[Alias('uv_scale')] +[ComponentModel.DefaultBindingProperty('uv_scale')] +[Single[]] +$UvScale, +# Set the uv_pixel_interval of OBSDoodleShader +[Alias('uv_pixel_interval')] +[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +[Single[]] +$UvPixelInterval, +# Set the rand_f of OBSDoodleShader +[Alias('rand_f')] +[ComponentModel.DefaultBindingProperty('rand_f')] [Single] -$Angle, -# Set the center_x of OBSSwirlShader -[Alias('center_x')] -[ComponentModel.DefaultBindingProperty('center_x')] +$RandF, +# Set the uv_size of OBSDoodleShader +[Alias('uv_size')] +[ComponentModel.DefaultBindingProperty('uv_size')] +[Single[]] +$UvSize, +# Set the Doodle_Scale_Percent of OBSDoodleShader +[Alias('Doodle_Scale_Percent')] +[ComponentModel.DefaultBindingProperty('Doodle_Scale_Percent')] [Single] -$CenterX, -# Set the center_y of OBSSwirlShader -[Alias('center_y')] -[ComponentModel.DefaultBindingProperty('center_y')] +$DoodleScalePercent, +# Set the Snap_Percent of OBSDoodleShader +[Alias('Snap_Percent')] +[ComponentModel.DefaultBindingProperty('Snap_Percent')] [Single] -$CenterY, -# Set the animate of OBSSwirlShader -[ComponentModel.DefaultBindingProperty('animate')] -[Management.Automation.SwitchParameter] -$Animate, -# Set the inverse of OBSSwirlShader -[ComponentModel.DefaultBindingProperty('inverse')] -[Management.Automation.SwitchParameter] -$Inverse, -# Set the notes of OBSSwirlShader -[ComponentModel.DefaultBindingProperty('notes')] +$SnapPercent, +# Set the Notes of OBSDoodleShader +[ComponentModel.DefaultBindingProperty('Notes')] [String] $Notes, # The name of the source. This must be provided when adding an item for the first time @@ -40204,83 +31025,94 @@ $UseShaderTime process { -$shaderName = 'Swirl' -$ShaderNoun = 'OBSSwirlShader' +$shaderName = 'doodle' +$ShaderNoun = 'OBSDoodleShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -//Created by Radegast Stravinsky for obs-shaderfilter 9/2020 -uniform float radius< - string label = "Radius"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.5; // -uniform float angle< - string label = "Angle"; - string widget_type = "slider"; - float minimum = -360.0; - float maximum = 360.0; - float step = 0.01; -> = 270.0; // +// doodle effect by Charles Fettinger (https://github.com/Oncorporation) 5/2019 +// for use with obs-shaderfilter 1.0 +uniform float4x4 ViewProj; +uniform texture2d image; -uniform float center_x< - string label = "Center x"; +uniform float elapsed_time; +uniform float2 uv_offset; +uniform float2 uv_scale; +uniform float2 uv_pixel_interval; +uniform float rand_f; +uniform float2 uv_size; + +uniform float Doodle_Scale_Percent< + string label = "Doodle Scale Percent"; string widget_type = "slider"; float minimum = 0.0; - float maximum = 0.5; - float step = 0.001; -> = 0.25; // -uniform float center_y< - string label = "Center y"; + float maximum = 100.0; + float step = 0.1; +> = 2.5; +uniform float Snap_Percent< + string label = "Snap Percent"; string widget_type = "slider"; - float minimum = 0.0; - float maximum = 0.5; - float step = 0.001; -> = 0.25; // + float minimum = 1.0; + float maximum = 100.0; + float step = 0.1; +> = 7.5; +uniform string Notes< + string widget_type = "info"; +> = "Doodle skews the image by the Scale Percent, Snap Percent controls the number of doodles per second."; -uniform bool animate = false; -uniform bool inverse = false; +sampler_state textureSampler { + Filter = Linear; + AddressU = Border; + AddressV = Border; + BorderColor = 00000000; +}; -uniform string notes< - string widget_type = "info"; -> = "Distorts the screen, twisting the image in a circular motion." +struct VertData { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; -float4 mainImage(VertData v_in) : TARGET +float3 rand3(float3 co) { - - float2 center = float2(center_x, center_y); - VertData v_out; - v_out.pos = v_in.pos; - float2 hw = uv_size; - float ar = 1. * hw.y/hw.x; + float j = 4096.0*sin(dot(co, float3(17.0, 59.4, 15.0))); + float3 result; + result.z = frac(512.0*j); + j *= .125; + result.x = frac(512.0*j); + j *= .125; + result.y = frac(512.0*j); + return result - 0.5; +} - v_out.uv = 1. * v_in.uv - center; - - center.x /= ar; - v_out.uv.x /= ar; - - float dist = distance(v_out.uv, center); - if (dist < radius) - { - float percent = (radius-dist)/(radius); - percent = inverse == false ? percent : 1 - percent; +float snap(float x, float snap) +{ + return snap * round(x / max(0.01,snap)); +} - float theta = percent * percent * radians(angle * (animate == true ? sin(elapsed_time) : 1.0)); - float s = sin(theta); - float c = cos(theta); - v_out.uv = float2(dot(v_out.uv-center, float2(c,-s)), dot(v_out.uv-center, float2(s,c))); - v_out.uv += (2 * center); - - v_out.uv.x *= ar; +VertData mainTransform(VertData v_in) +{ + VertData vert_out; + vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); + vert_out.uv = v_in.uv * uv_scale + uv_offset; + float time = snap((1 + sin(elapsed_time)) * 0.5, Snap_Percent * .01); + float rand = snap(rand_f, Snap_Percent *.01); + float2 noise = rand3(v_in.pos.xyz + float3(time,0.0,0.0)).xy * (Doodle_Scale_Percent * .01); + vert_out.uv.xy += noise; - return image.Sample(textureSampler, v_out.uv); - } - else - { - return image.Sample(textureSampler, v_in.uv ); - } - + return vert_out; +} + +float4 mainImage(VertData v_in) : TARGET +{ + return image.Sample(textureSampler, v_in.uv); +} + +technique Draw +{ + pass p0 + { + vertex_shader = mainTransform(v_in); + pixel_shader = mainImage(v_in); + } } ' @@ -40380,82 +31212,18 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSTetraShader { +function Get-OBSDrawingsShader { -[Alias('Set-OBSTetraShader','Add-OBSTetraShader')] +[Alias('Set-OBSDrawingsShader','Add-OBSDrawingsShader')] param( -# Set the redR of OBSTetraShader -[ComponentModel.DefaultBindingProperty('redR')] -[Single] -$RedR, -# Set the redG of OBSTetraShader -[ComponentModel.DefaultBindingProperty('redG')] -[Single] -$RedG, -# Set the redB of OBSTetraShader -[ComponentModel.DefaultBindingProperty('redB')] -[Single] -$RedB, -# Set the yelR of OBSTetraShader -[ComponentModel.DefaultBindingProperty('yelR')] -[Single] -$YelR, -# Set the yelG of OBSTetraShader -[ComponentModel.DefaultBindingProperty('yelG')] -[Single] -$YelG, -# Set the yelB of OBSTetraShader -[ComponentModel.DefaultBindingProperty('yelB')] -[Single] -$YelB, -# Set the grnR of OBSTetraShader -[ComponentModel.DefaultBindingProperty('grnR')] -[Single] -$GrnR, -# Set the grnG of OBSTetraShader -[ComponentModel.DefaultBindingProperty('grnG')] -[Single] -$GrnG, -# Set the grnB of OBSTetraShader -[ComponentModel.DefaultBindingProperty('grnB')] -[Single] -$GrnB, -# Set the cynR of OBSTetraShader -[ComponentModel.DefaultBindingProperty('cynR')] -[Single] -$CynR, -# Set the cynG of OBSTetraShader -[ComponentModel.DefaultBindingProperty('cynG')] -[Single] -$CynG, -# Set the cynB of OBSTetraShader -[ComponentModel.DefaultBindingProperty('cynB')] -[Single] -$CynB, -# Set the bluR of OBSTetraShader -[ComponentModel.DefaultBindingProperty('bluR')] -[Single] -$BluR, -# Set the bluG of OBSTetraShader -[ComponentModel.DefaultBindingProperty('bluG')] -[Single] -$BluG, -# Set the bluB of OBSTetraShader -[ComponentModel.DefaultBindingProperty('bluB')] -[Single] -$BluB, -# Set the magR of OBSTetraShader -[ComponentModel.DefaultBindingProperty('magR')] -[Single] -$MagR, -# Set the magG of OBSTetraShader -[ComponentModel.DefaultBindingProperty('magG')] -[Single] -$MagG, -# Set the magB of OBSTetraShader -[ComponentModel.DefaultBindingProperty('magB')] -[Single] -$MagB, +# Set the AngleNum of OBSDrawingsShader +[ComponentModel.DefaultBindingProperty('AngleNum')] +[Int32] +$AngleNum, +# Set the SampNum of OBSDrawingsShader +[ComponentModel.DefaultBindingProperty('SampNum')] +[Int32] +$SampNum, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -40486,205 +31254,144 @@ $UseShaderTime process { -$shaderName = 'tetra' -$ShaderNoun = 'OBSTetraShader' +$shaderName = 'drawings' +$ShaderNoun = 'OBSDrawingsShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Tetrahedral Interpolation Shader for OBS - -uniform float redR< - string label = "Red in Red"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2.0; - float step = 0.01; -> = 1.0; +//based on https://www.shadertoy.com/view/ldlcWs -uniform float redG< - string label = "Green in Red"; +uniform int AngleNum< + string label = "Number of angles"; string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.01; -> = 0.0; - -uniform float redB< - string label = "Blue in Red"; + int minimum = 0.0; + int maximum = 25; + int step = 1; +> = 3; +uniform int SampNum< + string label = "Number of samples"; string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.01; -> = 0.0; + int minimum = 0.0; + int maximum = 25; + int step = 1; +> = 9; -uniform float yelR< - string label = "Red in Yellow"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2.0; - float step = 0.01; -> = 1.0; +float4 getCol(float2 pos) +{ + // take aspect ratio into account + float2 uv=pos; + float4 c1=image.Sample(textureSampler, uv); + float4 e=smoothstep(float4(-0.05,-0.05,-0.05,-0.05),float4(-0.0,-0.0,-0.0,-0.0),float4(uv,float2(1,1)-uv)); + c1=lerp(float4(1,1,1,0),c1,e.x*e.y*e.z*e.w); + float d=clamp(dot(c1.xyz,float3(-.5,1.,-.5)),0.0,1.0); + float4 c2=float4(.7,.7,.7,.7); + return min(lerp(c1,c2,1.8*d),.7); +} -uniform float yelG< - string label = "Green in Yellow"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2.0; - float step = 0.01; -> = 1.0; - -uniform float yelB< - string label = "Blue in Yellow"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.01; -> = 0.0; - -uniform float grnR< - string label = "Red in Green"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.01; -> = 0.0; - -uniform float grnG< - string label = "Green in Green"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2.0; - float step = 0.01; -> = 1.0; - -uniform float grnB< - string label = "Blue in Green"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.01; -> = 0.0; - -uniform float cynR< - string label = "Red in Cyan"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.01; -> = 0.0; - -uniform float cynG< - string label = "Green in Cyan"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2.0; - float step = 0.01; -> = 1.0; - -uniform float cynB< - string label = "Blue in Cyan"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2.0; - float step = 0.01; -> = 1.0; - -uniform float bluR< - string label = "Red in Blue"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.01; -> = 0.0; - -uniform float bluG< - string label = "Green in Blue"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.01; -> = 0.0; - -uniform float bluB< - string label = "Blue in Blue"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2.0; - float step = 0.01; -> = 1.0; +float4 getColHT(float2 pos) +{ + return smoothstep(0.795,1.05,getCol(pos)*.8+.2+1.0); +} -uniform float magR< - string label = "Red in Magenta"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2.0; - float step = 0.01; -> = 1.0; +float getVal(float2 pos) +{ + float4 c=getCol(pos); + return pow(dot(c.xyz,float3(.333,.333,.333)),1.)*1.; +} -uniform float magG< - string label = "Green in Magenta"; - string widget_type = "slider"; - float minimum = -1.0; - float maximum = 1.0; - float step = 0.01; -> = 0.0; +float2 getGrad(float2 pos, float eps) +{ + float2 d=float2(eps,0.); + return float2( + getVal(pos+d.xy)-getVal(pos-d.xy), + getVal(pos+d.yx)-getVal(pos-d.yx) + )/eps/2.; +} -uniform float magB< - string label = "Blue in Magenta"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 2.0; - float step = 0.01; -> = 1.0; + float lum( float3 c) { + return dot(c, float3(0.3, 0.59, 0.11)); + } -float3 tetra(float3 RGBimage, float3 red, float3 yel, float3 grn, float3 cyn, float3 blu, float3 mag) { - float r = RGBimage.x; - float g = RGBimage.y; - float b = RGBimage.z; - float3 wht = float3(1.0, 1.0, 1.0); + float3 clipcolor( float3 c) { + float l = lum(c); + float n = min(min(c.r, c.g), c.b); + float x = max(max(c.r, c.g), c.b); + + if (n < 0.0) { + c.r = l + ((c.r - l) * l) / (l - n); + c.g = l + ((c.g - l) * l) / (l - n); + c.b = l + ((c.b - l) * l) / (l - n); + } + if (x > 1.25) { + c.r = l + ((c.r - l) * (1.0 - l)) / (x - l); + c.g = l + ((c.g - l) * (1.0 - l)) / (x - l); + c.b = l + ((c.b - l) * (1.0 - l)) / (x - l); + } + return c; + } - if (r > g) { - if (g > b) { - // r > g > b - return r * red + g * (yel - red) + b * (wht - yel); - } else if (r > b) { - // r > b > g - return r * red + g * (wht - mag) + b * (mag - red); - } else { - // b > r > g - return r * (mag - blu) + g * (wht - mag) + b * blu; - } - } else { - if (b > g) { - // b > g > r - return r * (wht - cyn) + g * (cyn - blu) + b * blu; - } else if (b > r) { - // g > b > r - return r * (wht - cyn) + g * grn + b * (cyn - grn); - } else { - // g > r > b - return r * (yel - grn) + g * grn + b * (wht - yel); - } - } -} + float3 setlum( float3 c, float l) { + float d = l - lum(c); + c = c + float3(d,d,d); + return clipcolor(0.85*c); + } float4 mainImage(VertData v_in) : TARGET { - float4 inputColor = image.Sample(textureSampler, v_in.uv); - float alpha = inputColor.a; + float2 pos = v_in.uv; + float3 col = float3(0,0,0); + float3 col2 = float3(0,0,0); + float sum=0.; + + for(int i=0;i = 100.0; + int minimum = -100; + int maximum = 100; + int step = 1; +> = 5; +uniform int shadow_offset_y< + string label = "Shadow offset y"; + string widget_type = "slider"; + int minimum = -100; + int maximum = 100; + int step = 1; +> = 5; +uniform int shadow_blur_size< + string label = "Shadow blur size"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 15; + int step = 1; +> = 3; +uniform string notes< + string widget_type = "info"; +> = "blur size is limited to a max of 15 to ensure GPU"; -float greyScale(float3 c) { - return 0.29 * c.r + 0.60 * c.g + 0.11; -} +uniform float4 shadow_color; -float3 heatMap(float greyValue) { - float3 heat; - heat.r = smoothstep(0.5, 0.8, greyValue); - if(greyValue >= 0.8333) { - heat.r *= (1.1 - greyValue) * 5.0; - } - if(greyValue > 0.6) { - heat.g = smoothstep(1.0, 0.7, greyValue); - } else { - heat.g = smoothstep(0.0, 0.7, greyValue); - } - heat.b = smoothstep(1.0, 0.0, greyValue); - if(greyValue <= 0.3333) { - heat.b *= greyValue / 0.3; - } - return heat; -} +uniform bool is_alpha_premultiplied; float4 mainImage(VertData v_in) : TARGET { - float4 c = image.Sample(textureSampler, v_in.uv); - float greyValue = greyScale(c.rgb); - float3 h = heatMap(greyValue*(strength/100.0)); - return float4(h.r, h.g, h.b, c.a); + int shadow_blur_size_limited = max(0, min(15, shadow_blur_size)); + int shadow_blur_samples = int(pow(float(shadow_blur_size_limited * 2 + 1), 2.0)); + + float4 color = image.Sample(textureSampler, v_in.uv); + float2 shadow_uv = float2(v_in.uv.x - uv_pixel_interval.x * float(shadow_offset_x), + v_in.uv.y - uv_pixel_interval.y * float(shadow_offset_y)); + + float sampled_shadow_alpha = 0.0; + + for (int blur_x = -shadow_blur_size_limited; blur_x <= shadow_blur_size_limited; blur_x++) + { + for (int blur_y = -shadow_blur_size_limited; blur_y <= shadow_blur_size_limited; blur_y++) + { + float2 blur_uv = shadow_uv + float2(uv_pixel_interval.x * float(blur_x), uv_pixel_interval.y * float(blur_y)); + sampled_shadow_alpha += image.Sample(textureSampler, blur_uv).a / float(shadow_blur_samples); + } + } + + float4 final_shadow_color = float4(shadow_color.r, shadow_color.g, shadow_color.b, shadow_color.a * sampled_shadow_alpha); + return final_shadow_color * (1.0-color.a) + color * (is_alpha_premultiplied?color.a:1.0); } + ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -40960,26 +31709,61 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSTvCrtSubpixelShader { +function Get-OBSDrunkShader { -[Alias('Set-OBSTvCrtSubpixelShader','Add-OBSTvCrtSubpixelShader')] +[Alias('Set-OBSDrunkShader','Add-OBSDrunkShader')] param( -# Set the channelWidth of OBSTvCrtSubpixelShader -[ComponentModel.DefaultBindingProperty('channelWidth')] +# Set the color_matrix of OBSDrunkShader +[Alias('color_matrix')] +[ComponentModel.DefaultBindingProperty('color_matrix')] +[Single[][]] +$ColorMatrix, +# Set the glow_percent of OBSDrunkShader +[Alias('glow_percent')] +[ComponentModel.DefaultBindingProperty('glow_percent')] [Int32] -$ChannelWidth, -# Set the channelHeight of OBSTvCrtSubpixelShader -[ComponentModel.DefaultBindingProperty('channelHeight')] +$GlowPercent, +# Set the blur of OBSDrunkShader +[ComponentModel.DefaultBindingProperty('blur')] [Int32] -$ChannelHeight, -# Set the hGap of OBSTvCrtSubpixelShader -[ComponentModel.DefaultBindingProperty('hGap')] +$Blur, +# Set the min_brightness of OBSDrunkShader +[Alias('min_brightness')] +[ComponentModel.DefaultBindingProperty('min_brightness')] [Int32] -$HGap, -# Set the vGap of OBSTvCrtSubpixelShader -[ComponentModel.DefaultBindingProperty('vGap')] +$MinBrightness, +# Set the max_brightness of OBSDrunkShader +[Alias('max_brightness')] +[ComponentModel.DefaultBindingProperty('max_brightness')] [Int32] -$VGap, +$MaxBrightness, +# Set the pulse_speed_percent of OBSDrunkShader +[Alias('pulse_speed_percent')] +[ComponentModel.DefaultBindingProperty('pulse_speed_percent')] +[Int32] +$PulseSpeedPercent, +# Set the Apply_To_Alpha_Layer of OBSDrunkShader +[Alias('Apply_To_Alpha_Layer')] +[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] +[Management.Automation.SwitchParameter] +$ApplyToAlphaLayer, +# Set the glow_color of OBSDrunkShader +[Alias('glow_color')] +[ComponentModel.DefaultBindingProperty('glow_color')] +[String] +$GlowColor, +# Set the ease of OBSDrunkShader +[ComponentModel.DefaultBindingProperty('ease')] +[Management.Automation.SwitchParameter] +$Ease, +# Set the glitch of OBSDrunkShader +[ComponentModel.DefaultBindingProperty('glitch')] +[Management.Automation.SwitchParameter] +$Glitch, +# Set the notes of OBSDrunkShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -41010,80 +31794,162 @@ $UseShaderTime process { -$shaderName = 'tv-crt-subpixel' -$ShaderNoun = 'OBSTvCrtSubpixelShader' +$shaderName = 'drunk' +$ShaderNoun = 'OBSDrunkShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// https://www.shadertoy.com/view/dlBBz1 adopted for OBS by Exeldro +// Drunk shader by Charles Fettinger (https://github.com/Oncorporation) 2/2019 +//Converted to OpenGL by Q-mii & Exeldro March 11, 2022 +uniform float4x4 color_matrix; -// width of a single color channel in pixels -uniform int channelWidth< - string label = "Channel Width"; + +uniform int glow_percent< + string label = "Glow percent"; string widget_type = "slider"; - int minimum = 1; - int maximum = 20; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 10; +uniform int blur< + string label = "Blur"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; int step = 1; > = 1; - -// height of color channels in pixels -uniform int channelHeight< - string label = "Channel Height"; +uniform int min_brightness< + string label = "Min brightness"; string widget_type = "slider"; - int minimum = 1; - int maximum = 20; + int minimum = 0; + int maximum = 100; int step = 1; -> = 3; - -// horizontal distance between two neighboring pixels -uniform int hGap< - string label = "Horizontal Gap"; +> = 27; +uniform int max_brightness< + string label = "Max brightness"; string widget_type = "slider"; - int minimum = 1; - int maximum = 20; + int minimum = 0; + int maximum = 100; int step = 1; -> = 1; - -// vertical distance between two neighboring pixels -uniform int vGap< - string label = "Vertical Gap"; +> = 100; +uniform int pulse_speed_percent< + string label = "Pulse speed percent"; string widget_type = "slider"; - int minimum = 1; - int maximum = 20; + int minimum = 0; + int maximum = 100; int step = 1; -> = 1; +> = 0; +uniform bool Apply_To_Alpha_Layer = true; +uniform float4 glow_color; +uniform bool ease; +uniform bool glitch; +uniform string notes< + string widget_type = "info"; +> ="''drunk refers to the bad blur effect of using 4 coordinates to blur. ''blur'' - the distance between the 4 copies (recommend 1-4)"; -float4 mainImage(VertData v_in) : TARGET -{ - float columns = float(channelWidth * 3 + hGap); - float pixelHeight = float(channelHeight + vGap); - float2 fragCoord = v_in.uv * uv_size; - float2 sampleRes = float2(uv_size.x / columns, uv_size.y / pixelHeight); - float2 pixel = float2(floor(fragCoord.x / columns), floor(fragCoord.y / pixelHeight)); - float2 sampleUv = pixel / sampleRes; +// Gaussian Blur +float Gaussian(float x, float o) { + const float pivalue = 3.1415926535897932384626433832795; + return (1.0 / (o * sqrt(2.0 * pivalue))) * exp((-(x * x)) / (2 * (o * o))); +} - // color of sample point - float4 col = image.Sample(textureSampler, sampleUv); - - int column = int(fragCoord.x) % (channelWidth * 3 + hGap); - // set color based on which channel this fragment corresponds to - if (column < channelWidth * 1) col = float4(col.r, 0.0, 0.0, col.a); - else if (column < channelWidth * 2) col = float4(0.0, col.g, 0.0, col.a); - else if (column < channelWidth * 3) col = float4(0.0, 0.0, col.b, col.a); - else col = float4(0.0, 0.0, 0.0, col.a); +float EaseInOutCircTimer(float t,float b,float c,float d){ + t /= d/2; + if (t < 1) return -c/2 * (sqrt(1 - t*t) - 1) + b; + t -= 2; + return c/2 * (sqrt(1 - t*t) + 1) + b; +} - // offset every other column of pixels - int height = int(pixelHeight); - if (int(pixel.x) % 2 == 0) { - if (int(fragCoord.y) % height >= height - vGap) col = float4(0.0, 0.0, 0.0, col.a); - } else { - if (int(fragCoord.y) % height < vGap) col = float4(0.0, 0.0, 0.0, col.a); - } +float BlurStyler(float t,float b,float c,float d,bool ease) +{ + if (ease) return EaseInOutCircTimer(t,0,c,d); + return t; +} - // Output to screen - return col; +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 mainImage(VertData v_in) : TARGET +{ + float2 offsets[4]; + offsets[0] = float2(-0.05, 0.066); + offsets[1] = float2(-0.05, -0.066); + offsets[2] = float2(0.05, -0.066); + offsets[3] = float2(0.05, 0.066); + + // convert input for vector math + float blur_amount = float(blur) /100; + float glow_amount = float(glow_percent) * 0.1; + float speed = float(pulse_speed_percent) * 0.01; + float luminance_floor = float(min_brightness) * 0.01; + float luminance_ceiling = float(max_brightness) * 0.01; + + float4 color = image.Sample(textureSampler, v_in.uv); + float4 temp_color = color; + bool glitch_on = glitch; + + //circular easing variable + float t = 1 + sin(elapsed_time * speed); + float b = 0.0; //start value + float c = 2.0; //change value + float d = 2.0; //duration + + //if(color.a <= 0.0) color.rgb = float3(0.0,0.0,0.0); + float4 glitch_color = glow_color; + + for (int n = 0; n < 4; n++){ + //blur sample + b = BlurStyler(t,0,c,d,ease); + float4 ncolor = image.Sample(textureSampler, v_in.uv + (blur_amount * b) * offsets[n]) ; + + //test for rand_f color + if (glitch) { + glitch_color = float4(glow_color.rgb * rand_f,glow_color.a); + if ((color.r == rand_f) || (color.g == rand_f) || (color.b == rand_f)) + { + glitch_on = true; + } + } + + float intensity = ncolor.r * 0.299 + ncolor.g * 0.587 + ncolor.b * 0.114; + if (((intensity >= luminance_floor) && (intensity <= luminance_ceiling)) || // test luminance + ((color.r == glow_color.r) && (color.g == glow_color.g) && (color.b == glow_color.b)) || //test for chosen color + glitch_on) //test for rand color + { + //glow calc + if (ncolor.a > 0.0 || Apply_To_Alpha_Layer == false) + { + ncolor.a = clamp(ncolor.a * glow_amount, 0.0, 1.0); + //temp_color = max(temp_color,ncolor) * glow_color ;//* ((1-ncolor.a) + color * ncolor.a); + //temp_color += (ncolor * float4(glow_color.rbg, glow_amount)); + + // use temp_color as floor, add glow, use highest alpha of blur pixels, then multiply by glow color + // max is used to simulate addition of vector texture color + temp_color = float4(max(temp_color.rgb, ncolor.rgb * (glow_amount * (b / 2))), // color effected by glow over time + max(temp_color.a, (glow_amount * (b / 2)))) // alpha affected by glow over time + * (glitch_color * (b / 2)); // glow color affected by glow over time + } + } + } + // grab lighter color + return max(color,temp_color); } + + ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -41181,28 +32047,135 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSTwistShader { +function Get-OBSDynamicMaskShader { -[Alias('Set-OBSTwistShader','Add-OBSTwistShader')] +[Alias('Set-OBSDynamicMaskShader','Add-OBSDynamicMaskShader')] param( -# Set the center_x_percent of OBSTwistShader -[Alias('center_x_percent')] -[ComponentModel.DefaultBindingProperty('center_x_percent')] -[Int32] -$CenterXPercent, -# Set the center_y_percent of OBSTwistShader -[Alias('center_y_percent')] -[ComponentModel.DefaultBindingProperty('center_y_percent')] -[Int32] -$CenterYPercent, -# Set the power of OBSTwistShader -[ComponentModel.DefaultBindingProperty('power')] +# Set the input_source of OBSDynamicMaskShader +[Alias('input_source')] +[ComponentModel.DefaultBindingProperty('input_source')] +[String] +$InputSource, +# Set the red_base_value of OBSDynamicMaskShader +[Alias('red_base_value')] +[ComponentModel.DefaultBindingProperty('red_base_value')] [Single] -$Power, -# Set the rotation of OBSTwistShader -[ComponentModel.DefaultBindingProperty('rotation')] +$RedBaseValue, +# Set the red_red_input_value of OBSDynamicMaskShader +[Alias('red_red_input_value')] +[ComponentModel.DefaultBindingProperty('red_red_input_value')] [Single] -$Rotation, +$RedRedInputValue, +# Set the red_green_input_value of OBSDynamicMaskShader +[Alias('red_green_input_value')] +[ComponentModel.DefaultBindingProperty('red_green_input_value')] +[Single] +$RedGreenInputValue, +# Set the red_blue_input_value of OBSDynamicMaskShader +[Alias('red_blue_input_value')] +[ComponentModel.DefaultBindingProperty('red_blue_input_value')] +[Single] +$RedBlueInputValue, +# Set the red_alpha_input_value of OBSDynamicMaskShader +[Alias('red_alpha_input_value')] +[ComponentModel.DefaultBindingProperty('red_alpha_input_value')] +[Single] +$RedAlphaInputValue, +# Set the red_multiplier of OBSDynamicMaskShader +[Alias('red_multiplier')] +[ComponentModel.DefaultBindingProperty('red_multiplier')] +[Single] +$RedMultiplier, +# Set the green_base_value of OBSDynamicMaskShader +[Alias('green_base_value')] +[ComponentModel.DefaultBindingProperty('green_base_value')] +[Single] +$GreenBaseValue, +# Set the green_red_input_value of OBSDynamicMaskShader +[Alias('green_red_input_value')] +[ComponentModel.DefaultBindingProperty('green_red_input_value')] +[Single] +$GreenRedInputValue, +# Set the green_green_input_value of OBSDynamicMaskShader +[Alias('green_green_input_value')] +[ComponentModel.DefaultBindingProperty('green_green_input_value')] +[Single] +$GreenGreenInputValue, +# Set the green_blue_input_value of OBSDynamicMaskShader +[Alias('green_blue_input_value')] +[ComponentModel.DefaultBindingProperty('green_blue_input_value')] +[Single] +$GreenBlueInputValue, +# Set the green_alpha_input_value of OBSDynamicMaskShader +[Alias('green_alpha_input_value')] +[ComponentModel.DefaultBindingProperty('green_alpha_input_value')] +[Single] +$GreenAlphaInputValue, +# Set the green_multiplier of OBSDynamicMaskShader +[Alias('green_multiplier')] +[ComponentModel.DefaultBindingProperty('green_multiplier')] +[Single] +$GreenMultiplier, +# Set the blue_base_value of OBSDynamicMaskShader +[Alias('blue_base_value')] +[ComponentModel.DefaultBindingProperty('blue_base_value')] +[Single] +$BlueBaseValue, +# Set the blue_red_input_value of OBSDynamicMaskShader +[Alias('blue_red_input_value')] +[ComponentModel.DefaultBindingProperty('blue_red_input_value')] +[Single] +$BlueRedInputValue, +# Set the blue_green_input_value of OBSDynamicMaskShader +[Alias('blue_green_input_value')] +[ComponentModel.DefaultBindingProperty('blue_green_input_value')] +[Single] +$BlueGreenInputValue, +# Set the blue_blue_input_value of OBSDynamicMaskShader +[Alias('blue_blue_input_value')] +[ComponentModel.DefaultBindingProperty('blue_blue_input_value')] +[Single] +$BlueBlueInputValue, +# Set the blue_alpha_input_value of OBSDynamicMaskShader +[Alias('blue_alpha_input_value')] +[ComponentModel.DefaultBindingProperty('blue_alpha_input_value')] +[Single] +$BlueAlphaInputValue, +# Set the blue_multiplier of OBSDynamicMaskShader +[Alias('blue_multiplier')] +[ComponentModel.DefaultBindingProperty('blue_multiplier')] +[Single] +$BlueMultiplier, +# Set the alpha_base_value of OBSDynamicMaskShader +[Alias('alpha_base_value')] +[ComponentModel.DefaultBindingProperty('alpha_base_value')] +[Single] +$AlphaBaseValue, +# Set the alpha_red_input_value of OBSDynamicMaskShader +[Alias('alpha_red_input_value')] +[ComponentModel.DefaultBindingProperty('alpha_red_input_value')] +[Single] +$AlphaRedInputValue, +# Set the alpha_green_input_value of OBSDynamicMaskShader +[Alias('alpha_green_input_value')] +[ComponentModel.DefaultBindingProperty('alpha_green_input_value')] +[Single] +$AlphaGreenInputValue, +# Set the alpha_blue_input_value of OBSDynamicMaskShader +[Alias('alpha_blue_input_value')] +[ComponentModel.DefaultBindingProperty('alpha_blue_input_value')] +[Single] +$AlphaBlueInputValue, +# Set the alpha_alpha_input_value of OBSDynamicMaskShader +[Alias('alpha_alpha_input_value')] +[ComponentModel.DefaultBindingProperty('alpha_alpha_input_value')] +[Single] +$AlphaAlphaInputValue, +# Set the alpha_multiplier of OBSDynamicMaskShader +[Alias('alpha_multiplier')] +[ComponentModel.DefaultBindingProperty('alpha_multiplier')] +[Single] +$AlphaMultiplier, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -41233,59 +32206,220 @@ $UseShaderTime process { -$shaderName = 'twist' -$ShaderNoun = 'OBSTwistShader' +$shaderName = 'dynamic-mask' +$ShaderNoun = 'OBSDynamicMaskShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform int center_x_percent< - string label = "center x percentage"; +uniform texture2d input_source< + string label = "Input Source"; +>; + +uniform float red_base_value< + string label = "Base Value"; string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; -uniform int center_y_percent< - string label = "center y percentage"; + string group = "Red Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 1.0; +uniform float red_red_input_value< + string label = "Red Input Value"; string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; -uniform float power< - string label = "power"; + string group = "Red Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 0.0; +uniform float red_green_input_value< + string label = "Green Input Value"; string widget_type = "slider"; - float minimum = 0.0; - float maximum = 5.0; - float step = 0.001; -> = 0.3; -uniform float rotation< - string label = "rotation"; + string group = "Red Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 0.0; +uniform float red_blue_input_value< + string label = "Blue Input Value"; string widget_type = "slider"; + string group = "Red Channel"; float minimum = -100.0; float maximum = 100.0; - float step = 0.001; -> = 2.0; + float step = 0.01; +> = 0.0; +uniform float red_alpha_input_value< + string label = "Alpha Input Value"; + string widget_type = "slider"; + string group = "Red Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 0.0; +uniform float red_multiplier< + string label = "Multiplier"; + string widget_type = "slider"; + string group = "Red Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 1.0; -#ifndef OPENGL -#define mat2 float2x2 -#endif +uniform float green_base_value< + string label = "Base Value"; + string widget_type = "slider"; + string group = "Green Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 1.0; +uniform float green_red_input_value< + string label = "Red Input Value"; + string widget_type = "slider"; + string group = "Green Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 0.0; +uniform float green_green_input_value< + string label = "Green Input Value"; + string widget_type = "slider"; + string group = "Green Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 0.0; +uniform float green_blue_input_value< + string label = "Blue Input Value"; + string widget_type = "slider"; + string group = "Green Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 0.0; +uniform float green_alpha_input_value< + string label = "Alpha Input Value"; + string widget_type = "slider"; + string group = "Green Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 0.0; +uniform float green_multiplier< + string label = "Multiplier"; + string widget_type = "slider"; + string group = "Green Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 1.0; -mat2 rotate(float angle){ - return mat2(float2(cos(angle), -sin(angle)), float2(sin(angle), cos(angle))); -} +uniform float blue_base_value< + string label = "Base Value"; + string widget_type = "slider"; + string group = "Blue Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 1.0; +uniform float blue_red_input_value< + string label = "Red Input Value"; + string widget_type = "slider"; + string group = "Blue Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 0.0; +uniform float blue_green_input_value< + string label = "Green Input Value"; + string widget_type = "slider"; + string group = "Blue Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 0.0; +uniform float blue_blue_input_value< + string label = "Blue Input Value"; + string widget_type = "slider"; + string group = "Blue Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 0.0; +uniform float blue_alpha_input_value< + string label = "Alpha Input Value"; + string widget_type = "slider"; + string group = "Blue Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 0.0; +uniform float blue_multiplier< + string label = "Multiplier"; + string widget_type = "slider"; + string group = "Blue Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 1.0; + +uniform float alpha_base_value< + string label = "Base Value"; + string widget_type = "slider"; + string group = "Alpha Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 1.0; +uniform float alpha_red_input_value< + string label = "Red Input Value"; + string widget_type = "slider"; + string group = "Alpha Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 0.0; +uniform float alpha_green_input_value< + string label = "Green Input Value"; + string widget_type = "slider"; + string group = "Alpha Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 0.0; +uniform float alpha_blue_input_value< + string label = "Blue Input Value"; + string widget_type = "slider"; + string group = "Alpha Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 0.0; +uniform float alpha_alpha_input_value< + string label = "Alpha Input Value"; + string widget_type = "slider"; + string group = "Alpha Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 0.0; +uniform float alpha_multiplier< + string label = "Multiplier"; + string widget_type = "slider"; + string group = "Alpha Channel"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 1.0; float4 mainImage(VertData v_in) : TARGET { - float2 center_pos = float2(center_x_percent * .01, center_y_percent * .01); - float d = distance(center_pos,v_in.uv); - if(d > power){ - return image.Sample(textureSampler, v_in.uv); - } - float r = (cos(d*3.14159265359/power) +1)/2 * rotation; - float2 pos = v_in.uv - center_pos; - pos = mul(pos, rotate(r)); - pos += center_pos; - return image.Sample(textureSampler, pos); + float4 input_color = input_source.Sample(textureSampler, v_in.uv); + float4 mask; + mask.r = (red_base_value + red_red_input_value * input_color.r + red_green_input_value * input_color.g + red_blue_input_value * input_color.b + red_alpha_input_value * input_color.a) * red_multiplier; + mask.g = (green_base_value + green_red_input_value * input_color.r + green_green_input_value * input_color.g + green_blue_input_value * input_color.b + green_alpha_input_value * input_color.a) * green_multiplier; + mask.b = (blue_base_value + blue_red_input_value * input_color.r + blue_green_input_value * input_color.g + blue_blue_input_value * input_color.b + blue_alpha_input_value * input_color.a) * blue_multiplier; + mask.a = (alpha_base_value + alpha_red_input_value * input_color.r + alpha_green_input_value * input_color.g + alpha_blue_input_value * input_color.b + alpha_alpha_input_value * input_color.a) * alpha_multiplier; + float4 base = image.Sample(textureSampler, v_in.uv); + return base * mask; } ' @@ -41385,73 +32519,63 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSTwoPassDropShadowShader { +function Get-OBSEdgeDetectionShader { -[Alias('Set-OBSTwoPassDropShadowShader','Add-OBSTwoPassDropShadowShader')] +[Alias('Set-OBSEdgeDetectionShader','Add-OBSEdgeDetectionShader')] param( -# Set the ViewProj of OBSTwoPassDropShadowShader -[ComponentModel.DefaultBindingProperty('ViewProj')] -[Single[][]] -$ViewProj, -# Set the image of OBSTwoPassDropShadowShader -[ComponentModel.DefaultBindingProperty('image')] -[String] -$Image, -# Set the elapsed_time of OBSTwoPassDropShadowShader -[Alias('elapsed_time')] -[ComponentModel.DefaultBindingProperty('elapsed_time')] +# Set the sensitivity of OBSEdgeDetectionShader +[ComponentModel.DefaultBindingProperty('sensitivity')] [Single] -$ElapsedTime, -# Set the uv_offset of OBSTwoPassDropShadowShader -[Alias('uv_offset')] -[ComponentModel.DefaultBindingProperty('uv_offset')] -[Single[]] -$UvOffset, -# Set the uv_scale of OBSTwoPassDropShadowShader -[Alias('uv_scale')] -[ComponentModel.DefaultBindingProperty('uv_scale')] -[Single[]] -$UvScale, -# Set the uv_pixel_interval of OBSTwoPassDropShadowShader -[Alias('uv_pixel_interval')] -[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] -[Single[]] -$UvPixelInterval, -# Set the rand_f of OBSTwoPassDropShadowShader +$Sensitivity, +# Set the invert_edge of OBSEdgeDetectionShader +[Alias('invert_edge')] +[ComponentModel.DefaultBindingProperty('invert_edge')] +[Management.Automation.SwitchParameter] +$InvertEdge, +# Set the edge_color of OBSEdgeDetectionShader +[Alias('edge_color')] +[ComponentModel.DefaultBindingProperty('edge_color')] +[String] +$EdgeColor, +# Set the edge_multiply of OBSEdgeDetectionShader +[Alias('edge_multiply')] +[ComponentModel.DefaultBindingProperty('edge_multiply')] +[Management.Automation.SwitchParameter] +$EdgeMultiply, +# Set the non_edge_color of OBSEdgeDetectionShader +[Alias('non_edge_color')] +[ComponentModel.DefaultBindingProperty('non_edge_color')] +[String] +$NonEdgeColor, +# Set the non_edge_multiply of OBSEdgeDetectionShader +[Alias('non_edge_multiply')] +[ComponentModel.DefaultBindingProperty('non_edge_multiply')] +[Management.Automation.SwitchParameter] +$NonEdgeMultiply, +# Set the alpha_channel of OBSEdgeDetectionShader +[Alias('alpha_channel')] +[ComponentModel.DefaultBindingProperty('alpha_channel')] +[Management.Automation.SwitchParameter] +$AlphaChannel, +# Set the alpha_level of OBSEdgeDetectionShader +[Alias('alpha_level')] +[ComponentModel.DefaultBindingProperty('alpha_level')] +[Single] +$AlphaLevel, +# Set the alpha_invert of OBSEdgeDetectionShader +[Alias('alpha_invert')] +[ComponentModel.DefaultBindingProperty('alpha_invert')] +[Management.Automation.SwitchParameter] +$AlphaInvert, +# Set the rand_f of OBSEdgeDetectionShader [Alias('rand_f')] [ComponentModel.DefaultBindingProperty('rand_f')] [Single] $RandF, -# Set the uv_size of OBSTwoPassDropShadowShader -[Alias('uv_size')] -[ComponentModel.DefaultBindingProperty('uv_size')] -[Single[]] -$UvSize, -# Set the shadow_offset_x of OBSTwoPassDropShadowShader -[Alias('shadow_offset_x')] -[ComponentModel.DefaultBindingProperty('shadow_offset_x')] -[Int32] -$ShadowOffsetX, -# Set the shadow_offset_y of OBSTwoPassDropShadowShader -[Alias('shadow_offset_y')] -[ComponentModel.DefaultBindingProperty('shadow_offset_y')] -[Int32] -$ShadowOffsetY, -# Set the shadow_blur_size of OBSTwoPassDropShadowShader -[Alias('shadow_blur_size')] -[ComponentModel.DefaultBindingProperty('shadow_blur_size')] -[Int32] -$ShadowBlurSize, -# Set the shadow_color of OBSTwoPassDropShadowShader -[Alias('shadow_color')] -[ComponentModel.DefaultBindingProperty('shadow_color')] +# Set the notes of OBSEdgeDetectionShader +[ComponentModel.DefaultBindingProperty('notes')] [String] -$ShadowColor, -# Set the is_alpha_premultiplied of OBSTwoPassDropShadowShader -[Alias('is_alpha_premultiplied')] -[ComponentModel.DefaultBindingProperty('is_alpha_premultiplied')] -[Management.Automation.SwitchParameter] -$IsAlphaPremultiplied, +$Notes, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -41482,125 +32606,99 @@ $UseShaderTime process { -$shaderName = 'two-pass-drop-shadow' -$ShaderNoun = 'OBSTwoPassDropShadowShader' +$shaderName = 'edge_detection' +$ShaderNoun = 'OBSEdgeDetectionShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -//Converted to OpenGL by Q-mii & Exeldro February 22, 2022 -uniform float4x4 ViewProj; -uniform texture2d image; - -uniform float elapsed_time; -uniform float2 uv_offset; -uniform float2 uv_scale; -uniform float2 uv_pixel_interval; -uniform float rand_f; -uniform float2 uv_size; - -sampler_state textureSampler { - Filter = Linear; - AddressU = Border; - AddressV = Border; - BorderColor = 00000000; -}; - -struct VertData { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; - -VertData mainTransform(VertData v_in) -{ - VertData vert_out; - vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); - vert_out.uv = v_in.uv * uv_scale + uv_offset; - return vert_out; -} - -uniform int shadow_offset_x< - string label = "shadow offset x"; - string widget_type = "slider"; - int minimum = -1000; - int maximum = 1000; - int step = 1; ->; -uniform int shadow_offset_y< - string label = "shadow offset y"; +// Edge Detection for OBS Studio +// originally from Andersama (https://github.com/Andersama) +// Modified and improved my Charles Fettinger (https://github.com/Oncorporation) 1/2019 +//Converted to OpenGL by Q-mii & Exeldro March 8, 2022 +uniform float sensitivity< + string label = "Sensitivity"; string widget_type = "slider"; - int minimum = -1000; - int maximum = 1000; - int step = 1; ->; -uniform int shadow_blur_size< - string label = "shadow blur size"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.05; +uniform bool invert_edge; +uniform float4 edge_color = {1.0,1.0,1.0,1.0}; +uniform bool edge_multiply; +uniform float4 non_edge_color = {0.0,0.0,0.0,0.0}; +uniform bool non_edge_multiply; +uniform bool alpha_channel; +uniform float alpha_level< + string label = "Alpha level"; string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; ->; - -uniform float4 shadow_color; + float minimum = 0.0; + float maximum = 100.0; + float step = 1.0; +> = 100.0; +uniform bool alpha_invert; +uniform float rand_f; -uniform bool is_alpha_premultiplied; +uniform string notes< + string widget_type = "info"; +> = "''sensitivity'' - 0.01 is max and will create the most edges. Increasing this value decreases the number of edges detected. ''edge non edge color'' - the color to recolor vs the original image. ''edge or non edge multiply'' - multiplies the color against the original color giving it a tint instead of replacing the color. White represents no tint. ''invert edge'' - flips the sensativity and is great for testing and fine tuning. ''alpha channel'' - use an alpha channel to replace original color with transparency. ''alpha_level'' - transparency amount modifier where 1.0 = base luminance (recommend 0.00 - 2.00). ''alpha_invert'' - flip what is transparent from darks (default) to lights"; float4 mainImage(VertData v_in) : TARGET { - int shadow_blur_samples = int(shadow_blur_size + 1);//pow(shadow_blur_size * 2 + 1, 2); - - float4 color = image.Sample(textureSampler, v_in.uv); - float2 shadow_uv = float2(v_in.uv.x - uv_pixel_interval.x * int(shadow_offset_x), - v_in.uv.y - uv_pixel_interval.y * int(shadow_offset_y)); - - float sampled_shadow_alpha = 0; - - for (int blur_x = -shadow_blur_size; blur_x <= shadow_blur_size; blur_x++) - { - float2 blur_uv = shadow_uv + float2(uv_pixel_interval.x * blur_x, 0); - sampled_shadow_alpha += image.Sample(textureSampler, blur_uv).a; - } + float4 c = image.Sample(textureSampler, v_in.uv); - sampled_shadow_alpha /= shadow_blur_samples; - - float4 final_shadow_color = float4(shadow_color.rgb, shadow_color.a * sampled_shadow_alpha); - - return final_shadow_color * (1-color.a) + color * (is_alpha_premultiplied?1.0:color.a); -} - -float4 mainImage_2_end(VertData v_in) : TARGET -{ - int shadow_blur_samples = shadow_blur_size + 1;//pow(shadow_blur_size * 2 + 1, 2); - - float4 color = image.Sample(textureSampler, v_in.uv); - float2 shadow_uv = float2(v_in.uv.x - uv_pixel_interval.x * shadow_offset_x, - v_in.uv.y - uv_pixel_interval.y * shadow_offset_y); - - float sampled_shadow_alpha = 0; - - for (int blur_y = -shadow_blur_size; blur_y <= shadow_blur_size; blur_y++) - { - float2 blur_uv = shadow_uv + float2(0, uv_pixel_interval.y * blur_y); - sampled_shadow_alpha += image.Sample(textureSampler, blur_uv).a; - } + float s = 3; + float hstep = uv_pixel_interval.x; + float vstep = uv_pixel_interval.y; - sampled_shadow_alpha /= shadow_blur_samples; - - float4 final_shadow_color = float4(shadow_color.rgb, shadow_color.a * sampled_shadow_alpha); - - return final_shadow_color * (1-color.a) + color * (is_alpha_premultiplied?1.0:color.a); -} - -technique Draw -{ - pass p0 - { - vertex_shader = mainTransform(v_in); - pixel_shader = mainImage(v_in); + float offsetx = (hstep * s) / 2.0; + float offsety = (vstep * s) / 2.0; + + float4 lum = float4(0.30, 0.59, 0.11, 1 ); + float samples[9]; + + int index = 0; + for(int i = 0; i < s; i++){ + for(int j = 0; j < s; j++){ + samples[index] = dot(image.Sample(textureSampler, float2(v_in.uv.x + (i * hstep) - offsetx, v_in.uv.y + (j * vstep) - offsety )), lum); + index++; + } } - pass p1 - { - vertex_shader = mainTransform(v_in); - pixel_shader = mainImage_2_end(v_in); + float vert = samples[2] + samples[8] + (2 * samples[5]) - samples[0] - (2 * samples[3]) - samples[6]; + float hori = samples[6] + (2 * samples[7]) + samples[8] - samples[0] - (2 * samples[1]) - samples[2]; + float4 col; + + float o = ((vert * vert) + (hori * hori)); + bool isEdge = o > sensitivity; + if(invert_edge){ + isEdge = !isEdge; + } + if(isEdge) { + col = edge_color; + if(edge_multiply){ + col *= c; + } + } else { + col = non_edge_color; + if(non_edge_multiply){ + col *= c; + } + } + + if (alpha_invert) { + lum = 1.0 - lum; + } + + if(alpha_channel){ + if (edge_multiply && isEdge) { + return clamp(lerp(c, col, alpha_level), 0.0, 1.0); + } + else { + // use max instead of multiply + return clamp(lerp(c, float4(max(c.r, col.r), max(c.g, col.g), max(c.b, col.b), 1.0), alpha_level), 0.0, 1.0); + } + } else { + // col.a = col.a * alpha_level; + return col; } } @@ -41701,37 +32799,114 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSVCRShader { +function Get-OBSEmbersShader { -[Alias('Set-OBSVCRShader','Add-OBSVCRShader')] +[Alias('Set-OBSEmbersShader','Add-OBSEmbersShader')] param( -# Set the vertical_shift of OBSVCRShader -[Alias('vertical_shift')] -[ComponentModel.DefaultBindingProperty('vertical_shift')] +# Set the ViewProj of OBSEmbersShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the image of OBSEmbersShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the elapsed_time of OBSEmbersShader +[Alias('elapsed_time')] +[ComponentModel.DefaultBindingProperty('elapsed_time')] [Single] -$VerticalShift, -# Set the distort of OBSVCRShader -[ComponentModel.DefaultBindingProperty('distort')] +$ElapsedTime, +# Set the uv_offset of OBSEmbersShader +[Alias('uv_offset')] +[ComponentModel.DefaultBindingProperty('uv_offset')] +[Single[]] +$UvOffset, +# Set the uv_scale of OBSEmbersShader +[Alias('uv_scale')] +[ComponentModel.DefaultBindingProperty('uv_scale')] +[Single[]] +$UvScale, +# Set the uv_size of OBSEmbersShader +[Alias('uv_size')] +[ComponentModel.DefaultBindingProperty('uv_size')] +[Single[]] +$UvSize, +# Set the uv_pixel_interval of OBSEmbersShader +[Alias('uv_pixel_interval')] +[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +[Single[]] +$UvPixelInterval, +# Set the rand_f of OBSEmbersShader +[Alias('rand_f')] +[ComponentModel.DefaultBindingProperty('rand_f')] [Single] -$Distort, -# Set the vignet of OBSVCRShader -[ComponentModel.DefaultBindingProperty('vignet')] +$RandF, +# Set the rand_instance_f of OBSEmbersShader +[Alias('rand_instance_f')] +[ComponentModel.DefaultBindingProperty('rand_instance_f')] [Single] -$Vignet, -# Set the stripe of OBSVCRShader -[ComponentModel.DefaultBindingProperty('stripe')] +$RandInstanceF, +# Set the rand_activation_f of OBSEmbersShader +[Alias('rand_activation_f')] +[ComponentModel.DefaultBindingProperty('rand_activation_f')] [Single] -$Stripe, -# Set the vertical_factor of OBSVCRShader -[Alias('vertical_factor')] -[ComponentModel.DefaultBindingProperty('vertical_factor')] +$RandActivationF, +# Set the loops of OBSEmbersShader +[ComponentModel.DefaultBindingProperty('loops')] +[Int32] +$Loops, +# Set the local_time of OBSEmbersShader +[Alias('local_time')] +[ComponentModel.DefaultBindingProperty('local_time')] [Single] -$VerticalFactor, -# Set the vertical_height of OBSVCRShader -[Alias('vertical_height')] -[ComponentModel.DefaultBindingProperty('vertical_height')] +$LocalTime, +# Set the notes of OBSEmbersShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# Set the Animation_Speed of OBSEmbersShader +[Alias('Animation_Speed')] +[ComponentModel.DefaultBindingProperty('Animation_Speed')] [Single] -$VerticalHeight, +$AnimationSpeed, +# Set the Movement_Direction_Horizontal of OBSEmbersShader +[Alias('Movement_Direction_Horizontal')] +[ComponentModel.DefaultBindingProperty('Movement_Direction_Horizontal')] +[Single] +$MovementDirectionHorizontal, +# Set the Movement_Direction_Vertical of OBSEmbersShader +[Alias('Movement_Direction_Vertical')] +[ComponentModel.DefaultBindingProperty('Movement_Direction_Vertical')] +[Single] +$MovementDirectionVertical, +# Set the Movement_Speed_Percent of OBSEmbersShader +[Alias('Movement_Speed_Percent')] +[ComponentModel.DefaultBindingProperty('Movement_Speed_Percent')] +[Int32] +$MovementSpeedPercent, +# Set the Layers_Count of OBSEmbersShader +[Alias('Layers_Count')] +[ComponentModel.DefaultBindingProperty('Layers_Count')] +[Int32] +$LayersCount, +# Set the lumaMin of OBSEmbersShader +[ComponentModel.DefaultBindingProperty('lumaMin')] +[Single] +$LumaMin, +# Set the lumaMinSmooth of OBSEmbersShader +[ComponentModel.DefaultBindingProperty('lumaMinSmooth')] +[Single] +$LumaMinSmooth, +# Set the Alpha_Percentage of OBSEmbersShader +[Alias('Alpha_Percentage')] +[ComponentModel.DefaultBindingProperty('Alpha_Percentage')] +[Single] +$AlphaPercentage, +# Set the Apply_To_Alpha_Layer of OBSEmbersShader +[Alias('Apply_To_Alpha_Layer')] +[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] +[Management.Automation.SwitchParameter] +$ApplyToAlphaLayer, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -41762,108 +32937,370 @@ $UseShaderTime process { -$shaderName = 'VCR' -$ShaderNoun = 'OBSVCRShader' +$shaderName = 'embers' +$ShaderNoun = 'OBSEmbersShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -//based on https://www.shadertoy.com/view/ldjGzV -//Converted to OpenGL by Exeldro February 19, 2022 -uniform float vertical_shift< - string label = "vertical shift"; +// Embers effect by Charles Fettinger for obs-shaderfilter plugin 8/2020 v.1 +// https://github.com/Oncorporation/obs-shaderfilter +// https://www.shadertoy.com/view/wl2Gzc - coverted from and updated + +uniform float4x4 ViewProj; +uniform texture2d image; + +uniform float elapsed_time; +uniform float2 uv_offset; +uniform float2 uv_scale; +uniform float2 uv_size; +uniform float2 uv_pixel_interval; +uniform float rand_f; +uniform float rand_instance_f; +uniform float rand_activation_f; +uniform int loops; +uniform float local_time; +uniform string notes< + string widget_type = "info"; +> = "luma is applied with Apply to Alpha Layer. Movement Speed and Direction can be negatives"; + +#ifndef OPENGL +#define mat2 float2x2 +#define fract frac +#define mix lerp +#endif + +sampler_state textureSampler { + Filter = Linear; + AddressU = Clamp; + AddressV = Clamp; +}; + +uniform float Animation_Speed < + string label = "Animation Speed"; + string widget_type = "slider"; + float minimum = 0.1; + float maximum = 10.0; + float step = 0.01; + float scale = 1.; +> = 1.5; + +uniform float Movement_Direction_Horizontal< + string label = "Movement Direction Horizontal"; string widget_type = "slider"; - float minimum = -5.0; - float maximum = 5.0; - float step = 0.001; -> = 0.4; -uniform float distort< - string label = "distort"; + float minimum = -100.0; + float maximum = 100.0; + float step = 1.0; +> = 5.0; +uniform float Movement_Direction_Vertical< + string label = "Movement Direction Vertical"; string widget_type = "slider"; - float minimum = 0; - float maximum = 5.0; - float step = 0.001; -> = 1.2; -uniform float vignet< - string label = "vignet"; + float minimum = -100.0; + float maximum = 100.0; + float step = 1.0; +> = 10.0; + +uniform int Movement_Speed_Percent< + string label = "Movement Speed Percent"; string widget_type = "slider"; - float minimum = -5.0; - float maximum = 5.0; - float step = 0.001; -> = 1.0; -uniform float stripe< - string label = "stripe"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 5; + +uniform int Layers_Count < + string label = "Layers"; string widget_type = "slider"; - float minimum = -5.0; - float maximum = 5.0; - float step = 0.001; -> = 1.0; -uniform float vertical_factor< - string label = "vertical factor"; + int minimum = 1.0; + int maximum = 100.0; + int step = 1; +> = 15; +/* ps start +*/ + + +uniform float lumaMin< + string label = "Luma Min"; string widget_type = "slider"; - float minimum = -5.0; - float maximum = 5.0; - float step = 0.001; -> = 1.0; -uniform float vertical_height< - string label = "vertical height"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.01; +uniform float lumaMinSmooth< + string label = "Luma Min Smooth"; string widget_type = "slider"; float minimum = 0.0; - float maximum = 1000.0; + float maximum = 1.0; + float step = 0.01; +> = 0.01; +uniform float Alpha_Percentage< + string label = "Alpha Percentage"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; float step = 0.1; -> = 30.0; +> = 100.0; +uniform bool Apply_To_Alpha_Layer = true; -float onOff(float a, float b, float c) +#define PI 3.1415927 +#define TWO_PI 6.283185 + +#define PARTICLE_SIZE 0.009 + +#define PARTICLE_SCALE float2(0.5, 1.6) +#define PARTICLE_SCALE_VAR float2(0.25, 0.2) + +#define PARTICLE_BLOOM_SCALE float2(0.5, 0.8) +#define PARTICLE_BLOOM_SCALE_VAR float2(0.3, 0.1) + +#define SPARK_COLOR float3(1.0, 0.4, 0.05) * 1.5 +#define BLOOM_COLOR float3(1.0, 0.4, 0.05) * 0.8 +#define SMOKE_COLOR float3(1.0, 0.43, 0.1) * 0.8 + +#define SIZE_MOD 1.05 +#define ALPHA_MOD 0.9 +#define Movement_Direction float2(Movement_Direction_Horizontal, Movement_Direction_Vertical) +#define Movement_Speed Movement_Speed_Percent * 0.01 +#define UV float2(fragCoord.xy / uv_size) + +float hash1_2(float2 x) { - return step(c, sin(elapsed_time + a*cos(elapsed_time*b))); + return fract(sin(dot(x, float2(52.127, 61.2871))) * 521.582); } -float ramp(float y, float start, float end) +float2 hash2_2(float2 x) { - float inside = step(start,y) - step(end,y); - float fact = (y-start)/(end-start)*inside; - return (1.-fact) * inside; - + mat2 m = mat2(20.52, 24.1994, 70.291, 80.171); + float2 y = mul(x, m); + return fract(sin(y) * 492.194); } -float modu(float x, float y) +//Simple interpolated noise +float2 noise2_2(float2 uv) { - return (x / y) - floor(x / y); + //float2 f = fract(uv); + float2 f = smoothstep(0.0, 1.0, fract(uv)); + + float2 uv00 = floor(uv); + float2 uv01 = uv00 + float2(0, 1); + float2 uv10 = uv00 + float2(1, 0); + float2 uv11 = uv00 + 1.0; + float2 v00 = hash2_2(uv00); + float2 v01 = hash2_2(uv01); + float2 v10 = hash2_2(uv10); + float2 v11 = hash2_2(uv11); + + float2 v0 = mix(v00, v01, f.y); + float2 v1 = mix(v10, v11, f.y); + float2 v = mix(v0, v1, f.x); + + return v; } -float stripes(float2 uv) +//Simple interpolated noise +float noise1_2(float2 uv) { - return ramp(modu(uv.y*4. + elapsed_time/2.+sin(elapsed_time + sin(elapsed_time*0.63)),1.),0.5,0.6)*stripe; + float2 f = fract(uv); + + float2 uv00 = floor(uv); + float2 uv01 = uv00 + float2(0, 1); + float2 uv10 = uv00 + float2(1, 0); + float2 uv11 = uv00 + 1.0; + + float v00 = hash1_2(uv00); + float v01 = hash1_2(uv01); + float v10 = hash1_2(uv10); + float v11 = hash1_2(uv11); + + float v0 = mix(v00, v01, f.y); + float v1 = mix(v10, v11, f.y); + float v = mix(v0, v1, f.x); + + return v; } -float4 getVideo(float2 uv) +float layeredNoise1_2(float2 uv, float sizeMod, float alphaMod, int layers, float animation) { - float2 look = uv; - float window = 1./(1.+20.*(look.y-modu(elapsed_time/4.,1.))*(look.y-modu(elapsed_time/4.,1.))); - look.x = look.x + sin(look.y*10. + elapsed_time)/50.*onOff(4.,4.,.3)*(1.+cos(elapsed_time*80.))*window; - float vShift = vertical_shift*onOff(2.,3.,.9)*(sin(elapsed_time)*sin(elapsed_time*20.) + - (0.5 + 0.1*sin(elapsed_time*200.)*cos(elapsed_time))); - look.y = modu((look.y + vShift) , 1.); - return image.Sample(textureSampler, look); + float noise = 0.0; + float alpha = 1.0; + float size = 1.0; + float2 offset; + for (int i = 0; i < layers; i++) + { + offset += hash2_2(float2(alpha, size)) * 10.0; + + //Adding noise with movement + noise += noise1_2(uv * size + elapsed_time * animation * 8.0 * Movement_Direction * Movement_Speed + offset) * alpha; + alpha *= alphaMod; + size *= sizeMod; + } + + noise *= (1.0 - alphaMod) / (1.0 - pow(alphaMod, float(layers))); + return noise; } -float2 screenDistort(float2 uv) +//Rotates point around 0,0 +float2 rotate(float2 vpoint, float deg) { - uv -= float2(.5,.5); - uv = uv*distort*(1./1.2+2.*uv.x*uv.x*uv.y*uv.y); - uv += float2(.5,.5); - return uv; + float s = sin(deg); + float c = cos(deg); + mat2 m = mat2(s, c, -c, s); + return mul(vpoint, m); } -float4 mainImage(VertData v_in) : TARGET +//Cell center from point on the grid +float2 voronoiPointFromRoot(float2 root, float deg) { - float2 uv = v_in.uv; - uv = screenDistort(uv); - float4 video = getVideo(uv); - float vigAmt = 3.+.3*sin(elapsed_time + 5.*cos(elapsed_time*5.)); - float vignette = ((1.-vigAmt*(uv.y-.5)*(uv.y-.5))*(1.-vigAmt*(uv.x-.5)*(uv.x-.5))-1.)*vignet+1.; - video += stripes(uv); - video *= vignette; - video *= (((12.+modu((uv.y*vertical_height+elapsed_time),1.))/13.)-1.)*vertical_factor+1.; - return float4(video.r, video.g, video.b ,1.0); + float2 vpoint = hash2_2(root) - 0.5; + float s = sin(deg); + float c = cos(deg); + mat2 m = mat2(s, c, -c, s); + vpoint = mul(vpoint, m) * 0.66; + vpoint += root + 0.5; + return vpoint; +} + +//Voronoi cell point rotation degrees +float degFromRootUV(in float2 uv) +{ + return elapsed_time * Animation_Speed * (hash1_2(uv) - 0.5) * 2.0; +} + +float2 randomAround2_2(in float2 vpoint, in float2 range, in float2 uv) +{ + return vpoint + (hash2_2(uv) - 0.5) * range; +} + + +float3 fireParticles(in float2 uv, in float2 originalUV) +{ + float3 particles = float3(0.0, 0.0, 0.0); + float2 rootUV = floor(uv); + float deg = degFromRootUV(rootUV); + float2 pointUV = voronoiPointFromRoot(rootUV, deg); + float dist = 2.0; + float distBloom = 0.0; + + //UV manipulation for the faster particle movement + float2 tempUV = uv + (noise2_2(uv * 2.0) - 0.5) * 0.1; + tempUV += -(noise2_2(uv * 3.0 + elapsed_time) - 0.5) * 0.07; + + //Sparks sdf + dist = length(rotate(tempUV - pointUV, 0.7) * randomAround2_2(PARTICLE_SCALE, PARTICLE_SCALE_VAR, rootUV)); + + //Bloom sdf + distBloom = length(rotate(tempUV - pointUV, 0.7) * randomAround2_2(PARTICLE_BLOOM_SCALE, PARTICLE_BLOOM_SCALE_VAR, rootUV)); + + //Add sparks + particles += (1.0 - smoothstep(PARTICLE_SIZE * 0.6, PARTICLE_SIZE * 3.0, dist)) * SPARK_COLOR; + + //Add bloom + particles += pow((1.0 - smoothstep(0.0, PARTICLE_SIZE * 6.0, distBloom)) * 1.0, 3.0) * BLOOM_COLOR; + + //Upper disappear curve randomization + float border = (hash1_2(rootUV) - 0.5) * 2.0; + float disappear = 1.0 - smoothstep(border, border + 0.5, originalUV.y); + + //Lower appear curve randomization + border = (hash1_2(rootUV + 0.214) - 1.8) * 0.7; + float appear = smoothstep(border, border + 0.4, originalUV.y); + + return particles * disappear * appear; +} + + +//Layering particles to imitate 3D view +float3 layeredParticles(in float2 uv, in float sizeMod, in float alphaMod, in int layers, in float smoke) +{ + float3 particles = float3(0.0, 0.0, 0.0); + float size = 1.0; + float alpha = 1.0; + float2 offset = float2(0.0, 0.0); + float2 noiseOffset; + float2 bokehUV; + + for (int i = 0; i < layers; i++) + { + //Particle noise movement + noiseOffset = (noise2_2(uv * size * 2.0 + 0.5) - 0.5) * 0.15; + + //UV with applied movement + bokehUV = (uv * size + elapsed_time * Movement_Direction * Movement_Speed) + offset + noiseOffset; + + //Adding particles if there is more smoke, remove smaller particles + particles += fireParticles(bokehUV, uv) * alpha * (1.0 - smoothstep(0.0, 1.0, smoke) * (float(i) / float(layers))); + + //Moving uv origin to avoid generating the same particles + offset += hash2_2(float2(alpha, alpha)) * 10.0; + + alpha *= alphaMod; + size *= sizeMod; + } + + return particles; +} + + +void mainImage(out float4 fragColor, in float2 fragCoord) +{ + float2 uv = (2.0 * fragCoord - uv_size.xy) / uv_size.x; + float vignette = 1.0 - smoothstep(0.4, 1.4, length(uv + float2(0.0, 0.3))); + + uv *= 1.8; + float alpha = clamp(Alpha_Percentage * .01, 0, 1.0); + + float smokeIntensity = layeredNoise1_2(uv * 10.0 + elapsed_time * 4.0 * Movement_Direction * Movement_Speed, 1.7, 0.7, 6, 0.2); + smokeIntensity *= pow(1.0 - smoothstep(-1.0, 1.6, uv.y), 2.0); + float3 smoke = smokeIntensity * SMOKE_COLOR * 0.8 * vignette; + + //Cutting holes in smoke + smoke *= pow(layeredNoise1_2(uv * 4.0 + elapsed_time * 0.5 * Movement_Direction * Movement_Speed, 1.8, 0.5, 3, 0.2), + 2.0) * 1.5; + + float3 particles = layeredParticles(uv, SIZE_MOD, ALPHA_MOD, Layers_Count, smokeIntensity); + + float4 col = float4(particles + smoke + SMOKE_COLOR * 0.02, alpha); + col.rgb *= vignette; + col.rgb = smoothstep(-0.08, 1.0, col.rgb); + + if (Apply_To_Alpha_Layer) + { + float4 original_color = image.Sample(textureSampler, UV); + + float luma = dot(col.rgb, float3(0.299, 0.587, 0.114)); + float luma_min = smoothstep(lumaMin, lumaMin + lumaMinSmooth, luma); + col.a = clamp(luma_min, 0.0, 1.0); + + col.rgb = lerp(original_color.rgb, col.rgb, alpha); //apply alpha slider + col = lerp(original_color, col, col.a); //remove black background color + } + + fragColor = col; +} + +/*ps end*/ + +struct VertFragData { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; + +VertFragData VSDefault(VertFragData vtx) { + vtx.pos = mul(float4(vtx.pos.xyz, 1.0), ViewProj); + return vtx; +} + +float4 PSDefault(VertFragData vtx) : TARGET { + float4 col = float4(1., 1., 1., 1.); + mainImage(col, vtx.uv * uv_size); + return col; +} + +technique Draw +{ + pass + { + vertex_shader = VSDefault(vtx); + pixel_shader = PSDefault(vtx); + } } ' @@ -41963,55 +33400,38 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSVHSShader { +function Get-OBSEmbossColorShader { -[Alias('Set-OBSVHSShader','Add-OBSVHSShader')] +[Alias('Set-OBSEmbossColorShader','Add-OBSEmbossColorShader')] param( -# Set the range of OBSVHSShader -[ComponentModel.DefaultBindingProperty('range')] -[Single] -$Range, -# Set the offsetIntensity of OBSVHSShader -[ComponentModel.DefaultBindingProperty('offsetIntensity')] -[Single] -$OffsetIntensity, -# Set the noiseQuality of OBSVHSShader -[ComponentModel.DefaultBindingProperty('noiseQuality')] -[Single] -$NoiseQuality, -# Set the noiseIntensity of OBSVHSShader -[ComponentModel.DefaultBindingProperty('noiseIntensity')] -[Single] -$NoiseIntensity, -# Set the colorOffsetIntensity of OBSVHSShader -[ComponentModel.DefaultBindingProperty('colorOffsetIntensity')] -[Single] -$ColorOffsetIntensity, -# Set the Alpha_Percentage of OBSVHSShader -[Alias('Alpha_Percentage')] -[ComponentModel.DefaultBindingProperty('Alpha_Percentage')] +# Set the Angle_Steps of OBSEmbossColorShader +[Alias('Angle_Steps')] +[ComponentModel.DefaultBindingProperty('Angle_Steps')] +[Int32] +$AngleSteps, +# Set the Radius_Steps of OBSEmbossColorShader +[Alias('Radius_Steps')] +[ComponentModel.DefaultBindingProperty('Radius_Steps')] +[Int32] +$RadiusSteps, +# Set the ampFactor of OBSEmbossColorShader +[ComponentModel.DefaultBindingProperty('ampFactor')] [Single] -$AlphaPercentage, -# Set the Apply_To_Image of OBSVHSShader -[Alias('Apply_To_Image')] -[ComponentModel.DefaultBindingProperty('Apply_To_Image')] -[Management.Automation.SwitchParameter] -$ApplyToImage, -# Set the Replace_Image_Color of OBSVHSShader -[Alias('Replace_Image_Color')] -[ComponentModel.DefaultBindingProperty('Replace_Image_Color')] +$AmpFactor, +# Set the Up_Down_Percent of OBSEmbossColorShader +[Alias('Up_Down_Percent')] +[ComponentModel.DefaultBindingProperty('Up_Down_Percent')] +[Int32] +$UpDownPercent, +# Set the Apply_To_Alpha_Layer of OBSEmbossColorShader +[Alias('Apply_To_Alpha_Layer')] +[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] [Management.Automation.SwitchParameter] -$ReplaceImageColor, -# Set the Color_To_Replace of OBSVHSShader -[Alias('Color_To_Replace')] -[ComponentModel.DefaultBindingProperty('Color_To_Replace')] +$ApplyToAlphaLayer, +# Set the notes of OBSEmbossColorShader +[ComponentModel.DefaultBindingProperty('notes')] [String] -$ColorToReplace, -# Set the Apply_To_Specific_Color of OBSVHSShader -[Alias('Apply_To_Specific_Color')] -[ComponentModel.DefaultBindingProperty('Apply_To_Specific_Color')] -[Management.Automation.SwitchParameter] -$ApplyToSpecificColor, +$Notes, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -42042,136 +33462,89 @@ $UseShaderTime process { -$shaderName = 'VHS' -$ShaderNoun = 'OBSVHSShader' +$shaderName = 'emboss_color' +$ShaderNoun = 'OBSEmbossColorShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -//based on https://www.shadertoy.com/view/Ms3XWH converted by Exeldro v 1.0 -//updated by Charles ''Surn'' Fettinger for obs-shaderfilter 9/2020 -//Converted to OpenGL by Exeldro February 19, 2022 -//Use improved input fields by Exeldro April 15, 2023 -uniform float range< - string label = "Wave size (0.05)"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 0.20; - float step = 0.01; -> = 0.05; -uniform float offsetIntensity< - string label = "Offset intensity (0.02)"; +// Color Emboss shader by Charles Fettinger for obs-shaderfilter plugin 4/2019 +//https://github.com/Oncorporation/obs-shaderfilter +//Converted to OpenGL by Q-mii & Exeldro February 18, 2022 +uniform int Angle_Steps< + string label = "Angle Steps"; string widget_type = "slider"; - float minimum = 0.01; - float maximum = 0.20; - float step = 0.01; -> = 0.02; -uniform float noiseQuality< - string label = "Noise number of lines (250)"; + int minimum = 1; + int maximum = 20; + int step = 1; +> = 9; // +uniform int Radius_Steps< + string label = "Radius Steps"; string widget_type = "slider"; - float minimum = 1.0; - float maximum = 1000.0; - float step = 10.0; -> = 250.0; -uniform float noiseIntensity< - string label = "Noise intensity (0.88)"; + int minimum = 0; + int maximum = 20; + int step = 1; +> = 4; // +uniform float ampFactor< + string label = "amp Factor"; string widget_type = "slider"; float minimum = 0.0; float maximum = 10.0; float step = 0.01; -> = 0.88; -uniform float colorOffsetIntensity< - string label = "Color offset intensity (1.3)"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 10.0; - float step = 0.1; -> = 1.3; -uniform float Alpha_Percentage< - string label = "Aplha percentage (100.0)"; +> = 12.0; +uniform int Up_Down_Percent< + string label = "Up Down Percent"; string widget_type = "slider"; - float minimum = 0.0; - float maximum = 100.0; - float step = 1.0; -> = 100.0; -uniform bool Apply_To_Image; -uniform bool Replace_Image_Color; -uniform float4 Color_To_Replace; -uniform bool Apply_To_Specific_Color; - -float dot2(float2 a,float2 b){ - return a.x*b.x+a.y*b.y; -} + int minimum = -100; + int maximum = 100; + int step = 1; +> = 0; +uniform bool Apply_To_Alpha_Layer = true; +uniform string notes< + string widget_type = "info"; +> = "Steps limited in range from 0 to 20. Edit shader to remove limits at your own risk."; -float rand(float2 co) +float4 mainImage(VertData v_in) : TARGET { - return frac(sin(dot2(co.xy ,float2(12.9898,78.233))) * 43758.5453); -} + float radiusSteps = clamp(Radius_Steps, 0, 20); + float angleSteps = clamp(Angle_Steps, 1, 20); + float PI = 3.1415926535897932384626433832795;//acos(-1); + int totalSteps = int(radiusSteps * angleSteps); + float minRadius = (1 * uv_pixel_interval.y); + float maxRadius = (6 * uv_pixel_interval.y); -float verticalBar(float pos, float uvY, float offset) -{ - float edge0 = (pos - range); - float edge1 = (pos + range); + float angleDelta = ((2 * PI) / angleSteps); + float radiusDelta = ((maxRadius - minRadius) / radiusSteps); + float embossAngle = 0.25 * PI; - float x = smoothstep(edge0, pos, uvY) * offset; - x -= smoothstep(pos, edge1, uvY) * offset; - return x; -} + float4 c0 = image.Sample(textureSampler, v_in.uv); + float4 origColor = c0; + float4 accumulatedColor = float4(0,0,0,0); -float modu(float x, float y) -{ - return (x / y) - floor(x / y); -} + if (c0.a > 0.0 || Apply_To_Alpha_Layer == false) + { + for (int radiusStep = 0; radiusStep < radiusSteps; radiusStep++) { + float radius = minRadius + radiusStep * radiusDelta; -float dot4(float4 a,float4 b){ - return a.r*b.r+a.g*b.g+a.b*b.b+a.a*b.a; -} + for (float angle = 0; angle < (2 * PI); angle += angleDelta) { + float2 currentCoord; -float4 mainImage(VertData v_in) : TARGET -{ - float2 uv = v_in.uv; - for (float i = 0.0; i < 0.71; i += 0.1313) - { - float d = modu(elapsed_time * i, 1.7); - float o = sin(1.0 - tan(elapsed_time * 0.24 * i)); - o *= offsetIntensity; - uv.x += verticalBar(d, uv.y, o); - } - float uvY = uv.y; - uvY *= noiseQuality; - uvY = float(int(uvY)) * (1.0 / noiseQuality); - float noise = rand(float2(elapsed_time * 0.00001, uvY)); - uv.x += noise * noiseIntensity / 100.0; + float xDiff = radius * cos(angle); + float yDiff = radius * sin(angle); - float2 offsetR = float2(0.006 * sin(elapsed_time), 0.0) * colorOffsetIntensity; - float2 offsetG = float2(0.0073 * (cos(elapsed_time * 0.97)), 0.0) * colorOffsetIntensity; + currentCoord = v_in.uv + float2(xDiff, yDiff); + float4 currentColor = image.Sample(textureSampler, currentCoord); + float4 colorDiff = abs(c0 - currentColor); + float currentFraction = ((radiusSteps + 1 - radiusStep)) / (radiusSteps + 1); + accumulatedColor += currentFraction * colorDiff / totalSteps * sign(angle - PI);; - float4 rgba = image.Sample(textureSampler, uv); - float r = image.Sample(textureSampler, uv + offsetR).r; - float g = image.Sample(textureSampler, uv + offsetG).g; - float b = rgba.b; + } + } + accumulatedColor *= ampFactor; - rgba = float4(r, g, b, rgba.a); - - float4 color; - float4 original_color; - if (Apply_To_Image) - { - color = image.Sample(textureSampler, v_in.uv); - original_color = color; - float luma = dot4(color, float4(0.30, 0.59, 0.11, 1.0)); - if (Replace_Image_Color) - color = float4(luma,luma,luma,luma); - rgba = lerp(original_color, rgba * color, clamp(Alpha_Percentage * .01, 0, 1.0)); - - } - if (Apply_To_Specific_Color) - { - color = image.Sample(textureSampler, v_in.uv); - original_color = color; - color = (distance(color.rgb, Color_To_Replace.rgb) <= 0.075) ? rgba : color; - rgba = lerp(original_color, color, clamp(Alpha_Percentage * .01, 0, 1.0)); - } - - return rgba; + c0 = lerp(c0 + accumulatedColor, c0 - accumulatedColor, (Up_Down_Percent * 0.01)); + } + //return c0 + accumulatedColor; // down; + //return c0 - accumulatedColor; // up + return c0; } ' @@ -42271,26 +33644,20 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSVignettingShader { +function Get-OBSEmbossShader { -[Alias('Set-OBSVignettingShader','Add-OBSVignettingShader')] +[Alias('Set-OBSEmbossShader','Add-OBSEmbossShader')] param( -# Set the innerRadius of OBSVignettingShader -[ComponentModel.DefaultBindingProperty('innerRadius')] -[Single] -$InnerRadius, -# Set the outerRadius of OBSVignettingShader -[ComponentModel.DefaultBindingProperty('outerRadius')] -[Single] -$OuterRadius, -# Set the opacity of OBSVignettingShader -[ComponentModel.DefaultBindingProperty('opacity')] -[Single] -$Opacity, -# Set the notes of OBSVignettingShader -[ComponentModel.DefaultBindingProperty('notes')] -[String] -$Notes, +# Set the Use_Color of OBSEmbossShader +[Alias('Use_Color')] +[ComponentModel.DefaultBindingProperty('Use_Color')] +[Management.Automation.SwitchParameter] +$UseColor, +# Set the Apply_To_Alpha_Layer of OBSEmbossShader +[Alias('Apply_To_Alpha_Layer')] +[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] +[Management.Automation.SwitchParameter] +$ApplyToAlphaLayer, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -42321,60 +33688,42 @@ $UseShaderTime process { -$shaderName = 'vignetting' -$ShaderNoun = 'OBSVignettingShader' +$shaderName = 'emboss' +$ShaderNoun = 'OBSEmbossShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -//Converted to OpenGL by Q-mii & Exeldro February 21, 2022 -uniform float innerRadius< - string label = "inner radius"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 5.0; - float step = 0.001; -> = 0.9; -uniform float outerRadius< - string label = "outer radius"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 5.0; - float step = 0.001; -> = 1.5; -uniform float opacity< - string label = "opacity"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.8; -uniform string notes< - string widget_type = "info"; -> = "inner radius will always be shown, outer radius is the falloff"; +// Spotlight By Charles Fettinger (https://github.com/Oncorporation) 4/2019 +//Converted to OpenGL by Q-mii & Exeldro March 8, 2022 +uniform bool Use_Color; +uniform bool Apply_To_Alpha_Layer = true; float4 mainImage(VertData v_in) : TARGET { - float PI = 3.1415926535897932384626433832795;//acos(-1); - - float4 c0 = image.Sample(textureSampler, v_in.uv); - float verticalDim = 0.5 + sin (v_in.uv.y * PI) * 0.9 ; - - float xTrans = (v_in.uv.x * 2) - 1; - float yTrans = 1 - (v_in.uv.y * 2); - - float radius = sqrt(pow(xTrans, 2) + pow(yTrans, 2)); - float subtraction = max(0, radius - innerRadius) / max((outerRadius - innerRadius), 0.01); - float factor = 1 - subtraction; + float dx = 1 / uv_size.x; + float dy = 1 / uv_size.y; - float4 vignetColor = c0 * factor; - vignetColor *= verticalDim; + float4 c0 = image.Sample(textureSampler, v_in.uv); + if (c0.a > 0.0 || Apply_To_Alpha_Layer == false) + { + float4 c1 = image.Sample(textureSampler, v_in.uv + float2(-dx, -dy)); + float4 c2 = image.Sample(textureSampler, v_in.uv + float2(0, -dy)); + float4 c4 = image.Sample(textureSampler, v_in.uv + float2(-dx, 0)); + float4 c6 = image.Sample(textureSampler, v_in.uv + float2(dx, 0)); + float4 c8 = image.Sample(textureSampler, v_in.uv + float2(0, dy)); + float4 c9 = image.Sample(textureSampler, v_in.uv + float2(dx, dy)); - vignetColor *= opacity; - c0 *= 1-opacity; + c0 = (-c1 - c2 - c4 + c6 + c8 + c9); + float c = (c0.r + c0.g + c0.b) / 3 + 0.5; + c0 = float4(c,c,c,c); - float4 output_color = c0 + vignetColor; - - return float4(output_color); + if (Use_Color) + { + float4 rgba = image.Sample(textureSampler, v_in.uv); + return (0.5 * rgba) + c0; + } + } + return c0; } ' @@ -42474,18 +33823,60 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSVoronoiPixelationShader { +function Get-OBSExeldroBentCameraShader { -[Alias('Set-OBSVoronoiPixelationShader','Add-OBSVoronoiPixelationShader')] +[Alias('Set-OBSExeldroBentCameraShader','Add-OBSExeldroBentCameraShader')] param( -# Set the pixH of OBSVoronoiPixelationShader -[ComponentModel.DefaultBindingProperty('pixH')] +# Set the left_side_width of OBSExeldroBentCameraShader +[Alias('left_side_width')] +[ComponentModel.DefaultBindingProperty('left_side_width')] [Single] -$PixH, -# Set the alternative of OBSVoronoiPixelationShader -[ComponentModel.DefaultBindingProperty('alternative')] -[Management.Automation.SwitchParameter] -$Alternative, +$LeftSideWidth, +# Set the left_side_size of OBSExeldroBentCameraShader +[Alias('left_side_size')] +[ComponentModel.DefaultBindingProperty('left_side_size')] +[Single] +$LeftSideSize, +# Set the left_side_shadow of OBSExeldroBentCameraShader +[Alias('left_side_shadow')] +[ComponentModel.DefaultBindingProperty('left_side_shadow')] +[Single] +$LeftSideShadow, +# Set the left_flip_width of OBSExeldroBentCameraShader +[Alias('left_flip_width')] +[ComponentModel.DefaultBindingProperty('left_flip_width')] +[Single] +$LeftFlipWidth, +# Set the left_flip_shadow of OBSExeldroBentCameraShader +[Alias('left_flip_shadow')] +[ComponentModel.DefaultBindingProperty('left_flip_shadow')] +[Single] +$LeftFlipShadow, +# Set the right_side_width of OBSExeldroBentCameraShader +[Alias('right_side_width')] +[ComponentModel.DefaultBindingProperty('right_side_width')] +[Single] +$RightSideWidth, +# Set the right_side_size of OBSExeldroBentCameraShader +[Alias('right_side_size')] +[ComponentModel.DefaultBindingProperty('right_side_size')] +[Single] +$RightSideSize, +# Set the right_side_shadow of OBSExeldroBentCameraShader +[Alias('right_side_shadow')] +[ComponentModel.DefaultBindingProperty('right_side_shadow')] +[Single] +$RightSideShadow, +# Set the right_flip_width of OBSExeldroBentCameraShader +[Alias('right_flip_width')] +[ComponentModel.DefaultBindingProperty('right_flip_width')] +[Single] +$RightFlipWidth, +# Set the right_flip_shadow of OBSExeldroBentCameraShader +[Alias('right_flip_shadow')] +[ComponentModel.DefaultBindingProperty('right_flip_shadow')] +[Single] +$RightFlipShadow, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -42516,98 +33907,126 @@ $UseShaderTime process { -$shaderName = 'voronoi-pixelation' -$ShaderNoun = 'OBSVoronoiPixelationShader' +$shaderName = 'exeldro-bent-camera' +$ShaderNoun = 'OBSExeldroBentCameraShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// https://www.shadertoy.com/view/sd3yzn adopted by Exeldro - -uniform float pixH< - string label = "Size"; +uniform float left_side_width< + string label = "Left side width"; string widget_type = "slider"; - float minimum = 4.0; - float maximum = 500.0; + float minimum = 0.0; + float maximum = 1.0; float step = 0.01; -> = 100.0; -uniform bool alternative; - -float2 fract2(float2 v){ - return float2(v.x - floor(v.x), v.y - floor(v.y)); -} - -float2 random2( float2 p ) { - return fract2(sin(float2(dot(p,float2(127.1,311.7)),dot(p,float2(269.5,183.3))))*43758.5453); -} -float2 randomSpin(float2 p, float f){ - return 1.0 * float2( - cos( f * elapsed_time * 3.14159 * sign(random2(p).y - 0.5) + random2(p).y * 3.14159), - sin( f * elapsed_time * 3.14159 * sign(random2(p).x - 0.5) + random2(p).x * 3.14159)); -} -float4 VoronoiPixelation(float2 uv, float pixH ){ - float2 pixInt = fract2(uv * pixH); - float2 pixExt = floor(uv * pixH); - float m_dist = 10.0; - float2 relClos = float2(0.0, 0.0); - float2 relRot = 0.5 * float2(cos(elapsed_time), sin(elapsed_time)); - - - for (int y= -3; y <= 3; y++) { - for (int x= -3; x <= 3; x++) { - float2 neighbor = float2(float(x),float(y)); - - float2 point1 = random2(pixExt + neighbor); - float2 relRot = randomSpin(pixExt + neighbor, 0.5); - float2 diff = neighbor + relRot + point1 - pixInt; - float dist = length(diff); - if(dist < m_dist){ - m_dist = dist; - relClos = neighbor; - } - } - } - float2 nPoint = pixExt + relClos + randomSpin(pixExt + relClos, 0.5) + random2(pixExt + relClos); - nPoint = nPoint / pixH; - nPoint.x = nPoint.x * uv_scale.x ; - - return image.Sample(textureSampler, nPoint); -} -float4 VoronoiPixelation2(float2 uv, float pixH ){ - float2 pixInt = fract2(uv * pixH); - float2 pixExt = floor(uv * pixH); - float m_dist = 10.0; - float2 relClos = float2(0.0, 0.0); - float2 relRot = 0.5 * float2(cos(elapsed_time), sin(elapsed_time)); - - - for (int y= -3; y <= 3; y++) { - for (int x= -3; x <= 3; x++) { - float2 neighbor = float2(float(x),float(y)); - - float2 point2 = random2(pixExt + neighbor); - float2 relRot = randomSpin(pixExt + neighbor, 0.5); - float2 diff = neighbor + relRot + point2 - pixInt; - float dist = length(diff); - if(dist < m_dist){ - m_dist = dist; - relClos = neighbor; - } - } - } - float2 nPoint = pixExt + relClos + random2(pixExt + relClos); - nPoint = nPoint / pixH; - nPoint.x = nPoint.x * uv_scale.x; - - return image.Sample(textureSampler, nPoint); -} +> = 0.1; +uniform float left_side_size< + string label = "Left side size"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.9; +uniform float left_side_shadow< + string label = "Left side shadow"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.8; +uniform float left_flip_width< + string label = "Left flip width"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.05; +uniform float left_flip_shadow< + string label = "Left flip shadow"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.6; +uniform float right_side_width< + string label = "Right side width"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.1; +uniform float right_side_size< + string label = "Right side size"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.9; +uniform float right_side_shadow< + string label = "Right side shadow"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.8; +uniform float right_flip_width< + string label = "Right flip width"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.05; +uniform float right_flip_shadow< + string label = "Right flip shadow"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.6; float4 mainImage(VertData v_in) : TARGET { - if (alternative) { - return VoronoiPixelation2(v_in.uv, pixH); - } else { - return VoronoiPixelation(v_in.uv, pixH); + float2 pos=v_in.uv; + float shadow = 1.0; + if(pos.x < left_side_width){ + pos.y -= 0.5; + pos.y /= left_side_size; + pos.y += 0.5; + pos.x -= left_side_width + left_flip_width / 2.0; + pos.x /= left_side_size; + pos.x += left_side_width + left_flip_width / 2.0; + shadow = left_side_shadow; + }else if(pos.x < left_side_width + left_flip_width){ + float factor = 1.0 - ((left_side_width + left_flip_width)-pos.x)/left_flip_width*(1.0 - left_side_size); + pos.y -= 0.5; + pos.y /= factor; + pos.y += 0.5; + pos.x -= left_side_width + left_flip_width; + pos.x /= factor; + pos.x += left_side_width + left_flip_width; + shadow = left_flip_shadow; + } + + if(1.0 - pos.x < right_side_width){ + pos.y -= 0.5; + pos.y /= right_side_size; + pos.y += 0.5; + pos.x -= 1.0 - (right_side_width + right_flip_width / 2.0); + pos.x /= right_side_size; + pos.x += 1.0 - (right_side_width + right_flip_width / 2.0); + shadow = right_side_shadow; + }else if(1.0 - pos.x < right_side_width + right_flip_width){ + float factor = 1.0 - ((right_side_width + right_flip_width) - (1.0 - pos.x))/right_flip_width*(1.0 - right_side_size); + pos.y -= 0.5; + pos.y /= factor; + pos.y += 0.5; + pos.x -= 1.0 - (right_side_width + right_flip_width); + pos.x /= factor; + pos.x += 1.0 -(right_side_width + right_flip_width); + shadow = right_flip_shadow; } + float4 p_color = image.Sample(textureSampler, pos); + p_color.rgb *= shadow; + return p_color; } ' } @@ -42706,48 +34125,30 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSZigZagShader { +function Get-OBSFadeTransitionShader { -[Alias('Set-OBSZigZagShader','Add-OBSZigZagShader')] +[Alias('Set-OBSFadeTransitionShader','Add-OBSFadeTransitionShader')] param( -# Set the radius of OBSZigZagShader -[ComponentModel.DefaultBindingProperty('radius')] -[Single] -$Radius, -# Set the angle of OBSZigZagShader -[ComponentModel.DefaultBindingProperty('angle')] -[Single] -$Angle, -# Set the period of OBSZigZagShader -[ComponentModel.DefaultBindingProperty('period')] -[Single] -$Period, -# Set the amplitude of OBSZigZagShader -[ComponentModel.DefaultBindingProperty('amplitude')] -[Single] -$Amplitude, -# Set the center_x of OBSZigZagShader -[Alias('center_x')] -[ComponentModel.DefaultBindingProperty('center_x')] -[Single] -$CenterX, -# Set the center_y of OBSZigZagShader -[Alias('center_y')] -[ComponentModel.DefaultBindingProperty('center_y')] -[Single] -$CenterY, -# Set the phase of OBSZigZagShader -[ComponentModel.DefaultBindingProperty('phase')] -[Single] -$Phase, -# Set the animate of OBSZigZagShader -[ComponentModel.DefaultBindingProperty('animate')] -[Int32] -$Animate, -# Set the notes of OBSZigZagShader -[ComponentModel.DefaultBindingProperty('notes')] +# Set the image_a of OBSFadeTransitionShader +[Alias('image_a')] +[ComponentModel.DefaultBindingProperty('image_a')] [String] -$Notes, +$ImageA, +# Set the image_b of OBSFadeTransitionShader +[Alias('image_b')] +[ComponentModel.DefaultBindingProperty('image_b')] +[String] +$ImageB, +# Set the transition_time of OBSFadeTransitionShader +[Alias('transition_time')] +[ComponentModel.DefaultBindingProperty('transition_time')] +[Single] +$TransitionTime, +# Set the convert_linear of OBSFadeTransitionShader +[Alias('convert_linear')] +[ComponentModel.DefaultBindingProperty('convert_linear')] +[Management.Automation.SwitchParameter] +$ConvertLinear, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -42778,121 +34179,29 @@ $UseShaderTime process { -$shaderName = 'ZigZag' -$ShaderNoun = 'OBSZigZagShader' +$shaderName = 'fade-transition' +$ShaderNoun = 'OBSFadeTransitionShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -//Created by Radegast Stravinsky for obs-shaderfilter 9/2020 -uniform float radius< - string label = "radius"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 5.0; - float step = 0.001; -> = 0.0; -uniform float angle< - string label = "angle"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 360.0; - float step = 0.1; -> = 180.0; -uniform float period< - string label = "period"; +uniform texture2d image_a; +uniform texture2d image_b; +uniform float transition_time< + string label = "Transittion Time"; string widget_type = "slider"; float minimum = 0.0; - float maximum = 5.0; + float maximum = 1.0; float step = 0.001; > = 0.5; -uniform float amplitude< - string label = "amplitude"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 5.0; - float step = 0.001; -> = 1.0; - -uniform float center_x< - string label = "center x"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 0.5; - float step = 0.001; -> = 0.25; -uniform float center_y< - string label = "center y"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 0.5; - float step = 0.001; -> = 0.25; - -uniform float phase< - string label = "phase"; - string widget_type = "slider"; - float minimum = 0.0; - float maximum = 5.0; - float step = 0.001; -> = 1.0; -uniform int animate< - string label = "animate"; - string widget_type = "select"; - int option_0_value = 0; - string option_0_label = "No"; - int option_1_value = 1; - string option_1_label = "Amplitude"; - int option_2_value = 2; - string option_2_label = "Time"; -> = 0; - - -uniform string notes = "Distorts the screen, creating a rippling effect that moves clockwise and anticlockwise." - +uniform bool convert_linear = true; float4 mainImage(VertData v_in) : TARGET { - float2 center = float2(center_x, center_y); - VertData v_out; - v_out.pos = v_in.pos; - float2 hw = uv_size; - float ar = 1. * hw.y/hw.x; - - v_out.uv = 1. * v_in.uv - center; - - center.x /= ar; - v_out.uv.x /= ar; - - float dist = distance(v_out.uv, center); - if (dist < radius) - { - float percent = (radius-dist)/radius; - float theta = percent * percent * - ( - animate == 1 ? - amplitude * sin(elapsed_time) : - amplitude - ) - * sin(percent * percent / period * radians(angle) + (phase + - ( - animate == 2 ? - elapsed_time : - 0 - ))); - - float s = sin(theta); - float c = cos(theta); - v_out.uv = float2(dot(v_out.uv-center, float2(c,-s)), dot(v_out.uv-center, float2(s,c))); - v_out.uv += (2 * center); - - v_out.uv.x *= ar; - - return image.Sample(textureSampler, v_out.uv); - } - else - { - return image.Sample(textureSampler, v_in.uv); - } - + float4 a_val = image_a.Sample(textureSampler, v_in.uv); + float4 b_val = image_b.Sample(textureSampler, v_in.uv); + float4 rgba = lerp(a_val, b_val, transition_time); + if(convert_linear) + rgba.rgb = srgb_nonlinear_to_linear(rgba.rgb); + return rgba; } ' } @@ -42991,35 +34300,34 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSZoomBlurShader { +function Get-OBSFillColorGradientShader { -[Alias('Set-OBSZoomBlurShader','Add-OBSZoomBlurShader')] +[Alias('Set-OBSFillColorGradientShader','Add-OBSFillColorGradientShader')] param( -# Set the samples of OBSZoomBlurShader -[ComponentModel.DefaultBindingProperty('samples')] -[Int32] -$Samples, -# Set the magnitude of OBSZoomBlurShader -[ComponentModel.DefaultBindingProperty('magnitude')] +# Set the Fill of OBSFillColorGradientShader +[ComponentModel.DefaultBindingProperty('Fill')] [Single] -$Magnitude, -# Set the speed_percent of OBSZoomBlurShader -[Alias('speed_percent')] -[ComponentModel.DefaultBindingProperty('speed_percent')] +$Fill, +# Set the Gradient_Width of OBSFillColorGradientShader +[Alias('Gradient_Width')] +[ComponentModel.DefaultBindingProperty('Gradient_Width')] +[Single] +$GradientWidth, +# Set the Gradient_Offset of OBSFillColorGradientShader +[Alias('Gradient_Offset')] +[ComponentModel.DefaultBindingProperty('Gradient_Offset')] +[Single] +$GradientOffset, +# Set the Fill_Direction of OBSFillColorGradientShader +[Alias('Fill_Direction')] +[ComponentModel.DefaultBindingProperty('Fill_Direction')] [Int32] -$SpeedPercent, -# Set the ease of OBSZoomBlurShader -[ComponentModel.DefaultBindingProperty('ease')] -[Management.Automation.SwitchParameter] -$Ease, -# Set the glitch of OBSZoomBlurShader -[ComponentModel.DefaultBindingProperty('glitch')] -[Management.Automation.SwitchParameter] -$Glitch, -# Set the notes of OBSZoomBlurShader -[ComponentModel.DefaultBindingProperty('notes')] +$FillDirection, +# Set the Fill_Color of OBSFillColorGradientShader +[Alias('Fill_Color')] +[ComponentModel.DefaultBindingProperty('Fill_Color')] [String] -$Notes, +$FillColor, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -43050,106 +34358,81 @@ $UseShaderTime process { -$shaderName = 'zoom_blur' -$ShaderNoun = 'OBSZoomBlurShader' +$shaderName = 'fill_color_gradient' +$ShaderNoun = 'OBSFillColorGradientShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// zoom blur shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 -// https://github.com/Oncorporation/obs-shaderfilter -// https://github.com/dinfinity/mpc-pixel-shaders/blob/master/PS_Zoom%20Blur.hlsl -//for Media Player Classic HC or BE -//Converted to OpenGL by Q-mii & Exeldro February 18, 2022 -uniform int samples < - string label = "Samples"; +uniform float Fill< + string label = "Fill"; string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 32; -uniform float magnitude< - string label = "Magnitude"; + float minimum = 0; + float maximum = 1; + float step = 0.005; +> = 0.500; + +uniform float Gradient_Width< + string label = "Gradient Width"; string widget_type = "slider"; - float minimum = 0.0; - float maximum = 1.0; - float step = 0.001; -> = 0.5; -uniform int speed_percent < - string label = "Speed percent"; + float minimum = 0; + float maximum = 0.15; // Adjust the maximum value as needed + float step = 0.01; +> = 0.05; + +uniform float Gradient_Offset< + string label = "Gradient Offset"; string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 0; -uniform bool ease; -uniform bool glitch; -uniform string notes< - string widget_type = "info"; -> = "Speed Percent above zero will animate the zoom. Keep samples low to save power"; + float minimum = 0; + float maximum = 0.100; // Adjust the maximum value as needed + float step = 0.005; +> = 0.00; -float EaseInOutCircTimer(float t,float b,float c,float d){ - t /= d/2; - if (t < 1) return -c/2 * (sqrt(1 - t*t) - 1) + b; - t -= 2; - return c/2 * (sqrt(1 - t*t) + 1) + b; -} +uniform int Fill_Direction< + string label = "Fill from:"; + string widget_type = "select"; + int option_0_value = 0; + string option_0_label = "Left"; + int option_1_value = 1; + string option_1_label = "Right"; + int option_2_value = 2; + string option_2_label = "Bottom"; + int option_3_value = 3; + string option_3_label = "Top"; +> = 0; -float Styler(float t,float b,float c,float d,bool ease) -{ - if (ease) return EaseInOutCircTimer(t,0,c,d); - return t; -} +uniform float4 Fill_Color; float4 mainImage(VertData v_in) : TARGET { - float speed = speed_percent * 0.01; - - // circular easing variable - float t = 1.0 + sin(elapsed_time * speed); - float b = 0.0; //start value - float c = 2.0; //change value - float d = 2.0; //duration - - if (glitch) t = clamp(t + ((rand_f *2) - 1), 0.0,2.0); - - b = Styler(t, 0, c, d, ease); - float sample_speed = max(samples * b, 1.0); - - float PI = 3.1415926535897932384626433832795;//acos(-1); - float4 c0 = image.Sample(textureSampler, v_in.uv); - - float xTrans = (v_in.uv.x*2)-1; - float yTrans = 1-(v_in.uv.y*2); - - float angle = atan(yTrans/xTrans) + PI; - if (sign(xTrans) == 1) { - angle+= PI; - } - float radius = sqrt(pow(xTrans,2) + pow(yTrans,2)); + float distanceToEdge = 0.0; - float2 currentCoord; - float4 accumulatedColor = float4(0,0,0,0); + // Calculate distance to the fill edge based on the selected direction + if (Fill_Direction == 0) + distanceToEdge = Fill - v_in.uv.x; + else if (Fill_Direction == 1) + distanceToEdge = v_in.uv.x - (1.0 - Fill); + else if (Fill_Direction == 2) + distanceToEdge = v_in.uv.y - (1.0 - Fill); + else if (Fill_Direction == 3) + distanceToEdge = Fill - v_in.uv.y; - float4 currentColor = image.Sample(textureSampler, currentCoord); - accumulatedColor = currentColor; + // Calculate the gradient factor based on the distance to the edge and the gradient width + float gradientOffset = (Fill == 0.0) ? 0.0 : (Fill == 1.0 ? 0.0 : Gradient_Offset); + float gradientWidth = (Fill == 0.0 || Fill == 1.0) ? 0.0 : Gradient_Width; - accumulatedColor = c0/sample_speed; - for(int i = 1; i< sample_speed; i++) { - float currentRadius ; - // Distance to center dependent - currentRadius = max(0,radius - (radius/1000 * i * magnitude * b)); + // Adjust distanceToEdge by the Gradient_Offset + distanceToEdge += gradientOffset; - // Continuous; - // currentRadius = max(0,radius - (0.0004 * i)); + // Normalize the distance to be between 0 and 1 + distanceToEdge = saturate(distanceToEdge); - currentCoord.x = (currentRadius * cos(angle)+1.0)/2.0; - currentCoord.y = -1* ((currentRadius * sin(angle)-1.0)/2.0); + // float gradientWidth = Fill < 1.0 ? Gradient_Width : Gradient_Width * (1.0 - Fill); + // float gradientFactor = smoothstep(0.0, gradientWidth, distanceToEdge); + float gradientFactor = clamp(distanceToEdge / gradientWidth, 0.0, 1.0); - float4 currentColor = image.Sample(textureSampler, currentCoord); - accumulatedColor += currentColor/sample_speed; - - } + // Blend between the fill color and the original image color using the gradient factor + float4 finalColor = lerp(image.Sample(textureSampler, v_in.uv), Fill_Color, gradientFactor); - return accumulatedColor; + return finalColor; } ' @@ -43249,24 +34532,24 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSZoomShader { +function Get-OBSFillColorLinearShader { -[Alias('Set-OBSZoomShader','Add-OBSZoomShader')] +[Alias('Set-OBSFillColorLinearShader','Add-OBSFillColorLinearShader')] param( -# Set the center_x_percent of OBSZoomShader -[Alias('center_x_percent')] -[ComponentModel.DefaultBindingProperty('center_x_percent')] -[Int32] -$CenterXPercent, -# Set the center_y_percent of OBSZoomShader -[Alias('center_y_percent')] -[ComponentModel.DefaultBindingProperty('center_y_percent')] -[Int32] -$CenterYPercent, -# Set the power of OBSZoomShader -[ComponentModel.DefaultBindingProperty('power')] +# Set the Fill of OBSFillColorLinearShader +[ComponentModel.DefaultBindingProperty('Fill')] [Single] -$Power, +$Fill, +# Set the Fill_Direction of OBSFillColorLinearShader +[Alias('Fill_Direction')] +[ComponentModel.DefaultBindingProperty('Fill_Direction')] +[Int32] +$FillDirection, +# Set the Fill_Color of OBSFillColorLinearShader +[Alias('Fill_Color')] +[ComponentModel.DefaultBindingProperty('Fill_Color')] +[String] +$FillColor, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -43297,39 +34580,57 @@ $UseShaderTime process { -$shaderName = 'zoom' -$ShaderNoun = 'OBSZoomShader' +$shaderName = 'fill_color_linear' +$ShaderNoun = 'OBSFillColorLinearShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -uniform int center_x_percent< - string label = "center x percent"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; -uniform int center_y_percent< - string label = "center y percent"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; -uniform float power< - string label = "power"; +uniform float Fill< + string label = "Fill"; string widget_type = "slider"; float minimum = 0; - float maximum = 20.0; - float step = 0.001; -> = 1.75; + float maximum = 1; + float step = 0.005; +>; +uniform int Fill_Direction< + string label = "Fill from:"; + string widget_type = "select"; + int option_0_value = 0; + string option_0_label = "Left"; + int option_1_value = 1; + string option_1_label = "Right"; + int option_2_value = 2; + string option_2_label = "Top"; + int option_3_value = 3; + string option_3_label = "Bottom"; +> = 0; +uniform float4 Fill_Color; float4 mainImage(VertData v_in) : TARGET { - float2 center_pos = float2(center_x_percent * .01, center_y_percent * .01); - float2 uv = v_in.uv; - uv.x = (v_in.uv.x - center_pos.x) * power + center_pos.x; - uv.y = (v_in.uv.y - center_pos.y) * power + center_pos.y; - return image.Sample(textureSampler, uv); + bool is_inside_fill = true; + + // Check if the pixel is within the specified "fill width" on the left side + if(Fill_Direction == 0){ + is_inside_fill = v_in.uv.x > Fill; + } + if(Fill_Direction == 1) + { + is_inside_fill = v_in.uv.x < (1.0 - Fill); + } + if(Fill_Direction == 2) + { + is_inside_fill = v_in.uv.y > Fill; + } + if(Fill_Direction == 3) + { + is_inside_fill = v_in.uv.y < (1.0 - Fill); + } + + // Invert is_inside_fill + is_inside_fill = !is_inside_fill; + + // If inside the "fill," make the pixel selected colour; otherwise, use the original image color + return is_inside_fill ? Fill_Color : image.Sample(textureSampler, v_in.uv); } ' } @@ -43428,30 +34729,39 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSZoomXYShader { +function Get-OBSFillColorRadialDegreesShader { -[Alias('Set-OBSZoomXYShader','Add-OBSZoomXYShader')] +[Alias('Set-OBSFillColorRadialDegreesShader','Add-OBSFillColorRadialDegreesShader')] param( -# Set the center_x_percent of OBSZoomXYShader -[Alias('center_x_percent')] -[ComponentModel.DefaultBindingProperty('center_x_percent')] -[Int32] -$CenterXPercent, -# Set the center_y_percent of OBSZoomXYShader -[Alias('center_y_percent')] -[ComponentModel.DefaultBindingProperty('center_y_percent')] +# Set the Fill_Direction of OBSFillColorRadialDegreesShader +[Alias('Fill_Direction')] +[ComponentModel.DefaultBindingProperty('Fill_Direction')] [Int32] -$CenterYPercent, -# Set the x_power of OBSZoomXYShader -[Alias('x_power')] -[ComponentModel.DefaultBindingProperty('x_power')] +$FillDirection, +# Set the Fill of OBSFillColorRadialDegreesShader +[ComponentModel.DefaultBindingProperty('Fill')] [Single] -$XPower, -# Set the y_power of OBSZoomXYShader -[Alias('y_power')] -[ComponentModel.DefaultBindingProperty('y_power')] +$Fill, +# Set the Start_Angle of OBSFillColorRadialDegreesShader +[Alias('Start_Angle')] +[ComponentModel.DefaultBindingProperty('Start_Angle')] [Single] -$YPower, +$StartAngle, +# Set the Offset_X of OBSFillColorRadialDegreesShader +[Alias('Offset_X')] +[ComponentModel.DefaultBindingProperty('Offset_X')] +[Single] +$OffsetX, +# Set the Offset_Y of OBSFillColorRadialDegreesShader +[Alias('Offset_Y')] +[ComponentModel.DefaultBindingProperty('Offset_Y')] +[Single] +$OffsetY, +# Set the Fill_Color of OBSFillColorRadialDegreesShader +[Alias('Fill_Color')] +[ComponentModel.DefaultBindingProperty('Fill_Color')] +[String] +$FillColor, # The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] [Alias('SceneItemName')] @@ -43482,54 +34792,97 @@ $UseShaderTime process { -$shaderName = 'Zoom_XY' -$ShaderNoun = 'OBSZoomXYShader' +$shaderName = 'fill_color_radial_degrees' +$ShaderNoun = 'OBSFillColorRadialDegreesShader' if (-not $psBoundParameters['ShaderText']) { $psBoundParameters['ShaderText'] = $ShaderText = ' -// Zoom XY Shader - -// A simple twist on the Zoom Shader in https://github.com/exeldro/obs-shaderfilter/ +#define PI 3.141592653589793238 -// The allow for an independent Horizontal and Vertical Zoom. +uniform int Fill_Direction< + string label = "Fill Direction"; + string widget_type = "select"; + int option_0_value = 0; + string option_0_label = "Clockwise"; + int option_1_value = 1; + string option_1_label = "Counter-Clockwise"; +> = 0; -uniform int center_x_percent< - string label = "center x percent"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; -uniform int center_y_percent< - string label = "center y percent"; - string widget_type = "slider"; - int minimum = 0; - int maximum = 100; - int step = 1; -> = 50; -uniform float x_power< - string label = "x power"; +uniform float Fill< + string label = "Fill"; string widget_type = "slider"; float minimum = 0; - float maximum = 20.0; - float step = 0.001; -> = 1; + float maximum = 360; + float step = 1.00000; +>; -uniform float y_power< - string label = "y power"; +uniform float Start_Angle< + string label = "Start Angle"; string widget_type = "slider"; float minimum = 0; - float maximum = 20.0; - float step = 0.001; -> = 1; + float maximum = 720; + float step = 1.00000; +> = 360.0; + +uniform float Offset_X< + string label = "Offset X"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.01; +> = 0.0; + +uniform float Offset_Y< + string label = "Offset Y"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.01; +> = 0.0; + +uniform float4 Fill_Color; float4 mainImage(VertData v_in) : TARGET { - float2 center_pos = float2(center_x_percent * .01, center_y_percent * .01); - float2 uv = v_in.uv; - uv.x = (v_in.uv.x - center_pos.x) * x_power + center_pos.x; - uv.y = (v_in.uv.y - center_pos.y) * y_power + center_pos.y; - return image.Sample(textureSampler, uv); + // Calculate the center of the screen based on aspect ratio + float aspectRatioX = uv_size.x / uv_size.y; + float2 center = float2(0.5 * aspectRatioX + Offset_X, 0.5 + Offset_Y); + + // Normalize the UV coordinates based on aspect ratio + float2 normalizedUV = v_in.uv * float2(aspectRatioX, 1.0); + + // Calculate the direction vector from the center to the current pixel + float2 dir = normalizedUV - center; + + // Calculate the angle in radians + float angle = atan2(dir.y, dir.x); + + // Convert angle from radians to degrees + angle = degrees(angle); + + // Offset the angle to start from the specified starting angle + angle += Start_Angle + 90.0; // Subtract 90 degrees to start at 12 o''clock + if (angle >= 360.0) + angle -= 360.0; + + // Adjust the angle based on the selected fill direction + if (Fill_Direction == 1) { + // Counter-clockwise fill + angle = 360.0 - angle; + } + + // Ensure angle is within [0, 360] range + if (angle < 0.0) + angle += 360.0; + else if (angle >= 360.0) + angle -= 360.0; + + // Check if the angle is within the specified "fill width" + bool is_inside_fill = angle < Fill; + + // If inside the "fill," make the pixel selected color; otherwise, use the original image color + return is_inside_fill ? Fill_Color : image.Sample(textureSampler, v_in.uv); } + ' } $MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 @@ -43627,1603 +34980,7222 @@ switch -regex ($myVerb) { #.ExternalHelp obs-powershell-Help.xml -function Set-OBS3DFilter { - - - [Alias('Add-OBS3DFilter')] - param( - # The Field of View - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("fov")] - [double] - $FieldOfView, - - # The Rotation along the X-axis - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("rot_x")] - [double] - $RotationX, +function Get-OBSFillColorRadialPercentageShader { - # The Rotation along the Y-axis - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("rot_y")] - [double] - $RotationY, - - # The Rotation along the Z-axis - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("rot_z")] - [double] - $RotationZ, +[Alias('Set-OBSFillColorRadialPercentageShader','Add-OBSFillColorRadialPercentageShader')] +param( +# Set the Fill_Direction of OBSFillColorRadialPercentageShader +[Alias('Fill_Direction')] +[ComponentModel.DefaultBindingProperty('Fill_Direction')] +[Int32] +$FillDirection, +# Set the Fill of OBSFillColorRadialPercentageShader +[ComponentModel.DefaultBindingProperty('Fill')] +[Single] +$Fill, +# Set the Start_Angle of OBSFillColorRadialPercentageShader +[Alias('Start_Angle')] +[ComponentModel.DefaultBindingProperty('Start_Angle')] +[Single] +$StartAngle, +# Set the Offset_X of OBSFillColorRadialPercentageShader +[Alias('Offset_X')] +[ComponentModel.DefaultBindingProperty('Offset_X')] +[Single] +$OffsetX, +# Set the Offset_Y of OBSFillColorRadialPercentageShader +[Alias('Offset_Y')] +[ComponentModel.DefaultBindingProperty('Offset_Y')] +[Single] +$OffsetY, +# Set the Fill_Color of OBSFillColorRadialPercentageShader +[Alias('Fill_Color')] +[ComponentModel.DefaultBindingProperty('Fill_Color')] +[String] +$FillColor, +# 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 +) - # The Position along the X-axis - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("pos_x")] - [double] - $PositionX, - # The Position along the Y-axis - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("pos_y")] - [double] - $PositionY, +process { +$shaderName = 'fill_color_radial_percentage' +$ShaderNoun = 'OBSFillColorRadialPercentageShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +#define PI 3.141592653589793238 - # The Position along the Z-axis - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("pos_z")] - [double] - $PositionZ, +uniform int Fill_Direction< + string label = "Fill Direction"; + string widget_type = "select"; + int option_0_value = 0; + string option_0_label = "Clockwise"; + int option_1_value = 1; + string option_1_label = "Counter-Clockwise"; +> = 0; - # The scale of the source along the X-axis - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("scale_x")] - [double] - $ScaleX, +uniform float Fill< + string label = "Fill"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.00005; +> = 0.0; - # The scale of the source along the Y-axis - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("scale_y")] - [double] - $ScaleY, +uniform float Start_Angle< + string label = "Start Angle"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 720; + float step = 1.00000; +> = 360.0; - # If set, will remove a filter if one already exists. - # If this is not provided and the filter already exists, the settings of the filter will be changed. - [switch] - $Force - ) - dynamicParam { - $baseCommand = - if (-not $script:AddOBSSourceFilter) { - $script:AddOBSSourceFilter = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSSourceFilter','Function') - $script:AddOBSSourceFilter - } else { - $script:AddOBSSourceFilter - } - $IncludeParameter = @() - $ExcludeParameter = 'FilterKind','FilterSettings' +uniform float Offset_X< + string label = "Offset X"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.01; +> = 0.0; +uniform float Offset_Y< + string label = "Offset Y"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.01; +> = 0.0; - $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() - :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { - if ($ExcludeParameter) { - foreach ($exclude in $ExcludeParameter) { - if ($paramName -like $exclude) { continue nextInputParameter} - } - } - if ($IncludeParameter) { - $shouldInclude = - foreach ($include in $IncludeParameter) { - if ($paramName -like $include) { $true;break} - } - if (-not $shouldInclude) { continue nextInputParameter } - } - - $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( - $baseCommand.Parameters[$paramName].Name, - $baseCommand.Parameters[$paramName].ParameterType, - $baseCommand.Parameters[$paramName].Attributes - )) - } - $DynamicParameters +uniform float4 Fill_Color; - } - process { - $myParameters = [Ordered]@{} + $PSBoundParameters - - if (-not $myParameters["FilterName"]) { - $filterName = $myParameters["FilterName"] = "3Band3D" - } - - $myParameterData = [Ordered]@{} - foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { +float4 mainImage(VertData v_in) : TARGET +{ + // Calculate the center of the screen based on aspect ratio + float aspectRatioX = uv_size.x / uv_size.y; + float2 center = float2(0.5 * aspectRatioX + Offset_X, 0.5 + Offset_Y); - $bindToPropertyName = $null - - foreach ($attribute in $parameter.Attributes) { - if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { - $bindToPropertyName = $attribute.Name - break - } - } + // Normalize the UV coordinates based on aspect ratio + float2 normalizedUV = v_in.uv * float2(aspectRatioX, 1.0); - if (-not $bindToPropertyName) { continue } - if ($myParameters.Contains($parameter.Name)) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] - if ($myParameters[$parameter.Name] -is [switch]) { - $myParameterData[$bindToPropertyName] = $parameter.Name -as [bool] - } - } - } - - $addSplat = @{ - filterName = $myParameters["FilterName"] - SourceName = $myParameters["SourceName"] - filterKind = "3d_effect_filter" - filterSettings = $myParameterData - NoResponse = $myParameters["NoResponse"] - } + // Calculate the direction vector from the center to the current pixel + float2 dir = normalizedUV - center; - if ($MyParameters["PassThru"]) { - $addSplat.Passthru = $MyParameters["PassThru"] - if ($MyInvocation.InvocationName -like 'Add-*') { - Add-OBSSourceFilter @addSplat - } else { - $addSplat.Remove('FilterKind') - Set-OBSSourceFilterSettings @addSplat - } - return - } + // Calculate the angle in radians + float angle = atan2(dir.y, dir.x); - # Add the input. - $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 - + // Convert angle from radians to degrees + angle = degrees(angle); - # If we got back an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # and that error was saying the source already exists, - if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { - # then check if we use the -Force. - if ($Force) { # If we do, remove the input - Remove-OBSSourceFilter -FilterName $addSplat.FilterName -SourceName $addSplat.SourceName - # and re-add our result. - $outputAddedResult = Add-OBSInput @addSplat *>&1 - } else { - # Otherwise, get the existing filter. - $existingFilter = Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName - # then apply the settings - $existingFilter.Set($addSplat.filterSettings) - # and output them - $existingFilter - # (don't forget to null the result, so we don't show this error) - $outputAddedResult = $null - } - } + // Offset the angle to start from the specified starting angle + angle += Start_Angle + 90.0; // Subtract 90 degrees to start at 12 o''clock + if (angle >= 360.0) + angle -= 360.0; - # If the output was still an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # use $psCmdlet.WriteError so that it shows the error correctly. - $psCmdlet.WriteError($outputAddedResult) - } - - } - # Otherwise, if we had a result - elseif ($outputAddedResult) { - # Otherwise, get the input from the filters. - Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName - - } - + // Adjust the angle based on the selected fill direction + if (Fill_Direction == 1) { + // Counter-clockwise fill + angle = 360.0 - angle; } -} - - -#.ExternalHelp obs-powershell-Help.xml -function Set-OBSColorFilter { - - - [Alias('Add-OBSColorFilter','Add-OBSColorCorrectionFilter','Set-OBSColorCorrectionFilter')] - param( - # The opacity, as a number between 0 and 1. - [Parameter(ValueFromPipelineByPropertyName)] - [ValidateRange(0,1)] - [ComponentModel.DefaultBindingProperty("opacity")] - [double] - $Opacity, - - # The brightness, as a number between -1 and 1. - [Parameter(ValueFromPipelineByPropertyName)] - [ValidateRange(-1,1)] - [ComponentModel.DefaultBindingProperty("brightness")] - [double] - $Brightness, - - # The constrast, as a number between -4 and 4. - [Parameter(ValueFromPipelineByPropertyName)] - [ValidateRange(-4,4)] - [ComponentModel.DefaultBindingProperty("contrast")] - [double] - $Contrast, - - # The gamma correction, as a number between -3 and 3. - [Parameter(ValueFromPipelineByPropertyName)] - [ValidateRange(-3,3)] - [ComponentModel.DefaultBindingProperty("gamma")] - [double] - $Gamma, - - # The saturation, as a number between -1 and 5. - [Parameter(ValueFromPipelineByPropertyName)] - [ValidateRange(-1,5)] - [ComponentModel.DefaultBindingProperty("saturation")] - [double] - $Saturation, - - # The change in hue, as represented in degrees around a color cicrle - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("hue_shift")] - [Alias('Spin')] - [double] - $Hue, - # Multiply this color by all pixels within the source. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("color_multiply")] - [string] - $MultiplyColor, + // Ensure angle is within [0, 360] range + if (angle < 0.0) + angle += 360.0; + else if (angle >= 360.0) + angle -= 360.0; - # Add all this color to all pixels within the source. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("color_add")] - [string] - $AddColor, + // Calculate the percentage of the angle + float anglePercentage = angle / 360.0; - # If set, will remove a filter if one already exists. - # If this is not provided and the filter already exists, the settings of the filter will be changed. - [switch] - $Force - ) - dynamicParam { - $baseCommand = - if (-not $script:AddOBSSourceFilter) { - $script:AddOBSSourceFilter = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSSourceFilter','Function') - $script:AddOBSSourceFilter - } else { - $script:AddOBSSourceFilter - } - $IncludeParameter = @() - $ExcludeParameter = 'FilterKind','FilterSettings' + // Check if the angle percentage is within the specified "fill percentage" + bool is_inside_fill = anglePercentage < Fill; + // If inside the "fill," make the pixel selected color; otherwise, use the original image color + return is_inside_fill ? Fill_Color : image.Sample(textureSampler, v_in.uv); +} - $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() - :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { - if ($ExcludeParameter) { - foreach ($exclude in $ExcludeParameter) { - if ($paramName -like $exclude) { continue nextInputParameter} +' +} +$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 } - if ($IncludeParameter) { - $shouldInclude = - foreach ($include in $IncludeParameter) { - if ($paramName -like $include) { $true;break} + } + '(?>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] } - if (-not $shouldInclude) { continue nextInputParameter } + continue nextParameter + } } - - $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( - $baseCommand.Parameters[$paramName].Name, - $baseCommand.Parameters[$paramName].ParameterType, - $baseCommand.Parameters[$paramName].Attributes - )) - } - $DynamicParameters - } - begin { - filter ToOBSColor { - - if ($_ -is [uint32]) { $_ } - elseif ($_ -is [string]) { - if ($_ -match '^\#[a-f0-9]{3,4}$') { - $_ = $_ -replace '[a-f0-9]','$0$0' - } - - if ($_ -match '^#[a-f0-9]{8}$') { - $_ -replace '#','0x' -as [UInt32] - } - elseif ($_ -match '^#[a-f0-9]{6}$') { - $_ -replace '#','0xff' -as [UInt32] - } - } - - } - - } - process { - $myParameters = [Ordered]@{} + $PSBoundParameters - - if (-not $myParameters["FilterName"]) { - $FilterName = $myParameters["FilterName"] = "ColorCorrection" + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - - $myParameterData = [Ordered]@{} - foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { - $bindToPropertyName = $null - - foreach ($attribute in $parameter.Attributes) { - if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { - $bindToPropertyName = $attribute.Name - break - } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } - if (-not $bindToPropertyName) { continue } - if ($myParameters.Contains($parameter.Name)) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] - if ($myParameters[$parameter.Name] -is [switch]) { - $myParameterData[$bindToPropertyName] = $parameter.Name -as [bool] - } + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - - if ($myParameterData.color_add) { - $myParameterData.color_add = $myParameterData.color_add | ToOBSColor + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($myParameterData.color_multiply) { - $myParameterData.color_multiply = $myParameterData.color_multiply | ToOBSColor + 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 + } - - $addSplat = @{ - filterName = $myParameters["FilterName"] - SourceName = $myParameters["SourceName"] - filterKind = "color_filter_v2" - filterSettings = $myParameterData - NoResponse = $myParameters["NoResponse"] + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } - - if ($MyParameters["PassThru"]) { - $addSplat.Passthru = $MyParameters["PassThru"] - if ($MyInvocation.InvocationName -like 'Add-*') { - Add-OBSSourceFilter @addSplat - } else { - $addSplat.Remove('FilterKind') - Set-OBSSourceFilterSettings @addSplat - } - return - } - - # Add the input. - $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 + } +} - if ($PassThru) { - return $outputAddedResult - } +} - # If we got back an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # and that error was saying the source already exists, - if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { - # then check if we use the -Force. - if ($Force) { # If we do, remove the input - Remove-OBSSourceFilter -FilterName $addSplat.FilterName -SourceName $addSplat.SourceName - # and re-add our result. - $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 - } else { - # Otherwise, get the existing filter. - $existingFilter = Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName - # then apply the settings - $existingFilter.Set($addSplat.filterSettings) - # and output them - $existingFilter - # (don't forget to null the result, so we don't show this error) - $outputAddedResult = $null - } - } - # If the output was still an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # use $psCmdlet.WriteError so that it shows the error correctly. - $psCmdlet.WriteError($outputAddedResult) - } - - } - # Otherwise, if we had a result - elseif ($outputAddedResult) { - # Otherwise, get the input from the filters. - Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName - } - - } -} +} #.ExternalHelp obs-powershell-Help.xml -function Set-OBSEqualizerFilter { - - - [Alias('Add-OBSEqualizierFilter','Add-OBS3BandEqualizerFilter','Set-OBS3BandEqualizerFilter')] - param( - # The change in low frequencies. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("low")] - [ValidateRange(-20,20)] - [double] - $Low, +function Get-OBSFilterTemplateShader { - # The change in mid frequencies. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("mid")] - [ValidateRange(-20,20)] - [double] - $Mid, +[Alias('Set-OBSFilterTemplateShader','Add-OBSFilterTemplateShader')] +param( +# Set the ViewProj of OBSFilterTemplateShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the image of OBSFilterTemplateShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the elapsed_time of OBSFilterTemplateShader +[Alias('elapsed_time')] +[ComponentModel.DefaultBindingProperty('elapsed_time')] +[Single] +$ElapsedTime, +# Set the uv_offset of OBSFilterTemplateShader +[Alias('uv_offset')] +[ComponentModel.DefaultBindingProperty('uv_offset')] +[Single[]] +$UvOffset, +# Set the uv_scale of OBSFilterTemplateShader +[Alias('uv_scale')] +[ComponentModel.DefaultBindingProperty('uv_scale')] +[Single[]] +$UvScale, +# Set the uv_pixel_interval of OBSFilterTemplateShader +[Alias('uv_pixel_interval')] +[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +[Single[]] +$UvPixelInterval, +# Set the uv_size of OBSFilterTemplateShader +[Alias('uv_size')] +[ComponentModel.DefaultBindingProperty('uv_size')] +[Single[]] +$UvSize, +# Set the rand_f of OBSFilterTemplateShader +[Alias('rand_f')] +[ComponentModel.DefaultBindingProperty('rand_f')] +[Single] +$RandF, +# Set the rand_instance_f of OBSFilterTemplateShader +[Alias('rand_instance_f')] +[ComponentModel.DefaultBindingProperty('rand_instance_f')] +[Single] +$RandInstanceF, +# Set the rand_activation_f of OBSFilterTemplateShader +[Alias('rand_activation_f')] +[ComponentModel.DefaultBindingProperty('rand_activation_f')] +[Single] +$RandActivationF, +# Set the loops of OBSFilterTemplateShader +[ComponentModel.DefaultBindingProperty('loops')] +[Int32] +$Loops, +# Set the local_time of OBSFilterTemplateShader +[Alias('local_time')] +[ComponentModel.DefaultBindingProperty('local_time')] +[Single] +$LocalTime, +# Set the notes of OBSFilterTemplateShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# 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 +) - # The change in high frequencies. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("high")] - [ValidateRange(-20,20)] - [double] - $High, - # If set, will remove a filter if one already exists. - # If this is not provided and the filter already exists, the settings of the filter will be changed. - [switch] - $Force - ) - dynamicParam { - $baseCommand = - if (-not $script:AddOBSSourceFilter) { - $script:AddOBSSourceFilter = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSSourceFilter','Function') - $script:AddOBSSourceFilter - } else { - $script:AddOBSSourceFilter - } - $IncludeParameter = @() - $ExcludeParameter = 'FilterKind','FilterSettings' +process { +$shaderName = 'filter_template' +$ShaderNoun = 'OBSFilterTemplateShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//My shader modified by Me for use with obs-shaderfilter month/year v.02 +//Section to converting GLSL to HLSL - can delete if unneeded +#define vec2 float2 +#define vec3 float3 +#define vec4 float4 +#define ivec2 int2 +#define ivec3 int3 +#define ivec4 int4 +#define mat2 float2x2 +#define mat3 float3x3 +#define mat4 float4x4 +#define fract frac +#define mix lerp +#define iTime float +#define iTime elapsed_time +#define iResolution float4(uv_size,uv_pixel_interval) - $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() - :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { - if ($ExcludeParameter) { - foreach ($exclude in $ExcludeParameter) { - if ($paramName -like $exclude) { continue nextInputParameter} - } - } - if ($IncludeParameter) { - $shouldInclude = - foreach ($include in $IncludeParameter) { - if ($paramName -like $include) { $true;break} - } - if (-not $shouldInclude) { continue nextInputParameter } - } - - $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( - $baseCommand.Parameters[$paramName].Name, - $baseCommand.Parameters[$paramName].ParameterType, - $baseCommand.Parameters[$paramName].Attributes - )) - } - $DynamicParameters +/* +**Shaders have these variables pre loaded by the plugin** +**this section can be deleted** - } - process { - $myParameters = [Ordered]@{} + $PSBoundParameters - - if (-not $myParameters["FilterName"]) { - $filterName = $myParameters["FilterName"] = "3BandEqualizer" - } - - $myParameterData = [Ordered]@{} - foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { +struct VertData { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; - $bindToPropertyName = $null - - foreach ($attribute in $parameter.Attributes) { - if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { - $bindToPropertyName = $attribute.Name - break - } - } +uniform float4x4 ViewProj; +uniform texture2d image; - if (-not $bindToPropertyName) { continue } - if ($myParameters.Contains($parameter.Name)) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] - if ($myParameters[$parameter.Name] -is [switch]) { - $myParameterData[$bindToPropertyName] = $parameter.Name -as [bool] - } - } - } - - $addSplat = @{ - filterName = $myParameters["FilterName"] - SourceName = $myParameters["SourceName"] - filterKind = "basic_eq_filter" - filterSettings = $myParameterData - } +uniform float elapsed_time; +uniform float2 uv_offset; +uniform float2 uv_scale; +uniform float2 uv_pixel_interval; +uniform float2 uv_size; +uniform float rand_f; +uniform float rand_instance_f; +uniform float rand_activation_f; +uniform int loops; +uniform float local_time; +*/ +uniform string notes< + string widget_type = "info"; +> = "add notes here"; - if ($MyParameters["PassThru"]) { - $addSplat.Passthru = $MyParameters["PassThru"] - if ($MyInvocation.InvocationName -like 'Add-*') { - Add-OBSSourceFilter @addSplat - } else { - $addSplat.Remove('FilterKind') - Set-OBSSourceFilterSettings @addSplat - } - return - } - # Add the input. - $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 - +float4 mainImage(VertData v_in) : TARGET +{ + return image.Sample(textureSampler, v_in.uv); +} - # If we got back an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # and that error was saying the source already exists, - if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { - # then check if we use the -Force. - if ($Force) { # If we do, remove the input - Remove-OBSSourceFilter -FilterName $addSplat.FilterName -SourceName $addSplat.SourceName - # and re-add our result. - $outputAddedResult = Add-OBSInput @addSplat *>&1 - } else { - # Otherwise, get the existing filter. - $existingFilter = Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName - # then apply the settings - $existingFilter.Set($addSplat.filterSettings) - # and output them - $existingFilter - # (don't forget to null the result, so we don't show this error) - $outputAddedResult = $null - } - } +/* +**Shaders use the built in Draw technique** +**this section can be deleted** - # If the output was still an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # use $psCmdlet.WriteError so that it shows the error correctly. - $psCmdlet.WriteError($outputAddedResult) +technique Draw +{ + pass + { + vertex_shader = mainTransform(v_in); + pixel_shader = mainImage(v_in); + } +} +*/ + +' +} +$MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 +if (-not $myNoun) { + $myNoun = $myVerb + $myVerb = 'Get' +} +switch -regex ($myVerb) { + Get { + $FilterNamePattern = "(?>$( + if ($FilterName) { + [Regex]::Escape($FilterName) } - - } - # Otherwise, if we had a result - elseif ($outputAddedResult) { - # Otherwise, get the input from the filters. - Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.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 } - } -} - - -#.ExternalHelp obs-powershell-Help.xml -function Set-OBSGainFilter { - - - [Alias('Add-OBSGainFilter')] - param( - # The Audio Gain, in decibels. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("db")] - [double] - $Gain, + '(?>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 set, will remove a filter if one already exists. - # If this is not provided and the filter already exists, the settings of the filter will be changed. - [switch] - $Force - ) - dynamicParam { - $baseCommand = - if (-not $script:AddOBSSourceFilter) { - $script:AddOBSSourceFilter = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSSourceFilter','Function') - $script:AddOBSSourceFilter - } else { - $script:AddOBSSourceFilter + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - $IncludeParameter = @() - $ExcludeParameter = 'FilterKind','FilterSettings' + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } - $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() - :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { - if ($ExcludeParameter) { - foreach ($exclude in $ExcludeParameter) { - if ($paramName -like $exclude) { continue nextInputParameter} + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - if ($IncludeParameter) { - $shouldInclude = - foreach ($include in $IncludeParameter) { - if ($paramName -like $include) { $true;break} - } - if (-not $shouldInclude) { continue nextInputParameter } - } - - $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( - $baseCommand.Parameters[$paramName].Name, - $baseCommand.Parameters[$paramName].ParameterType, - $baseCommand.Parameters[$paramName].Attributes - )) - } - $DynamicParameters - } - process { - $myParameters = [Ordered]@{} + $PSBoundParameters - - if (-not $myParameters["FilterName"]) { - $filterName = $myParameters["FilterName"] = "Gain" + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - $addSplat = @{ - filterName = $myParameters["FilterName"] - SourceName = $myParameters["SourceName"] - filterKind = "gain_filter" - filterSettings = [Ordered]@{db=$Gain} - NoResponse = $myParameters["NoResponse"] + + 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 ($MyParameters["PassThru"]) { - $addSplat.Passthru = $MyParameters["PassThru"] - if ($MyInvocation.InvocationName -like 'Add-*') { - Add-OBSSourceFilter @addSplat - } else { - $addSplat.Remove('FilterKind') - Set-OBSSourceFilterSettings @addSplat - } - return + 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 } + } +} - # Add the input. - $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 +} - # If we got back an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # and that error was saying the source already exists, - if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { - # then check if we use the -Force. - if ($Force) { # If we do, remove the input - Remove-OBSSourceFilter -FilterName $addSplat.FilterName -SourceName $addSplat.SourceName - # and re-add our result. - $outputAddedResult = Add-OBSInput @addSplat *>&1 - } else { - # Otherwise, get the existing filter. - $existingFilter = Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName - # then apply the settings - $existingFilter.Set($addSplat.filterSettings) - # and output them - $existingFilter - # (don't forget to null the result, so we don't show this error) - $outputAddedResult = $null + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSFire3Shader { + +[Alias('Set-OBSFire3Shader','Add-OBSFire3Shader')] +param( +# Set the ViewProj of OBSFire3Shader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the image of OBSFire3Shader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the elapsed_time of OBSFire3Shader +[Alias('elapsed_time')] +[ComponentModel.DefaultBindingProperty('elapsed_time')] +[Single] +$ElapsedTime, +# Set the uv_offset of OBSFire3Shader +[Alias('uv_offset')] +[ComponentModel.DefaultBindingProperty('uv_offset')] +[Single[]] +$UvOffset, +# Set the uv_scale of OBSFire3Shader +[Alias('uv_scale')] +[ComponentModel.DefaultBindingProperty('uv_scale')] +[Single[]] +$UvScale, +# Set the uv_pixel_interval of OBSFire3Shader +[Alias('uv_pixel_interval')] +[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +[Single[]] +$UvPixelInterval, +# Set the uv_size of OBSFire3Shader +[Alias('uv_size')] +[ComponentModel.DefaultBindingProperty('uv_size')] +[Single[]] +$UvSize, +# Set the rand_f of OBSFire3Shader +[Alias('rand_f')] +[ComponentModel.DefaultBindingProperty('rand_f')] +[Single] +$RandF, +# Set the rand_instance_f of OBSFire3Shader +[Alias('rand_instance_f')] +[ComponentModel.DefaultBindingProperty('rand_instance_f')] +[Single] +$RandInstanceF, +# Set the rand_activation_f of OBSFire3Shader +[Alias('rand_activation_f')] +[ComponentModel.DefaultBindingProperty('rand_activation_f')] +[Single] +$RandActivationF, +# Set the loops of OBSFire3Shader +[ComponentModel.DefaultBindingProperty('loops')] +[Int32] +$Loops, +# Set the local_time of OBSFire3Shader +[Alias('local_time')] +[ComponentModel.DefaultBindingProperty('local_time')] +[Single] +$LocalTime, +# Set the Movement_Direction_Horizontal of OBSFire3Shader +[Alias('Movement_Direction_Horizontal')] +[ComponentModel.DefaultBindingProperty('Movement_Direction_Horizontal')] +[Single] +$MovementDirectionHorizontal, +# Set the Movement_Direction_Vertical of OBSFire3Shader +[Alias('Movement_Direction_Vertical')] +[ComponentModel.DefaultBindingProperty('Movement_Direction_Vertical')] +[Single] +$MovementDirectionVertical, +# Set the Alpha_Percentage of OBSFire3Shader +[Alias('Alpha_Percentage')] +[ComponentModel.DefaultBindingProperty('Alpha_Percentage')] +[Int32] +$AlphaPercentage, +# Set the Speed of OBSFire3Shader +[ComponentModel.DefaultBindingProperty('Speed')] +[Int32] +$Speed, +# Set the Invert of OBSFire3Shader +[ComponentModel.DefaultBindingProperty('Invert')] +[Management.Automation.SwitchParameter] +$Invert, +# Set the lumaMin of OBSFire3Shader +[ComponentModel.DefaultBindingProperty('lumaMin')] +[Single] +$LumaMin, +# Set the lumaMinSmooth of OBSFire3Shader +[ComponentModel.DefaultBindingProperty('lumaMinSmooth')] +[Single] +$LumaMinSmooth, +# Set the Apply_To_Image of OBSFire3Shader +[Alias('Apply_To_Image')] +[ComponentModel.DefaultBindingProperty('Apply_To_Image')] +[Management.Automation.SwitchParameter] +$ApplyToImage, +# Set the Replace_Image_Color of OBSFire3Shader +[Alias('Replace_Image_Color')] +[ComponentModel.DefaultBindingProperty('Replace_Image_Color')] +[Management.Automation.SwitchParameter] +$ReplaceImageColor, +# Set the Color_To_Replace of OBSFire3Shader +[Alias('Color_To_Replace')] +[ComponentModel.DefaultBindingProperty('Color_To_Replace')] +[String] +$ColorToReplace, +# Set the Apply_To_Specific_Color of OBSFire3Shader +[Alias('Apply_To_Specific_Color')] +[ComponentModel.DefaultBindingProperty('Apply_To_Specific_Color')] +[Management.Automation.SwitchParameter] +$ApplyToSpecificColor, +# Set the Full_Width of OBSFire3Shader +[Alias('Full_Width')] +[ComponentModel.DefaultBindingProperty('Full_Width')] +[Management.Automation.SwitchParameter] +$FullWidth, +# Set the Flame_Size of OBSFire3Shader +[Alias('Flame_Size')] +[ComponentModel.DefaultBindingProperty('Flame_Size')] +[Single] +$FlameSize, +# Set the Spark_Grid_Height of OBSFire3Shader +[Alias('Spark_Grid_Height')] +[ComponentModel.DefaultBindingProperty('Spark_Grid_Height')] +[Single] +$SparkGridHeight, +# Set the Flame_Modifier of OBSFire3Shader +[Alias('Flame_Modifier')] +[ComponentModel.DefaultBindingProperty('Flame_Modifier')] +[Single] +$FlameModifier, +# Set the Flame_Tongue_Size of OBSFire3Shader +[Alias('Flame_Tongue_Size')] +[ComponentModel.DefaultBindingProperty('Flame_Tongue_Size')] +[Single] +$FlameTongueSize, +# 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 = 'fire-3' +$ShaderNoun = 'OBSFire3Shader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//My effect modified by Me for use with obs-shaderfilter month/year v.02 +//Converted to OpenGL by Q-mii & Exeldro February 22, 2022 +uniform float4x4 ViewProj; +uniform texture2d image; + +//Section to converting GLSL to HLSL - can delete +#define vec2 float2 +#define vec3 float3 +#define vec4 float4 +#define ivec2 int2 +#define ivec3 int3 +#define ivec4 int4 +#define mat2 float2x2 +#define mat3 float3x3 +#define mat4 float4x4 +#define fract frac +#define mix lerp + + +uniform float elapsed_time; +uniform float2 uv_offset; +uniform float2 uv_scale; +uniform float2 uv_pixel_interval; +uniform float2 uv_size; +uniform float rand_f; +uniform float rand_instance_f; +uniform float rand_activation_f; +uniform int loops; +uniform float local_time; + +uniform float Movement_Direction_Horizontal< + string label = "Movement Direction Horizontal"; + string widget_type = "slider"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 0.0; +uniform float Movement_Direction_Vertical< + string label = "Movement Direction Vertical"; + string widget_type = "slider"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.01; +> = 0.0; + +#define iTime elapsed_time +#define iResolution float4(uv_size,uv_pixel_interval) +#define Movement_Direction float2(Movement_Direction_Horizontal, Movement_Direction_Vertical) + +uniform int Alpha_Percentage< + string label = "Alpha Percentage"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 90; +uniform int Speed< + string label = "Speed"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 80; +uniform bool Invert = false; +uniform float lumaMin< + string label = "Luma Min"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.01; +uniform float lumaMinSmooth< + string label = "Luma Min Smooth"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.04; +uniform bool Apply_To_Image = true; +uniform bool Replace_Image_Color = true; +uniform float4 Color_To_Replace; +uniform bool Apply_To_Specific_Color = false; + +sampler_state textureSampler { + Filter = Linear; + AddressU = Border; + AddressV = Border; + BorderColor = 00000000; +}; + +struct VertData { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; + +VertData mainTransform(VertData v_in) +{ + VertData vert_out; + vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); + float2 uv = v_in.uv; + if(Invert) + uv = 1.0 - v_in.uv; + vert_out.uv = v_in.uv * uv_scale + uv_offset; + return vert_out; +} + +int2 iMouse() +{ + return int2(Movement_Direction.x * uv_size.x, Movement_Direction.y * uv_size.y); +} + + +float mod(float x, float y) +{ + return x - y * floor(x / y); +} + +float2 mod2(float2 x, float2 y) +{ + return x - y * floor(x / y); +} + +/*ps start*/ +#define PI 3.1415926535897932384626433832795 +uniform bool Full_Width = false; + +uniform float Flame_Size< + string label = "Flame Size"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.01; +> = 1.0; + +uniform float Spark_Grid_Height< + string label = "Spark Grid Size"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 50.0; + +uniform float Flame_Modifier< + string label = "Flame Modifier"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 2.0; + float step = 0.01; +> = 1.0; + +uniform float Flame_Tongue_Size< + string label = "Flame Tongue Size"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 2.0; + float step = 0.01; +> = 8.5; + +// +// Description : Array and textureless GLSL 2D/3D/4D simplex +// noise functions. +// Author : Ian McEwan, Ashima Arts. +// Maintainer : ijm +// Lastmod : 20110822 (ijm) +// License : Copyright (C) 2011 Ashima Arts. All rights reserved. +// Distributed under the MIT License. See LICENSE file. +// https://github.com/ashima/webgl-noise +// + +vec3 mod2893(vec3 x) +{ + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +vec4 mod289(vec4 x) +{ + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +vec4 permute(vec4 x) +{ + return mod289(((x * 34.0) + 1.0) * x); +} + +vec4 taylorInvSqrt(vec4 r) +{ + return 1.79284291400159 - 0.85373472095314 * r; +} + +float snoise(vec3 v) +{ + const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0); + const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); + +// First corner + vec3 i = floor(v + dot(v, C.yyy)); + vec3 x0 = v - i + dot(i, C.xxx); + +// Other corners + vec3 g = step(x0.yzx, x0.xyz); + vec3 l = 1.0 - g; + vec3 i1 = min(g.xyz, l.zxy); + vec3 i2 = max(g.xyz, l.zxy); + + // x0 = x0 - 0.0 + 0.0 * C.xxx; + // x1 = x0 - i1 + 1.0 * C.xxx; + // x2 = x0 - i2 + 2.0 * C.xxx; + // x3 = x0 - 1.0 + 3.0 * C.xxx; + vec3 x1 = x0 - i1 + C.xxx; + vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y + vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y + +// Permutations + i = mod2893(i); + vec4 p = permute(permute(permute( + i.z + vec4(0.0, i1.z, i2.z, 1.0)) + + i.y + vec4(0.0, i1.y, i2.y, 1.0)) + + i.x + vec4(0.0, i1.x, i2.x, 1.0)); + +// Gradients: 7x7 points over a square, mapped onto an octahedron. +// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) + float n_ = 0.142857142857; // 1.0/7.0 + vec3 ns = n_ * D.wyz - D.xzx; + + vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) + + vec4 x_ = floor(j * ns.z); + vec4 y_ = floor(j - 7.0 * x_); // mod(j,N) + + vec4 x = x_ * ns.x + ns.yyyy; + vec4 y = y_ * ns.x + ns.yyyy; + vec4 h = 1.0 - abs(x) - abs(y); + + vec4 b0 = vec4(x.xy, y.xy); + vec4 b1 = vec4(x.zw, y.zw); + + //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; + //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; + vec4 s0 = floor(b0) * 2.0 + 1.0; + vec4 s1 = floor(b1) * 2.0 + 1.0; + vec4 sh = -step(h, vec4(0.0, 0.0, 0.0, 0.0)); + + vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; + vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww; + + vec3 p0 = vec3(a0.xy, h.x); + vec3 p1 = vec3(a0.zw, h.y); + vec3 p2 = vec3(a1.xy, h.z); + vec3 p3 = vec3(a1.zw, h.w); + +//Normalise gradients + //vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); + vec4 norm = rsqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + +// Mix final noise value + vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0); + m = m * m; + return 42.0 * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3))); +} + +////////////////////////////////////////////////////////////// + +// PRNG +// From https://www.shadertoy.com/view/4djSRW +float prng(in vec2 seed) +{ + seed = fract(seed * vec2(5.3983, 5.4427)); + seed += dot(seed.yx, seed.xy + vec2(21.5351, 14.3137)); + return fract(seed.x * seed.y * 95.4337); +} + +////////////////////////////////////////////////////////////// + +float noiseStack(vec3 pos, int octaves, float falloff) +{ + float noise = snoise(vec3(pos)); + float off = 1.0; + if (octaves > 1) + { + pos *= 2.0; + off *= falloff; + noise = (1.0 - off) * noise + off * snoise(vec3(pos)); + } + if (octaves > 2) + { + pos *= 2.0; + off *= falloff; + noise = (1.0 - off) * noise + off * snoise(vec3(pos)); + } + if (octaves > 3) + { + pos *= 2.0; + off *= falloff; + noise = (1.0 - off) * noise + off * snoise(vec3(pos)); + } + return (1.0 + noise) / 2.0; +} + +vec2 noiseStackUV(vec3 pos, int octaves, float falloff, float diff) +{ + float displaceA = noiseStack(pos, octaves, falloff); + float displaceB = noiseStack(pos + vec3(3984.293, 423.21, 5235.19), octaves, falloff); + return vec2(displaceA, displaceB); +} + +float4 mainImage(VertData v_in) : TARGET +{ + float2 UV = (1.0 - v_in.uv) * uv_scale; + if (Invert) + UV = v_in.uv * uv_scale; + float alpha = saturate(Alpha_Percentage * .01); + float flame_size = clamp(Flame_Size * .01, 0.0, 4.0); + + vec2 resolution = (.25 * uv_scale * UV.xy) + (0.75 * uv_scale); + if (Full_Width) + { + resolution = (2.0 * (UV.xy)) / 1.0; //iResolution.xy; + + } + resolution.x = mul(resolution.x, 1 / 1); + float time = iTime * (Speed * 0.01); + //vec2 drag = iMouse().xy; + vec2 offset = iMouse().xy; + // + float xpart = UV.x / resolution.x; + float ypart = UV.y / resolution.y; + // + + float ypartClip = UV.y / ( flame_size * 75.0); + float ypartClippedFalloff = clamp(2.0 - ypartClip, 0.0, 1.0); + float ypartClipped = min(ypartClip, 1.0); + float ypartClippedn = (1 - ypartClipped); + // + float xfuel = pow(1.0 - abs(2.0 * xpart - 1.0), 0.5); //pow(1.0-abs(2.0*xpart-1.0),0.5); + // + float timeSpeed = 0.5 * (Speed * 0.01); + float realTime = -1.0 * timeSpeed * time; + // + vec2 coordScaled = -1 * Flame_Tongue_Size * UV - 0.1 * offset; + vec3 position = vec3(coordScaled, 0.0); // +vec3(1223.0, 6434.0, 8425.0); + vec3 flow = vec3(4.1 * (0.5 - xpart) * pow(ypartClippedn, 4.0), -2.0 * xfuel * pow(ypartClippedn, 64.0), 0.0); + vec3 timing = realTime * vec3(0.0, -1.7, 1.1) + flow; + // + vec3 displacePos = vec3(1.0, 0.5, 1.0) * 2.4 * position + realTime * vec3(0.01, -0.7, 1.3); + vec3 displace3 = vec3(noiseStackUV(displacePos, 2, 0.4, 0.1), 0.0); + // + vec3 noiseCoord = (vec3(2.0, 1.0, 1.0) * position + timing + 0.4 * displace3) / 1.0; + float noise = noiseStack(noiseCoord, 3, 0.4); + // + float flames = pow(ypartClipped, 0.3 * xfuel) * pow(noise, 0.3 * xfuel); + // + float f = ypartClippedFalloff * pow(Flame_Modifier - flames * flames * flames, 8.0); + float fff = f * f * f; + vec3 fire = 1.5 * vec3(f, fff, fff * fff); + // + // smoke + float smokeNoise = 0.5 + snoise(0.4 * position + timing * vec3(1.0, 1.0, 0.2)) / 2.0; + float smokePart = 0.3 * pow(xfuel, 3.0) * pow(ypart, 2.0) * (smokeNoise + 0.4 * (1.0 - noise)); + vec3 smoke = vec3(smokePart, smokePart, smokePart); + // + // sparks + float sparkGridSize = Spark_Grid_Height; + vec2 sparkCoord = UV *uv_size - vec2(2.0 * offset.x, 190.0 * sin(realTime)); + sparkCoord -= 30.0 * noiseStackUV(0.01 * vec3(sparkCoord, 15.0 * time), 1, 0.4, 0.1); + sparkCoord += 100.0 * flow.xy; + if (mod(sparkCoord.y / sparkGridSize, 2.0) < 1.0) + sparkCoord.x += 0.5 * sparkGridSize; + vec2 sparkGridIndex = vec2(floor(sparkCoord / sparkGridSize)); + float sparkRandom = prng( sparkGridIndex); + float sparkLife = min(10.0 * (1.0 - min((sparkGridIndex.y + (190.0 * realTime / sparkGridSize)) / (24.0 - 20.0 * sparkRandom), 1.0)), 1.0); + vec3 sparks = vec3(0.0, 0.0, 0.0); + if (sparkLife > 0.0) + { + float sparkSize = xfuel * xfuel * sparkRandom * 0.08; + float sparkRadians = 999.0 * sparkRandom * 2.0 * PI + 2.0 * time; + vec2 sparkCircular = vec2(sin(sparkRadians), cos(sparkRadians)); + vec2 sparkOffset = (0.5 - sparkSize) * sparkGridSize * sparkCircular; + vec2 sparkModulus = mod2(sparkCoord + sparkOffset, float2(sparkGridSize, sparkGridSize)) - 0.5 * float2(sparkGridSize, sparkGridSize); + float sparkLength = length(sparkModulus); + float sparksGray = max(0.0, 1.0 - sparkLength / (sparkSize * sparkGridSize)); + sparks = sparkLife * sparksGray * vec3(1.0, 0.3, 0.0); + } + // + float4 rgba = vec4(max(fire, sparks) + smoke, 1.0); + + // remove dark areas per user + float luma_fire = dot(rgba.rgb, float3(0.299, 0.587, 0.114)); + float luma_min_fire = smoothstep(lumaMin, lumaMin + lumaMinSmooth, luma_fire); + rgba.a = clamp(luma_min_fire, 0.0, alpha); + + float4 color; + float4 original_color; + if (Apply_To_Image) + { + float4 color = image.Sample(textureSampler, v_in.uv); + float4 original_color = color; + if (color.a > 0.0) + { + float luma = color.r * 0.299 + color.g * 0.587 + color.b * 0.114; + if (Replace_Image_Color) + color = float4(luma, luma, luma, luma); + rgba = lerp(original_color, lerp(original_color,rgba * color,rgba.a), alpha); + } + else + { + rgba = color; + } + + } + if (Apply_To_Specific_Color) + { + color = image.Sample(textureSampler, v_in.uv); + original_color = color; + color = (distance(color.rgb, Color_To_Replace.rgb) <= 0.075) ? rgba : color; + rgba = lerp(original_color, color, alpha); + } + + return rgba; +} + +technique Draw +{ + pass + { + vertex_shader = mainTransform(v_in); + pixel_shader = mainImage(v_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 + } + } +} + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSFireShader { + +[Alias('Set-OBSFireShader','Add-OBSFireShader')] +param( +# Set the Alpha_Percentage of OBSFireShader +[Alias('Alpha_Percentage')] +[ComponentModel.DefaultBindingProperty('Alpha_Percentage')] +[Int32] +$AlphaPercentage, +# Set the Speed of OBSFireShader +[ComponentModel.DefaultBindingProperty('Speed')] +[Int32] +$Speed, +# Set the Flame_Size of OBSFireShader +[Alias('Flame_Size')] +[ComponentModel.DefaultBindingProperty('Flame_Size')] +[Int32] +$FlameSize, +# Set the Fire_Type of OBSFireShader +[Alias('Fire_Type')] +[ComponentModel.DefaultBindingProperty('Fire_Type')] +[Int32] +$FireType, +# Set the Invert of OBSFireShader +[ComponentModel.DefaultBindingProperty('Invert')] +[Management.Automation.SwitchParameter] +$Invert, +# Set the lumaMin of OBSFireShader +[ComponentModel.DefaultBindingProperty('lumaMin')] +[Single] +$LumaMin, +# Set the lumaMinSmooth of OBSFireShader +[ComponentModel.DefaultBindingProperty('lumaMinSmooth')] +[Single] +$LumaMinSmooth, +# Set the Apply_To_Image of OBSFireShader +[Alias('Apply_To_Image')] +[ComponentModel.DefaultBindingProperty('Apply_To_Image')] +[Management.Automation.SwitchParameter] +$ApplyToImage, +# Set the Replace_Image_Color of OBSFireShader +[Alias('Replace_Image_Color')] +[ComponentModel.DefaultBindingProperty('Replace_Image_Color')] +[Management.Automation.SwitchParameter] +$ReplaceImageColor, +# Set the Apply_To_Specific_Color of OBSFireShader +[Alias('Apply_To_Specific_Color')] +[ComponentModel.DefaultBindingProperty('Apply_To_Specific_Color')] +[Management.Automation.SwitchParameter] +$ApplyToSpecificColor, +# Set the Color_To_Replace of OBSFireShader +[Alias('Color_To_Replace')] +[ComponentModel.DefaultBindingProperty('Color_To_Replace')] +[String] +$ColorToReplace, +# Set the Notes of OBSFireShader +[ComponentModel.DefaultBindingProperty('Notes')] +[String] +$Notes, +# 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 = 'fire' +$ShaderNoun = 'OBSFireShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//fire shader modified by Charles Fettinger for use with obs-shaderfilter 07/20 v.6 +// https://github.com/Oncorporation/obs-shaderfilter plugin +// https://www.shadertoy.com/view/MtcGD7 original version +//Converted to OpenGL by Q-mii & Exeldro February 22, 2022 +//v.5 +// flicker +// flame type +// apply to image +// replace image color +// speed +// flame size +// alpha +// invert direction/position + + +//Section to converting GLSL to HLSL - can delete +#define vec2 float2 +#define vec3 float3 +#define vec4 float4 +#define ivec2 int2 +#define ivec3 int3 +#define ivec4 int4 +#define mat2 float2x2 +#define mat3 float3x3 +#define mat4 float4x4 +#define fract frac +#define mix lerp + +uniform int Alpha_Percentage< + string label = "Aplha Percentage"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 90; +uniform int Speed< + string label = "Speed"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 200; + int step = 1; +> = 100; +uniform int Flame_Size< + string label = "Flame Size"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 200; + int step = 1; +> = 70; +uniform int Fire_Type< + string label = "Fire Type"; + string widget_type = "select"; + int option_0_value = 0; + string option_0_label = "Smaller and more whisps"; + int option_1_value = 1; + string option_1_label = "Larger and more volume"; +> = 1; + +uniform bool Invert < + string name = "Invert"; +> = false; +uniform float lumaMin< + string label = "Luma min"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.01; +uniform float lumaMinSmooth< + string label = "Luma min smooth"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.04; +uniform bool Apply_To_Image; +uniform bool Replace_Image_Color; +uniform bool Apply_To_Specific_Color; +uniform float4 Color_To_Replace; +uniform string Notes< + string widget_type = "info"; +> = "Luma cuts reveals background, flame size is percentage screen size, Alpha Percentage adjusts color"; + +vec3 rgb2hsv(vec3 c) +{ + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +vec3 hsv2rgb(vec3 c) +{ + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} + +float rand(vec2 n) +{ + return fract(sin(cos(dot(n, vec2(12.9898, 12.1414)))) * 83758.5453); + //return sin(rand_f, n); +} + +float noise(vec2 n) +{ + const vec2 d = vec2(0.0, 1.0); + vec2 b = floor(n), f = smoothstep(vec2(0.0, 0.0), vec2(1.0, 1.0), fract(n)); + return mix(mix(rand(b), rand(b + d.yx), f.x), mix(rand(b + d.xy), rand(b + d.yy), f.x), f.y); +} + +float fbm(vec2 n) +{ + float total = 0.0, amplitude = 1.0; + for (int i = 0; i < 5; i++) + { + total += noise(n) * amplitude; + n += n * 1.7; + amplitude *= 0.47; + } + return total; +} + +float4 mainImage(VertData v_in) : TARGET +{ + float2 iResolution = uv_scale; + float flame_size = clamp(Flame_Size * .01,-5,5); + + // inverting direction is logically inverted to allow the bottom up to be normal + float fire_base = (v_in.uv.y / iResolution.y); + float2 fire_pix = v_in.uv.xy + float2(flame_size -1,0); + float direction = -1.0 * clamp(Speed*.01,-5,5); + if (!Invert) + { + direction *= -1.0; + fire_base = 1 - fire_base; + fire_pix = 1 - fire_pix; + } + float iTime = direction * elapsed_time; + + const vec3 c1 = vec3(0.5, 0.0, 0.1); + const vec3 c2 = vec3(0.9, 0.1, 0.0); + const vec3 c3 = vec3(0.2, 0.1, 0.7); + const vec3 c4 = vec3(1.0, 0.9, 0.1); + const vec3 c5 = vec3(0.1, 0.1, 0.1); + const vec3 c6 = vec3(0.9, 0.9, 0.9); + + vec2 speed = vec2(1.2, 0.1) * clamp(Speed*.01,-5,5); + float shift = 1.327 * (1/flame_size) - sin(iTime * 2.0) / 2.4; + float alpha = saturate(Alpha_Percentage * .01); + + //change the constant term for all kinds of cool distance versions, + //make plus/minus to switch between + //ground fire and fire rain! + float dist = 3.5 - sin(iTime * 0.4) / 1.89; + + vec2 p = fire_pix * dist / iResolution.xx; + p.x -= iTime / 1.1; + float3 black = float3(0,0,0); + vec3 fire; + + if (Fire_Type == 1) + { + //fire version 1 larger and more volume + float q = fbm(p - iTime * 0.01 + 1.0 * sin(iTime) / 10.0); + float qb = fbm(p - iTime * 0.002 + 0.1 * cos(iTime) / 5.0); + float q2 = fbm(p - iTime * 0.44 - 5.0 * cos(iTime) / 7.0) -6.0; + float q3 = fbm(p - iTime * 0.9 - 10.0 * cos(iTime) / 30.0) -4.0; + float q4 = fbm(p - iTime * 2.0 - 20.0 * sin(iTime) / 20.0) +2.0; + q = (q + qb - .4 * q2 - 2.0 * q3 + .6 * q4) / 3.8; + + vec2 r = vec2(fbm(p + q / 2.0 - iTime* speed.x - p.x - p.y), + fbm(p - q - iTime* speed.y)) ; + vec3 c = mix(c1, c2, fbm(p + r)) + mix(c3, c4, r.x) - mix(c5, c6, r.y); + fire = vec3(c * max(cos(shift * fire_base) - (rand_f *.05),0.05)); + + fire += .05; + fire.r *= .8; + vec3 hsv = rgb2hsv(fire); + hsv.y *= hsv.z * 1.1; + hsv.z *= hsv.y * 1.13; + hsv.y = (2.2 - hsv.z * .9) * 1.20; + fire = hsv2rgb(hsv); + } + else + { + // fire version 0 - smaller and more whisps + p += (rand_f *.01); + float q = fbm(p - iTime * 0.3+1.0*sin(iTime+0.5)/2.0); + float qb = fbm(p - iTime * 0.4+0.1*cos(iTime)/2.0); + float q2 = fbm(p - iTime * 0.44 - 5.0*cos(iTime)/2.0) - 6.0; + float q3 = fbm(p - iTime * 0.9 - 10.0*cos(iTime)/15.0)-4.0; + float q4 = fbm(p - iTime * 1.4 - 20.0*sin(iTime)/14.0)+2.0; + q = (q + qb - .4 * q2 -2.0*q3 + .6*q4)/3.8; + + vec2 r = vec2(fbm(p + q /2.0 + iTime * speed.x - p.x - p.y), + fbm(p + q - iTime * speed.y)) * shift; + vec3 c = mix(c1, c2, fbm(p + r)) + mix(c3, c4, r.x) - mix(c5, c6, r.y); + //fire = vec3(1.0/(pow(c+1.61,vec3(4.0,4.0,4.0))) * max(cos(shift * fire_base),0)); + + fire = vec3(1.0,.2,.05)/(pow((r.y+r.y)* max(.0,p.y)+0.1, 4.0)) ;//* max(.1,(cos(shift * fire_base))); + fire += (black*0.01*pow((r.y+r.y)*.65,5.0)+0.055)*mix( vec3(.9,.4,.3),vec3(.7,.5,.2), v_in.uv.y); + fire = fire/(1.0+max(black,fire)); + } + float4 rgba = vec4(fire.x, fire.y, fire.z, alpha); + + // remove dark areas per user + float luma_fire = dot(rgba.rgb,float3(0.299,0.587,0.114)); + float luma_min_fire = smoothstep(lumaMin, lumaMin + lumaMinSmooth, luma_fire); + rgba.a = clamp(luma_min_fire,0.0,alpha); + + float4 color; + float4 original_color; + if (Apply_To_Image) + { + color = image.Sample(textureSampler, v_in.uv); + original_color = color; + if (color.a > 0.0) + { + float luma = color.r * 0.299 + color.g * 0.587 + color.b * 0.114; + if (Replace_Image_Color) + color = float4(luma, luma, luma, luma); + rgba = lerp(original_color, lerp(original_color,rgba * color,rgba.a), alpha); + } + else + { + rgba = color; + } + + } + if (Apply_To_Specific_Color) + { + color = image.Sample(textureSampler, v_in.uv); + original_color = color; + color = (distance(color.rgb, Color_To_Replace.rgb) <= 0.075) ? rgba : color; + rgba = lerp(original_color, color, alpha); + } + return rgba; +} + + + + +' +} +$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 + } + } +} + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSFireworks2Shader { + +[Alias('Set-OBSFireworks2Shader','Add-OBSFireworks2Shader')] +param( +# Set the Speed of OBSFireworks2Shader +[ComponentModel.DefaultBindingProperty('Speed')] +[Single] +$Speed, +# 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 = 'fireworks2' +$ShaderNoun = 'OBSFireworks2Shader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// based on https://www.shadertoy.com/view/4dBGRw + +uniform float Speed< + string label = "Speed"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 200.0; + float step = 1.0; +> = 100.0; + +#ifndef OPENGL +#define mat2 float2x2 +#define mix lerp +float mod(float x, float y) +{ + return x - y * floor(x / y); +} +#endif +//Creates a diagonal red-and-white striped pattern. +float3 barberpole(float2 pos, float2 rocketpos){ + float d = (pos.x-rocketpos.x)+(pos.y-rocketpos.y); + float3 col=float3(1.0,1.0,1.0); + + d = mod(d*20.,2.0); + if(d>1.0){ + col=float3(1.0,0.0,0.0); + } + return col; +} + +float4 rocket(float2 pos, float2 rocketpos){ + float4 col = float4(0.0,0.0,0.0,0.0); + float f = 0.; + float absx= abs(rocketpos.x - pos.x); + float absy = abs(rocketpos.y-pos.y); + //wooden stick + if(absx<0.01&&absy<0.22){ + col=float4(1.0,0.5,0.5,1.0); + } + + //Barberpole + + if(absx<0.05&&absy<0.15){ + col=float4(barberpole(pos, rocketpos),1.0); + } + //Rocket Point + float pointw=(rocketpos.y-pos.y-0.25)*-0.7; + if((rocketpos.y-pos.y)>0.1){ + f=smoothstep(pointw-0.001,pointw+0.001,absx); + + col=mix(float4(1.0,0.0,0.0,1.0),col, f); + } + //Shadow + + f =-.5 + smoothstep(-0.05, 0.05, (rocketpos.x-pos.x)); + col.rgb *= 0.7+f; + + return col; +} + + + +float rand(float val, float seed){ + return cos(val*sin(val*seed)*seed); +} + +float distance2( in float2 a, in float2 b ) { return dot(a-b,a-b); } + + + +float4 drawParticles(float2 pos, float3 particolor, float time, float2 cpos, float gravity, float seed, float timelength){ + float4 col= float4(0.0,0.0,0.0,0.0); + float2 pp = float2(1.0,0.0); + mat2 rr = mat2( cos(1.0), -sin(1.0), sin(1.0), cos(1.0) ); + for(float i=1.0;i<=128.0;i++){ + float d=rand(i, seed); + float fade=(i/128.0)*time; + float2 particpos = cpos + time*pp*d; + pp = mul(rr,pp); + col.rgb = mix(particolor/fade, col, smoothstep(0.0, 0.0001, distance2(particpos, pos))); + } + col.rgb*=smoothstep(0.0,1.0,(timelength-time)/timelength); + col.a = col.r+col.g+col.b; + return col; +} +float4 drawFireworks(float time, float2 uv, float3 particolor, float seed){ + + float timeoffset = 2.0; + float4 col=float4(0.0,0.0,0.0,0.0); + if(time<=0.){ + return col; + } + time *= Speed /100.0; + if(mod(time, 6.0)>timeoffset){ + col= drawParticles(uv, particolor, mod(time, 6.0)-timeoffset, float2(rand(ceil(time/6.0),seed),-0.5), 0.5, ceil(time/6.0), seed); + }else{ + + col= rocket(uv*3., float2(3.*rand(ceil(time/6.0),seed),3.*(-0.5+(timeoffset-mod(time, 6.0))))); + } + return col; +} + +float4 mainImage(VertData v_in) : TARGET +{ + float2 uv =float2(1.0,1.0) - 2.0* v_in.uv; + uv.y = -uv.y; + uv.x *= uv_size.x/uv_size.y; + float4 col = image.Sample(textureSampler, v_in.uv); + //col.rgb += 0.1*uv.y; + float4 c; + c = drawFireworks(elapsed_time , uv,float3(1.0,0.1,0.1), 1.); + col = mix(col, c, c.a); + c = drawFireworks(elapsed_time-2.0, uv,float3(0.0,1.0,0.5), 2.); + col = mix(col, c, c.a); + c = drawFireworks(elapsed_time-4.0, uv,float3(1.0,1.0,0.1), 3.); + col = mix(col, c, c.a); + + return col; +} +' +} +$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 + } + } +} + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSFireworksShader { + +[Alias('Set-OBSFireworksShader','Add-OBSFireworksShader')] +param( +# Set the show_flash of OBSFireworksShader +[Alias('show_flash')] +[ComponentModel.DefaultBindingProperty('show_flash')] +[Management.Automation.SwitchParameter] +$ShowFlash, +# Set the show_stars of OBSFireworksShader +[Alias('show_stars')] +[ComponentModel.DefaultBindingProperty('show_stars')] +[Management.Automation.SwitchParameter] +$ShowStars, +# Set the use_transparancy of OBSFireworksShader +[Alias('use_transparancy')] +[ComponentModel.DefaultBindingProperty('use_transparancy')] +[Management.Automation.SwitchParameter] +$UseTransparancy, +# 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 = 'fireworks' +$ShaderNoun = 'OBSFireworksShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +#ifndef OPENGL +#define mat2 float2x2 +#define fract frac +#define mix lerp +#endif + +uniform bool show_flash = true; +uniform bool show_stars = true; +uniform bool use_transparancy = true; + +float distLine(float2 p, float2 a, float2 b) { + float2 pa = p - a; + float2 ba = b - a; + float t = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); + return length(pa - ba * t); +} + +float linef(float2 uv, float2 a, float2 b, float w) { + //return smoothstep(w, w - 0.01, distLine(uv, a, b)); + return w / distLine(uv, a, b); +} + +float N21(float2 p) { + p = fract(p * float2(233.34, 851.73)); + p += dot(p, p + 23.45); + return fract(p.x * p.y); +} + +float2 N22(float2 p) { + float n = N21(p); + return float2(n, N21(p + n)); +} + +float N11(float n) { + return fract(sin(dot(float2(cos(n), sin(n)) ,float2(27.9898, 38.233))) * 88.5453); +} + +float particle(float2 uv, float2 p, float2 v, float r, float t) { + float g = -9.81; + float x = p.x + v.x * t; + float y = p.y + v.y * t + g / 2.0 * t * t; + float2 j = (float2(x, y) - uv) * 20.0; + float sparkle = 1.0 / dot(j, j); + return sparkle; +} + +float2 p1(float2 p, float h, float t) { + return float2(p.x, p.y + clamp(pow(t, 5.0), 0.0, h)); +} + +float2 p2(float2 p, float h, float t) { + return float2(p.x, p.y + clamp(pow(0.95 * t, 5.0), 0.0, h)); +} + +float endTime(float h) { + return pow(h, 1.0 / 5.0) * 1.1; +} + +float explosion(float2 uv, float2 p, float s, float n, float f, float t) { + + float m = 0.0; + float dt = 0.5; + float seed2 = 0.32; + for(float i = 0.0; i < n; i++) { + seed2 += i; + float2 rand = float2(1.0, 2.0) * (float2(-1.0, 1.0) + 2.0 * N22(float2(seed2, i))); + float2 v = float2(cos(seed2), sin(seed2)) + rand; + m += particle(uv, p, v, s, t) * smoothstep(2.0, 2.0 - dt, t) * smoothstep(0.0, dt, t); + } + return m; +} + +float fireworks(float2 uv, float2 p, float h, float n, float s, float f, float t) { + float2 p1v = p1(p, h, t); + float e = endTime(h); + return explosion(uv, p1v, s, n, f, t - e * 0.9); +} + +float shaft(float2 uv, float2 p, float w, float h, float t) { + float2 p1v = p1(p, h, t) + float2(0.0, 0.3); + float2 p2v = p2(p, h, t); + float e = 1.0 / 0.95 * endTime(h); + float2 j = (p1v - uv) * 15.0; + float sparkle = 1.0 / dot(j, j); + return (linef(uv, p1v, p2v, w) + sparkle) * smoothstep(e, e - 0.5, t) * 0.5; +} + +float3 base(float2 uv) { + return 0.5 + 0.5 * cos(elapsed_time + uv.xyx + float3(0, 2, 4)); +} + +float back(float2 uv, float2 p, float t) { + float dt = 0.3; + float j = length(p - uv); + float m = exp(-0.005 * j * j); + return 0.2 * m * smoothstep(-dt / 4.0, 0.0, t) * smoothstep(dt, 0.0, t); +} + +float stars(float2 uv) { + float r = N21(uv); + return smoothstep(0.001, 0.0, r); +} + +float mod(float x, float y) +{ + return x - y * floor(x / y); +} + +float4 mainImage( VertData v_in ) : TARGET +{ + float2 uv = v_in.uv - float2(0.5,0.5); + uv.y = uv.y * -1; + float t = elapsed_time / 10.0; + float scale = 10.0; + uv *= scale; + // + float4 col = image.Sample(textureSampler, v_in.uv); + if(show_stars){ + float c = stars(uv); + if(use_transparancy){ + col += float4(c,c,c,c)*(1.0-col.a); + }else{ + col += float4(c,c,c,c);//*(1.0-orig_col.a); + } + + } + + float a = -0.035 * sin(t * 15.0); + float co = cos(a); + float si = sin(a); + mat2 trans1 = mat2(float2(co, si), float2(-si, co)); + float2 trans2 = float2(-15.0 * a, 0.0); +#ifndef OPENGL + uv = mul(uv, trans1); +#else + uv *= trans1; +#endif + uv += trans2; + + for(float i = 0.0; i < 1.0; i += 1.0 / 8.0) { + float ti = mod(t * 9.0 - i * 5.0, 4.0); + float scale = mix(2.0, 0.3, ti / 4.0); + float2 uvs = uv * scale; + float rand = N11(i); + float h = 10.0 + rand * 4.0; + float w = 0.02; + float n = 80.0; + float s = 0.9; + float f = 1.5; + float2 p = float2(mix(-8.0, 8.0, rand), -10.0); + float fw = fireworks(uvs, p, h, n, s, f, ti); + float3 bc = base(uv); + col += float4(bc*fw, fw); + col += shaft(uvs, p, w, h, ti); + if(show_flash){ + if(use_transparancy){ + col += back(uvs, float2(p.x, p.y + h), ti - 1.8)*col.a; + }else{ + col += back(uvs, float2(p.x, p.y + h), ti - 1.8); + } + } + } + + return col; +} +' +} +$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 + } + } +} + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSFisheyeShader { + +[Alias('Set-OBSFisheyeShader','Add-OBSFisheyeShader')] +param( +# Set the center_x_percent of OBSFisheyeShader +[Alias('center_x_percent')] +[ComponentModel.DefaultBindingProperty('center_x_percent')] +[Single] +$CenterXPercent, +# Set the center_y_percent of OBSFisheyeShader +[Alias('center_y_percent')] +[ComponentModel.DefaultBindingProperty('center_y_percent')] +[Single] +$CenterYPercent, +# Set the power of OBSFisheyeShader +[ComponentModel.DefaultBindingProperty('power')] +[Single] +$Power, +# 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 = 'fisheye' +$ShaderNoun = 'OBSFisheyeShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform float center_x_percent< + string label = "Center x percent"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 50.0; +uniform float center_y_percent< + string label = "Center y percent"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 50.0; +uniform float power< + string label = "Power"; + string widget_type = "slider"; + float minimum = -2.0; + float maximum = 2.0; + float step = 0.01; +> = 1.75; + +float4 mainImage(VertData v_in) : TARGET +{ + float2 center_pos = float2(center_x_percent * .01, center_y_percent * .01); + float2 uv = v_in.uv; + if (power >= 0.0001){ + float b = sqrt(dot(center_pos, center_pos)); + uv = center_pos + normalize(v_in.uv - center_pos) * tan(distance(center_pos, v_in.uv) * power) * b / tan( b * power); + } else if(power <= -0.0001){ + float b; + if (uv_pixel_interval.x < uv_pixel_interval.y){ + b = center_pos.x; + } else { + b = center_pos.y; + } + uv = center_pos + normalize(v_in.uv - center_pos) * atan(distance(center_pos, v_in.uv) * -power * 10.0) * b / atan(-power * b * 10.0); + } + return image.Sample(textureSampler, uv); +} + +' +} +$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 + } + } +} + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSFisheyeXyShader { + +[Alias('Set-OBSFisheyeXyShader','Add-OBSFisheyeXyShader')] +param( +# Set the center_x_percent of OBSFisheyeXyShader +[Alias('center_x_percent')] +[ComponentModel.DefaultBindingProperty('center_x_percent')] +[Single] +$CenterXPercent, +# Set the center_y_percent of OBSFisheyeXyShader +[Alias('center_y_percent')] +[ComponentModel.DefaultBindingProperty('center_y_percent')] +[Single] +$CenterYPercent, +# Set the power_x of OBSFisheyeXyShader +[Alias('power_x')] +[ComponentModel.DefaultBindingProperty('power_x')] +[Single] +$PowerX, +# Set the power_y of OBSFisheyeXyShader +[Alias('power_y')] +[ComponentModel.DefaultBindingProperty('power_y')] +[Single] +$PowerY, +# 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 = 'fisheye-xy' +$ShaderNoun = 'OBSFisheyeXyShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform float center_x_percent< + string label = "Center x percent"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 50.0; +uniform float center_y_percent< + string label = "Center y percent"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 50.0; +uniform float power_x< + string label = "Power x"; + string widget_type = "slider"; + float minimum = -2.0; + float maximum = 2.0; + float step = 0.01; +> = 1.75; +uniform float power_y< + string label = "Power y"; + string widget_type = "slider"; + float minimum = -2.0; + float maximum = 2.0; + float step = 0.01; +> = 1.75; + +float4 mainImage(VertData v_in) : TARGET +{ + float2 center_pos = float2(center_x_percent * .01, center_y_percent * .01); + float2 uv = v_in.uv; + if (power_x >= 0.0001){ + float b = sqrt(dot(center_pos, center_pos)); + uv.x = (center_pos + normalize(v_in.uv - center_pos) * tan(distance(center_pos, v_in.uv) * power_x) * b / tan( b * power_x)).x; + } else if(power_x <= -0.0001){ + float b; + if (uv_pixel_interval.x < uv_pixel_interval.y){ + b = center_pos.x; + } else { + b = center_pos.y; + } + uv.x = (center_pos + normalize(v_in.uv - center_pos) * atan(distance(center_pos, v_in.uv) * -power_x * 10.0) * b / atan(-power_x * b * 10.0)).x; + } + if (power_y >= 0.0001){ + float b = sqrt(dot(center_pos, center_pos)); + uv.y = (center_pos + normalize(v_in.uv - center_pos) * tan(distance(center_pos, v_in.uv) * power_y) * b / tan( b * power_y)).y; + } else if(power_y <= -0.0001){ + float b; + if (uv_pixel_interval.x < uv_pixel_interval.y){ + b = center_pos.x; + } else { + b = center_pos.y; + } + uv.y = (center_pos + normalize(v_in.uv - center_pos) * atan(distance(center_pos, v_in.uv) * -power_y * 10.0) * b / atan(-power_y * b * 10.0)).y; + } + return image.Sample(textureSampler, uv); +} + +' +} +$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 + } + } +} + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSFlipShader { + +[Alias('Set-OBSFlipShader','Add-OBSFlipShader')] +param( +# Set the Horizontal of OBSFlipShader +[ComponentModel.DefaultBindingProperty('Horizontal')] +[Management.Automation.SwitchParameter] +$Horizontal, +# Set the Vertical of OBSFlipShader +[ComponentModel.DefaultBindingProperty('Vertical')] +[Management.Automation.SwitchParameter] +$Vertical, +# 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 = 'Flip' +$ShaderNoun = 'OBSFlipShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// A Simple Flip Shader + +uniform bool Horizontal< + string label = "Flip horizontally"; +> = true; +uniform bool Vertical< + string label = "Flip vertically"; +> = true; + +float4 mainImage(VertData v_in) : TARGET +{ + float2 pos = v_in.uv; + if (Horizontal == true) { + pos.x = 1 - pos.x; + } + if (Vertical == true) { + pos.y = 1 - pos.y; + } + + return image.Sample(textureSampler, pos); +} + +' +} +$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 + } + } +} + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSFrostedGlassShader { + +[Alias('Set-OBSFrostedGlassShader','Add-OBSFrostedGlassShader')] +param( +# Set the Alpha_Percent of OBSFrostedGlassShader +[Alias('Alpha_Percent')] +[ComponentModel.DefaultBindingProperty('Alpha_Percent')] +[Single] +$AlphaPercent, +# Set the Amount of OBSFrostedGlassShader +[ComponentModel.DefaultBindingProperty('Amount')] +[Single] +$Amount, +# Set the Scale of OBSFrostedGlassShader +[ComponentModel.DefaultBindingProperty('Scale')] +[Single] +$Scale, +# Set the Animate of OBSFrostedGlassShader +[ComponentModel.DefaultBindingProperty('Animate')] +[Management.Automation.SwitchParameter] +$Animate, +# Set the Horizontal_Border of OBSFrostedGlassShader +[Alias('Horizontal_Border')] +[ComponentModel.DefaultBindingProperty('Horizontal_Border')] +[Management.Automation.SwitchParameter] +$HorizontalBorder, +# Set the Border_Offset of OBSFrostedGlassShader +[Alias('Border_Offset')] +[ComponentModel.DefaultBindingProperty('Border_Offset')] +[Single] +$BorderOffset, +# Set the Border_Color of OBSFrostedGlassShader +[Alias('Border_Color')] +[ComponentModel.DefaultBindingProperty('Border_Color')] +[String] +$BorderColor, +# Set the notes of OBSFrostedGlassShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# 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 = 'frosted_glass' +$ShaderNoun = 'OBSFrostedGlassShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Frosted Glass shader by Charles Fettinger for obs-shaderfilter plugin 4/2019 +//https://github.com/Oncorporation/obs-shaderfilter + +uniform float Alpha_Percent< + string label = "Alpha Percent"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.1; +> = 100.0; +uniform float Amount< + string label = "Amount"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.03; +uniform float Scale< + string label = "Scale"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.01; +> = 5.1; +uniform bool Animate; +uniform bool Horizontal_Border; +uniform float Border_Offset< + string label = "Border Offset"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 2.0; + float step = 0.01; +> = 1.1; +uniform float4 Border_Color = {.8,.5,1.0,1.0}; +uniform string notes< + string widget_type = "info"; +> = "Change shader with Scale and Amount, move Border with Border Offset. Alpha is Opacity of overlay."; + +float rand(float2 co) +{ + float scale = Scale; + if (Animate) + scale *= rand_f; + float2 v1 = float2(92.0,80.0); + float2 v2 = float2(41.0,62.0); + return frac(sin(dot(co.xy ,v1)) + cos(dot(co.xy ,v2)) * scale); +} + +float4 mainImage(VertData v_in) : TARGET +{ + float4 rgba = image.Sample(textureSampler, v_in.uv); + float3 tc = rgba.rgb * Border_Color.rgb; + + float uv_compare = v_in.uv.x; + if (Horizontal_Border) + uv_compare = v_in.uv.y; + + if (uv_compare < (Border_Offset - 0.005)) + { + float2 randv = float2(rand(v_in.uv.yx),rand(v_in.uv.yx)); + tc = image.Sample(textureSampler, v_in.uv + (randv*Amount)).rgb; + } + else if (uv_compare >= (Border_Offset + 0.005)) + { + tc = image.Sample(textureSampler, v_in.uv).rgb; + } + return lerp(rgba,float4(tc,1.0),(Alpha_Percent * 0.01)); +} + +' +} +$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 + } + } +} + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSGammaCorrectionShader { + +[Alias('Set-OBSGammaCorrectionShader','Add-OBSGammaCorrectionShader')] +param( +# Set the Red of OBSGammaCorrectionShader +[ComponentModel.DefaultBindingProperty('Red')] +[Single] +$Red, +# Set the Green of OBSGammaCorrectionShader +[ComponentModel.DefaultBindingProperty('Green')] +[Single] +$Green, +# Set the Blue of OBSGammaCorrectionShader +[ComponentModel.DefaultBindingProperty('Blue')] +[Single] +$Blue, +# Set the notes of OBSGammaCorrectionShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# 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 = 'gamma_correction' +$ShaderNoun = 'OBSGammaCorrectionShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Gamma Correction shader by Charles Fettinger for obs-shaderfilter plugin 4/2019 +//https://github.com/Oncorporation/obs-shaderfilter + +uniform float Red< + string label = "Red"; + string widget_type = "slider"; + float minimum = 0.1; + float maximum = 10.0; + float step = 0.01; +> = 2.2; +uniform float Green< + string label = "Green"; + string widget_type = "slider"; + float minimum = 0.1; + float maximum = 10.0; + float step = 0.01; +> = 2.2; +uniform float Blue< + string label = "Blue"; + string widget_type = "slider"; + float minimum = 0.1; + float maximum = 10.0; + float step = 0.01; +> = 2.2; +uniform string notes< + string widget_type = "info"; +> = "Modify Colors to correct for gamma, use equal values for general correction." + +float4 mainImage(VertData v_in) : TARGET +{ + float3 gammaRGB = float3(clamp(Red,0.1,10.0),clamp(Green,0.1,10.0),clamp(Blue,0.1,10.0)); + float4 c = image.Sample(textureSampler, v_in.uv); + c.rgb = pow(c.rgb, 1.0 / gammaRGB); + return c; +} +' +} +$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 + } + } +} + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSGaussianBlurAdvancedShader { + +[Alias('Set-OBSGaussianBlurAdvancedShader','Add-OBSGaussianBlurAdvancedShader')] +param( +# Set the Directions of OBSGaussianBlurAdvancedShader +[ComponentModel.DefaultBindingProperty('Directions')] +[Single] +$Directions, +# Set the Quality of OBSGaussianBlurAdvancedShader +[ComponentModel.DefaultBindingProperty('Quality')] +[Single] +$Quality, +# Set the Size of OBSGaussianBlurAdvancedShader +[ComponentModel.DefaultBindingProperty('Size')] +[Single] +$Size, +# Set the Mask_Left of OBSGaussianBlurAdvancedShader +[Alias('Mask_Left')] +[ComponentModel.DefaultBindingProperty('Mask_Left')] +[Single] +$MaskLeft, +# Set the Mask_Right of OBSGaussianBlurAdvancedShader +[Alias('Mask_Right')] +[ComponentModel.DefaultBindingProperty('Mask_Right')] +[Single] +$MaskRight, +# Set the Mask_Top of OBSGaussianBlurAdvancedShader +[Alias('Mask_Top')] +[ComponentModel.DefaultBindingProperty('Mask_Top')] +[Single] +$MaskTop, +# Set the Mask_Bottom of OBSGaussianBlurAdvancedShader +[Alias('Mask_Bottom')] +[ComponentModel.DefaultBindingProperty('Mask_Bottom')] +[Single] +$MaskBottom, +# 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-advanced' +$ShaderNoun = 'OBSGaussianBlurAdvancedShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform float Directions< + string label = "Directions (16.0)"; + string widget_type = "slider"; + float minimum = 1.0; + float maximum = 100.0; + float step = 1.0; +> = 16.0; // BLUR DIRECTIONS (Default 16.0 - More is better but slower) +uniform float Quality< + string label = "Quality (4.0)"; + string widget_type = "slider"; + float minimum = 1.0; + float maximum = 100.0; + float step = 1.0; +> = 4.0; // BLUR QUALITY (Default 4.0 - More is better but slower) +uniform float Size< + string label = "Size (8.0)"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 1.0; +> = 8.0; // BLUR SIZE (Radius) +uniform float Mask_Left< + string label = "Mask left (1.0)"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 1.0; +uniform float Mask_Right< + string label = "Mask right (1.0)"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 1.0; +uniform float Mask_Top< + string label = "Mask top (1.0)"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 1.0; +uniform float Mask_Bottom< + string label = "Mask bottom (1.0)"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 1.0; + +float4 mainImage(VertData v_in) : TARGET +{ + if(Mask_Left + Mask_Right > 1.0){ + if(v_in.uv.x > Mask_Left || 1.0 - v_in.uv.x > Mask_Right ){ + return image.Sample(textureSampler, v_in.uv); + } + }else{ + if((v_in.uv.x > Mask_Left) && (1.0-v_in.uv.x > Mask_Right)){ + return image.Sample(textureSampler, v_in.uv); + } + } + if(Mask_Top + Mask_Bottom > 1.0){ + if(v_in.uv.y > Mask_Top || 1.0 - v_in.uv.y > Mask_Bottom){ + return image.Sample(textureSampler, v_in.uv); + } + }else { + if((v_in.uv.y > Mask_Top) && (1.0-v_in.uv.y > Mask_Bottom)){ + return image.Sample(textureSampler, v_in.uv); + } + } + + float Pi = 6.28318530718; // Pi*2 + + float4 c = image.Sample(textureSampler, v_in.uv); + float4 oc = c; + float transparent = oc.a; + int count = 1; + float samples = oc.a; + + // Blur calculations + [loop] for( float d=0.0; d 0.0) + c /= samples; + + c.a = transparent / count; + return c; +} +' +} +$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 + } + } +} + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +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 + } + } +} + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSGaussianBlurSimpleShader { + +[Alias('Set-OBSGaussianBlurSimpleShader','Add-OBSGaussianBlurSimpleShader')] +param( +# Set the Strength of OBSGaussianBlurSimpleShader +[ComponentModel.DefaultBindingProperty('Strength')] +[Int32] +$Strength, +# Set the Mask_Left of OBSGaussianBlurSimpleShader +[Alias('Mask_Left')] +[ComponentModel.DefaultBindingProperty('Mask_Left')] +[Single] +$MaskLeft, +# Set the Mask_Right of OBSGaussianBlurSimpleShader +[Alias('Mask_Right')] +[ComponentModel.DefaultBindingProperty('Mask_Right')] +[Single] +$MaskRight, +# Set the Mask_Top of OBSGaussianBlurSimpleShader +[Alias('Mask_Top')] +[ComponentModel.DefaultBindingProperty('Mask_Top')] +[Single] +$MaskTop, +# Set the Mask_Bottom of OBSGaussianBlurSimpleShader +[Alias('Mask_Bottom')] +[ComponentModel.DefaultBindingProperty('Mask_Bottom')] +[Single] +$MaskBottom, +# 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-simple' +$ShaderNoun = 'OBSGaussianBlurSimpleShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform int Strength< + string label = "Strength (1)"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 25; + int step = 1; +> = 1.0; +uniform float Mask_Left< + string label = "Mask left (1.0)"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 1.0; +uniform float Mask_Right< + string label = "Mask right (1.0)"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 1.0; +uniform float Mask_Top< + string label = "Mask top (1.0)"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 1.0; +uniform float Mask_Bottom< + string label = "Mask bottom (1.0)"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 1.0; + +float4 mainImage(VertData v_in) : TARGET +{ + if(Strength <= 0) + return image.Sample(textureSampler, v_in.uv); + + if(Mask_Left + Mask_Right > 1.0){ + if(v_in.uv.x > Mask_Left || 1.0 - v_in.uv.x > Mask_Right ){ + return image.Sample(textureSampler, v_in.uv); + } + }else{ + if((v_in.uv.x > Mask_Left) && (1.0-v_in.uv.x > Mask_Right)){ + return image.Sample(textureSampler, v_in.uv); + } + } + if(Mask_Top + Mask_Bottom > 1.0){ + if(v_in.uv.y > Mask_Top || 1.0 - v_in.uv.y > Mask_Bottom){ + return image.Sample(textureSampler, v_in.uv); + } + }else { + if((v_in.uv.y > Mask_Top) && (1.0-v_in.uv.y > Mask_Bottom)){ + return image.Sample(textureSampler, v_in.uv); + } + } + + float Pi = 6.28318530718; // Pi*2 + + float Directions = float(Strength) * 4.0; // BLUR DIRECTIONS (Default 16.0 - More is better but slower) + float Quality = float(Strength); // BLUR QUALITY (Default 4.0 - More is better but slower) + float Size = float(Strength) * float(Strength); // BLUR SIZE (Radius) + + float4 c = image.Sample(textureSampler, v_in.uv); + float4 oc = c; + float transparent = oc.a; + int count = 1; + float samples = oc.a; + + // Blur calculations + [loop] for( float d=0.0; d 0.0) + c /= samples; + + c.a = transparent / count; + return c; +} +' +} +$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 + } + } +} + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSGaussianExampleShader { + +[Alias('Set-OBSGaussianExampleShader','Add-OBSGaussianExampleShader')] +param( +# Set the ViewProj of OBSGaussianExampleShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the image of OBSGaussianExampleShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the elapsed_time of OBSGaussianExampleShader +[Alias('elapsed_time')] +[ComponentModel.DefaultBindingProperty('elapsed_time')] +[Single] +$ElapsedTime, +# Set the uv_offset of OBSGaussianExampleShader +[Alias('uv_offset')] +[ComponentModel.DefaultBindingProperty('uv_offset')] +[Single[]] +$UvOffset, +# Set the uv_scale of OBSGaussianExampleShader +[Alias('uv_scale')] +[ComponentModel.DefaultBindingProperty('uv_scale')] +[Single[]] +$UvScale, +# Set the uv_size of OBSGaussianExampleShader +[Alias('uv_size')] +[ComponentModel.DefaultBindingProperty('uv_size')] +[Single[]] +$UvSize, +# Set the uv_pixel_interval of OBSGaussianExampleShader +[Alias('uv_pixel_interval')] +[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +[Single[]] +$UvPixelInterval, +# Set the initial_image of OBSGaussianExampleShader +[Alias('initial_image')] +[ComponentModel.DefaultBindingProperty('initial_image')] +[String] +$InitialImage, +# Set the before_image of OBSGaussianExampleShader +[Alias('before_image')] +[ComponentModel.DefaultBindingProperty('before_image')] +[String] +$BeforeImage, +# Set the after_image of OBSGaussianExampleShader +[Alias('after_image')] +[ComponentModel.DefaultBindingProperty('after_image')] +[String] +$AfterImage, +# Set the text_color of OBSGaussianExampleShader +[Alias('text_color')] +[ComponentModel.DefaultBindingProperty('text_color')] +[String] +$TextColor, +# Set the max_distance of OBSGaussianExampleShader +[Alias('max_distance')] +[ComponentModel.DefaultBindingProperty('max_distance')] +[Single] +$MaxDistance, +# Set the exp of OBSGaussianExampleShader +[ComponentModel.DefaultBindingProperty('exp')] +[Single] +$Exp, +# 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-example' +$ShaderNoun = 'OBSGaussianExampleShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform float4x4 ViewProj; +uniform texture2d image; + +uniform float elapsed_time; +uniform float2 uv_offset; +uniform float2 uv_scale; +uniform float2 uv_size; +uniform float2 uv_pixel_interval; + +/*-------------------------. +| :: Texture and sampler:: | +''-------------------------*/ + + +uniform texture2d initial_image; +sampler_state initial_sampler +{ + Filter = Linear; + AddressU = Border; + AddressV = Border; + BorderColor = 00000000; + texture2d = initial_image; +}; + +uniform texture2d before_image; +sampler_state before_sampler { + Filter = Linear; + AddressU = Border; + AddressV = Border; + BorderColor = 00000000; + texture2d = before_image; +}; + +uniform texture2d after_image; +sampler_state after_sampler { + Filter = Linear; + AddressU = Border; + AddressV = Border; + BorderColor = 00000000; + texture2d = after_image; +}; + +sampler_state textureSampler { + Filter = Linear; + AddressU = Border; + AddressV = Border; + BorderColor = 00000000; +}; + +struct VertData { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; + +struct ColorData { + float4 initial_color : SV_TARGET0; + float4 before_color: SV_TARGET1; + float4 after_color : SV_TARGET2; +}; + +uniform float4 text_color; +uniform float max_distance; +uniform float exp; + +#define PI 3.141592653589793238462643383279502884197169399375105820974 + +VertData mainTransform(VertData v_in) +{ + VertData vert_out = v_in; + vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); + vert_out.uv = v_in.uv * uv_scale + uv_offset; + return vert_out; +} + +float4 grayscale(float4 color) +{ + float grayscale = color.r * 0.3 + color.g * 0.59 + color.b * 0.11; + return float4(grayscale, grayscale, grayscale, color.a); +} + +float4 gaussian(VertData v_in, float angle) +{ + float rad = radians(angle); + float2 dir = float2(sin(rad), cos(rad)) * (uv_pixel_interval * max_distance); + float2 dir_2 = dir * 2.0; + float4 ret = image.Sample(textureSampler, v_in.uv) * 0.375; + + float4 px_away = image.Sample(textureSampler, v_in.uv + dir); + px_away += image.Sample(textureSampler, v_in.uv - dir); + px_away *= 0.25; + + float4 px_2_away = image.Sample(textureSampler, v_in.uv + dir_2); + px_2_away += image.Sample(textureSampler, v_in.uv + dir_2); + px_2_away *= 0.0625; + + return ret + px_away + px_2_away; +} + +ColorData setColorData(VertData v_in): SV_TARGET0 +{ + //string RenderTarget0 = "initial_image"; + ColorData cd;// = (ColorData)0; + cd.initial_color = image.Sample(textureSampler, v_in.uv); + cd.before_color = float4(0.0,0.0,1.0,1.0); + cd.after_color = float4(1.0,0.0,0.0,1.0); + return cd; +} + +float4 blurImageH(VertData v_in) : SV_TARGET1 +{ + //string RenderTarget1 = "before_image"; + //ColorData cd = (ColorData)0; + //cd.initial_color = image.Sample(textureSampler, v_in.uv); + //cd.before_color = float4(0.0,0.0,1.0,1.0);//gaussian(v_in, 0); + return float4(0.0,0.0,1.0,1.0); +} + +float4 blurImageV(VertData v_in) : SV_TARGET2 +{ + //string RenderTarget2 = "after_image"; + //ColorData cd = (ColorData)0; + //cd.after_color = float4(1.0,0.0,0.0,1.0); //gaussian(v_in, 90); + return float4(1.0,0.0,0.0,1.0); +} + +float4 mainImage(VertData v_in) : SV_TARGET0 +{ + float4 color; + ColorData cd;// = (ColorData)0; + + //cd.initial_color = initial_image.Sample(initial_sampler, v_in.uv); + //cd.before_color = before_image.Sample(before_sampler, v_in.uv); + cd.after_color = after_image.Sample(before_sampler, v_in.uv); + + if (max_distance <= 5) { + color = cd.before_color; + } + else { + color = cd.after_color;//image.Sample(textureSampler, v_in.uv); + } + + float4 gray = grayscale(color); + float4 gray_text = grayscale(text_color); + float d = distance(gray.rgb, gray_text.rgb); + if (d <= dot(max_distance, uv_pixel_interval.x * max_distance)){ + float d_c = pow(d*2, exp) / pow(2, exp); + d_c = sin(d_c * PI / 2); + d = pow(1.0 - sin(d * PI/4), exp); + + color.rgb = float3(d,d,d); + } + + return color; +} + +technique Draw +{ + pass pre + { + vertex_shader = mainTransform(v_in); + pixel_shader = setColorData(v_in); + } + + pass b0 + { + vertex_shader = mainTransform(v_in); + pixel_shader = blurImageH(v_in); + } + + pass b1 + { + vertex_shader = mainTransform(v_in); + pixel_shader = blurImageV(v_in); + } + + pass p0 + { + vertex_shader = mainTransform(v_in); + pixel_shader = mainImage(v_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 + } + } +} + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSGaussianSimpleShader { + +[Alias('Set-OBSGaussianSimpleShader','Add-OBSGaussianSimpleShader')] +param( +# Set the ViewProj of OBSGaussianSimpleShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the image of OBSGaussianSimpleShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the elapsed_time of OBSGaussianSimpleShader +[Alias('elapsed_time')] +[ComponentModel.DefaultBindingProperty('elapsed_time')] +[Single] +$ElapsedTime, +# Set the uv_offset of OBSGaussianSimpleShader +[Alias('uv_offset')] +[ComponentModel.DefaultBindingProperty('uv_offset')] +[Single[]] +$UvOffset, +# Set the uv_scale of OBSGaussianSimpleShader +[Alias('uv_scale')] +[ComponentModel.DefaultBindingProperty('uv_scale')] +[Single[]] +$UvScale, +# Set the uv_pixel_interval of OBSGaussianSimpleShader +[Alias('uv_pixel_interval')] +[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +[Single[]] +$UvPixelInterval, +# Set the uv_size of OBSGaussianSimpleShader +[Alias('uv_size')] +[ComponentModel.DefaultBindingProperty('uv_size')] +[Single[]] +$UvSize, +# Set the rand_f of OBSGaussianSimpleShader +[Alias('rand_f')] +[ComponentModel.DefaultBindingProperty('rand_f')] +[Single] +$RandF, +# Set the rand_instance_f of OBSGaussianSimpleShader +[Alias('rand_instance_f')] +[ComponentModel.DefaultBindingProperty('rand_instance_f')] +[Single] +$RandInstanceF, +# Set the rand_activation_f of OBSGaussianSimpleShader +[Alias('rand_activation_f')] +[ComponentModel.DefaultBindingProperty('rand_activation_f')] +[Single] +$RandActivationF, +# Set the loops of OBSGaussianSimpleShader +[ComponentModel.DefaultBindingProperty('loops')] +[Int32] +$Loops, +# Set the local_time of OBSGaussianSimpleShader +[Alias('local_time')] +[ComponentModel.DefaultBindingProperty('local_time')] +[Single] +$LocalTime, +# Set the samples of OBSGaussianSimpleShader +[ComponentModel.DefaultBindingProperty('samples')] +[Int32] +$Samples, +# Set the LOD of OBSGaussianSimpleShader +[ComponentModel.DefaultBindingProperty('LOD')] +[Int32] +$LOD, +# 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-simple' +$ShaderNoun = 'OBSGaussianSimpleShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Single-pass gaussian blur - fast shader modified by Charles Fettinger for use with obs-shaderfilter 7/2020 v.01 +// https://github.com/Oncorporation/obs-shaderfilter +// https://www.shadertoy.com/view/ltScRG Converted inspiration + +//Section to converting GLSL to HLSL - can delete +#define vec2 float2 +#define vec3 float3 +#define vec4 float4 +#define ivec2 int2 +#define ivec3 int3 +#define ivec4 int4 +#define mat2 float2x2 +#define mat3 float3x3 +#define mat4 float4x4 +#define fract frac +#define mix lerp +#define iTime float + +/* +**Shaders have these variables pre loaded by the plugin** +**this section can be deleted** + +uniform float4x4 ViewProj; +uniform texture2d image; + +uniform float elapsed_time; +uniform float2 uv_offset; +uniform float2 uv_scale; +uniform float2 uv_pixel_interval; +uniform float2 uv_size; +uniform float rand_f; +uniform float rand_instance_f; +uniform float rand_activation_f; +uniform int loops; +uniform float local_time; +*/ + +// 16x acceleration of https://www.shadertoy.com/view/4tSyzy +// by applying gaussian at intermediate MIPmap level. + +uniform int samples< + string label = "Samples"; + string widget_type = "slider"; + int minimum = 1; + int maximum = 25; + int step = 1; +> = 16; +uniform int LOD< + string label = "LOD"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 25; + int step = 1; +> = 2; // gaussian done on MIPmap at scale LOD + +float gaussian(vec2 i) +{ + float sigma = (float(samples) * .25); + return exp(-.5 * dot(i /= sigma, i)) / (6.28 * sigma * sigma); +} + +vec4 blur(vec2 U, vec2 scale) +{ + vec4 O = vec4(0,0,0,0); + int sLOD = (1 << LOD); // tile size = 2^LOD + int s = samples / sLOD; + + for (int i = 0; i < s * s; i++) + { + vec2 d = vec2(i % s, i / s) * float(sLOD) - float(samples) * 0.5; + O += gaussian(d) * image.SampleLevel(textureSampler, U + (scale * gaussian(d)), float(LOD)); + //O += gaussian(d) * image.Sample(textureSampler, U + i * d * float(LOD)); + //O += image.Sample(textureSampler, U + gaussian(d) * float(LOD)); + } + + return O / O.a; +} + +float4 mainImage(VertData v_in) : TARGET +{ + float2 iResolution = uv_scale;//uv_size * uv_scale + uv_offset; + //float2 iResolution = 1 - v_in.uv + 1.0; + //float4 rgba = image.SampleLevel(textureSampler, v_in.uv * uv_scale + uv_offset,4.0); + return blur(v_in.uv / iResolution, 1.0 / iResolution); + //return rgba; +} + + + + + + +' +} +$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 + } + } +} + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSGbCameraShader { + +[Alias('Set-OBSGbCameraShader','Add-OBSGbCameraShader')] +param( +# Set the pixelSize of OBSGbCameraShader +[ComponentModel.DefaultBindingProperty('pixelSize')] +[Single] +$PixelSize, +# Set the dither_factor of OBSGbCameraShader +[Alias('dither_factor')] +[ComponentModel.DefaultBindingProperty('dither_factor')] +[Single] +$DitherFactor, +# Set the alternative_bayer of OBSGbCameraShader +[Alias('alternative_bayer')] +[ComponentModel.DefaultBindingProperty('alternative_bayer')] +[Management.Automation.SwitchParameter] +$AlternativeBayer, +# Set the brightness of OBSGbCameraShader +[ComponentModel.DefaultBindingProperty('brightness')] +[Single] +$Brightness, +# Set the contrast of OBSGbCameraShader +[ComponentModel.DefaultBindingProperty('contrast')] +[Single] +$Contrast, +# Set the gamma of OBSGbCameraShader +[ComponentModel.DefaultBindingProperty('gamma')] +[Single] +$Gamma, +# Set the color_1 of OBSGbCameraShader +[Alias('color_1')] +[ComponentModel.DefaultBindingProperty('color_1')] +[String] +$Color1, +# Set the color_2 of OBSGbCameraShader +[Alias('color_2')] +[ComponentModel.DefaultBindingProperty('color_2')] +[String] +$Color2, +# Set the color_3 of OBSGbCameraShader +[Alias('color_3')] +[ComponentModel.DefaultBindingProperty('color_3')] +[String] +$Color3, +# Set the color_4 of OBSGbCameraShader +[Alias('color_4')] +[ComponentModel.DefaultBindingProperty('color_4')] +[String] +$Color4, +# 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 = 'gb-camera' +$ShaderNoun = 'OBSGbCameraShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +/* + * ------------------------------------------------------------ + * "THE BEERWARE LICENSE" (Revision 42): + * maple wrote this code. As long as you retain this + * notice, you can do whatever you want with this stuff. If we + * meet someday, and you think this stuff is worth it, you can + * buy me a beer in return. + * ------------------------------------------------------------ + * from https://www.shadertoy.com/view/3tSXRh + * adopted for OBS by Exeldro + * ------------------------------------------------------------ + */ + +uniform float pixelSize< + string label = "Pixel Size"; + string widget_type = "slider"; + float minimum = 1.0; + float maximum = 50.0; + float step = 0.1; +> = 3.0; + +uniform float dither_factor< + string label = "Dither Factor"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.01; +> = 0.8; + +uniform bool alternative_bayer; + +uniform float brightness< + string label = "Brightness"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.01; +> = 0.0; +uniform float contrast< + string label = "Contrast"; + string widget_type = "slider"; + float minimum = -10.0; + float maximum = 10.0; + float step = 0.01; +> = 1.0; +uniform float gamma< + string label = "Gamma"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.01; +> = 0.6; + +uniform float4 color_1 = {0.18, 0, 0.18, 1.0}; +uniform float4 color_2 = {0.37, 0.15, 0.47, 1.0}; +uniform float4 color_3 = {0.97, 0.56, 0.12, 1.0}; +uniform float4 color_4 = {0.97, 0.94, 0.53, 1.0}; + +// quantize coords to low resolution +float2 pixelize(float2 uv, float2 pixelSize) { + float2 factor = pixelSize / uv_size; + return floor(uv / factor) * factor; +} + +float3 colorLUT(float3 color) { + float gray = color.r*0.3 + color.g*0.59 + color.b*0.11; + if(gray < 0.25) + return color_1.rgb; + if(gray < 0.50) + return color_2.rgb; + if(gray < 0.75) + return color_3.rgb; + return color_4.rgb; +} + +// adjust brightness, contrast and gamma levels of a color +float3 levels(float3 color, float brightness, float contrast, float3 gamma) { + float3 value = (color - 0.5) * contrast + 0.5; + value = clamp(value + brightness, 0.0, 1.0); + return clamp(float3(pow(abs(value.r), gamma.x),pow(abs(value.g), gamma.y),pow(abs(value.b), gamma.z)), 0.0, 1.0); +} +float3 levels(float3 color, float brightness, float contrast, float gamma) { + return levels(color, brightness, contrast, float3(gamma, gamma, gamma)); +} + +// applies the dithering filter to a color map +float3 dither8x8(float2 coord, float3 color, float2 pixelSize) { + // reduces pixel space to the selected pixel size + float2 pixelCoord = floor((coord * uv_size) / pixelSize + float2(0.5, 0.5)); + + // applies the bayer matrix filter to the color map + pixelCoord = pixelCoord - 8.0 * floor(pixelCoord/8.0); + int index = int(pixelCoord.x + (pixelCoord.y * 8.0)); + float bayer; + if (alternative_bayer){ +#ifdef OPENGL + const int[64] bayer8 = int[64]( +#else + const int bayer8[64] = { +#endif + 0, 32, 8, 40, 2, 34, 10, 42, /* 8x8 Bayer ordered dithering */ + 48, 16, 56, 24, 50, 18, 58, 26, /* pattern. Each input pixel */ + 12, 44, 4, 36, 14, 46, 6, 38, /* is scaled to the 0..63 range */ + 60, 28, 52, 20, 62, 30, 54, 22, /* before looking in this table */ + 3, 35, 11, 43, 1, 33, 9, 41, /* to determine the action. */ + 51, 19, 59, 27, 49, 17, 57, 25, + 15, 47, 7, 39, 13, 45, 5, 37, + 63, 31, 55, 23, 61, 29, 53, 21 +#ifdef OPENGL + ); +#else + }; +#endif + bayer = (bayer8[index]-31.0)/32.0; + } else { +#ifdef OPENGL + const int[64] bayer8 = int[64]( +#else + const int bayer8[64] = { +#endif + 0, 48, 12, 60, 3, 51, 15, 63, + 32, 16, 44, 28, 35, 19, 47, 31, + 8, 56, 4, 52, 11, 59, 7, 55, + 40, 24, 36, 20, 43, 27, 39, 23, + 2, 50, 14, 62, 1, 49, 13, 61, + 34, 18, 46, 30, 33, 17, 45, 29, + 10, 58, 6, 54, 9, 57, 5, 53, + 42, 26, 38, 22, 41, 25, 37, 21 +#ifdef OPENGL + ); +#else + }; +#endif + bayer = (bayer8[index]-31.0)/32.0; + } + float3 bayerColor = (color + float3(bayer,bayer,bayer) * (dither_factor / 8.0)); + // limits it to the selected palette + color = colorLUT(bayerColor); + + return color; +} + +float4 mainImage(VertData v_in) : TARGET +{ + float2 texcoord = pixelize(v_in.uv, float2(pixelSize,pixelSize)); + texcoord = clamp(texcoord, 0.001, 1.0); + float4 c = image.Sample(textureSampler, texcoord); + float3 color = c.rgb; + + color = levels(color, brightness, contrast, float3(gamma, gamma, gamma)); + + color = dither8x8(texcoord, color, float2(pixelSize,pixelSize)); + + return float4(color.r, color.g, color.b, c.a); +} + +' +} +$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 + } + } +} + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSGlassShader { + +[Alias('Set-OBSGlassShader','Add-OBSGlassShader')] +param( +# Set the Alpha_Percent of OBSGlassShader +[Alias('Alpha_Percent')] +[ComponentModel.DefaultBindingProperty('Alpha_Percent')] +[Single] +$AlphaPercent, +# Set the Offset_Amount of OBSGlassShader +[Alias('Offset_Amount')] +[ComponentModel.DefaultBindingProperty('Offset_Amount')] +[Single] +$OffsetAmount, +# Set the xSize of OBSGlassShader +[ComponentModel.DefaultBindingProperty('xSize')] +[Int32] +$XSize, +# Set the ySize of OBSGlassShader +[ComponentModel.DefaultBindingProperty('ySize')] +[Int32] +$YSize, +# Set the Reflection_Offset of OBSGlassShader +[Alias('Reflection_Offset')] +[ComponentModel.DefaultBindingProperty('Reflection_Offset')] +[Int32] +$ReflectionOffset, +# Set the Horizontal_Border of OBSGlassShader +[Alias('Horizontal_Border')] +[ComponentModel.DefaultBindingProperty('Horizontal_Border')] +[Management.Automation.SwitchParameter] +$HorizontalBorder, +# Set the Border_Offset of OBSGlassShader +[Alias('Border_Offset')] +[ComponentModel.DefaultBindingProperty('Border_Offset')] +[Single] +$BorderOffset, +# Set the Border_Color of OBSGlassShader +[Alias('Border_Color')] +[ComponentModel.DefaultBindingProperty('Border_Color')] +[String] +$BorderColor, +# Set the Glass_Color of OBSGlassShader +[Alias('Glass_Color')] +[ComponentModel.DefaultBindingProperty('Glass_Color')] +[String] +$GlassColor, +# Set the notes of OBSGlassShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# 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 = 'glass' +$ShaderNoun = 'OBSGlassShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Glass shader by Charles Fettinger for obs-shaderfilter plugin 4/2019 +//https://github.com/Oncorporation/obs-shaderfilter +//Converted to OpenGl by Q-mii & Exeldro February 25, 2022 +uniform float Alpha_Percent< + string label = "Alpha Percent"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.1; +> = 100.0; +uniform float Offset_Amount< + string label = "Offset Amount"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.01; +> = 0.8; +uniform int xSize< + string label = "x Size"; + string widget_type = "slider"; + int minimum = 1; + int maximum = 100; + int step = 1; +> = 8; +uniform int ySize< + string label = "y Size"; + string widget_type = "slider"; + int minimum = 1; + int maximum = 100; + int step = 1; +> = 8; +uniform int Reflection_Offset< + string label = "Reflection Offset"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 2; +uniform bool Horizontal_Border; +uniform float Border_Offset< + string label = "Border Offset"; + string widget_type = "slider"; + float minimum = -0.01; + float maximum = 1.01; + float step = 0.01; +> = 0.5; +uniform float4 Border_Color = {.8,.5,1.0,1.0}; +uniform float4 Glass_Color; +uniform string notes< + string widget_type = "info"; +> = "xSize, ySize are for distortion. Offset Amount and Reflection Offset change glass properties. Alpha is Opacity of overlay."; + +float mod(float a, float b){ + float d = a / b; + return (d-floor(d))*b; +} + +float4 mainImage(VertData v_in) : TARGET +{ + + + int xSubPixel = int(mod((v_in.uv.x * uv_size.x) , float(clamp(xSize,1,100)))); + int ySubPixel = int(mod((v_in.uv.y * uv_size.y) , float(clamp(ySize,1,100)))); + float2 offsets = float2(Offset_Amount * xSubPixel / uv_size.x, Offset_Amount * ySubPixel / uv_size.y); + float2 uv = v_in.uv + offsets; + float2 uv2 = float2(uv.x + (Reflection_Offset / uv_size.x),uv.y + (Reflection_Offset / uv_size.y)); + + float4 rgba = image.Sample(textureSampler, v_in.uv); + float4 rgba_output = float4(rgba.rgb * Border_Color.rgb, rgba.a); + rgba = image.Sample(textureSampler, uv); + float4 rgba_glass = image.Sample(textureSampler, uv2); + + float uv_compare = v_in.uv.x; + if (Horizontal_Border) + uv_compare = v_in.uv.y; + + if (uv_compare < (Border_Offset - 0.005)) + { + rgba_output = (rgba + rgba_glass) *.5 * Glass_Color; + } + else if (uv_compare >= (Border_Offset + 0.005)) + { + rgba_output = image.Sample(textureSampler, v_in.uv); + } + return lerp(rgba,rgba_output,(Alpha_Percent * 0.01)); +} + +' +} +$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 + } + } +} + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSGlitchAnalogShader { + +[Alias('Set-OBSGlitchAnalogShader','Add-OBSGlitchAnalogShader')] +param( +# Set the scan_line_jitter_displacement of OBSGlitchAnalogShader +[Alias('scan_line_jitter_displacement')] +[ComponentModel.DefaultBindingProperty('scan_line_jitter_displacement')] +[Single] +$ScanLineJitterDisplacement, +# Set the scan_line_jitter_threshold_percent of OBSGlitchAnalogShader +[Alias('scan_line_jitter_threshold_percent')] +[ComponentModel.DefaultBindingProperty('scan_line_jitter_threshold_percent')] +[Int32] +$ScanLineJitterThresholdPercent, +# Set the vertical_jump_amount of OBSGlitchAnalogShader +[Alias('vertical_jump_amount')] +[ComponentModel.DefaultBindingProperty('vertical_jump_amount')] +[Single] +$VerticalJumpAmount, +# Set the vertical_speed of OBSGlitchAnalogShader +[Alias('vertical_speed')] +[ComponentModel.DefaultBindingProperty('vertical_speed')] +[Single] +$VerticalSpeed, +# Set the horizontal_shake of OBSGlitchAnalogShader +[Alias('horizontal_shake')] +[ComponentModel.DefaultBindingProperty('horizontal_shake')] +[Single] +$HorizontalShake, +# Set the color_drift_amount of OBSGlitchAnalogShader +[Alias('color_drift_amount')] +[ComponentModel.DefaultBindingProperty('color_drift_amount')] +[Single] +$ColorDriftAmount, +# Set the color_drift_speed of OBSGlitchAnalogShader +[Alias('color_drift_speed')] +[ComponentModel.DefaultBindingProperty('color_drift_speed')] +[Single] +$ColorDriftSpeed, +# Set the pulse_speed_percent of OBSGlitchAnalogShader +[Alias('pulse_speed_percent')] +[ComponentModel.DefaultBindingProperty('pulse_speed_percent')] +[Int32] +$PulseSpeedPercent, +# Set the alpha_percent of OBSGlitchAnalogShader +[Alias('alpha_percent')] +[ComponentModel.DefaultBindingProperty('alpha_percent')] +[Int32] +$AlphaPercent, +# Set the rotate_colors of OBSGlitchAnalogShader +[Alias('rotate_colors')] +[ComponentModel.DefaultBindingProperty('rotate_colors')] +[Management.Automation.SwitchParameter] +$RotateColors, +# Set the Apply_To_Alpha_Layer of OBSGlitchAnalogShader +[Alias('Apply_To_Alpha_Layer')] +[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] +[Management.Automation.SwitchParameter] +$ApplyToAlphaLayer, +# Set the Replace_Image_Color of OBSGlitchAnalogShader +[Alias('Replace_Image_Color')] +[ComponentModel.DefaultBindingProperty('Replace_Image_Color')] +[Management.Automation.SwitchParameter] +$ReplaceImageColor, +# Set the Apply_To_Specific_Color of OBSGlitchAnalogShader +[Alias('Apply_To_Specific_Color')] +[ComponentModel.DefaultBindingProperty('Apply_To_Specific_Color')] +[Management.Automation.SwitchParameter] +$ApplyToSpecificColor, +# Set the Color_To_Replace of OBSGlitchAnalogShader +[Alias('Color_To_Replace')] +[ComponentModel.DefaultBindingProperty('Color_To_Replace')] +[String] +$ColorToReplace, +# Set the notes of OBSGlitchAnalogShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# 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 = 'glitch_analog' +$ShaderNoun = 'OBSGlitchAnalogShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// analog glitch shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 +//https://github.com/Oncorporation/obs-shaderfilter +//Converted to OpenGL by Q-mii & Exeldro February 22, 2022 +uniform float scan_line_jitter_displacement< + string label = "Scan line jitter"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 33.0; // (displacement, threshold) +uniform int scan_line_jitter_threshold_percent< + string label = "scan line jitter threshold percent"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 95; +uniform float vertical_jump_amount< + string label = "Vertical jump amount"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +>; +uniform float vertical_speed< + string label = "Vertical speed"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +>;// (amount, speed) +uniform float horizontal_shake< + string label = "Horizontal shake"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +>; +uniform float color_drift_amount< + string label = "Color drift amount"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +>; +uniform float color_drift_speed< + string label = "Color drift speed"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +>;// (amount, speed) +uniform int pulse_speed_percent< + string label = "Pulse speed percent"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 0; +uniform int alpha_percent< + string label = "Aplha percent"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 100; +uniform bool rotate_colors; +uniform bool Apply_To_Alpha_Layer = false; +uniform bool Replace_Image_Color; +uniform bool Apply_To_Specific_Color; +uniform float4 Color_To_Replace; +uniform string notes< + string widget_type = "info"; +> ="play with settings!"; + + +float nrand(float x, float y) +{ + float value = dot(float2(x, y), float2(12.9898 , 78.233 )); + return frac(sin(value) * 43758.5453); +} + +float4 mainImage(VertData v_in) : TARGET +{ + float speed = pulse_speed_percent * 0.01; + float alpha = alpha_percent * 0.01; + float scan_line_jitter_threshold = scan_line_jitter_threshold_percent * 0.01; + float u = v_in.uv.x; + float v = v_in.uv.y; + float t = sin(elapsed_time * speed) * 2 - 1; + float4 rgba = image.Sample(textureSampler, v_in.uv); + + // Scan line jitter + float jitter = nrand(v, t) * 2 - 1; + jitter *= step(scan_line_jitter_threshold, abs(jitter)) * scan_line_jitter_displacement; + + // Vertical jump + float jump = lerp(v, frac(v + (t * vertical_speed)), vertical_jump_amount); + + // Horizontal shake + float shake = ((t * (u + rand_f)/2) - 0.5) * horizontal_shake; + + //// Color drift + float drift = sin(jump + color_drift_speed) * color_drift_amount; + + float2 src1 = float2(rgba.x, rgba.z) * clamp(frac(float2(u + jitter + shake, jump)), -10.0, 10.0); + float2 src2 = float2(rgba.y, rgba.w) * frac(float2(u + jitter + shake + drift, jump)); + + if(rotate_colors) + { + // get general time number between 0 and 4 + float tx = (t + 1) * 2; + // 3 steps c1->c2, c2->c3, c3->c1 + //when between 0 - 1 only c1 rises then falls + //(min(tx, 2.0) * 0.5) range between 0-2 converted to 0-1-0 + src1.x = lerp(src1.x, rgba.x, clamp((min(tx, 2.0) * 0.5),0.0,0.5)); + //((min(max(1.0, tx),3.0) - 1) * 0.5) range between 1-3 converted to 0-1-0 + src2.x = lerp(src2.x, rgba.y, clamp(((min(max(1.0, tx),3.0) - 1) * 0.5),0.0,0.5)); + //((min(2.0, tx) -2) * 0.5) range between 2 and 4 converted to 0-1-0 + src1.y = lerp(src1.y, rgba.z, clamp(((min(2.0, tx) -2) * 0.5),0.0,0.5)); + + } + + float4 color = rgba; + float4 original_color = color; + rgba = float4(src1.x, src2.x, src1.y, alpha); + + if (Apply_To_Alpha_Layer) + { + float luma = color.r * 0.299 + color.g * 0.587 + color.b * 0.114; + if (Replace_Image_Color) + color = float4(luma, luma, luma, luma); + rgba = lerp(original_color, rgba * color, alpha); + } + + if (Apply_To_Specific_Color) + { + color = original_color; + color = (distance(color.rgb, Color_To_Replace.rgb) <= 0.075) ? rgba : color; + rgba = lerp(original_color, color, alpha); + } + + return rgba; +} + +' +} +$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 the output was still an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # use $psCmdlet.WriteError so that it shows the error correctly. - $psCmdlet.WriteError($outputAddedResult) + 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 + } + } +} + +} + + +} + + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSGlitchPeriodicShader { + +[Alias('Set-OBSGlitchPeriodicShader','Add-OBSGlitchPeriodicShader')] +param( +# Set the PERI of OBSGlitchPeriodicShader +[ComponentModel.DefaultBindingProperty('PERI')] +[Single] +$PERI, +# Set the DURA of OBSGlitchPeriodicShader +[ComponentModel.DefaultBindingProperty('DURA')] +[Single] +$DURA, +# Set the AMPL of OBSGlitchPeriodicShader +[ComponentModel.DefaultBindingProperty('AMPL')] +[Single] +$AMPL, +# Set the SCRA of OBSGlitchPeriodicShader +[ComponentModel.DefaultBindingProperty('SCRA')] +[Single] +$SCRA, +# 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 = 'glitch-periodic' +$ShaderNoun = 'OBSGlitchPeriodicShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Created by Éric Nicolas (ccjmne) for use with obs-shaderfilter 12/2025 +// Port of: https://www.shadertoy.com/view/WfVfDh +// Originally forked from: https://www.shadertoy.com/view/MtXBDs + +#define PI 3.14159265359 + +/* For visual explanation of the paramters, see */ +/* https://www.desmos.com/calculator/vezu1wyqma */ +/* */ +/* Period How often a glitch occurs (in seconds) 0–? */ +/* Duration How long a glitch lasts (in seconds) 0–Period */ +/* Amplitude How intense a glitch is 0–1 */ +/* Scratchiness How jittery a glitch is 0–1 */ + +uniform float PERI< + string label = "Period"; + string widget_type = "slider"; + float minimum = 1.; + float maximum = 60.; + float step = 1.; +> = 6.; + +uniform float DURA< + string label = "Duration"; + string widget_type = "slider"; + float minimum = 0.; + float maximum = 60.; + float step = .01; +> = .5; + +uniform float AMPL< + string label = "Amplitude"; + string widget_type = "slider"; + float minimum = 0.; + float maximum = 1.; + float step = .01; +> = .15; + +uniform float SCRA< + string label = "Scratchiness"; + string widget_type = "slider"; + float minimum = 0.; + float maximum = 1.; + float step = .01; +> = .2; + +float random2d(float2 n) { + return frac(sin(dot(n, float2(12.9898, 4.1414))) * 43758.5453); +} + +float randomRange(in float2 seed, in float lo, in float hi) { + return lo + random2d(seed) * (hi - lo); +} + +float insideRange(float v, float bottom, float top) { + return step(bottom, v) - step(top, v); +} + +float4 mainImage(VertData v_in): TARGET { + float time = floor(elapsed_time * SCRA * 60.); + float2 uv = v_in.uv; + + // Periodic intermittence + float AMP = AMPL * (cos(2. * PI * max(0., (mod(-elapsed_time / PERI, 1.) - 1.) * PERI / DURA + 1.)) * -.5 + .5); + + float4 outCol = image.Sample(textureSampler, uv); + + // Randomly offset slices horizontally + float offsetMax = AMP / 2.; + for (float i = 0.; i < 10. * AMP; i += 1.) { + float sliceY = random2d( float2(time, 2345. + i)); + float sliceH = random2d( float2(time, 9035. + i)) * .25; + float offsetH = randomRange(float2(time, 9625. + i), -offsetMax, offsetMax); + float2 uvOff = uv; + uvOff.x += offsetH; + if (insideRange(uv.y, sliceY, frac(sliceY + sliceH)) == 1.) { + outCol = image.Sample(textureSampler, uvOff); + } + } + + // Slightly offset one entire channel + offsetMax = AMP / 6.; + float2 colOff = float2( + randomRange(float2(time, 9545.), -offsetMax, offsetMax), + randomRange(float2(time, 7205.), -offsetMax, offsetMax) + ); + float rnd = random2d(float2(time , 9545.)); + if (rnd < .33) outCol.r = image.Sample(textureSampler, uv + colOff).r; + else if (rnd < .66) outCol.g = image.Sample(textureSampler, uv + colOff).g; + else outCol.b = image.Sample(textureSampler, uv + colOff).b; + + return outCol; +} + +' +} +$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 } - # Otherwise, if we had a result - elseif ($outputAddedResult) { - # Otherwise, get the input from the filters. - Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName - + 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 } - } } +} + + +} #.ExternalHelp obs-powershell-Help.xml -function Set-OBSRenderDelayFilter { - - - [Alias('Add-OBSRenderDelayFilter')] - param( - # The RenderDelay. - [Parameter(ValueFromPipelineByPropertyName)] - [timespan] - $RenderDelay, +function Get-OBSGlitchShader { - # If set, will remove a filter if one already exists. - # If this is not provided and the filter already exists, the settings of the filter will be changed. - [switch] - $Force - ) - dynamicParam { - $baseCommand = - if (-not $script:AddOBSSourceFilter) { - $script:AddOBSSourceFilter = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSSourceFilter','Function') - $script:AddOBSSourceFilter - } else { - $script:AddOBSSourceFilter - } - $IncludeParameter = @() - $ExcludeParameter = 'FilterKind','FilterSettings' +[Alias('Set-OBSGlitchShader','Add-OBSGlitchShader')] +param( +# Set the AMT of OBSGlitchShader +[ComponentModel.DefaultBindingProperty('AMT')] +[Single] +$AMT, +# Set the SPEED of OBSGlitchShader +[ComponentModel.DefaultBindingProperty('SPEED')] +[Single] +$SPEED, +# 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 +) - $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() - :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { - if ($ExcludeParameter) { - foreach ($exclude in $ExcludeParameter) { - if ($paramName -like $exclude) { continue nextInputParameter} - } - } - if ($IncludeParameter) { - $shouldInclude = - foreach ($include in $IncludeParameter) { - if ($paramName -like $include) { $true;break} - } - if (-not $shouldInclude) { continue nextInputParameter } - } - - $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( - $baseCommand.Parameters[$paramName].Name, - $baseCommand.Parameters[$paramName].ParameterType, - $baseCommand.Parameters[$paramName].Attributes - )) - } - $DynamicParameters +process { +$shaderName = 'glitch' +$ShaderNoun = 'OBSGlitchShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//based on https://www.shadertoy.com/view/MtXBDs +//inputs +uniform float AMT< + string label = "AMT"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.2; //0 - 1 glitch amount +uniform float SPEED< + string label = "Speed"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.6; //0 - 1 speed + +//2D (returns 0 - 1) +float random2d(float2 n) { + return frac(sin(dot(n, float2(12.9898, 4.1414))) * 43758.5453); +} + +float randomRange (in float2 seed, in float min, in float max) { + return min + random2d(seed) * (max - min); +} + +// return 1 if v inside 1d range +float insideRange(float v, float bottom, float top) { + return step(bottom, v) - step(top, v); +} + + +float4 mainImage(VertData v_in) : TARGET +{ + + float time = floor(elapsed_time * SPEED * 60.0); + float2 uv = v_in.uv; + + //copy orig + float4 outCol = image.Sample(textureSampler, uv); + + //randomly offset slices horizontally + float maxOffset = AMT/2.0; + for (float i = 0.0; i < 10.0 * AMT; i += 1.0) { + float sliceY = random2d(float2(time , 2345.0 + float(i))); + float sliceH = random2d(float2(time , 9035.0 + float(i))) * 0.25; + float hOffset = randomRange(float2(time , 9625.0 + float(i)), -maxOffset, maxOffset); + float2 uvOff = uv; + uvOff.x += hOffset; + if (insideRange(uv.y, sliceY, frac(sliceY+sliceH)) == 1.0 ){ + outCol = image.Sample(textureSampler, uvOff); + } } - process { - $myParameters = [Ordered]@{} + $PSBoundParameters + + //do slight offset on one entire channel + float maxColOffset = AMT/6.0; + float rnd = random2d(float2(time , 9545.0)); + float2 colOffset = float2(randomRange(float2(time , 9545.0),-maxColOffset,maxColOffset), + randomRange(float2(time , 7205.0),-maxColOffset,maxColOffset)); + if (rnd < 0.33){ + outCol.r = image.Sample(textureSampler, uv + colOffset).r; - if (-not $myParameters["FilterName"]) { - $filterName = $myParameters["FilterName"] = "RenderDelay" - } - - - $myParameterData = [Ordered]@{ - delay_ms = if ($RenderDelay.Ticks -lt 10kb) { - [int]$RenderDelay.Ticks - } else { - [int]$RenderDelay.TotalMilliseconds + }else if (rnd < 0.66){ + outCol.g = image.Sample(textureSampler, uv + colOffset).g; + + } else{ + outCol.b = image.Sample(textureSampler, uv + colOffset).b; + } + + return outCol; +} +' +} +$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 } - $addSplat = @{ - filterName = $myParameters["FilterName"] - SourceName = $myParameters["SourceName"] - filterKind = "gpu_delay" - filterSettings = $myParameterData - NoResponse = $myParameters["NoResponse"] + } + '(?>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 ($MyParameters["PassThru"]) { - $addSplat.Passthru = $MyParameters["PassThru"] - if ($MyInvocation.InvocationName -like 'Add-*') { - Add-OBSSourceFilter @addSplat - } else { - $addSplat.Remove('FilterKind') - Set-OBSSourceFilterSettings @addSplat - } - return + + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Add the input. - $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } - # If we got back an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # and that error was saying the source already exists, - if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { - # then check if we use the -Force. - if ($Force) { # If we do, remove the input - Remove-OBSSourceFilter -FilterName $addSplat.FilterName -SourceName $addSplat.SourceName - # and re-add our result. - $outputAddedResult = Add-OBSInput @addSplat *>&1 - } else { - # Otherwise, get the existing filter. - $existingFilter = Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName - # then apply the settings - $existingFilter.Set($addSplat.filterSettings) - # and output them - $existingFilter - # (don't forget to null the result, so we don't show this error) - $outputAddedResult = $null - } + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } + } - # If the output was still an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # use $psCmdlet.WriteError so that it shows the error correctly. - $psCmdlet.WriteError($outputAddedResult) - } - + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - # Otherwise, if we had a result - elseif ($outputAddedResult) { - # Otherwise, get the input from the filters. - Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName - + + 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 } - } } +} + + +} #.ExternalHelp obs-powershell-Help.xml -function Set-OBSScaleFilter { - - - [Alias('Add-OBSScaleFilter')] - param( - # The Resolution. Can either width x height (e.g. 1920x1080) or an aspect ratio (16:9). - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("resolution")] - [Alias('Scale')] - [string] - $Resolution, +function Get-OBSGlowShader { - # The sampling method. It will default to "lanczos". - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("sampling")] - [string] - $Sampling = 'lanczos', +[Alias('Set-OBSGlowShader','Add-OBSGlowShader')] +param( +# Set the glow_percent of OBSGlowShader +[Alias('glow_percent')] +[ComponentModel.DefaultBindingProperty('glow_percent')] +[Int32] +$GlowPercent, +# Set the blur of OBSGlowShader +[ComponentModel.DefaultBindingProperty('blur')] +[Int32] +$Blur, +# Set the min_brightness of OBSGlowShader +[Alias('min_brightness')] +[ComponentModel.DefaultBindingProperty('min_brightness')] +[Int32] +$MinBrightness, +# Set the max_brightness of OBSGlowShader +[Alias('max_brightness')] +[ComponentModel.DefaultBindingProperty('max_brightness')] +[Int32] +$MaxBrightness, +# Set the pulse_speed of OBSGlowShader +[Alias('pulse_speed')] +[ComponentModel.DefaultBindingProperty('pulse_speed')] +[Int32] +$PulseSpeed, +# Set the ease of OBSGlowShader +[ComponentModel.DefaultBindingProperty('ease')] +[Management.Automation.SwitchParameter] +$Ease, +# Set the notes of OBSGlowShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# 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 +) - # If set, will keep the aspect ratio when scaling. - # This is only valid if the sampling method is set to "lanczos". - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("undistort")] - [Alias('Undistort')] - [switch] - $KeepAspectRatio, - # If set, will remove a filter if one already exists. - # If this is not provided and the filter already exists, the settings of the filter will be changed. - [switch] - $Force - ) - dynamicParam { - $baseCommand = - if (-not $script:AddOBSSourceFilter) { - $script:AddOBSSourceFilter = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSSourceFilter','Function') - $script:AddOBSSourceFilter - } else { - $script:AddOBSSourceFilter - } - $IncludeParameter = @() - $ExcludeParameter = 'FilterKind','FilterSettings' +process { +$shaderName = 'glow' +$ShaderNoun = 'OBSGlowShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//Converted to OpenGL by Exeldro February 21, 2022 +uniform int glow_percent< + string label = "Glow percent"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 10; +uniform int blur< + string label = "Blur"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 1; +uniform int min_brightness< + string label = "Min brightness"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 27; +uniform int max_brightness< + string label = "Max brightness"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 100; +uniform int pulse_speed< + string label = "Pulse speed"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 0; +uniform bool ease; +uniform string notes< + string widget_type = "info"; +> = "''ease'' - makes the animation pause at the begin and end for a moment,''glow_percent'' - how much brightness to add (recommend 0-100). ''blur'' - how far should the glow extend (recommend 1-4).''pulse_speed'' - (0-100). ''min/max brightness'' - floor and ceiling brightness level to target for glows."; + + +float EaseInOutCircTimer(float t,float b,float c,float d){ + t /= d/2.0; + if (t < 1.0) return -c/2.0 * (sqrt(1.0 - t*t) - 1.0) + b; + t -= 2.0; + return c/2.0 * (sqrt(1.0 - t*t) + 1.0) + b; +} + +float BlurStyler(float t,float b,float c,float d,bool ease) +{ + if (ease) return EaseInOutCircTimer(t,0.0,c,d); + return t; +} + +float4 mainImage(VertData v_in) : TARGET +{ + float2 offsets[4]; + offsets[0] = float2(-0.1, 0.125); + offsets[1] = float2(-0.1, -0.125); + offsets[2] = float2(0.1, -0.125); + offsets[3] = float2(0.1, 0.125); + + // convert input for vector math + float4 col = image.Sample(textureSampler, v_in.uv); + float blur_amount = float(blur) /100.0; + float glow_amount = float(glow_percent) * 0.01; + float speed = float(pulse_speed) * 0.01; + float luminance_floor = float(min_brightness) /100.0; + float luminance_ceiling = float(max_brightness) /100.0; + + if (col.a > 0.0) + { + //circular easing variable + float t = 1.0 + sin(elapsed_time * speed); + float b = 0.0; //start value + float c = 2.0; //change value + float d = 2.0; //duration + + // simple glow calc + for (int n = 0; n < 4; n++) { + b = BlurStyler(t, 0, c, d, ease); + float4 ncolor = image.Sample(textureSampler, v_in.uv + (blur_amount * b) * offsets[n]); + float intensity = ncolor.r * 0.299 + ncolor.g * 0.587 + ncolor.b * 0.114; + if ((intensity >= luminance_floor) && (intensity <= luminance_ceiling)) + { + ncolor.a = clamp(ncolor.a * glow_amount, 0.0, 1.0); + col += (ncolor * (glow_amount * b)); + } + } + } + return col; +} - $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() - :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { - if ($ExcludeParameter) { - foreach ($exclude in $ExcludeParameter) { - if ($paramName -like $exclude) { continue nextInputParameter} +' +} +$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 } - if ($IncludeParameter) { - $shouldInclude = - foreach ($include in $IncludeParameter) { - if ($paramName -like $include) { $true;break} + } + '(?>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] } - if (-not $shouldInclude) { continue nextInputParameter } + continue nextParameter + } } - - $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( - $baseCommand.Parameters[$paramName].Name, - $baseCommand.Parameters[$paramName].ParameterType, - $baseCommand.Parameters[$paramName].Attributes - )) - } - $DynamicParameters - } - process { - $myParameters = [Ordered]@{} + $PSBoundParameters - - if (-not $myParameters["FilterName"]) { - $filterName = $myParameters["FilterName"] = "Scale" - } - - $addSplat = @{ - filterName = $myParameters["FilterName"] - SourceName = $myParameters["SourceName"] - filterKind = "scale_filter" - filterSettings = [Ordered]@{resolution=$Resolution;sampling=$Sampling;undistort=$KeepAspectRatio -as [bool]} - NoResponse = $myParameters["NoResponse"] - } - - if ($MyParameters["PassThru"]) { - $addSplat.Passthru = $MyParameters["PassThru"] - if ($MyInvocation.InvocationName -like 'Add-*') { - Add-OBSSourceFilter @addSplat - } else { - $addSplat.Remove('FilterKind') - Set-OBSSourceFilterSettings @addSplat - } - return + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Add the input. - $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } - # If we got back an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # and that error was saying the source already exists, - if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { - # then check if we use the -Force. - if ($Force) { # If we do, remove the input - Remove-OBSSourceFilter -FilterName $addSplat.FilterName -SourceName $addSplat.SourceName - # and re-add our result. - $outputAddedResult = Add-OBSInput @addSplat *>&1 - } else { - # Otherwise, get the existing filter. - $existingFilter = Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName - # then apply the settings - $existingFilter.Set($addSplat.filterSettings) - # and output them - $existingFilter - # (don't forget to null the result, so we don't show this error) - $outputAddedResult = $null - } + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } + } - # If the output was still an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # use $psCmdlet.WriteError so that it shows the error correctly. - $psCmdlet.WriteError($outputAddedResult) - } - + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - # Otherwise, if we had a result - elseif ($outputAddedResult) { - # Otherwise, get the input from the filters. - Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName - + + 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 } - } } +} - -#.ExternalHelp obs-powershell-Help.xml -function Set-OBSScrollFilter { - - - param( - # The horizontal scroll speed. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("speed_x")] - [Alias('SpeedX', 'Speed_X','HSpeed')] - [double] - $HorizontalSpeed, - - # The vertical scroll speed. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("speed_y")] - [Alias('SpeedY', 'Speed_Y','VSpeed')] - [double] - $VerticalSpeed, - - # If set, will not loop - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("loop")] - [switch] - $NoLoop, - # If provided, will limit the width. - [Parameter(ValueFromPipelineByPropertyName)] - [ValidateRange(-500, 500)] - [ComponentModel.DefaultBindingProperty("cx")] - [Alias('LimitX', 'Limit_CX','WidthLimit')] - [double] - $LimitWidth, +} - # If provided, will limit the height. - [Parameter(ValueFromPipelineByPropertyName)] - [ValidateRange(-500, 500)] - [ComponentModel.DefaultBindingProperty("cy")] - [Alias('LimitY', 'Limit_CY','HeightLimit')] - [double] - $LimitHeight, + +#.ExternalHelp obs-powershell-Help.xml +function Get-OBSGradientShader { - # If set, will remove a filter if one already exists. - # If this is not provided and the filter already exists, the settings of the filter will be changed. - [switch] - $Force - ) - dynamicParam { - $baseCommand = - if (-not $script:AddOBSSourceFilter) { - $script:AddOBSSourceFilter = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSSourceFilter','Function') - $script:AddOBSSourceFilter - } else { - $script:AddOBSSourceFilter - } - $IncludeParameter = @() - $ExcludeParameter = 'FilterKind','FilterSettings' +[Alias('Set-OBSGradientShader','Add-OBSGradientShader')] +param( +# Set the start_color of OBSGradientShader +[Alias('start_color')] +[ComponentModel.DefaultBindingProperty('start_color')] +[String] +$StartColor, +# Set the start_step of OBSGradientShader +[Alias('start_step')] +[ComponentModel.DefaultBindingProperty('start_step')] +[Single] +$StartStep, +# Set the middle_color of OBSGradientShader +[Alias('middle_color')] +[ComponentModel.DefaultBindingProperty('middle_color')] +[String] +$MiddleColor, +# Set the middle_step of OBSGradientShader +[Alias('middle_step')] +[ComponentModel.DefaultBindingProperty('middle_step')] +[Single] +$MiddleStep, +# Set the end_color of OBSGradientShader +[Alias('end_color')] +[ComponentModel.DefaultBindingProperty('end_color')] +[String] +$EndColor, +# Set the end_step of OBSGradientShader +[Alias('end_step')] +[ComponentModel.DefaultBindingProperty('end_step')] +[Single] +$EndStep, +# Set the alpha_percent of OBSGradientShader +[Alias('alpha_percent')] +[ComponentModel.DefaultBindingProperty('alpha_percent')] +[Int32] +$AlphaPercent, +# Set the pulse_speed of OBSGradientShader +[Alias('pulse_speed')] +[ComponentModel.DefaultBindingProperty('pulse_speed')] +[Int32] +$PulseSpeed, +# Set the ease of OBSGradientShader +[ComponentModel.DefaultBindingProperty('ease')] +[Management.Automation.SwitchParameter] +$Ease, +# Set the rotate_colors of OBSGradientShader +[Alias('rotate_colors')] +[ComponentModel.DefaultBindingProperty('rotate_colors')] +[Management.Automation.SwitchParameter] +$RotateColors, +# Set the Apply_To_Alpha_Layer of OBSGradientShader +[Alias('Apply_To_Alpha_Layer')] +[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] +[Management.Automation.SwitchParameter] +$ApplyToAlphaLayer, +# Set the Apply_To_Specific_Color of OBSGradientShader +[Alias('Apply_To_Specific_Color')] +[ComponentModel.DefaultBindingProperty('Apply_To_Specific_Color')] +[Management.Automation.SwitchParameter] +$ApplyToSpecificColor, +# Set the Color_To_Replace of OBSGradientShader +[Alias('Color_To_Replace')] +[ComponentModel.DefaultBindingProperty('Color_To_Replace')] +[String] +$ColorToReplace, +# Set the horizontal of OBSGradientShader +[ComponentModel.DefaultBindingProperty('horizontal')] +[Management.Automation.SwitchParameter] +$Horizontal, +# Set the vertical of OBSGradientShader +[ComponentModel.DefaultBindingProperty('vertical')] +[Management.Automation.SwitchParameter] +$Vertical, +# Set the gradient_center_width_percentage of OBSGradientShader +[Alias('gradient_center_width_percentage')] +[ComponentModel.DefaultBindingProperty('gradient_center_width_percentage')] +[Int32] +$GradientCenterWidthPercentage, +# Set the gradient_center_height_percentage of OBSGradientShader +[Alias('gradient_center_height_percentage')] +[ComponentModel.DefaultBindingProperty('gradient_center_height_percentage')] +[Int32] +$GradientCenterHeightPercentage, +# Set the notes of OBSGradientShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# 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 +) - $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() - :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { - if ($ExcludeParameter) { - foreach ($exclude in $ExcludeParameter) { - if ($paramName -like $exclude) { continue nextInputParameter} - } - } - if ($IncludeParameter) { - $shouldInclude = - foreach ($include in $IncludeParameter) { - if ($paramName -like $include) { $true;break} - } - if (-not $shouldInclude) { continue nextInputParameter } - } - - $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( - $baseCommand.Parameters[$paramName].Name, - $baseCommand.Parameters[$paramName].ParameterType, - $baseCommand.Parameters[$paramName].Attributes - )) - } - $DynamicParameters +process { +$shaderName = 'gradient' +$ShaderNoun = 'OBSGradientShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// gradient shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 +//https://github.com/Oncorporation/obs-shaderfilter +//Converted to OpenGL by Q-mii & Exeldro February 25, 2022 +uniform float4 start_color = { 0.1, 0.3, 0.1, 1.0 }; +uniform float start_step< + string label = "Start step"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.15; +uniform float4 middle_color = { 1.0, 1.0, 1.0, 1.0 }; +uniform float middle_step< + string label = "Middle step"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.4; +uniform float4 end_color = { 0.75, 0.75, 0.75, 1.0}; +uniform float end_step< + string label = "End step"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.9; +uniform int alpha_percent< + string label = "Alpha percent"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 90; +uniform int pulse_speed< + string label = "Pulse speed"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 0; +uniform bool ease; +uniform bool rotate_colors; +uniform bool Apply_To_Alpha_Layer = true; +uniform bool Apply_To_Specific_Color; +uniform float4 Color_To_Replace; +uniform bool horizontal; +uniform bool vertical; +uniform int gradient_center_width_percentage< + string label = "gradient center width percentage"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform int gradient_center_height_percentage< + string label = "gradient center height percentage"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform string notes< + string widget_type = "info"; +> = "gradient center items will change the center location. Pulse Speed greater than 0 will animate. Easing seem to be too fast."; - } - process { - $myParameters = [Ordered]@{} + $PSBoundParameters - - if (-not $myParameters["FilterName"]) { - $filterName = $myParameters["FilterName"] = "Scroll" - } - - $myParameterData = [Ordered]@{} - foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { +float EaseInOutCircTimer(float t, float b, float c, float d) { + t /= d / 2; + if (t < 1) return -c / 2 * (sqrt(1 - t * t) - 1) + b; + t -= 2; + return c / 2 * (sqrt(1 - t * t) + 1) + b; +} - $bindToPropertyName = $null - - foreach ($attribute in $parameter.Attributes) { - if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { - $bindToPropertyName = $attribute.Name - break - } - } +float BlurStyler(float t, float b, float c, float d, bool ease) +{ + if (ease) return EaseInOutCircTimer(t, 0, c, d); + return t; +} - if (-not $bindToPropertyName) { continue } - if ($myParameters.Contains($parameter.Name)) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] - if ($myParameters[$parameter.Name] -is [switch]) { - $myParameterData[$bindToPropertyName] = $parameter.Name -as [bool] - } - } - } +struct gradient +{ + float4 color; + float step; +}; - if ($myParameterData["loop"]) { - $myParameterData["loop"] = -not $myParameterData["loop"] - } - if ($myParameterData["cx"]) { - $myParameterData["limit_cx"] = $true - } - if ($myParameterData["cy"]) { - $myParameterData["limit_cy"] = $true - } - - $addSplat = @{ - filterName = $myParameters["FilterName"] - SourceName = $myParameters["SourceName"] - filterKind = "scroll_filter" - filterSettings = $myParameterData - NoResponse = $myParameters["NoResponse"] - } - if ($MyParameters["PassThru"]) { - $addSplat.Passthru = $MyParameters["PassThru"] - if ($MyInvocation.InvocationName -like 'Add-*') { - Add-OBSSourceFilter @addSplat - } else { - $addSplat.Remove('FilterKind') - Set-OBSSourceFilterSettings @addSplat - } - return - } +float4 mainImage(VertData v_in) : TARGET +{ + const float PI = 3.14159265f;//acos(-1); + float speed = float(pulse_speed) * 0.01; + float alpha = float(alpha_percent) * 0.01; + + //circular easing variable + float t = sin(elapsed_time * speed) * 2 - 1; + float b = 0.0; //start value + float c = 2.0; //change value + float d = 2.0; //duration - # Add the input. - $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 + float2 gradient_center = float2(float(gradient_center_width_percentage) * 0.01,float(gradient_center_height_percentage) * 0.01); + float4 color = image.Sample(textureSampler, v_in.uv); + float luminance = color.a * 0.299 + color.g * 0.587 + color.b * 0.114; + float4 gray = float4(luminance,luminance,luminance, 1); - # If we got back an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # and that error was saying the source already exists, - if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { - # then check if we use the -Force. - if ($Force) { # If we do, remove the input - Remove-OBSSourceFilter -FilterName $addSplat.FilterName -SourceName $addSplat.SourceName - # and re-add our result. - $outputAddedResult = Add-OBSInput @addSplat *>&1 - } else { - # Otherwise, get the existing filter. - $existingFilter = Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName - # then apply the settings - $existingFilter.Set($addSplat.filterSettings) - # and output them - $existingFilter - # (don't forget to null the result, so we don't show this error) - $outputAddedResult = $null - } - } + // skip if (alpha is zero and only apply to alpha layer is true) + if (!(color.a <= 0.0 && Apply_To_Alpha_Layer == true)) + { + b = BlurStyler(t, 0, c, d, ease); - # If the output was still an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # use $psCmdlet.WriteError so that it shows the error correctly. - $psCmdlet.WriteError($outputAddedResult) - } - - } - # Otherwise, if we had a result - elseif ($outputAddedResult) { - # Otherwise, get the input from the filters. - Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName - - } - - } -} + const int no_colors = 3; + float4 s_color = start_color; + float4 m_color = middle_color; + float4 e_color = end_color; - -#.ExternalHelp obs-powershell-Help.xml -function Set-OBSShaderFilter { - - - [Alias('Add-OBSShaderFilter')] - param( - # The text of the shader - [Parameter(ValueFromPipelineByPropertyName)] - [string]$ShaderText, + if (rotate_colors) + { + // get general time number between 0 and 4 + float tx = (b + 1) * 2; + // 3 steps c1->c2, c2->c3, c3->c1 + //when between 0 - 1 only c1 rises then falls - # The file path to the shader, or the short file name of the shader. - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('ShaderName')] - [string] - $ShaderFile, + if (tx <= 2.0) + { + s_color = lerp(start_color, middle_color, clamp((min(tx, 2.0) * 0.5) * 2, 0.0, 1.0)); + m_color = lerp(middle_color, end_color, clamp((min(tx, 2.0) * 0.5) * 2, 0.0, 1.0)); + e_color = lerp(end_color, start_color, clamp((min(tx, 2.0) * 0.5) * 2, 0.0, 1.0)); + } - # Any other settings for the shader. - # To see what the name of a shader setting is, change it in the user interface and then get the input's filters. - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('ShaderSettings')] - [PSObject] - $ShaderSetting, + if ((tx >= 1.0) && (tx <= 3.0)) + { + s_color = lerp(middle_color, end_color, clamp(((min(max(1.0, tx), 3.0) - 1) * 0.5) * 2, 0.0, 1.0)); + m_color = lerp(end_color, start_color, clamp(((min(max(1.0, tx), 3.0) - 1) * 0.5) * 2, 0.0, 1.0)); + e_color = lerp(start_color, middle_color, clamp(((min(max(1.0, tx), 3.0) - 1) * 0.5) * 2, 0.0, 1.0)); + } - # If set, will remove a filter if one already exists. - # If this is not provided and the filter already exists, the settings of the filter will be changed. - [switch] - $Force - ) - dynamicParam { - $baseCommand = - if (-not $script:AddOBSSourceFilter) { - $script:AddOBSSourceFilter = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSSourceFilter','Function') - $script:AddOBSSourceFilter - } else { - $script:AddOBSSourceFilter - } - $IncludeParameter = @() - $ExcludeParameter = 'FilterKind','FilterSettings' + if (tx >= 2.0) + { + s_color = lerp(end_color, start_color, clamp(((min(2.0, tx) - 2) * 0.5) * 2, 0.0, 1.0)); + m_color = lerp(start_color, middle_color, clamp(((min(2.0, tx) - 2) * 0.5) * 2, 0.0, 1.0)); + e_color = lerp(middle_color, end_color, clamp(((min(2.0, tx) - 2) * 0.5) * 2, 0.0, 1.0)); + } + if (tx < 0) + { + s_color = lerp(end_color, start_color, clamp(abs(max(1.0, tx)) * 2, 0.0, 1.0)); + m_color = lerp(start_color, middle_color, clamp(abs(max(1.0, tx)) * 2, 0.0, 1.0)); + e_color = lerp(middle_color, end_color, clamp(abs(max(1.0, tx)) * 2, 0.0, 1.0)); + } + } - $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() - :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { - if ($ExcludeParameter) { - foreach ($exclude in $ExcludeParameter) { - if ($paramName -like $exclude) { continue nextInputParameter} - } - } - if ($IncludeParameter) { - $shouldInclude = - foreach ($include in $IncludeParameter) { - if ($paramName -like $include) { $true;break} - } - if (-not $shouldInclude) { continue nextInputParameter } - } - - $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( - $baseCommand.Parameters[$paramName].Name, - $baseCommand.Parameters[$paramName].ParameterType, - $baseCommand.Parameters[$paramName].Attributes - )) - } - $DynamicParameters + float4 colors[no_colors]; + colors[0] =s_color; + colors[1] = m_color; + colors[2] = e_color; + float step[no_colors]; + step[0] = start_step; + step[1] = middle_step; + step[2] = end_step; - } - process { - $myParameters = [Ordered]@{} + $PSBoundParameters - - if (-not $myParameters["FilterName"]) { - $filterName = $myParameters["FilterName"] = "Shader" - } + float redness = max(min(color.r - color.g, color.r - color.b) / color.r, 0); + float greenness = max(min(color.g - color.r, color.g - color.b) / color.g, 0); + float blueness = max(min(color.b - color.r, color.b - color.g) / color.b, 0); - $shaderSettings = [Ordered]@{} - if ($ShaderText) { - $shaderSettings.shader_text = $ShaderText + float dist = distance(v_in.uv, gradient_center); + if (horizontal && (vertical == false)) + { + dist = distance(v_in.uv.y, gradient_center.y); + } + if (vertical && (horizontal == false)) + { + dist = distance(v_in.uv.x, gradient_center.x); + } + + float4 col = colors[0]; + for (int i = 1; i < no_colors; ++i) { + col = lerp(col, colors[i], smoothstep(step[i - 1], step[i], dist)); + } + col.a = clamp(alpha, 0.0, 1.0); + if (Apply_To_Alpha_Layer == false) + color.a = alpha; + if (Apply_To_Specific_Color) + { + col.a = alpha; + float4 original_color = image.Sample(textureSampler, v_in.uv); + col.rgb = (distance(color.rgb, Color_To_Replace.rgb) <= 0.075) ? col.rgb : original_color.rgb; } - elseif ($ShaderFile) { - if ($ShaderFile -match '[\\/]') { - $shaderSettings.shader_file_name = "$($ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($ShaderFile))" -replace "\\", "/" - } else { - if (-not $script:CachedOBSShaderFilters) { - $script:CachedOBSShaderFilters = - Get-OBS | # Get the OBS object - Select-Object -ExpandProperty Process | # which has a process - Split-Path | Split-Path | Split-Path | # from it's parent path, we go up three levels. - Join-Path -ChildPath data | Join-Path -ChildPath obs-plugins | # then down into plugin data. - Get-ChildItem -Filter obs-shaderfilter | - Get-ChildItem -Filter examples | - Get-ChildItem -File # get all of the files in this directory + // result = float4(redness, greenness,blueness,1); + //color *= float4(col.r, col.g, col.b, clamp(dot(color, luminance)* alpha, 0.0, 1.0)); + //color.rgb += col * alpha; + //color.a += clamp(1.0 - alpha, 0.0,1.0); + ///color.rgb *= (color.rgb * clamp(1.0- alpha, 0.0, 1.0)) + (col.rgb * clamp(alpha, 0.0, 1.0)); + //color = float4(max(color.r, col.r), max(color.g, col.g), max(color.b, col.b), clamp(dot(color, luminance) * alpha, 0.0, 1.0)); + color.rgb = lerp(color.rgb, col.rgb, clamp(alpha, 0.0, 1.0)); - } + } + return color; - $foundShaderFile = $script:CachedOBSShaderFilters | - Where-Object Name -Like "$shaderFile*" | - Select-Object -First 1 + +} - if ($foundShaderFile) { - $shaderSettings.shader_file_name = $foundShaderFile.FullName -replace "\\", "/" - } +' +} +$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 } - - if ($shaderSetting) { - if ($shaderSetting -is [Collections.IDictionary]) { - foreach ($kv in $shaderSetting.GetEnumerator()) { - $shaderSettings[$kv.Key] = $kv.Value - } - } elseif ($shaderSetting -is [psobject]) { - foreach ($prop in $shaderSetting.psobject.properties) { - $shaderSettings[$prop.Name] = $prop.Value + } + '(?>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 ($shaderSettings.shader_file_name) { - $shaderSettings.from_file = $true + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - - - $addSplat = @{ - filterName = $myParameters["FilterName"] - SourceName = $myParameters["SourceName"] - filterKind = "shader_filter" - filterSettings = $shaderSettings - NoResponse = $myParameters["NoResponse"] + + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName } - if ($MyParameters["PassThru"]) { - $addSplat.Passthru = $MyParameters["PassThru"] - if ($MyInvocation.InvocationName -like 'Add-*') { - Add-OBSSourceFilter @addSplat - } else { - $addSplat.Remove('FilterKind') - Set-OBSSourceFilterSettings @addSplat + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } - return } - # Add the filter. - $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 - - # If we got back an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # and that error was saying the source already exists, - if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { - # then check if we use the -Force. - if ($Force) { # If we do, remove the input - Remove-OBSSourceFilter -FilterName $addSplat.FilterName -SourceName $addSplat.SourceName - # and re-add our result. - $outputAddedResult = Add-OBSInput @addSplat *>&1 - } else { - # Otherwise, get the existing filter. - $existingFilter = Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName - # then apply the settings - $existingFilter.Set($addSplat.filterSettings) - # and output them - $existingFilter - # (don't forget to null the result, so we don't show this error) - $outputAddedResult = $null - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} + } - # If the output was still an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # use $psCmdlet.WriteError so that it shows the error correctly. - $psCmdlet.WriteError($outputAddedResult) - } - + 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 } - # Otherwise, if we had a result - elseif ($outputAddedResult) { - # Otherwise, get the input from the filters. - Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName - + 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 } - } } +} + + +} #.ExternalHelp obs-powershell-Help.xml -function Set-OBSSharpnessFilter { - - - [Alias('Add-OBSSharpnessFilter')] - param( - # The Sharpness. - [Parameter(ValueFromPipelineByPropertyName)] - [ComponentModel.DefaultBindingProperty("sharpness")] - [ValidateRange(0,1)] - [double] - $Sharpness, +function Get-OBSHalftoneShader { - # If set, will remove a filter if one already exists. - # If this is not provided and the filter already exists, the settings of the filter will be changed. - [switch] - $Force - ) - dynamicParam { - $baseCommand = - if (-not $script:AddOBSSourceFilter) { - $script:AddOBSSourceFilter = - $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSSourceFilter','Function') - $script:AddOBSSourceFilter - } else { - $script:AddOBSSourceFilter - } - $IncludeParameter = @() - $ExcludeParameter = 'FilterKind','FilterSettings' +[Alias('Set-OBSHalftoneShader','Add-OBSHalftoneShader')] +param( +# Set the threshold of OBSHalftoneShader +[ComponentModel.DefaultBindingProperty('threshold')] +[Single] +$Threshold, +# 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 +) - $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() - :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { - if ($ExcludeParameter) { - foreach ($exclude in $ExcludeParameter) { - if ($paramName -like $exclude) { continue nextInputParameter} +process { +$shaderName = 'halftone' +$ShaderNoun = 'OBSHalftoneShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +#define PI 3.1415926535897932384626433832795 +#define PI180 float(PI / 180.0) + +uniform float threshold< + string label = "Threshold"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.6; + +float sind(float a) +{ + return sin(a * PI180); +} + +float cosd(float a) +{ + return cos(a * PI180); +} + +float added(float2 sh, float sa, float ca, float2 c, float d) +{ + return 0.5 + 0.25 * cos((sh.x * sa + sh.y * ca + c.x) * d) + 0.25 * cos((sh.x * ca - sh.y * sa + c.y) * d); +} + +float4 mainImage(VertData v_in) : TARGET +{ + // Halftone dot matrix shader + // @author Tomek Augustyn 2010 + + // Ported from my old PixelBender experiment + // https://github.com/og2t/HiSlope/blob/master/src/hislope/pbk/fx/halftone/Halftone.pbk + + float coordX = v_in.uv.x; + float coordY = v_in.uv.y; + float2 dstCoord = float2(coordX, coordY); + float2 rotationCenter = float2(0.5, 0.5); + float2 shift = dstCoord - rotationCenter; + + float dotSize = 3.0; + float angle = 45.0; + + float rasterPattern = added(shift, sind(angle), cosd(angle), rotationCenter, PI / dotSize * 680.0); + float4 srcPixel = image.Sample(textureSampler, dstCoord); + + float avg = 0.2125 * srcPixel.r + 0.7154 * srcPixel.g + 0.0721 * srcPixel.b; + float gray = (rasterPattern * threshold + avg - threshold) / (1.0 - threshold); + + // uncomment to see how the raster pattern looks + // gray = rasterPattern; + + return float4(gray, gray, gray, 1.0); +} +' +} +$MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 +if (-not $myNoun) { + $myNoun = $myVerb + $myVerb = 'Get' +} +switch -regex ($myVerb) { + Get { + $FilterNamePattern = "(?>$( + if ($FilterName) { + [Regex]::Escape($FilterName) } - } - if ($IncludeParameter) { - $shouldInclude = - foreach ($include in $IncludeParameter) { - if ($paramName -like $include) { $true;break} - } - if (-not $shouldInclude) { continue nextInputParameter } - } - - $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( - $baseCommand.Parameters[$paramName].Name, - $baseCommand.Parameters[$paramName].ParameterType, - $baseCommand.Parameters[$paramName].Attributes - )) + 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 + } } - $DynamicParameters - + 'Remove' { + if ($SourceName) { + Get-OBSInput | + Where-Object InputName -eq $SourceName | + Get-OBSSourceFilterList | + Where-Object FilterName -Match $FilterNamePattern | + Remove-OBSSourceFilter + } } - process { - $myParameters = [Ordered]@{} + $PSBoundParameters - - if (-not $myParameters["FilterName"]) { - $filterName = $myParameters["FilterName"] = "Sharpness" + '(?>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 + } } - - $myParameterData = [Ordered]@{} - foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { - $bindToPropertyName = $null - - foreach ($attribute in $parameter.Attributes) { - if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { - $bindToPropertyName = $attribute.Name - break - } - } + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName + } - if (-not $bindToPropertyName) { continue } - if ($myParameters.Contains($parameter.Name)) { - $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] - if ($myParameters[$parameter.Name] -is [switch]) { - $myParameterData[$bindToPropertyName] = $parameter.Name -as [bool] - } - } - } - - $addSplat = @{ - filterName = $myParameters["FilterName"] - SourceName = $myParameters["SourceName"] - filterKind = "Sharpness_filter" - filterSettings = $myParameterData - NoResponse = $myParameters["NoResponse"] + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName } - if ($MyParameters["PassThru"]) { - $addSplat.Passthru = $MyParameters["PassThru"] - if ($MyInvocation.InvocationName -like 'Add-*') { - Add-OBSSourceFilter @addSplat - } else { - $addSplat.Remove('FilterKind') - Set-OBSSourceFilterSettings @addSplat + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } - return } - # Add the input. - $outputAddedResult = Add-OBSSourceFilter @addSplat *>&1 - - # If we got back an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # and that error was saying the source already exists, - if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { - # then check if we use the -Force. - if ($Force) { # If we do, remove the input - Remove-OBSSourceFilter -FilterName $addSplat.FilterName -SourceName $addSplat.SourceName - # and re-add our result. - $outputAddedResult = Add-OBSInput @addSplat *>&1 - } else { - # Otherwise, get the existing filter. - $existingFilter = Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName - # then apply the settings - $existingFilter.Set($addSplat.filterSettings) - # and output them - $existingFilter - # (don't forget to null the result, so we don't show this error) - $outputAddedResult = $null - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} + } - # If the output was still an error - if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { - # use $psCmdlet.WriteError so that it shows the error correctly. - $psCmdlet.WriteError($outputAddedResult) - } - + 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 } - # Otherwise, if we had a result - elseif ($outputAddedResult) { - # Otherwise, get the input from the filters. - Get-OBSSourceFilter -SourceName $addSplat.SourceName -FilterName $addSplat.FilterName - + 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 } - } } +} + + +} #.ExternalHelp obs-powershell-Help.xml -function Add-OBSInput { - +function Get-OBSHardBlinkShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'CreateInput')] -[Alias('obs.powershell.websocket.CreateInput')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSHardBlinkShader','Add-OBSHardBlinkShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputKind')] -[string] -$InputKind, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputSettings')] -[PSObject] -$InputSettings, - +# Set the timeon of OBSHardBlinkShader +[ComponentModel.DefaultBindingProperty('timeon')] +[Single] +$Timeon, +# Set the timeoff of OBSHardBlinkShader +[ComponentModel.DefaultBindingProperty('timeoff')] +[Single] +$Timeoff, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemEnabled')] -[switch] -$SceneItemEnabled, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'hard_blink' +$ShaderNoun = 'OBSHardBlinkShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// hard_blink shader created by https://github.com/WhazzItToYa +// +// Periodically makes the source image 100% transparent, in configurable intervals. +uniform float timeon< + string label = "Time On"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 0.5; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +uniform float timeoff< + string label = "Time Off"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 0.5; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +float4 mainImage(VertData v_in) : TARGET +{ + float4 color = image.Sample(textureSampler, v_in.uv); + float m = timeon + timeoff; + float t = elapsed_time % m; + if (t < timeon) { + return color; + } else { + return float4(color.r, color.g, color.b, 0.0); + } +} - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } +' +} +$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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -45232,105 +42204,212 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Add-OBSProfile { - +function Get-OBSHeatWaveSimpleShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'CreateProfile')] -[Alias('obs.powershell.websocket.CreateProfile')] +[Alias('Set-OBSHeatWaveSimpleShader','Add-OBSHeatWaveSimpleShader')] param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('profileName')] -[string] -$ProfileName, -# If set, will return the information that would otherwise be sent to OBS. +# Set the Rate of OBSHeatWaveSimpleShader +[ComponentModel.DefaultBindingProperty('Rate')] +[Single] +$Rate, +# Set the Strength of OBSHeatWaveSimpleShader +[ComponentModel.DefaultBindingProperty('Strength')] +[Single] +$Strength, +# Set the Distortion of OBSHeatWaveSimpleShader +[ComponentModel.DefaultBindingProperty('Distortion')] +[Single] +$Distortion, +# Set the Opacity of OBSHeatWaveSimpleShader +[ComponentModel.DefaultBindingProperty('Opacity')] +[Single] +$Opacity, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'heat-wave-simple' +$ShaderNoun = 'OBSHeatWaveSimpleShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Heat Wave Simple, Version 0.03, for OBS Shaderfilter +// Copyright ©️ 2022 by SkeletonBow +// License: GNU General Public License, version 2 +// +// Contact info: +// Twitter: +// Twitch: +// +// Description: +// Generate a crude pseudo heat wave displacement on an image source. +// +// Based on: https://www.shadertoy.com/view/td3GRn by Dombass +// +// Changelog: +// 0.03 - Added Opacity control +// 0.02 - Added crude Rate, Strength, and Distortion controls +// 0.01 - Initial release + +uniform float Rate< + string label = "Rate"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.1; +> = 5.0; +uniform float Strength< + string label = "Strength"; + string widget_type = "slider"; + float minimum = -25.0; + float maximum = 25.0; + float step = 0.01; +> = 1.0; +uniform float Distortion< + string label = "Distortion"; + string widget_type = "slider"; + float minimum = 3.0; + float maximum = 20.0; + float step = 0.01; +> = 10.0; +uniform float Opacity< + string label = "Opacity"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 100.00; +float4 mainImage( VertData v_in ) : TARGET +{ + float2 uv = v_in.uv; + float distort = clamp(Distortion, 3.0, 20.0); - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + // Time varying pixel color + float jacked_time = Rate*elapsed_time; + float2 scale = float2(0.5, 0.5); + float str = clamp(Strength, -25.0, 25.0) * 0.01; + + uv += str * sin(scale*jacked_time + length( uv ) * distort); + float4 c = image.Sample( textureSampler, uv); + c.a *= saturate(Opacity*0.01); + return c; +} + +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -45339,213 +42418,321 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Add-OBSScene { - +function Get-OBSHexagonShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'CreateScene')] -[Alias('obs.powershell.websocket.CreateScene')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSHexagonShader','Add-OBSHexagonShader')] param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, -# If set, will return the information that would otherwise be sent to OBS. +# Set the Hex_Color of OBSHexagonShader +[Alias('Hex_Color')] +[ComponentModel.DefaultBindingProperty('Hex_Color')] +[String] +$HexColor, +# Set the Alpha_Percent of OBSHexagonShader +[Alias('Alpha_Percent')] +[ComponentModel.DefaultBindingProperty('Alpha_Percent')] +[Int32] +$AlphaPercent, +# Set the Quantity of OBSHexagonShader +[ComponentModel.DefaultBindingProperty('Quantity')] +[Single] +$Quantity, +# Set the Border_Width of OBSHexagonShader +[Alias('Border_Width')] +[ComponentModel.DefaultBindingProperty('Border_Width')] +[Int32] +$BorderWidth, +# Set the Blend of OBSHexagonShader +[ComponentModel.DefaultBindingProperty('Blend')] +[Management.Automation.SwitchParameter] +$Blend, +# Set the Equilateral of OBSHexagonShader +[ComponentModel.DefaultBindingProperty('Equilateral')] +[Management.Automation.SwitchParameter] +$Equilateral, +# Set the Zoom_Animate of OBSHexagonShader +[Alias('Zoom_Animate')] +[ComponentModel.DefaultBindingProperty('Zoom_Animate')] +[Management.Automation.SwitchParameter] +$ZoomAnimate, +# Set the Speed_Percent of OBSHexagonShader +[Alias('Speed_Percent')] +[ComponentModel.DefaultBindingProperty('Speed_Percent')] +[Int32] +$SpeedPercent, +# Set the Glitch of OBSHexagonShader +[ComponentModel.DefaultBindingProperty('Glitch')] +[Management.Automation.SwitchParameter] +$Glitch, +# Set the Distort_X of OBSHexagonShader +[Alias('Distort_X')] +[ComponentModel.DefaultBindingProperty('Distort_X')] +[Single] +$DistortX, +# Set the Distort_Y of OBSHexagonShader +[Alias('Distort_Y')] +[ComponentModel.DefaultBindingProperty('Distort_Y')] +[Single] +$DistortY, +# Set the Offset_X of OBSHexagonShader +[Alias('Offset_X')] +[ComponentModel.DefaultBindingProperty('Offset_X')] +[Single] +$OffsetX, +# Set the Offset_Y of OBSHexagonShader +[Alias('Offset_Y')] +[ComponentModel.DefaultBindingProperty('Offset_Y')] +[Single] +$OffsetY, +# Set the notes of OBSHexagonShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'hexagon' +$ShaderNoun = 'OBSHexagonShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Hexagon shader by Charles Fettinger for obs-shaderfilter plugin 4/2019 +//https://github.com/Oncorporation/obs-shaderfilter +//Converted to OpenGL by Q-mii & Exeldro February 25, 2022 +uniform float4 Hex_Color; +uniform int Alpha_Percent< + string label = "Alpha percent"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 100; +uniform float Quantity< + string label = "Quantity"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 25; +uniform int Border_Width< + string label = "Border Width"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 115; + int step = 1; +> = 15; // <- -15 to 85, -15 off top +uniform bool Blend; +uniform bool Equilateral; +uniform bool Zoom_Animate; +uniform int Speed_Percent< + string label = "Speed Percent"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 100; +uniform bool Glitch; +uniform float Distort_X< + string label = "Distort X"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.01; +> = 1.0; +uniform float Distort_Y< + string label = "Distort Y"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.01; +> = 1.0; +uniform float Offset_X< + string label = "Offset X"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; +uniform float Offset_Y< + string label = "Offset X"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; +uniform string notes< + string widget_type = "info"; +>= "Tiles:equilateral: around 12.33,nonequilateral: square rootable number. Distort of 1 is normal."; - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } - +float mod(float x, float y) +{ + return x - y * floor(x/y); } +float2 mod2(float2 x, float2 y) +{ + return x - y * floor(x/y); +} -} - - -#.ExternalHelp obs-powershell-Help.xml -function Add-OBSSceneCollection { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'CreateSceneCollection')] -[Alias('obs.powershell.websocket.CreateSceneCollection')] -param( +// 0 on edges, 1 in non_edge +float hex(float2 p) { + float xyratio = 1; + if (Equilateral) + xyratio = uv_size.x /uv_size.y; -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneCollectionName')] -[string] -$SceneCollectionName, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + // calc p + p.x = mul(p.x,xyratio); + p.y += mod(floor(p.x) , 2.0)*0.5; + p = abs((mod2(p , float2(1.0, 1.0)) - 0.5)); + return abs(max(p.x*1.5 + p.y, p.y*2.0) -1); +} +float4 mainImage(VertData v_in) : TARGET +{ + float4 rgba = image.Sample(textureSampler, v_in.uv * uv_scale + uv_offset); + float alpha = float(Alpha_Percent) * 0.01; + float quantity = sqrt(clamp(Quantity, 0.0, 100.0)); + float border_width = clamp(float(Border_Width - 15), -15, 100) * 0.01; + float speed = float(Speed_Percent) * 0.01; + float time = (1 + sin(elapsed_time * speed))*0.5; + if (Zoom_Animate) + quantity *= time; -process { + // create a (pos)ition reference, hex radius and smoothstep out the non_edge + float2 pos = float2(v_in.uv.x * max(0,Distort_X), (1 - v_in.uv.y) * max(0,Distort_Y)) * uv_scale + uv_offset + float2(Offset_X, Offset_Y); + if (Glitch) + quantity *= lerp(pos.x, pos.y, rand_f); + float2 p = (pos * quantity); // number of hexes to be created + float r = (1.0 -0.7)*0.5; // cell default radius + float non_edge = smoothstep(0.0, r + border_width, hex(p)); // approach border become edge + // make the border colorable - non_edge is scaled + float4 c = float4(non_edge, non_edge,non_edge,1.0) ; + if (non_edge < 1) + { + c = Hex_Color; + c.a = alpha; + if (Blend) + c = lerp(rgba, c, 1 - non_edge); + return lerp(rgba,c,alpha); + } + return lerp(rgba, c * rgba, alpha); +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -45554,254 +42741,316 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Add-OBSSceneItem { - +function Get-OBSHslHsvSaturationShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'CreateSceneItem')] -[Alias('obs.powershell.websocket.CreateSceneItem')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -[Alias('Add-OBSSceneSource')] +[Alias('Set-OBSHslHsvSaturationShader','Add-OBSHslHsvSaturationShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, - +# Set the hslSaturationFactor of OBSHslHsvSaturationShader +[ComponentModel.DefaultBindingProperty('hslSaturationFactor')] +[Single] +$HslSaturationFactor, +# Set the hslGamma of OBSHslHsvSaturationShader +[ComponentModel.DefaultBindingProperty('hslGamma')] +[Single] +$HslGamma, +# Set the hsvSaturationFactor of OBSHslHsvSaturationShader +[ComponentModel.DefaultBindingProperty('hsvSaturationFactor')] +[Single] +$HsvSaturationFactor, +# Set the hsvGamma of OBSHslHsvSaturationShader +[ComponentModel.DefaultBindingProperty('hsvGamma')] +[Single] +$HsvGamma, +# Set the adjustmentOrder of OBSHslHsvSaturationShader +[ComponentModel.DefaultBindingProperty('adjustmentOrder')] +[Int32] +$AdjustmentOrder, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceName')] -[string] +[Alias('SceneItemName')] +[String] $SourceName, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceUuid')] -[string] -$SourceUuid, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemEnabled')] -[switch] -$SceneItemEnabled, -# If set, will return the information that would otherwise be sent to OBS. +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'hsl_hsv_saturation' +$ShaderNoun = 'OBSHslHsvSaturationShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Adjusted Saturation Shader for obs-shaderfilter using HLSL conventions - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +uniform float hslSaturationFactor< + string label = "HSL Sat Gain"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 5.0; + float step = 0.01; +> = 1.0; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +uniform float hslGamma< + string label = "HSL Sat Gamma"; + string widget_type = "slider"; + float minimum = 0.1; + float maximum = 10.0; + float step = 0.01; +> = 1.0; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } +uniform float hsvSaturationFactor< + string label = "HSV Sat Gain"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 5.0; + float step = 0.01; +> = 1.0; - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } +uniform float hsvGamma< + string label = "HSV Sat Gamma"; + string widget_type = "slider"; + float minimum = 0.1; + float maximum = 10.0; + float step = 0.01; +> = 1.0; - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } +uniform int adjustmentOrder< + string label = "Order"; + string widget_type = "select"; + int option_0_value = 1; + string option_0_label = "Parallel adjustment (both HSL and HSV operate on the original image and then blend)"; + int option_1_value = 2; + string option_1_label = "HSL first, then HSV"; + int option_2_value = 3; + string option_2_label = "HSV first, then HSL"; +> = 1; + +// HSV conversion + +float3 rgb2hsv(float3 c) { + float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g)); + float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} +float3 hsv2rgb(float3 c) { + float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * lerp(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); } +// HSL conversion -} +float3 rgb2hsl(float3 c) { + float maxVal = max(c.r, max(c.g, c.b)); + float minVal = min(c.r, min(c.g, c.b)); + float delta = maxVal - minVal; + float h = 0.0; + float s = 0.0; + float l = (maxVal + minVal) / 2.0; - -#.ExternalHelp obs-powershell-Help.xml -function Add-OBSSourceFilter { + if(delta != 0) { + if(l < 0.5) s = delta / (maxVal + minVal); + else s = delta / (2.0 - maxVal - minVal); + if(c.r == maxVal) h = (c.g - c.b) / delta + (c.g < c.b ? 6.0 : 0.0); + else if(c.g == maxVal) h = (c.b - c.r) / delta + 2.0; + else h = (c.r - c.g) / delta + 4.0; -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'CreateSourceFilter')] -[Alias('obs.powershell.websocket.CreateSourceFilter')] -param( + h /= 6.0; + } -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceName')] -[string] -$SourceName, + return float3(h, s, l); +} -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceUuid')] -[string] -$SourceUuid, +float hue2rgb(float p, float q, float t) { + if(t < 0.0) t += 1.0; + if(t > 1.0) t -= 1.0; + if(t < 1.0/6.0) return p + (q - p) * 6.0 * t; + if(t < 1.0/2.0) return q; + if(t < 2.0/3.0) return p + (q - p) * (2.0/3.0 - t) * 6.0; + return p; +} -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('filterName')] -[string] -$FilterName, +float3 hsl2rgb(float3 c) { + float r, g, b; -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('filterKind')] -[string] -$FilterKind, + if(c.y == 0.0) { + r = g = b = c.z; + } else { + float q = c.z < 0.5 ? c.z * (1.0 + c.y) : c.z + c.y - c.z * c.y; + float p = 2.0 * c.z - q; + r = hue2rgb(p, q, c.x + 1.0/3.0); + g = hue2rgb(p, q, c.x); + b = hue2rgb(p, q, c.x - 1.0/3.0); + } -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('filterSettings')] -[PSObject] -$FilterSettings, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + return float3(r, g, b); +} +float3 adjustColorWithOrder(float3 originalColor) { + if (adjustmentOrder == 1) { + // Parallel adjustment (both HSL and HSV operate on the original image and then blend) + float3 hslAdjusted = rgb2hsl(originalColor); + hslAdjusted.y = pow(hslAdjusted.y, (1/hslGamma)); + hslAdjusted.y *= hslSaturationFactor; + float3 hslAdjustedColor = hsl2rgb(hslAdjusted); + + float3 hsvAdjusted = rgb2hsv(originalColor); + hsvAdjusted.y = pow(hsvAdjusted.y, (1/hsvGamma)); + hsvAdjusted.y *= hsvSaturationFactor; + float3 hsvAdjustedColor = hsv2rgb(hsvAdjusted); + + float3 finalColor = (hslAdjustedColor + hsvAdjustedColor) * 0.5; + return finalColor; + } + else if (adjustmentOrder == 2) { + // HSL first, then HSV + float3 hslAdjusted = rgb2hsl(originalColor); + hslAdjusted.y = pow(hslAdjusted.y, (1/hslGamma)); + hslAdjusted.y *= hslSaturationFactor; + float3 afterHSL = hsl2rgb(hslAdjusted); + float3 hsvAdjusted = rgb2hsv(afterHSL); + hsvAdjusted.y = pow(hsvAdjusted.y, (1/hsvGamma)); + hsvAdjusted.y *= hsvSaturationFactor; + return hsv2rgb(hsvAdjusted); + } + else if (adjustmentOrder == 3) { + // HSV first, then HSL + float3 hsvAdjusted = rgb2hsv(originalColor); + hsvAdjusted.y = pow(hsvAdjusted.y, (1/hsvGamma)); + hsvAdjusted.y *= hsvSaturationFactor; + float3 afterHSV = hsv2rgb(hsvAdjusted); + float3 hslAdjusted = rgb2hsl(afterHSV); + hslAdjusted.y = pow(hslAdjusted.y, (1/hslGamma)); + hslAdjusted.y *= hslSaturationFactor; + return hsl2rgb(hslAdjusted); + } + return originalColor; // Default to original color in case of unexpected values +} -process { +// Final composite +float4 mainImage(VertData v_in) : TARGET +{ + float3 originalColor = image.Sample(textureSampler, v_in.uv).rgb; + float3 adjustedColor = adjustColorWithOrder(originalColor); + return float4(adjustedColor, 1.0); // preserving the original alpha +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -45810,127 +43059,235 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Copy-OBSSceneItem { - +function Get-OBSHueRotatonShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'DuplicateSceneItem')] -[Alias('obs.powershell.websocket.DuplicateSceneItem')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSHueRotatonShader','Add-OBSHueRotatonShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemId')] -[ValidateRange(0,[int]::MaxValue)] -[double] -$SceneItemId, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('destinationSceneName')] -[string] -$DestinationSceneName, - +# Set the Speed of OBSHueRotatonShader +[ComponentModel.DefaultBindingProperty('Speed')] +[Single] +$Speed, +# Set the Hue_Override of OBSHueRotatonShader +[Alias('Hue_Override')] +[ComponentModel.DefaultBindingProperty('Hue_Override')] +[Management.Automation.SwitchParameter] +$HueOverride, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('destinationSceneUuid')] -[string] -$DestinationSceneUuid, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'hue-rotaton' +$ShaderNoun = 'OBSHueRotatonShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Hue Rotation shader, version 1.0 for OBS Shaderfilter +// Copyright ©️ 2023 by SkeletonBow +// License: GNU General Public License, version 2 +// +// Contact info: +// Twitter: +// Twitch: +// YouTube: +// Soundcloud: +// +// Description: +// Rotates hue of input at a user configurable speed. Negative speed values reverse rotation. A hue +// override option is provided to force a specific rotating hue instead of the original image''s hue. +// +// Changelog: +// 1.0 - Initial release +/* + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +uniform float Speed< + string label = "Speed"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.001; +> = 10.00; +uniform bool Hue_Override = false; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } +float3 HUEtoRGB(in float H) +{ + float R = abs(H * 6 - 3) - 1; + float G = 2 - abs(H * 6 - 2); + float B = 2 - abs(H * 6 - 4); + return saturate(float3(R,G,B)); +} + +#define Epsilon 1e-10 + +float3 RGBtoHCV(in float3 RGB) +{ + // Based on work by Sam Hocevar and Emil Persson + float4 P = (RGB.g < RGB.b) ? float4(RGB.bg, -1.0, 2.0/3.0) : float4(RGB.gb, 0.0, -1.0/3.0); + float4 Q = (RGB.r < P.x) ? float4(P.xyw, RGB.r) : float4(RGB.r, P.yzx); + float C = Q.x - min(Q.w, Q.y); + float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z); + return float3(H, C, Q.x); +} + +float3 HSVtoRGB(in float3 HSV) +{ + float3 RGB = HUEtoRGB(HSV.x); + return ((RGB - 1) * HSV.y + 1) * HSV.z; +} + +float3 RGBtoHSV(in float3 RGB) +{ + float3 HCV = RGBtoHCV(RGB); + float S = HCV.y / (HCV.z + Epsilon); + return float3(HCV.x, S, HCV.z); +} + +float4 mainImage( VertData v_in ) : TARGET +{ + float2 uv = v_in.uv; + float4 col_in = image.Sample(textureSampler, uv); + float3 col_out; + float3 HSV = RGBtoHSV(col_in.rgb); + + if(Hue_Override) + HSV.x = elapsed_time * Speed * 0.01; + else + HSV.x += elapsed_time * Speed * 0.01; + + // Normalize Hue + HSV.x = frac(HSV.x); + + col_out = HSVtoRGB(HSV); + return float4(col_out, col_in.a); +} + +' +} +$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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -45939,204 +43296,192 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSCurrentPreviewScene { - +function Get-OBSIntensityScopeShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetCurrentPreviewScene')] -[Alias('obs.powershell.websocket.GetCurrentPreviewScene')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSIntensityScopeShader','Add-OBSIntensityScopeShader')] param( -# If set, will return the information that would otherwise be sent to OBS. +# Set the gain of OBSIntensityScopeShader +[ComponentModel.DefaultBindingProperty('gain')] +[Single] +$Gain, +# Set the blend of OBSIntensityScopeShader +[ComponentModel.DefaultBindingProperty('blend')] +[Single] +$Blend, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'intensity-scope' +$ShaderNoun = 'OBSIntensityScopeShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Robin Green, Dec 2016 +// Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. +// https://www.shadertoy.com/view/XtcSRs adopted for OBS by Exeldro +uniform float gain< + string label = "Gain"; + string widget_type = "slider"; + float minimum = 0.01; + float maximum = 1.00; + float step = 0.01; +> = 0.3; +uniform float blend< + string label = "Blend"; + string widget_type = "slider"; + float minimum = 0.00; + float maximum = 1.00; + float step = 0.01; +> = 0.6; +float4 mainImage(VertData v_in) : TARGET +{ + float2 uv = v_in.uv; + uv.y = 1.0 - uv.y; + + // calculate the intensity bucket for this pixel based on column height (padded at the top) + const float max_value = 270.0; + const float buckets = 512.0; + float bucket_min = log( max_value * floor(uv.y * buckets) / buckets ); + float bucket_max = log( max_value * floor((uv.y * buckets) + 1.0) / buckets ); + + // count the count the r,g,b and luma in this column that match the bucket + float4 count = float4(0.0, 0.0, 0.0, 0.0); + for( int i=0; i < 512; ++i ) { + float j = float(i) / buckets; + float4 pixel = image.Sample(textureSampler, float2(uv.x, j )) * 256.0; + + // calculate the Rec.709 luma for this pixel + pixel.a = pixel.r * 0.2126 + pixel.g * 0.7152 + pixel.b * 0.0722; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + float4 logpixel = log(pixel); + if( logpixel.r >= bucket_min && logpixel.r < bucket_max) count.r += 1.0; + if( logpixel.g >= bucket_min && logpixel.g < bucket_max) count.g += 1.0; + if( logpixel.b >= bucket_min && logpixel.b < bucket_max) count.b += 1.0; + if( logpixel.a >= bucket_min && logpixel.a < bucket_max) count.a += 1.0; + } + + // sum luma into RGB, tweak log intensity for readability + count.rgb = log(count.rgb * (1.0-blend) + count.aaa * blend) * gain; + + // output + return count; +} +' +} +$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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + continue nextParameter + } } - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSCurrentProgramScene { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetCurrentProgramScene')] -[Alias('obs.powershell.websocket.GetCurrentProgramScene')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -46145,204 +43490,266 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSCurrentSceneTransition { - +function Get-OBSInvertLumaShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetCurrentSceneTransition')] -[Alias('obs.powershell.websocket.GetCurrentSceneTransition')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSInvertLumaShader','Add-OBSInvertLumaShader')] param( -# If set, will return the information that would otherwise be sent to OBS. +# Set the Invert_Color of OBSInvertLumaShader +[Alias('Invert_Color')] +[ComponentModel.DefaultBindingProperty('Invert_Color')] +[Management.Automation.SwitchParameter] +$InvertColor, +# Set the Invert_Luma of OBSInvertLumaShader +[Alias('Invert_Luma')] +[ComponentModel.DefaultBindingProperty('Invert_Luma')] +[Management.Automation.SwitchParameter] +$InvertLuma, +# Set the Gamma_Correction of OBSInvertLumaShader +[Alias('Gamma_Correction')] +[ComponentModel.DefaultBindingProperty('Gamma_Correction')] +[Management.Automation.SwitchParameter] +$GammaCorrection, +# Set the Test_Ramp of OBSInvertLumaShader +[Alias('Test_Ramp')] +[ComponentModel.DefaultBindingProperty('Test_Ramp')] +[Management.Automation.SwitchParameter] +$TestRamp, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'invert-luma' +$ShaderNoun = 'OBSInvertLumaShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Invert shader 1.0 - for OBS Shaderfilter +// Copyright 2021 by SkeletonBow +// https://twitter.com/skeletonbowtv +// https://twitch.tv/skeletonbowtv +// Performs RGB color inversion or YUV luma inversion with optional sRGB gamma handling - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } +uniform bool Invert_Color = false; +uniform bool Invert_Luma = true; +uniform bool Gamma_Correction = true; +uniform bool Test_Ramp = false; +float3 encodeSRGB(float3 linearRGB) +{ + float3 a = float3(12.92,12.92,12.92) * linearRGB; + float3 b = float3(1.055,1.055,1.055) * pow(linearRGB, float3(1.0 / 2.4,1.0 / 2.4,1.0 / 2.4)) - float3(0.055,0.055,0.055); + float3 c = step(float3(0.0031308,0.0031308,0.0031308), linearRGB); + return float3(lerp(a, b, c)); } +float3 decodeSRGB(float3 screenRGB) +{ + float3 a = screenRGB / float3(12.92,12.92,12.92); + float3 b = pow((screenRGB + float3(0.055,0.055,0.055)) / float3(1.055,1.055,1.055), float3(2.4,2.4,2.4)); + float3 c = step(float3(0.04045,0.04045,0.04045), screenRGB); + return float3(lerp(a, b, c)); +} -} - - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSCurrentSceneTransitionCursor { - +float3 HUEtoRGB(in float H) +{ + float R = abs(H * 6 - 3) - 1; + float G = 2 - abs(H * 6 - 2); + float B = 2 - abs(H * 6 - 4); + return float3(clamp(float3(R,G,B), float3(0.0, 0.0, 0.0), float3(1.0, 1.0, 1.0))); +} -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetCurrentSceneTransitionCursor')] -[Alias('obs.powershell.websocket.GetCurrentSceneTransitionCursor')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) +float3 RGBtoYUV(float3 color) +{ + // YUV matriz (BT709 luma coefficients) +#ifdef OPENGL + float3x3 toYUV = float3x3( + float3(0.2126, -0.09991, 0.615), + float3(0.7152, -0.33609, -0.55861), + float3(0.0722, 0.436, -0.05639)); +#else + float3x3 toYUV = { + { 0.2126, -0.09991, 0.615 }, + { 0.7152, -0.33609, -0.55861 }, + { 0.0722, 0.436, -0.05639 }, + }; +#endif + return mul(color, toYUV); +} +float3 YUVtoRGB(float3 color) +{ + // YUV matriz (BT709) +#ifdef OPENGL + float3x3 fromYUV = float3x3( + float3(1.000, 1.000, 1.000), + float3(0.0, -0.21482, 2.12798), + float3(1.28033, -0.38059, 0.0)); +#else + float3x3 fromYUV = { + { 1.000, 1.000, 1.000 }, + { 0.0, -0.21482, 2.12798 }, + { 1.28033, -0.38059, 0.0 }, + }; +#endif + return mul(color, fromYUV); +} -process { +float3 generate_ramps(float3 color, float2 uv) +{ + float3 ramp = float3(0.0, 0.0, 0.0); + if(uv.y < 0.2) + ramp.r = uv.x; // Red ramp + else if(uv.y < 0.4) + ramp.g = uv.x; // Green ramp + else if(uv.y < 0.6) + ramp.b = uv.x; // Blue ramp + else if(uv.y < 0.8) + ramp = float3(uv.x, uv.x, uv.x); // Grey ramp + else + ramp = HUEtoRGB(uv.x); // Hue rainbow + + return ramp; +} +float4 mainImage( VertData v_in ) : TARGET +{ + float2 uv = v_in.uv; + float4 obstex = image.Sample( textureSampler, uv ); + float3 color = obstex.rgb; + // Apply sRGB gamma transfer encode + if(Gamma_Correction) color = encodeSRGB( color ); + // Override display with test patterns to visually see what is happening + if( Test_Ramp ) color = generate_ramps( obstex.rgb, uv ); + // RGB color invert + if( Invert_Color ) { + color = float3(1.0, 1.0, 1.0) - color; + } + // YUV luma invert + if( Invert_Luma ) { + float3 yuv = RGBtoYUV( color ); + yuv.x = 1.0 - yuv.x; + color = YUVtoRGB(yuv); + } + // Apply sRGB gamma transfer decode + if(Gamma_Correction) color = decodeSRGB( color ); + return float4(color, obstex.a); +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -46351,101 +43758,240 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSGroup { - +function Get-OBSLuminance2Shader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetGroupList')] -[Alias('obs.powershell.websocket.GetGroupList')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSLuminance2Shader','Add-OBSLuminance2Shader')] param( -# If set, will return the information that would otherwise be sent to OBS. +# Set the color of OBSLuminance2Shader +[ComponentModel.DefaultBindingProperty('color')] +[String] +$Color, +# Set the lumaMax of OBSLuminance2Shader +[ComponentModel.DefaultBindingProperty('lumaMax')] +[Single] +$LumaMax, +# Set the lumaMin of OBSLuminance2Shader +[ComponentModel.DefaultBindingProperty('lumaMin')] +[Single] +$LumaMin, +# Set the lumaMaxSmooth of OBSLuminance2Shader +[ComponentModel.DefaultBindingProperty('lumaMaxSmooth')] +[Single] +$LumaMaxSmooth, +# Set the lumaMinSmooth of OBSLuminance2Shader +[ComponentModel.DefaultBindingProperty('lumaMinSmooth')] +[Single] +$LumaMinSmooth, +# Set the invertImageColor of OBSLuminance2Shader +[ComponentModel.DefaultBindingProperty('invertImageColor')] +[Management.Automation.SwitchParameter] +$InvertImageColor, +# Set the invertAlphaChannel of OBSLuminance2Shader +[ComponentModel.DefaultBindingProperty('invertAlphaChannel')] +[Management.Automation.SwitchParameter] +$InvertAlphaChannel, +# Set the notes of OBSLuminance2Shader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'luminance2' +$ShaderNoun = 'OBSLuminance2Shader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//Converted to OpenGL by Q-mii & Exeldro February 25, 2022 +uniform float4 color; +uniform float lumaMax< + string label = "Luma Max"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 1.05; +uniform float lumaMin< + string label = "Luma Min"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 0.01; +uniform float lumaMaxSmooth< + string label = "Luma Max Smooth"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 0.10; +uniform float lumaMinSmooth< + string label = "Luma Min Smooth"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 0.01; +uniform bool invertImageColor; +uniform bool invertAlphaChannel; +uniform string notes< + string widget_type = "info"; +> = "''luma max'' - anything above will be transparent. ''luma min'' - anything below will be transparent. ''luma(min or max)Smooth - make the transparency fade in or out by a distance. ''invert color'' - inverts the color of the screen. ''invert alpha channel'' - flips all settings on thier head, which is excellent for testing."; +float4 InvertColor(float4 rgba_in) +{ + rgba_in.r = 1.0 - rgba_in.r; + rgba_in.g = 1.0 - rgba_in.g; + rgba_in.b = 1.0 - rgba_in.b; + rgba_in.a = 1.0 - rgba_in.a; + return rgba_in; +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float4 mainImage(VertData v_in) : TARGET +{ - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + float4 rgba = image.Sample(textureSampler, v_in.uv); + if (rgba.a > 0.0) + { + + if (invertImageColor) + { + rgba = InvertColor(rgba); + } + float luminance = rgba.r * color.r * 0.299 + rgba.g * color.g * 0.587 + rgba.b * color.b * 0.114; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + //intensity = min(max(intensity,minIntensity),maxIntensity); + float clo = smoothstep(lumaMin, lumaMin + lumaMinSmooth, luminance); + float chi = 1. - smoothstep(lumaMax - lumaMaxSmooth, lumaMax, luminance); + + float amask = clo * chi; + + if (invertAlphaChannel) + { + amask = 1.0 - amask; + } + rgba *= color; + rgba.a = clamp(amask, 0.0, 1.0); + + } + return rgba; +} + +' +} +$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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -46454,214 +44000,298 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSGroupSceneItem { - +function Get-OBSLuminanceAlphaShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetGroupSceneItemList')] -[Alias('obs.powershell.websocket.GetGroupSceneItemList')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSLuminanceAlphaShader','Add-OBSLuminanceAlphaShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, - +# Set the ViewProj of OBSLuminanceAlphaShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the image of OBSLuminanceAlphaShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the elapsed_time of OBSLuminanceAlphaShader +[Alias('elapsed_time')] +[ComponentModel.DefaultBindingProperty('elapsed_time')] +[Single] +$ElapsedTime, +# Set the uv_offset of OBSLuminanceAlphaShader +[Alias('uv_offset')] +[ComponentModel.DefaultBindingProperty('uv_offset')] +[Single[]] +$UvOffset, +# Set the uv_scale of OBSLuminanceAlphaShader +[Alias('uv_scale')] +[ComponentModel.DefaultBindingProperty('uv_scale')] +[Single[]] +$UvScale, +# Set the uv_pixel_interval of OBSLuminanceAlphaShader +[Alias('uv_pixel_interval')] +[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +[Single[]] +$UvPixelInterval, +# Set the rand_f of OBSLuminanceAlphaShader +[Alias('rand_f')] +[ComponentModel.DefaultBindingProperty('rand_f')] +[Single] +$RandF, +# Set the uv_size of OBSLuminanceAlphaShader +[Alias('uv_size')] +[ComponentModel.DefaultBindingProperty('uv_size')] +[Single[]] +$UvSize, +# Set the color_matrix of OBSLuminanceAlphaShader +[Alias('color_matrix')] +[ComponentModel.DefaultBindingProperty('color_matrix')] +[Single[][]] +$ColorMatrix, +# Set the color of OBSLuminanceAlphaShader +[ComponentModel.DefaultBindingProperty('color')] +[String] +$Color, +# Set the mul_val of OBSLuminanceAlphaShader +[Alias('mul_val')] +[ComponentModel.DefaultBindingProperty('mul_val')] +[Single] +$MulVal, +# Set the add_val of OBSLuminanceAlphaShader +[Alias('add_val')] +[ComponentModel.DefaultBindingProperty('add_val')] +[Single] +$AddVal, +# Set the level of OBSLuminanceAlphaShader +[ComponentModel.DefaultBindingProperty('level')] +[Single] +$Level, +# Set the invertAlphaChannel of OBSLuminanceAlphaShader +[ComponentModel.DefaultBindingProperty('invertAlphaChannel')] +[Management.Automation.SwitchParameter] +$InvertAlphaChannel, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'luminance_alpha' +$ShaderNoun = 'OBSLuminanceAlphaShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Luminance Alpha Effect By Charles Fettinger (https://github.com/Oncorporation) 2/2019 +//Converted to OpenGL by Q-mii & Exeldro February 22, 2022 +uniform float4x4 ViewProj; +uniform texture2d image; +uniform float elapsed_time; +uniform float2 uv_offset; +uniform float2 uv_scale; +uniform float2 uv_pixel_interval; +uniform float rand_f; +uniform float2 uv_size; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } - -} +uniform float4x4 color_matrix; +uniform float4 color; +uniform float mul_val< + string label = "Mulitply"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 1.0; +uniform float add_val< + string label = "Add"; + string widget_type = "slider"; + float minimum = -10.0; + float maximum = 10.0; + float step = 0.001; +> = 0.0; +uniform float level< + string label = "Level"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> =1.0; +uniform bool invertAlphaChannel; +sampler_state textureSampler { + Filter = Linear; + AddressU = Border; + AddressV = Border; + BorderColor = 00000000; +}; -} +struct VertDataIn { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSHotkey { +struct VertDataOut { + float4 pos : POSITION; + float2 uv : TEXCOORD0; + float2 uv2 : TEXCOORD1; +}; +VertDataOut mainTransform(VertDataIn v_in) +{ + VertDataOut vert_out; + vert_out.pos = mul(float4(v_in.pos.xyz, 1.0 ), ViewProj); + vert_out.uv = v_in.uv * mul_val + add_val; + vert_out.uv2 = v_in.uv ; + return vert_out; +} -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetHotkeyList')] -[Alias('obs.powershell.websocket.GetHotkeyList')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) +/*float3 GetLuminance(float4 rgba) +{ + float red = rbga.r; + float green = rgba.g; + float blue = rgba.b; + return (.299 * red) + (.587 * green) + (.114 * blue); +}*/ +float4 PSAlphaMaskRGBA(VertDataOut v_in) : TARGET +{ + float4 rgba = image.Sample(textureSampler, v_in.uv) ; + if (rgba.a > 0.0) + { + + float intensity = rgba.r * color.r * 0.299 + rgba.g * color.g * 0.587 + rgba.b * color.b * 0.114; + if (invertAlphaChannel) + { + intensity = 1.0 - intensity; + } + rgba *= color; + rgba.a = clamp((intensity * level), 0.0, 1.0); + + } + return rgba; +} -process { +technique Draw +{ + pass + { + vertex_shader = mainTransform(v_in); + pixel_shader = PSAlphaMaskRGBA(v_in); + } +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -46670,219 +44300,205 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSInput { - +function Get-OBSLuminanceShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputList')] -[Alias('obs.powershell.websocket.GetInputList')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSLuminanceShader','Add-OBSLuminanceShader')] param( - +# Set the color of OBSLuminanceShader +[ComponentModel.DefaultBindingProperty('color')] +[String] +$Color, +# Set the level of OBSLuminanceShader +[ComponentModel.DefaultBindingProperty('level')] +[Single] +$Level, +# Set the invertImageColor of OBSLuminanceShader +[ComponentModel.DefaultBindingProperty('invertImageColor')] +[Management.Automation.SwitchParameter] +$InvertImageColor, +# Set the invertAlphaChannel of OBSLuminanceShader +[ComponentModel.DefaultBindingProperty('invertAlphaChannel')] +[Management.Automation.SwitchParameter] +$InvertAlphaChannel, +# Set the notes of OBSLuminanceShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputKind')] -[string] -$InputKind, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'Luminance' +$ShaderNoun = 'OBSLuminanceShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//Converted to OpenGL by Exeldro February 22, 2022 +uniform float4 color; +uniform float level< + string label = "Level"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.01; +> = 1.0; +uniform bool invertImageColor; +uniform bool invertAlphaChannel; +uniform string notes< + string widget_type = "info"; +> = "''color'' - the color to add to the original image. Multiplies the color against the original color giving it a tint. White represents no tint. ''invertImageColor'' - - inverts the color of the screen, great for testing and fine tuning. ''level'' - transparency amount modifier where 1.0 = base luminance (recommend 0.00 - 10.00). ''invertAlphaChannel'' - flip what is transparent from darks (default) to lights"; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } - +float4 InvertColor(float4 rgba_in) +{ + rgba_in.r = 1.0 - rgba_in.r; + rgba_in.g = 1.0 - rgba_in.g; + rgba_in.b = 1.0 - rgba_in.b; + rgba_in.a = 1.0 - rgba_in.a; + return rgba_in; } +float4 mainImage(VertData v_in) : TARGET +{ -} - - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSInputAudioBalance { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputAudioBalance')] -[Alias('obs.powershell.websocket.GetInputAudioBalance')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + float4 rgba = image.Sample(textureSampler, v_in.uv); + if (rgba.a > 0.0) + { + + if (invertImageColor) + { + rgba = InvertColor(rgba); + } + float intensity = rgba.r * color.r * 0.299 + rgba.g * color.g * 0.587 + rgba.b * color.b * 0.114; + //intensity = min(max(intensity,minIntensity),maxIntensity); -process { + if (invertAlphaChannel) + { + intensity = 1.0 - intensity; + } + rgba *= color; + rgba.a = clamp((intensity * level), 0.0, 1.0); + + } + return rgba; +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -46891,445 +44507,439 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSInputAudioMonitorType { - +function Get-OBSMatrixShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputAudioMonitorType')] -[Alias('obs.powershell.websocket.GetInputAudioMonitorType')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSMatrixShader','Add-OBSMatrixShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - +# Set the ViewProj of OBSMatrixShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the image of OBSMatrixShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the elapsed_time of OBSMatrixShader +[Alias('elapsed_time')] +[ComponentModel.DefaultBindingProperty('elapsed_time')] +[Single] +$ElapsedTime, +# Set the uv_offset of OBSMatrixShader +[Alias('uv_offset')] +[ComponentModel.DefaultBindingProperty('uv_offset')] +[Single[]] +$UvOffset, +# Set the uv_scale of OBSMatrixShader +[Alias('uv_scale')] +[ComponentModel.DefaultBindingProperty('uv_scale')] +[Single[]] +$UvScale, +# Set the uv_size of OBSMatrixShader +[Alias('uv_size')] +[ComponentModel.DefaultBindingProperty('uv_size')] +[Single[]] +$UvSize, +# Set the uv_pixel_interval of OBSMatrixShader +[Alias('uv_pixel_interval')] +[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +[Single[]] +$UvPixelInterval, +# Set the rand_f of OBSMatrixShader +[Alias('rand_f')] +[ComponentModel.DefaultBindingProperty('rand_f')] +[Single] +$RandF, +# Set the rand_instance_f of OBSMatrixShader +[Alias('rand_instance_f')] +[ComponentModel.DefaultBindingProperty('rand_instance_f')] +[Single] +$RandInstanceF, +# Set the rand_activation_f of OBSMatrixShader +[Alias('rand_activation_f')] +[ComponentModel.DefaultBindingProperty('rand_activation_f')] +[Single] +$RandActivationF, +# Set the loops of OBSMatrixShader +[ComponentModel.DefaultBindingProperty('loops')] +[Int32] +$Loops, +# Set the local_time of OBSMatrixShader +[Alias('local_time')] +[ComponentModel.DefaultBindingProperty('local_time')] +[Single] +$LocalTime, +# Set the mouse of OBSMatrixShader +[ComponentModel.DefaultBindingProperty('mouse')] +[Single[]] +$Mouse, +# Set the Invert_Direction of OBSMatrixShader +[Alias('Invert_Direction')] +[ComponentModel.DefaultBindingProperty('Invert_Direction')] +[Management.Automation.SwitchParameter] +$InvertDirection, +# Set the lumaMin of OBSMatrixShader +[ComponentModel.DefaultBindingProperty('lumaMin')] +[Single] +$LumaMin, +# Set the lumaMinSmooth of OBSMatrixShader +[ComponentModel.DefaultBindingProperty('lumaMinSmooth')] +[Single] +$LumaMinSmooth, +# Set the Ratio of OBSMatrixShader +[ComponentModel.DefaultBindingProperty('Ratio')] +[Single] +$Ratio, +# Set the Alpha_Percentage of OBSMatrixShader +[Alias('Alpha_Percentage')] +[ComponentModel.DefaultBindingProperty('Alpha_Percentage')] +[Single] +$AlphaPercentage, +# Set the Apply_To_Alpha_Layer of OBSMatrixShader +[Alias('Apply_To_Alpha_Layer')] +[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] +[Management.Automation.SwitchParameter] +$ApplyToAlphaLayer, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'matrix' +$ShaderNoun = 'OBSMatrixShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Matrix effect by Charles Fettinger for obs-shaderfilter plugin 7/2020 v.2 +// https://github.com/Oncorporation/obs-shaderfilter +// https://www.shadertoy.com/view/XljBW3 The cat is a glitch (Matrix) - coverted from and updated +#define vec2 float2 +#define vec3 float3 +#define vec4 float4 +#define ivec2 int2 +#define ivec3 int3 +#define ivec4 int4 +#define mat2 float2x2 +#define mat3 float3x3 +#define mat4 float4x4 +#define fract frac +#define mix lerp +#define iTime float - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +uniform float4x4 ViewProj; +uniform texture2d image; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +uniform float elapsed_time; +uniform float2 uv_offset; +uniform float2 uv_scale; +uniform float2 uv_size; +uniform float2 uv_pixel_interval; +uniform float rand_f; +uniform float rand_instance_f; +uniform float rand_activation_f; +uniform int loops; +uniform float local_time; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } +uniform float2 mouse< + string label = "Virtual Mouse Coordinates"; + string widget_type = "slider"; + float2 minimum = {0, 0}; + float2 maximum = {100., 100.}; + float2 scale = {.01, .01}; + float2 step = {.01, .01}; +> = {0., 0.}; - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } +int2 iMouse() { + return int2(mouse.x * uv_size.x, mouse.y * uv_size.y); } +sampler_state textureSampler { + Filter = Linear; + AddressU = Clamp; + AddressV = Clamp; +}; -} - - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSInputAudioSyncOffset { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputAudioSyncOffset')] -[Alias('obs.powershell.websocket.GetInputAudioSyncOffset')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - +/* ps start -process { +*/ +uniform bool Invert_Direction< + string label = "Invert Direction"; +> = true; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +uniform float lumaMin< + string label = "Luma Min"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 0.01; +uniform float lumaMinSmooth< + string label = "Luma Min Smooth"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 0.01; +uniform float Ratio< + string label = "Ratio"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 4.0; +uniform float Alpha_Percentage< + string label = "Alpha Percentage"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 100; // +uniform bool Apply_To_Alpha_Layer = true; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +#define PI2 6.28318530718 +#define PI 3.1416 - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" +float vorocloud(float2 p){ + float f = 0.0; + float flow = 1.0; + float time = elapsed_time; + if(Invert_Direction){ + flow *= -1; + } + /* + //periodically stop + if (loops % 16 >= 8.0) + { + time = local_time - elapsed_time; + } + */ + + float r = clamp(Ratio,-50,50); + float2 pp = cos(float2(p.x * 14.0, (16.0 * p.y + cos(floor(p.x * 30.0)) + flow * time * PI2)) ); + p = cos(p * 12.1 + pp * r + sin(time/PI)*(r/PI) + 0.5 * cos(pp.x * r + sin(time/PI)*(r/PI))); - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } - + float2 pts[4]; + + pts[0] = float2(0.5, 0.6); + pts[1] = float2(-0.4, 0.4); + pts[2] = float2(0.2, -0.7); + pts[3] = float2(-0.3, -0.4); + + float d = 5.0; + + for(int i = 0; i < 4; i++){ + pts[i].x += 0.03 * cos(float(i)) + p.x; + pts[i].y += 0.03 * sin(float(i)) + p.y; + d = min(d, distance(pts[i], pp)); + } + + f = 2.0 * pow(1.0 - 0.3 * d, 13.0); + + f = min(f, 1.0); + + return f; } +vec4 scene(float2 UV){ + float alpha = clamp(Alpha_Percentage *.01 ,0,1.0); -} - - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSInputAudioTracks { - + float x = UV.x; + float y = UV.y; + + float2 p = float2(x, y) - 0.5; + + vec4 col = vec4(0.0,0.0,0.0,0.0); + col.g += 0.02; + + float v = vorocloud(p); + v = 0.2 * floor(v * 5.0); + + col.r += 0.1 * v; + col.g += 0.6 * v; + col.b += 0.5 * pow(v, 5.0); + + + v = vorocloud(p * 2.0); + v = 0.2 * floor(v * 5.0); + + col.r += 0.1 * v; + col.g += 0.2 * v; + col.b += 0.01 * pow(v, 5.0); + + col.a = 1.0; + float luma = dot(col.rgb,float3(0.299,0.587,0.114)); + float luma_min = smoothstep(lumaMin, lumaMin + lumaMinSmooth, luma); + col.a = clamp(luma_min,0.0,1.0); -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputAudioTracks')] -[Alias('obs.powershell.websocket.GetInputAudioTracks')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( + float4 original_color = image.Sample(textureSampler, UV); + + // skip if (alpha is zero and only apply to alpha layer is true) + if (!(original_color.a <= 0.0 && Apply_To_Alpha_Layer == true)) + { + if (Apply_To_Alpha_Layer == false) + original_color.a = alpha; + + col.rgb = lerp(original_color.rgb, col.rgb, alpha); //apply alpha slider + col = lerp(original_color, col, col.a); //remove black background color + } + else + { + col.a = original_color.a; + } -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, + return col; +} -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 uv = fragCoord.xy / uv_size; + fragColor = scene(uv); +} +/*ps end*/ -process { +struct VertFragData { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; +VertFragData VSDefault(VertFragData vtx) { + vtx.pos = mul(float4(vtx.pos.xyz, 1.0), ViewProj); + return vtx; +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float4 PSDefault(VertFragData vtx) : TARGET { + float4 col = float4(1., 1., 1., 1.); + mainImage(col, vtx.uv * uv_size); + return col; +} - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +technique Draw +{ + pass + { + vertex_shader = VSDefault(vtx); + pixel_shader = PSDefault(vtx); + } +} - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } +' +} +$MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 +if (-not $myNoun) { + $myNoun = $myVerb + $myVerb = 'Get' +} +switch -regex ($myVerb) { + Get { + $FilterNamePattern = "(?>$( + if ($FilterName) { + [Regex]::Escape($FilterName) } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } + 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 } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + } + '(?>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 ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSInputDefaultSettings { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputDefaultSettings')] -[Alias('obs.powershell.websocket.GetInputDefaultSettings')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputKind')] -[string] -$InputKind, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -47338,106 +44948,155 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSInputKind { +function Get-OBSMotionBlurShader { - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputKindList')] -[Alias('obs.powershell.websocket.GetInputKindList')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSMotionBlurShader','Add-OBSMotionBlurShader')] param( - +# Set the previous_output of OBSMotionBlurShader +[Alias('previous_output')] +[ComponentModel.DefaultBindingProperty('previous_output')] +[String] +$PreviousOutput, +# Set the strength of OBSMotionBlurShader +[ComponentModel.DefaultBindingProperty('strength')] +[Single] +$Strength, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('unversioned')] -[switch] -$Unversioned, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'motion_blur' +$ShaderNoun = 'OBSMotionBlurShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform texture2d previous_output; +uniform float strength< + string label = "strength"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} +float4 mainImage(VertData v_in) : TARGET +{ + return lerp(image.Sample(textureSampler, v_in.uv), previous_output.Sample(textureSampler, v_in.uv), 1.0 - pow(2, -7 * strength)); +} +' +} +$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 } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } + } + '(?>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 + } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + } } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -47446,111 +45105,147 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSInputMute { - +function Get-OBSMultiplyShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputMute')] -[Alias('obs.powershell.websocket.GetInputMute')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSMultiplyShader','Add-OBSMultiplyShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - +# Set the other_image of OBSMultiplyShader +[Alias('other_image')] +[ComponentModel.DefaultBindingProperty('other_image')] +[String] +$OtherImage, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'multiply' +$ShaderNoun = 'OBSMultiplyShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform texture2d other_image; +float4 mainImage(VertData v_in) : TARGET +{ + float4 other = other_image.Sample(textureSampler, v_in.uv); + float4 base = image.Sample(textureSampler, v_in.uv); + return base * other; +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -47559,229 +45254,511 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSInputPropertiesListPropertyItems { - +function Get-OBSNightSkyShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputPropertiesListPropertyItems')] -[Alias('obs.powershell.websocket.GetInputPropertiesListPropertyItems')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSNightSkyShader','Add-OBSNightSkyShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - +# Set the speed of OBSNightSkyShader +[ComponentModel.DefaultBindingProperty('speed')] +[Single] +$Speed, +# Set the Include_Clouds of OBSNightSkyShader +[Alias('Include_Clouds')] +[ComponentModel.DefaultBindingProperty('Include_Clouds')] +[Management.Automation.SwitchParameter] +$IncludeClouds, +# Set the Include_Moon of OBSNightSkyShader +[Alias('Include_Moon')] +[ComponentModel.DefaultBindingProperty('Include_Moon')] +[Management.Automation.SwitchParameter] +$IncludeMoon, +# Set the center_width_percentage of OBSNightSkyShader +[Alias('center_width_percentage')] +[ComponentModel.DefaultBindingProperty('center_width_percentage')] +[Int32] +$CenterWidthPercentage, +# Set the center_height_percentage of OBSNightSkyShader +[Alias('center_height_percentage')] +[ComponentModel.DefaultBindingProperty('center_height_percentage')] +[Int32] +$CenterHeightPercentage, +# Set the Alpha_Percentage of OBSNightSkyShader +[Alias('Alpha_Percentage')] +[ComponentModel.DefaultBindingProperty('Alpha_Percentage')] +[Single] +$AlphaPercentage, +# Set the Apply_To_Image of OBSNightSkyShader +[Alias('Apply_To_Image')] +[ComponentModel.DefaultBindingProperty('Apply_To_Image')] +[Management.Automation.SwitchParameter] +$ApplyToImage, +# Set the Replace_Image_Color of OBSNightSkyShader +[Alias('Replace_Image_Color')] +[ComponentModel.DefaultBindingProperty('Replace_Image_Color')] +[Management.Automation.SwitchParameter] +$ReplaceImageColor, +# Set the number_stars of OBSNightSkyShader +[Alias('number_stars')] +[ComponentModel.DefaultBindingProperty('number_stars')] +[Int32] +$NumberStars, +# Set the SKY_COLOR of OBSNightSkyShader +[Alias('SKY_COLOR')] +[ComponentModel.DefaultBindingProperty('SKY_COLOR')] +[String] +$SKYCOLOR, +# Set the STAR_COLOR of OBSNightSkyShader +[Alias('STAR_COLOR')] +[ComponentModel.DefaultBindingProperty('STAR_COLOR')] +[String] +$STARCOLOR, +# Set the LIGHT_SKY of OBSNightSkyShader +[Alias('LIGHT_SKY')] +[ComponentModel.DefaultBindingProperty('LIGHT_SKY')] +[String] +$LIGHTSKY, +# Set the SKY_LIGHTNESS of OBSNightSkyShader +[Alias('SKY_LIGHTNESS')] +[ComponentModel.DefaultBindingProperty('SKY_LIGHTNESS')] +[Single] +$SKYLIGHTNESS, +# Set the MOON_COLOR of OBSNightSkyShader +[Alias('MOON_COLOR')] +[ComponentModel.DefaultBindingProperty('MOON_COLOR')] +[String] +$MOONCOLOR, +# Set the moon_size of OBSNightSkyShader +[Alias('moon_size')] +[ComponentModel.DefaultBindingProperty('moon_size')] +[Single] +$MoonSize, +# Set the moon_bump_size of OBSNightSkyShader +[Alias('moon_bump_size')] +[ComponentModel.DefaultBindingProperty('moon_bump_size')] +[Single] +$MoonBumpSize, +# Set the Moon_Position_x of OBSNightSkyShader +[Alias('Moon_Position_x')] +[ComponentModel.DefaultBindingProperty('Moon_Position_x')] +[Single] +$MoonPositionX, +# Set the Moon_Position_y of OBSNightSkyShader +[Alias('Moon_Position_y')] +[ComponentModel.DefaultBindingProperty('Moon_Position_y')] +[Single] +$MoonPositionY, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('propertyName')] -[string] -$PropertyName, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'night_sky' +$ShaderNoun = 'OBSNightSkyShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Night Sky shader by Charles Fettinger for obs-shaderfilter plugin 6/2020 v.65 +// https://github.com/Oncorporation/obs-shaderfilter +//https://www.shadertoy.com/view/3tfXRM Simple Night Sky - converted from and updated +//Converted to OpenGL by Q-mii & Exeldro February 22, 2022 +uniform float speed< + string label = "Speed"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 20.0; +uniform bool Include_Clouds = true; +uniform bool Include_Moon = true; +uniform int center_width_percentage< + string label = "Center width percentage"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform int center_height_percentage< + string label = "Center width percentage"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform float Alpha_Percentage< + string label = "Alpha Percentage"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 95.0; // +uniform bool Apply_To_Image = false; +uniform bool Replace_Image_Color = false; +uniform int number_stars< + string label = "Number stars"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 20; // +uniform float4 SKY_COLOR = { 0.027, 0.151, 0.354, 1.0 }; +uniform float4 STAR_COLOR = { 0.92, 0.92, 0.14, 1.0 }; +uniform float4 LIGHT_SKY = { 0.45, 0.61, 0.98, 1.0 }; +uniform float SKY_LIGHTNESS< + string label = "SKY LIGHTNESS"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = .3; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + // Moon +uniform float4 MOON_COLOR = { .4, .25, 0.25, 1.0 }; +uniform float moon_size< + string label = "Moon size"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.18; +uniform float moon_bump_size< + string label = "Moon bump size"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.14; +uniform float Moon_Position_x< + string label = "Moon Position x"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = -0.6; +uniform float Moon_Position_y< + string label = "Moon Position y"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = -0.3; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +#define PI 3.1416 + +//Noise functions from https://www.youtube.com/watch?v=zXsWftRdsvU +float noise11(float p) { + return frac(sin(p*633.1847) * 9827.95); +} + +float noise21(float2 p) { + return frac(sin(p.x*827.221 + p.y*3228.8275) * 878.121); +} + +float2 noise22(float2 p) { + return frac(float2(sin(p.x*9378.35), sin(p.y*75.589)) * 556.89); +} + +//From https://codepen.io/Tobsta/post/procedural-generation-part-1-1d-perlin-noise +float cosineInterpolation(float a, float b, float x) { + float ft = x * PI; + float f = (1. - cos(ft)) * .5; + return a * (1. - f) + b * f; +} + +float smoothNoise11(float p, float dist) { + float prev = noise11(p-dist); + float next = noise11(p+dist); + + return cosineInterpolation(prev, next, .5); +} + +float smoothNoise21(float2 uv, float cells) { + float2 lv = frac(uv*cells); + float2 id = floor(uv*cells); + + //smoothstep function: maybe change it later! + lv = lv*lv*(3.-2.*lv); + + float bl = noise21(id); + float br = noise21(id+float2(1.,0.)); + float b = lerp(bl, br, lv.x); + + float tl = noise21(id+float2(0.,1.)); + float tr = noise21(id+float2(1.,1.)); + float t = lerp(tl, tr, lv.x); + + return lerp(b, t, lv.y); +} - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } +float2 smoothNoise22(float2 uv, float cells) { + float2 lv = frac(uv*cells); + float2 id = floor(uv*cells); + + lv = lv*lv*(3.-2.*lv); + + float2 bl = noise22(id); + float2 br = noise22(id+float2(1.,0.)); + float2 b = lerp(bl, br, lv.x); + + float2 tl = noise22(id+float2(0.,1.)); + float2 tr = noise22(id+float2(1.,1.)); + float2 t = lerp(tl, tr, lv.x); + + return lerp(b, t, lv.y); +} - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" +float valueNoise11(float p) { + float c = smoothNoise11(p, 0.5); + c += smoothNoise11(p, 0.25)*.5; + c += smoothNoise11(p, 0.125)*.25; + c += smoothNoise11(p, 0.0625)*.125; - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } + return c /= .875; +} - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } +float valueNoise21(float2 uv) { + float c = smoothNoise21(uv, 4.); + c += smoothNoise21(uv, 8.)*.5; + c += smoothNoise21(uv, 16.)*.25; + c += smoothNoise21(uv, 32.)*.125; + c += smoothNoise21(uv, 64.)*.0625; + + return c /= .9375; +} +float2 valueNoise22(float2 uv) { + float2 c = smoothNoise22(uv, 4.); + c += smoothNoise22(uv, 8.)*.5; + c += smoothNoise22(uv, 16.)*.25; + c += smoothNoise22(uv, 32.)*.125; + c += smoothNoise22(uv, 64.)*.0625; + + return c /= .9375; } +float3 points(float2 p, float2 uv, float3 color, float size, float blur) { + float dist = distance(p, uv); + return color*smoothstep(size, size*(0.999-blur), dist); +} -} +float mapInterval(float x, float a, float b, float c, float d) { + return (x-a)/(b-a) * (d-c) + c; +} - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSInputSettings { +float blink(float time, float timeInterval) { + float halfInterval = timeInterval / 2.0; + //Get relative position in the bucket + float p = fmod(time, timeInterval); + + + if (p <= timeInterval / 2.) { + return smoothstep(0., 1., p/halfInterval); + } else { + return smoothstep(1., 0., (p-halfInterval)/halfInterval); + } +} +float3 sampleBumps(float2 p, float2 uv, float radius, float spin) { + float dist = distance(p, uv); + float3 BumpSamples = float3(0.,0.,0.); + + if (dist < radius) { + float bumps = (1.-valueNoise21(uv*spin))*.1; + BumpSamples = float3(bumps, bumps, bumps); + } + return BumpSamples; +} -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputSettings')] -[Alias('obs.powershell.websocket.GetInputSettings')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( +float4 mainImage(VertData v_in) : TARGET +{ + float4 rgba;// = image.Sample(textureSampler, v_in.uv); + float alpha = clamp(Alpha_Percentage *.01 ,0,1.0); + float2 center_pixel_coordinates = float2((center_width_percentage * 0.01), (center_height_percentage * 0.01)); + float2 st = v_in.uv* uv_scale; + float2 toCenter = center_pixel_coordinates - st; -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, + // Normalized pixel coordinates (from 0 to 1) + float2 uv = v_in.uv; + float2 ouv = uv; + uv -= .5; + uv.x *= uv_size.x/uv_size.y; + + float2 seed = toCenter / uv_size.xy; + + float time = elapsed_time + seed.x*speed; + + //float3 col = float3(0.0); + //float m = valueNoise21(uv); + float3 col = lerp(SKY_COLOR.rgb, LIGHT_SKY.rgb, ouv.y-SKY_LIGHTNESS); + + col *= SKY_LIGHTNESS - (1.-ouv.y); + + //Add clouds + if (Include_Clouds) + { + float2 timeUv = uv; + timeUv.x += time*.1; + timeUv.y += valueNoise11(timeUv.x+.352)*.01; + float cloud = valueNoise21(timeUv); + col += cloud*.1; + } -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + //Add stars in the top part of the scene + float timeInterval = speed *.5; //5.0 + float timeBucket = floor(time / timeInterval); + float2 moonPosition = float2(-1000, -1000); + if (Include_Moon) + { + moonPosition = float2(Moon_Position_x, Moon_Position_y); + col += points(moonPosition, uv, MOON_COLOR.rgb,moon_size, 0.3); + // Moon bumps + col += sampleBumps(moonPosition, uv, moon_bump_size, 9. + fmod(time*.1,9)); + } -process { + for (float i = 0.; i < clamp(number_stars,0,100); i++) { + float2 starPosition = float2(i/10., i/10.); + + starPosition.x = mapInterval(valueNoise11(timeBucket + i*827.913)-.4, 0., 1., 0.825, -0.825); + starPosition.y = mapInterval(valueNoise11(starPosition.x)-.3, 0., 1., 0.445, -0.445); + + float starIntensity = blink(time+ (rand_f * i), timeInterval ); + //Hide stars that are behind the moon + if (distance(starPosition, moonPosition) > moon_size) { + col += points(starPosition, uv, STAR_COLOR.rgb, 0.001, 0.0)*clamp(starIntensity-.1, 0.0, 1.0)*10.0; + col += points(starPosition, uv, STAR_COLOR.rgb, 0.009, 3.5)*starIntensity*3.0; + } + } + //col = float3(blink(time, timeInterval)); + rgba = float4(col,alpha); + // Output to screen + if (Apply_To_Image) + { + float4 color = image.Sample(textureSampler, v_in.uv); + float4 original_color = color; + float luma = color.r * 0.299 + color.g * 0.587 + color.b * 0.114; + if (Replace_Image_Color) + color = float4(luma, luma, luma, luma); + rgba = lerp(original_color, rgba * color,alpha); + + } + return rgba; +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -47790,214 +45767,210 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSInputVolume { - +function Get-OBSNoiseShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetInputVolume')] -[Alias('obs.powershell.websocket.GetInputVolume')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSNoiseShader','Add-OBSNoiseShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - +# Set the speed of OBSNoiseShader +[ComponentModel.DefaultBindingProperty('speed')] +[Single] +$Speed, +# Set the scale of OBSNoiseShader +[ComponentModel.DefaultBindingProperty('scale')] +[Single] +$Scale, +# Set the noiseLevel of OBSNoiseShader +[ComponentModel.DefaultBindingProperty('noiseLevel')] +[Single] +$NoiseLevel, +# Set the monochromatic of OBSNoiseShader +[ComponentModel.DefaultBindingProperty('monochromatic')] +[Management.Automation.SwitchParameter] +$Monochromatic, +# Set the use_rand of OBSNoiseShader +[Alias('use_rand')] +[ComponentModel.DefaultBindingProperty('use_rand')] +[Management.Automation.SwitchParameter] +$UseRand, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'noise' +$ShaderNoun = 'OBSNoiseShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform float speed< + string label = "Speed"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 100; + float step = 0.1; +> = 1; +uniform float scale< + string label = "Scale"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 10; + float step = 0.0001; +> = 6; +uniform float noiseLevel< + string label = "Noise Level"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 1; + float step = 0.001; +> = 1; +uniform bool monochromatic = false; +uniform bool use_rand = false; +float rand(float2 st) +{ + return frac(sin(dot(st.xy, float2(12.9898, 78.233))) * 43758.5453123); +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } - -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSLastReplayBufferReplay { +float4 mainImage(VertData v_in) : TARGET +{ + float time = rand_activation_f + (speed / 60) * elapsed_time * 0.00001; + if (use_rand) { + time = rand_f; + } -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetLastReplayBufferReplay')] -[Alias('obs.powershell.websocket.GetLastReplayBufferReplay')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + float4 x; + if (monochromatic) { + x = rand(float2(v_in.uv.x, v_in.uv.y) * scale + time + scale); + } else { + x = float4( + rand(float2(v_in.uv.x, v_in.uv.y) * scale + time + 1 * scale), + rand(float2(v_in.uv.x, v_in.uv.y) * scale + time + 2 * scale), + rand(float2(v_in.uv.x, v_in.uv.y) * scale + time + 3 * scale), + 1 + ); + } -process { + float4 rgba = image.Sample(textureSampler, v_in.uv); + float3 output = lerp(rgba, x, noiseLevel); - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + return float4(output.r, output.g, output.b, rgba.a); +} +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -48006,111 +45979,254 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSMediaInputStatus { +function Get-OBSNormalMapShader { - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetMediaInputStatus')] -[Alias('obs.powershell.websocket.GetMediaInputStatus')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSNormalMapShader','Add-OBSNormalMapShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - +# Set the strength of OBSNormalMapShader +[ComponentModel.DefaultBindingProperty('strength')] +[Single] +$Strength, +# Set the offsetHeight of OBSNormalMapShader +[ComponentModel.DefaultBindingProperty('offsetHeight')] +[Management.Automation.SwitchParameter] +$OffsetHeight, +# Set the invertR of OBSNormalMapShader +[ComponentModel.DefaultBindingProperty('invertR')] +[Management.Automation.SwitchParameter] +$InvertR, +# Set the invertG of OBSNormalMapShader +[ComponentModel.DefaultBindingProperty('invertG')] +[Management.Automation.SwitchParameter] +$InvertG, +# Set the invertH of OBSNormalMapShader +[ComponentModel.DefaultBindingProperty('invertH')] +[Management.Automation.SwitchParameter] +$InvertH, +# Set the type of OBSNormalMapShader +[ComponentModel.DefaultBindingProperty('type')] +[Int32] +$Type, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'normal_map' +$ShaderNoun = 'OBSNormalMapShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Normal map shader based on cpetry''s NormalMap-Online website +// https://github.com/cpetry/NormalMap-Online/blob/gh-pages/javascripts/shader/NormalMapShader.js +uniform float strength< + string label = "Strength"; + string widget_type = "slider"; + float minimum = 0.001; + float maximum = 10; + float step = 0.001; +> = 1; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +uniform bool offsetHeight = true; +uniform bool invertR = false; +uniform bool invertG = false; +uniform bool invertH = false; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +uniform int type< + string label = "Filter Type"; + string widget_type = "select"; + int option_0_value = 0; + string option_0_label = "Sobel"; + int option_1_value = 1; + string option_1_label = "Scharr"; +> = 0; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } +float4 mainImage( VertData v_in ) : TARGET { + float2 step = float2(1.0, 1.0) / uv_size; + float2 vUv = v_in.uv; + + float dz = 1 / strength; + float dz2 = dz * dz; + + float2 tlv = float2(vUv.x - step.x, vUv.y + step.y); + float2 lv = float2(vUv.x - step.x, vUv.y ); + float2 blv = float2(vUv.x - step.x, vUv.y - step.y); + float2 tv = float2(vUv.x , vUv.y + step.y); + float2 bv = float2(vUv.x , vUv.y - step.y); + float2 trv = float2(vUv.x + step.x, vUv.y + step.y); + float2 rv = float2(vUv.x + step.x, vUv.y ); + float2 brv = float2(vUv.x + step.x, vUv.y - step.y); + + tlv = float2(tlv.x >= 0.0 ? tlv.x : (1.0 + tlv.x), tlv.y >= 0.0 ? tlv.y : (1.0 + tlv.y)); + tlv = float2(tlv.x < 1.0 ? tlv.x : (tlv.x - 1.0 ), tlv.y < 1.0 ? tlv.y : (tlv.y - 1.0 )); + lv = float2( lv.x >= 0.0 ? lv.x : (1.0 + lv.x), lv.y >= 0.0 ? lv.y : (1.0 + lv.y)); + lv = float2( lv.x < 1.0 ? lv.x : ( lv.x - 1.0 ), lv.y < 1.0 ? lv.y : ( lv.y - 1.0 )); + blv = float2(blv.x >= 0.0 ? blv.x : (1.0 + blv.x), blv.y >= 0.0 ? blv.y : (1.0 + blv.y)); + blv = float2(blv.x < 1.0 ? blv.x : (blv.x - 1.0 ), blv.y < 1.0 ? blv.y : (blv.y - 1.0 )); + tv = float2( tv.x >= 0.0 ? tv.x : (1.0 + tv.x), tv.y >= 0.0 ? tv.y : (1.0 + tv.y)); + tv = float2( tv.x < 1.0 ? tv.x : ( tv.x - 1.0 ), tv.y < 1.0 ? tv.y : ( tv.y - 1.0 )); + bv = float2( bv.x >= 0.0 ? bv.x : (1.0 + bv.x), bv.y >= 0.0 ? bv.y : (1.0 + bv.y)); + bv = float2( bv.x < 1.0 ? bv.x : ( bv.x - 1.0 ), bv.y < 1.0 ? bv.y : ( bv.y - 1.0 )); + trv = float2(trv.x >= 0.0 ? trv.x : (1.0 + trv.x), trv.y >= 0.0 ? trv.y : (1.0 + trv.y)); + trv = float2(trv.x < 1.0 ? trv.x : (trv.x - 1.0 ), trv.y < 1.0 ? trv.y : (trv.y - 1.0 )); + rv = float2( rv.x >= 0.0 ? rv.x : (1.0 + rv.x), rv.y >= 0.0 ? rv.y : (1.0 + rv.y)); + rv = float2( rv.x < 1.0 ? rv.x : ( rv.x - 1.0 ), rv.y < 1.0 ? rv.y : ( rv.y - 1.0 )); + brv = float2(brv.x >= 0.0 ? brv.x : (1.0 + brv.x), brv.y >= 0.0 ? brv.y : (1.0 + brv.y)); + brv = float2(brv.x < 1.0 ? brv.x : (brv.x - 1.0 ), brv.y < 1.0 ? brv.y : (brv.y - 1.0 )); + + float tl = image.Sample(textureSampler, tlv).r; + float l = image.Sample(textureSampler, lv ).r; + float bl = image.Sample(textureSampler, blv).r; + float t = image.Sample(textureSampler, tv ).r; + float b = image.Sample(textureSampler, bv ).r; + float tr = image.Sample(textureSampler, trv).r; + float r = image.Sample(textureSampler, rv ).r; + float br = image.Sample(textureSampler, brv).r; + + float dx = 0.0; + float dy = 0.0; + + if(type == 0) { // Sobel + dx = tl + l*2.0 + bl - tr - r*2.0 - br; + dy = tl + t*2.0 + tr - bl - b*2.0 - br; + } + else { // Scharr + dx = tl*3.0 + l*10.0 + bl*3.0 - tr*3.0 - r*10.0 - br*3.0; + dy = tl*3.0 + t*10.0 + tr*3.0 - bl*3.0 - b*10.0 - br*3.0; + } + + float invH = invertH ? -1. : 1.; + float invR = invertR ? -1. : 1.; + float invG = invertG ? -1. : 1.; + + float4 normal = float4( + float3(dx * invR * invH, dy * invG * invH, dz), + image.Sample(textureSampler, vUv).a + ); + + l = sqrt((dx * dx) + (dy * dy) + dz2); + + if (offsetHeight) { + return float4(normal.xy / l * 0.5 + 0.5, normal.zw); + } + + return float4(normal.xyz / l * 0.5 + 0.5, normal.w); +} + +' +} +$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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -48119,101 +46235,155 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSMonitor { - +function Get-OBSOpacityShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetMonitorList')] -[Alias('obs.powershell.websocket.GetMonitorList')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSOpacityShader','Add-OBSOpacityShader')] param( -# If set, will return the information that would otherwise be sent to OBS. +# Set the Opacity of OBSOpacityShader +[ComponentModel.DefaultBindingProperty('Opacity')] +[Single] +$Opacity, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'opacity' +$ShaderNoun = 'OBSOpacityShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Opacity shader - for OBS Shaderfilter +// Copyright 2021 by SkeltonBowTV +// https://twitter.com/skeletonbowtv +// https://twitch.tv/skeletonbowtv +uniform float Opacity< + string label = "Opacity"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 200.0; + float step = 0.01; +> = 100.00; // 0.00 - 100.00 percent - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} +float4 mainImage( VertData v_in ) : TARGET +{ + float4 color = image.Sample( textureSampler, v_in.uv ); + return float4( color.rgb, color.a * Opacity * 0.01 ); +} +' +} +$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 } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } + } + '(?>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 + } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } + 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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -48222,101 +46392,217 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSOutput { - +function Get-OBSPagePeelShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetOutputList')] -[Alias('obs.powershell.websocket.GetOutputList')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSPagePeelShader','Add-OBSPagePeelShader')] param( -# If set, will return the information that would otherwise be sent to OBS. +# Set the Speed of OBSPagePeelShader +[ComponentModel.DefaultBindingProperty('Speed')] +[Single] +$Speed, +# Set the Position of OBSPagePeelShader +[ComponentModel.DefaultBindingProperty('Position')] +[Single] +$Position, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'page-peel' +$ShaderNoun = 'OBSPagePeelShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Simple Page Peel, Version 0.01, for OBS Shaderfilter +// Copyright ©️ 2023 by SkeletonBow +// License: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License +// Contact info: +// Twitter: +// Twitch: +// YouTube: +// Soundcloud: +// +// Based on Shadertoy shader by droozle +// +// Description: +// +// +// Changelog: +// 0.01 - Initial release +uniform float Speed< + string label = "Speed"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 50.0; + float step = 0.001; +> = 1.00; +uniform float Position< + string label = "Position"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.001; +> = 0.0; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float4 mainImage( VertData v_in ) : TARGET +{ + // Normalized pixel coordinates (from 0 to 1) + float2 aspect = float2( uv_size.x / uv_size.y, 1.0 ); + float2 uv = v_in.uv; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + float t = Position + elapsed_time * Speed; + // Define the fold. + float2 origin = float2( 0.6 + 0.4 * sin( t * 0.2 ), 0.5 + 0.5 * cos( t * 0.13 ) ) * aspect; + float2 normal = normalize( float2( 1.0, 2.0 * sin( t * 0.3 ) ) * aspect ); + + // Sample texture. + float3 col = image.Sample( textureSampler, uv ).rgb; // Front color. + + // Check on which side the pixel lies. + float2 pt = uv * aspect - origin; + float side = dot( pt, normal ); + if( side > 0.0 ) { + col *= 0.25; // Background color (peeled off). + + float shadow = smoothstep( 0.0, 0.05, side ); + col = lerp( col * 0.6, col, shadow ); + } + else { + // Find the mirror pixel. + pt = ( uv * aspect - 2.0 * side * normal ) / aspect; + + // Check if we''re still inside the image bounds. + if( pt.x >= 0.0 && pt.x < 1.0 && pt.y >= 0.0 && pt.y < 1.0 ) { + float4 back = image.Sample( textureSampler, pt ); // Back color. + back.rgb = back.rgb * 0.25 + 0.75; + + float shadow = smoothstep( 0.0, 0.2, -side ); + back.rgb = lerp( back.rgb * 0.2, back.rgb, shadow ); + + // Support for transparency. + col = lerp( col, back.rgb, back.a ); } + } + + // Output to screen + return float4(col,1.0); +} - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } +' +} +$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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -48325,106 +46611,230 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSOutputSettings { - +function Get-OBSPagePeelTransitionShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetOutputSettings')] -[Alias('obs.powershell.websocket.GetOutputSettings')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSPagePeelTransitionShader','Add-OBSPagePeelTransitionShader')] param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('outputName')] -[string] -$OutputName, -# If set, will return the information that would otherwise be sent to OBS. +# Set the image_a of OBSPagePeelTransitionShader +[Alias('image_a')] +[ComponentModel.DefaultBindingProperty('image_a')] +[String] +$ImageA, +# Set the image_b of OBSPagePeelTransitionShader +[Alias('image_b')] +[ComponentModel.DefaultBindingProperty('image_b')] +[String] +$ImageB, +# Set the transition_time of OBSPagePeelTransitionShader +[Alias('transition_time')] +[ComponentModel.DefaultBindingProperty('transition_time')] +[Single] +$TransitionTime, +# Set the convert_linear of OBSPagePeelTransitionShader +[Alias('convert_linear')] +[ComponentModel.DefaultBindingProperty('convert_linear')] +[Management.Automation.SwitchParameter] +$ConvertLinear, +# Set the page_color of OBSPagePeelTransitionShader +[Alias('page_color')] +[ComponentModel.DefaultBindingProperty('page_color')] +[String] +$PageColor, +# Set the page_transparency of OBSPagePeelTransitionShader +[Alias('page_transparency')] +[ComponentModel.DefaultBindingProperty('page_transparency')] +[Single] +$PageTransparency, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'page-peel-transition' +$ShaderNoun = 'OBSPagePeelTransitionShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform texture2d image_a; +uniform texture2d image_b; +uniform float transition_time< + string label = "Transittion Time"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.5; +uniform bool convert_linear = true; +uniform float4 page_color = {1.0, 1.0, 1.0, 1.0}; +uniform float page_transparency< + string label = "Page Transparency"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.5; + +float4 mainImage(VertData v_in) : TARGET +{ + // Normalized pixel coordinates (from 0 to 1) + float2 aspect = float2( uv_size.x / uv_size.y, 1.0 ); + float2 uv = v_in.uv; + float t = transition_time * 12.0 + 11.0; + // Define the fold. + float2 origin = float2( 0.6 + 0.6 * sin( t * 0.2 ), 0.5 + 0.5 * cos( t * 0.13 ) ) * aspect; + float2 normal = normalize( float2( 1.0, 2.0 * sin( t * 0.3 ) ) * aspect ); - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + // Sample texture. + float3 col = float3(1.0,0.0,0.0); + + // Check on which side the pixel lies. + float2 pt = uv * aspect - origin; + float side = dot( pt, normal ); + if( side > 0.0 ) { + // Next page + col = image_b.Sample( textureSampler, uv ).rgb; + + float shadow = smoothstep( 0.0, 0.05, side ); + col = lerp( col * 0.6, col, shadow ); + } + else { + + + // Find the mirror pixel. + pt = ( uv * aspect - 2.0 * side * normal ) / aspect; + + // Check if we''re still inside the image bounds. + if( pt.x >= 0.0 && pt.x < 1.0 && pt.y >= 0.0 && pt.y < 1.0 ) { + col = image_a.Sample( textureSampler, pt ).rgb; // Back color. + col = lerp(page_color.rgb, col, page_transparency); + + float shadow = smoothstep( 0.0, 0.2, -side ); + col = lerp( col * 0.2, col, shadow ); + }else{ + col = image_a.Sample( textureSampler, uv ).rgb; + } + } + + // Output to screen + if(convert_linear) + col = srgb_nonlinear_to_linear(col); + return float4(col,1.0); +} + +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -48433,435 +46843,429 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSOutputStatus { - +function Get-OBSPerlinNoiseShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetOutputStatus')] -[Alias('obs.powershell.websocket.GetOutputStatus')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSPerlinNoiseShader','Add-OBSPerlinNoiseShader')] param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('outputName')] -[string] -$OutputName, -# If set, will return the information that would otherwise be sent to OBS. +# Set the speed of OBSPerlinNoiseShader +[ComponentModel.DefaultBindingProperty('speed')] +[Single] +$Speed, +# Set the animated of OBSPerlinNoiseShader +[ComponentModel.DefaultBindingProperty('animated')] +[Management.Automation.SwitchParameter] +$Animated, +# Set the apply_to_channel of OBSPerlinNoiseShader +[Alias('apply_to_channel')] +[ComponentModel.DefaultBindingProperty('apply_to_channel')] +[Management.Automation.SwitchParameter] +$ApplyToChannel, +# Set the inverted of OBSPerlinNoiseShader +[ComponentModel.DefaultBindingProperty('inverted')] +[Management.Automation.SwitchParameter] +$Inverted, +# Set the multiply of OBSPerlinNoiseShader +[ComponentModel.DefaultBindingProperty('multiply')] +[Management.Automation.SwitchParameter] +$Multiply, +# Set the speed_horizonal of OBSPerlinNoiseShader +[Alias('speed_horizonal')] +[ComponentModel.DefaultBindingProperty('speed_horizonal')] +[Single] +$SpeedHorizonal, +# Set the speed_vertical of OBSPerlinNoiseShader +[Alias('speed_vertical')] +[ComponentModel.DefaultBindingProperty('speed_vertical')] +[Single] +$SpeedVertical, +# Set the iterations of OBSPerlinNoiseShader +[ComponentModel.DefaultBindingProperty('iterations')] +[Int32] +$Iterations, +# Set the white_noise of OBSPerlinNoiseShader +[Alias('white_noise')] +[ComponentModel.DefaultBindingProperty('white_noise')] +[Single] +$WhiteNoise, +# Set the black_noise of OBSPerlinNoiseShader +[Alias('black_noise')] +[ComponentModel.DefaultBindingProperty('black_noise')] +[Single] +$BlackNoise, +# Set the notes of OBSPerlinNoiseShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'perlin_noise' +$ShaderNoun = 'OBSPerlinNoiseShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// +// Noise Shader Library for Unity - https://github.com/keijiro/NoiseShader +// Modified and improved my Charles Fettinger (https://github.com/Oncorporation) 1/2019 +// +// Original work (webgl-noise) Copyright (C) 2011 Stefan Gustavson +// Translation and modification was made by Keijiro Takahashi. +// Conversion for OBS by Charles Fettinger. +// +// This shader is based on the webgl-noise GLSL shader. For further details +// of the original shader, please see the following description from the +// original source code. +// + // +// GLSL textureless classic 2D noise "cnoise", (white_noise) +// with an RSL-style periodic variant "pnoise" (black_noise). +// Author: Stefan Gustavson (stefan.gustavson@liu.se) +// Version: 2011-08-22 +// +// Many thanks to Ian McEwan of Ashima Arts for the +// ideas for permutation and gradient selection. +// +// Copyright (c) 2011 Stefan Gustavson. All rights reserved. +// Distributed under the MIT license. See LICENSE file. +// https://github.com/ashima/webgl-noise +//Converted to OpenGL by Q-mii & Exeldro March 8, 2022 + float4 mod(float4 x, float4 y) +{ + return x - y * floor(x / y); +} + float4 mod289(float4 x) +{ + return x - floor(x / 289.0) * 289.0; +} + float4 permute(float4 x) +{ + return mod289(((x*34.0)+1.0)*x); +} + float4 taylorInvSqrt(float4 r) +{ + return 1.79284291400159 - r * 0.85373472095314; +} + float2 fade(float2 t) { + return t*t*t*(t*(t*6.0-15.0)+10.0); +} + // Classic Perlin noise +float cnoise(float2 P) +{ + float4 Pi = floor(P.xyxy) + float4(0.0, 0.0, 1.0, 1.0); + float4 Pf = frac (P.xyxy) - float4(0.0, 0.0, 1.0, 1.0); + Pi = mod289(Pi); // To avoid truncation effects in permutation + float4 ix = Pi.xzxz; + float4 iy = Pi.yyww; + float4 fx = Pf.xzxz; + float4 fy = Pf.yyww; + float4 i = permute(permute(ix) + iy); + float4 gx = frac(i / 41.0) * 2.0 - 1.0 ; + float4 gy = abs(gx) - 0.5 ; + float4 tx = floor(gx + 0.5); + gx = gx - tx; + float2 g00 = float2(gx.x,gy.x); + float2 g10 = float2(gx.y,gy.y); + float2 g01 = float2(gx.z,gy.z); + float2 g11 = float2(gx.w,gy.w); + float4 norm = taylorInvSqrt(float4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); + g00 *= norm.x; + g01 *= norm.y; + g10 *= norm.z; + g11 *= norm.w; + float n00 = dot(g00, float2(fx.x, fy.x)); + float n10 = dot(g10, float2(fx.y, fy.y)); + float n01 = dot(g01, float2(fx.z, fy.z)); + float n11 = dot(g11, float2(fx.w, fy.w)); + float2 fade_xy = fade(Pf.xy); + float2 n_x = lerp(float2(n00, n01), float2(n10, n11), fade_xy.x); + float n_xy = lerp(n_x.x, n_x.y, fade_xy.y); + return 2.3 * n_xy; +} + // Classic Perlin noise, periodic variant +float pnoise(float2 P, float2 rep) +{ + float4 Pi = floor(P.xyxy) + float4(0.0, 0.0, 1.0, 1.0); + float4 Pf = frac (P.xyxy) - float4(0.0, 0.0, 1.0, 1.0); + Pi = mod(Pi, rep.xyxy); // To create noise with explicit period + Pi = mod289(Pi); // To avoid truncation effects in permutation + float4 ix = Pi.xzxz; + float4 iy = Pi.yyww; + float4 fx = Pf.xzxz; + float4 fy = Pf.yyww; + float4 i = permute(permute(ix) + iy); + float4 gx = frac(i / 41.0) * 2.0 - 1.0 ; + float4 gy = abs(gx) - 0.5 ; + float4 tx = floor(gx + 0.5); + gx = gx - tx; + float2 g00 = float2(gx.x,gy.x); + float2 g10 = float2(gx.y,gy.y); + float2 g01 = float2(gx.z,gy.z); + float2 g11 = float2(gx.w,gy.w); + float4 norm = taylorInvSqrt(float4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); + g00 *= norm.x; + g01 *= norm.y; + g10 *= norm.z; + g11 *= norm.w; + float n00 = dot(g00, float2(fx.x, fy.x)); + float n10 = dot(g10, float2(fx.y, fy.y)); + float n01 = dot(g01, float2(fx.z, fy.z)); + float n11 = dot(g11, float2(fx.w, fy.w)); + float2 fade_xy = fade(Pf.xy); + float2 n_x = lerp(float2(n00, n01), float2(n10, n11), fade_xy.x); + float n_xy = lerp(n_x.x, n_x.y, fade_xy.y); + return 2.3 * n_xy; +} + //The good bits~ adapting the noise generator for the plugin and giving some control over the shader + //todo: pseudorandom number generator w/ seed +uniform float speed< + string label = "Speed"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 0.5; +uniform bool animated; +uniform bool apply_to_channel; +uniform bool inverted; +uniform bool multiply; +uniform float speed_horizonal< + string label = "Speed horizontal"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 0.5; +uniform float speed_vertical< + string label = "Speed vertical"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 0; +uniform int iterations< + string label = "Iterations"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 20; + int step = 1; +> = 4; +//how much c_noise do we want? white +uniform float white_noise< + string label = "White noise"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 0.5; +//how much p_noise do we want? black +uniform float black_noise< + string label = "Black noise"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 0.5; +uniform string notes< + string widget_type = "info"; +> = "white noise and black noise and iterations.. enjoy!"; - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } - + float2 noisePosition(float t){ + return float2(sin(2.2 * t) - cos(1.4 * t), cos(1.3 * t) + sin(-1.9 *t)); +} + float4 mainImage(VertData v_in) : TARGET +{ + float4 color = image.Sample(textureSampler, v_in.uv); + float t = elapsed_time * speed; + float2 dir = float2(speed_horizonal,speed_vertical); + + if(!animated){ + float o = 0.5; + float scale = 1.0; + float w = 0.5; + for(int i = 0; i < iterations; i++){ + float2 coord = v_in.uv * scale; + float2 period = float2(scale * 2.0, scale * 2.0); + + if(white_noise == 0.0 && black_noise == 0.0){ + o += pnoise(coord, period) * w; + } else { + if(white_noise != 0.0){ + o += cnoise(coord) * w * white_noise; + } + if(black_noise != 0.0){ + o += pnoise(coord, period) * w * black_noise; + } + } + + //o += pnoise(coord, period) * w; + + scale *= 2.0; + w *= 0.5; + } + if(inverted){ + o = 1 - o; + } + if(apply_to_channel){ + if(multiply){ + return float4(color.r,color.g,color.b,color.a*o); + } else { + return float4(color.r,color.g,color.b,o); + } + } else { + return float4(o,o,o,1.0); + } + } else { + float o = 0.5; + float scale = 1.0; + float w = 0.5; + for(int i = 0; i < iterations; i++){ + float2 coord = (v_in.uv + t*dir) * scale; + float2 period = float2(scale * 2.0, scale * 2.0); + + if(white_noise == 0.0 && black_noise == 0.0){ + o += pnoise(coord, period) * w; + } else { + if(white_noise != 0.0){ + o += cnoise(coord) * w * white_noise; + } + if(black_noise != 0.0){ + o += pnoise(coord, period) * w * black_noise; + } + } + + scale *= 2.0; + w *= 0.5; + } + if(inverted){ + o = 1 - o; + } + if(apply_to_channel){ + if(multiply){ + return float4(color.r,color.g,color.b,color.a*o); + } else { + return float4(color.r,color.g,color.b,o); + } + } else { + return float4(o,o,o,1.0); + } + } } - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSPersistentData { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetPersistentData')] -[Alias('obs.powershell.websocket.GetPersistentData')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('realm')] -[string] -$Realm, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('slotName')] -[string] -$SlotName, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } +' +} +$MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 +if (-not $myNoun) { + $myNoun = $myVerb + $myVerb = 'Get' +} +switch -regex ($myVerb) { + Get { + $FilterNamePattern = "(?>$( + if ($FilterName) { + [Regex]::Escape($FilterName) } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } + else { + [Regex]::Escape($ShaderNoun -replace '^OBS' -replace 'Shader$'),[Regex]::Escape($shaderName) -join '|' } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload + ))" + if ($SourceName) { + Get-OBSInput | + Where-Object InputName -eq $SourceName | + Get-OBSSourceFilterList | + Where-Object FilterName -Match $FilterNamePattern } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } - -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSProfile { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetProfileList')] -[Alias('obs.powershell.websocket.GetProfileList')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } + $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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + continue nextParameter + } } - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSProfileParameter { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetProfileParameter')] -[Alias('obs.powershell.websocket.GetProfileParameter')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('parameterCategory')] -[string] -$ParameterCategory, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('parameterName')] -[string] -$ParameterName, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -48870,204 +47274,256 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSRecordDirectory { - +function Get-OBSPerspectiveShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetRecordDirectory')] -[Alias('obs.powershell.websocket.GetRecordDirectory')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSPerspectiveShader','Add-OBSPerspectiveShader')] param( -# If set, will return the information that would otherwise be sent to OBS. +# Set the angle_x of OBSPerspectiveShader +[Alias('angle_x')] +[ComponentModel.DefaultBindingProperty('angle_x')] +[Single] +$AngleX, +# Set the angle_y of OBSPerspectiveShader +[Alias('angle_y')] +[ComponentModel.DefaultBindingProperty('angle_y')] +[Single] +$AngleY, +# Set the angle_z of OBSPerspectiveShader +[Alias('angle_z')] +[ComponentModel.DefaultBindingProperty('angle_z')] +[Single] +$AngleZ, +# Set the perspective of OBSPerspectiveShader +[ComponentModel.DefaultBindingProperty('perspective')] +[Single] +$Perspective, +# Set the border_color of OBSPerspectiveShader +[Alias('border_color')] +[ComponentModel.DefaultBindingProperty('border_color')] +[String] +$BorderColor, +# Set the show_border of OBSPerspectiveShader +[Alias('show_border')] +[ComponentModel.DefaultBindingProperty('show_border')] +[Management.Automation.SwitchParameter] +$ShowBorder, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } +[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 = 'perspective' +$ShaderNoun = 'OBSPerspectiveShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Perspective Transform Shader for OBS +// Allows adjustable 3D perspective effects +// Usage: Add as filter in OBS via ShaderFilter plugin -} +uniform float angle_x< + string label = "X Rotation"; + string widget_type = "slider"; + float minimum = -180.0; + float maximum = 180.0; + float step = 1.0; +> = 0.0; - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSRecordStatus { +uniform float angle_y< + string label = "Y Rotation"; + string widget_type = "slider"; + float minimum = -180.0; + float maximum = 180.0; + float step = 1.0; +> = 0.0; +uniform float angle_z< + string label = "Z Rotation"; + string widget_type = "slider"; + float minimum = -180.0; + float maximum = 180.0; + float step = 1.0; +> = 0.0; -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetRecordStatus')] -[Alias('obs.powershell.websocket.GetRecordStatus')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) +uniform float perspective< + string label = "Perspective Strength"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.5; +uniform float4 border_color< + string label = "Border Color"; +> = {0.0, 0.0, 0.0, 1.0}; -process { +uniform bool show_border< + string label = "Show Border"; +> = true; +float4x4 rotationMatrix(float3 angles) +{ + float radX = radians(angles.x); + float radY = radians(angles.y); + float radZ = radians(angles.z); + + float sinX = sin(radX); + float cosX = cos(radX); + float sinY = sin(radY); + float cosY = cos(radY); + float sinZ = sin(radZ); + float cosZ = cos(radZ); + + return float4x4( + cosY*cosZ, -cosY*sinZ, sinY, 0, + sinX*sinY*cosZ + cosX*sinZ, -sinX*sinY*sinZ + cosX*cosZ, -sinX*cosY, 0, + -cosX*sinY*cosZ + sinX*sinZ, cosX*sinY*sinZ + sinX*cosZ, cosX*cosY, 0, + 0, 0, 0, 1 + ); +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float4 mainImage(VertData v_in) : TARGET +{ + float2 uv = v_in.uv; + + // Center coordinates + float2 center = float2(0.5, 0.5); + uv -= center; + + // Apply perspective + float perspectiveFactor = 1.0 / (1.0 + perspective * length(uv)); + uv *= perspectiveFactor; + + // Create rotation matrix + float3 angles = float3(angle_x, angle_y, angle_z); + float4x4 rotMat = rotationMatrix(angles); + + // Apply transformation + float4 transformed = mul(rotMat, float4(uv.x, uv.y, 0, 1)); + + // Restore center position + uv = transformed.xy + center; + + // Sample texture with border handling + if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) { + return show_border ? border_color : float4(0, 0, 0, 0); + } + + return image.Sample(textureSampler, uv); +} +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -49076,204 +47532,402 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSReplayBufferStatus { - +function Get-OBSPieChartShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetReplayBufferStatus')] -[Alias('obs.powershell.websocket.GetReplayBufferStatus')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSPieChartShader','Add-OBSPieChartShader')] param( -# If set, will return the information that would otherwise be sent to OBS. +# Set the inner_radius of OBSPieChartShader +[Alias('inner_radius')] +[ComponentModel.DefaultBindingProperty('inner_radius')] +[Single] +$InnerRadius, +# Set the outer_radius of OBSPieChartShader +[Alias('outer_radius')] +[ComponentModel.DefaultBindingProperty('outer_radius')] +[Single] +$OuterRadius, +# Set the start_angle of OBSPieChartShader +[Alias('start_angle')] +[ComponentModel.DefaultBindingProperty('start_angle')] +[Single] +$StartAngle, +# Set the total of OBSPieChartShader +[ComponentModel.DefaultBindingProperty('total')] +[Int32] +$Total, +# Set the part_1 of OBSPieChartShader +[Alias('part_1')] +[ComponentModel.DefaultBindingProperty('part_1')] +[Int32] +$Part1, +# Set the color_1 of OBSPieChartShader +[Alias('color_1')] +[ComponentModel.DefaultBindingProperty('color_1')] +[String] +$Color1, +# Set the part_2 of OBSPieChartShader +[Alias('part_2')] +[ComponentModel.DefaultBindingProperty('part_2')] +[Int32] +$Part2, +# Set the color_2 of OBSPieChartShader +[Alias('color_2')] +[ComponentModel.DefaultBindingProperty('color_2')] +[String] +$Color2, +# Set the part_3 of OBSPieChartShader +[Alias('part_3')] +[ComponentModel.DefaultBindingProperty('part_3')] +[Int32] +$Part3, +# Set the color_3 of OBSPieChartShader +[Alias('color_3')] +[ComponentModel.DefaultBindingProperty('color_3')] +[String] +$Color3, +# Set the part_4 of OBSPieChartShader +[Alias('part_4')] +[ComponentModel.DefaultBindingProperty('part_4')] +[Int32] +$Part4, +# Set the color_4 of OBSPieChartShader +[Alias('color_4')] +[ComponentModel.DefaultBindingProperty('color_4')] +[String] +$Color4, +# Set the part_5 of OBSPieChartShader +[Alias('part_5')] +[ComponentModel.DefaultBindingProperty('part_5')] +[Int32] +$Part5, +# Set the color_5 of OBSPieChartShader +[Alias('color_5')] +[ComponentModel.DefaultBindingProperty('color_5')] +[String] +$Color5, +# Set the part_6 of OBSPieChartShader +[Alias('part_6')] +[ComponentModel.DefaultBindingProperty('part_6')] +[Int32] +$Part6, +# Set the color_6 of OBSPieChartShader +[Alias('color_6')] +[ComponentModel.DefaultBindingProperty('color_6')] +[String] +$Color6, +# Set the part_7 of OBSPieChartShader +[Alias('part_7')] +[ComponentModel.DefaultBindingProperty('part_7')] +[Int32] +$Part7, +# Set the color_7 of OBSPieChartShader +[Alias('color_7')] +[ComponentModel.DefaultBindingProperty('color_7')] +[String] +$Color7, +# Set the part_8 of OBSPieChartShader +[Alias('part_8')] +[ComponentModel.DefaultBindingProperty('part_8')] +[Int32] +$Part8, +# Set the color_8 of OBSPieChartShader +[Alias('color_8')] +[ComponentModel.DefaultBindingProperty('color_8')] +[String] +$Color8, +# Set the part_9 of OBSPieChartShader +[Alias('part_9')] +[ComponentModel.DefaultBindingProperty('part_9')] +[Int32] +$Part9, +# Set the color_9 of OBSPieChartShader +[Alias('color_9')] +[ComponentModel.DefaultBindingProperty('color_9')] +[String] +$Color9, +# Set the part_10 of OBSPieChartShader +[Alias('part_10')] +[ComponentModel.DefaultBindingProperty('part_10')] +[Int32] +$Part10, +# Set the color_10 of OBSPieChartShader +[Alias('color_10')] +[ComponentModel.DefaultBindingProperty('color_10')] +[String] +$Color10, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'pie-chart' +$ShaderNoun = 'OBSPieChartShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform float inner_radius< + string label = "inner radius"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.1; +> = 32.0; +uniform float outer_radius< + string label = "outer radius"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.1; +> = 50.0; +uniform float start_angle< + string label = "Start angle"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 360.0; + float step = 0.1; +> = 90.0; +uniform int total< + string label = "Total"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 1000; + int step = 1; +> = 100; +uniform int part_1< + string label = "Part 1"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 1000; + int step = 1; +> = 50; +uniform float4 color_1 = {0.0,0.26,0.62,1.0}; +uniform int part_2< + string label = "Part 2"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 1000; + int step = 1; +> = 25; +uniform float4 color_2 = {0.24,0.40,0.68,1.0}; +uniform int part_3< + string label = "Part 3"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 1000; + int step = 1; +> = 10; +uniform float4 color_3 = {0.38,0.56,0.75,1.0}; +uniform int part_4< + string label = "Part 4"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 1000; + int step = 1; +> = 5; +uniform float4 color_4 = {0.52,0.72,0.81,1.0}; +uniform int part_5< + string label = "Part 5"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 1000; + int step = 1; +> = 3; +uniform float4 color_5 = {0.69,0.87,0.86,1.0}; +uniform int part_6< + string label = "Part 6"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 1000; + int step = 1; +> = 2; +uniform float4 color_6 = {1.0,0.79,0.73,1.0}; +uniform int part_7< + string label = "Part 7"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 1000; + int step = 1; +> = 1; +uniform float4 color_7 = {0.99,0.57,0.57,1.0}; +uniform int part_8< + string label = "Part 8"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 1000; + int step = 1; +> = 1; +uniform float4 color_8 = {0.91,0.36,0.44,1.0}; +uniform int part_9< + string label = "Part 9"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 1000; + int step = 1; +> = 1; +uniform float4 color_9 = {0.77,0.16,0.32,1.0}; +uniform int part_10< + string label = "Part 10"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 1000; + int step = 1; +> = 0; +uniform float4 color_10 = {0.58,0.0,0.23,1.0}; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} +float4 mainImage(VertData v_in) : TARGET +{ + const float pi = 3.14159265358979323846; +#ifdef OPENGL + float[10] parts = float[10](part_1, part_2, part_3, part_4, part_5, part_6, part_7, part_8, part_9, part_10); + float4[10] colors = float4[10](color_1, color_2, color_3, color_4, color_5, color_6, color_7, color_8, color_9, color_10); +#else + float parts[] = {part_1, part_2, part_3, part_4, part_5, part_6, part_7, part_8, part_9, part_10}; + float4 colors[] = {color_1, color_2, color_3, color_4, color_5, color_6, color_7, color_8, color_9, color_10}; +#endif + float2 center = float2(0.5, 0.5); + float2 factor; + if(uv_size.x < uv_size.y){ + factor = float2(1.0, uv_size.y/uv_size.x); + }else{ + factor = float2(uv_size.x/uv_size.y, 1.0); + } + center = center * factor; + float d = distance(center, v_in.uv * factor); + if(d > outer_radius/100.0 || d < inner_radius/100.0){ + return image.Sample(textureSampler, v_in.uv); + } + float2 toCenter = center - v_in.uv*factor; + float angle = atan2(toCenter.y ,toCenter.x); + angle = angle - (start_angle / 180.0 * pi); + if(angle < 0.0) + angle = pi + pi + angle; + if(angle < 0.0) + angle = pi + pi + angle; + angle = angle / (pi + pi); + float t = 0.0; + for(int i = 0; i < 10; i+=1) { + float part = parts[i]/total; + if(angle > t && angle <= t+part){ + return colors[i]; } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + t = t + part; + } + return image.Sample(textureSampler, v_in.uv); +} +' +} +$MyVerb, $myNoun = $MyInvocation.InvocationName -split '-',2 +if (-not $myNoun) { + $myNoun = $myVerb + $myVerb = 'Get' +} +switch -regex ($myVerb) { + Get { + $FilterNamePattern = "(?>$( + if ($FilterName) { + [Regex]::Escape($FilterName) } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } + 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 } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + } + '(?>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 ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSScene { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneList')] -[Alias('obs.powershell.websocket.GetSceneList')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -49282,214 +47936,192 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSceneCollection { - +function Get-OBSPixelationShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneCollectionList')] -[Alias('obs.powershell.websocket.GetSceneCollectionList')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSPixelationShader','Add-OBSPixelationShader')] param( -# If set, will return the information that would otherwise be sent to OBS. +# Set the Target_Width of OBSPixelationShader +[Alias('Target_Width')] +[ComponentModel.DefaultBindingProperty('Target_Width')] +[Single] +$TargetWidth, +# Set the Target_Height of OBSPixelationShader +[Alias('Target_Height')] +[ComponentModel.DefaultBindingProperty('Target_Height')] +[Single] +$TargetHeight, +# Set the notes of OBSPixelationShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'pixelation' +$ShaderNoun = 'OBSPixelationShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// pixelation shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 +// with help from SkeltonBowTV +// https://github.com/Oncorporation/obs-shaderfilter +//Converted to OpenGL by Exeldro February 15, 2022 +uniform float Target_Width< + string label = "Target Width"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 2000.0; + float step = 0.1; +> = 320.0; +uniform float Target_Height< + string label = "Target Height"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 2000.0; + float step = 0.1; +> = 180.0; +uniform string notes< + string widget_type = "info"; +> = "adjust width and height to your screen dimension"; +float4 mainImage(VertData v_in) : TARGET +{ + float targetWidth = Target_Width; + if(targetWidth < 2.0) + targetWidth = 2.0; + float targetHeight = Target_Height; + if(targetHeight < 2.0) + targetHeight = 2.0; + float2 tex1; + int pixelSizeX = int(uv_size.x / targetWidth); + int pixelSizeY = int(uv_size.y / targetHeight); - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + int pixelX = int(v_in.uv.x * uv_size.x); + int pixelY = int(v_in.uv.y * uv_size.y); - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + tex1.x = ((float(pixelX / pixelSizeX)*float(pixelSizeX)) / uv_size.x) + (float(pixelSizeX) / uv_size.x)/2.0; + tex1.y = ((float(pixelY / pixelSizeY)*float(pixelSizeY)) / uv_size.y) + (float(pixelSizeY) / uv_size.y)/2.0; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } + float4 c1 = image.Sample(textureSampler, tex1 ); - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } + return c1; +} - if ($PassThru) { - [PSCustomObject]$requestPayload +' +} +$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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $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 + } } -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSSceneItem { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneItemList')] -[Alias('obs.powershell.websocket.GetSceneItemList')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -49498,117 +48130,210 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSceneItemBlendMode { - +function Get-OBSPixelationTransitionShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneItemBlendMode')] -[Alias('obs.powershell.websocket.GetSceneItemBlendMode')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSPixelationTransitionShader','Add-OBSPixelationTransitionShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, - +# Set the transition_time of OBSPixelationTransitionShader +[Alias('transition_time')] +[ComponentModel.DefaultBindingProperty('transition_time')] +[Single] +$TransitionTime, +# Set the convert_linear of OBSPixelationTransitionShader +[Alias('convert_linear')] +[ComponentModel.DefaultBindingProperty('convert_linear')] +[Management.Automation.SwitchParameter] +$ConvertLinear, +# Set the power of OBSPixelationTransitionShader +[ComponentModel.DefaultBindingProperty('power')] +[Single] +$Power, +# Set the center_x of OBSPixelationTransitionShader +[Alias('center_x')] +[ComponentModel.DefaultBindingProperty('center_x')] +[Single] +$CenterX, +# Set the center_y of OBSPixelationTransitionShader +[Alias('center_y')] +[ComponentModel.DefaultBindingProperty('center_y')] +[Single] +$CenterY, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemId')] -[ValidateRange(0,[int]::MaxValue)] -[double] -$SceneItemId, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'pixelation-transition' +$ShaderNoun = 'OBSPixelationTransitionShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform float transition_time< + string label = "Transittion Time"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.5; +uniform bool convert_linear = true; +uniform float power< + string label = "Power"; + string widget_type = "slider"; + float minimum = 0.5; + float maximum = 8.0; + float step = 0.01; +> = 3.0; +uniform float center_x< + string label = "X"; + string widget_type = "slider"; + string group = "Center"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.5; +uniform float center_y< + string label = "Y"; + string widget_type = "slider"; + string group = "Center"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.5; +float4 mainImage(VertData v_in) : TARGET +{ + //1..0..1 + float scale = abs(transition_time - 0.5) * 2.0; + scale = pow(scale, power); - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + float2 uv = v_in.uv; + uv -= float2(center_x, center_y); + uv *= uv_size; + uv *= scale; + uv = floor(uv); + uv /= scale; + uv /= uv_size; + uv += float2(center_x, center_y); + uv = clamp(uv, 1.0/uv_size, 1.0); + float4 rgba = image.Sample(textureSampler, uv); + if(convert_linear) + rgba.rgb = srgb_nonlinear_to_linear(rgba.rgb); + return rgba; +} - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} +' +} +$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 } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } + } + '(?>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 + } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } + 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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -49617,117 +48342,238 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSceneItemEnabled { - +function Get-OBSPolarShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneItemEnabled')] -[Alias('obs.powershell.websocket.GetSceneItemEnabled')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSPolarShader','Add-OBSPolarShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, - +# Set the center_x of OBSPolarShader +[Alias('center_x')] +[ComponentModel.DefaultBindingProperty('center_x')] +[Single] +$CenterX, +# Set the center_y of OBSPolarShader +[Alias('center_y')] +[ComponentModel.DefaultBindingProperty('center_y')] +[Single] +$CenterY, +# Set the point_y of OBSPolarShader +[Alias('point_y')] +[ComponentModel.DefaultBindingProperty('point_y')] +[Single] +$PointY, +# Set the flip of OBSPolarShader +[ComponentModel.DefaultBindingProperty('flip')] +[Management.Automation.SwitchParameter] +$Flip, +# Set the rotate of OBSPolarShader +[ComponentModel.DefaultBindingProperty('rotate')] +[Single] +$Rotate, +# Set the repeat of OBSPolarShader +[ComponentModel.DefaultBindingProperty('repeat')] +[Single] +$Repeat, +# Set the scale of OBSPolarShader +[ComponentModel.DefaultBindingProperty('scale')] +[Single] +$Scale, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemId')] -[ValidateRange(0,[int]::MaxValue)] -[double] -$SceneItemId, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'polar' +$ShaderNoun = 'OBSPolarShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +#define PI 3.14159265359 +#define PI_2 6.2831 +#define mod(x,y) (x - y * floor(x / y)) +uniform float center_x< + string label = "Center x"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.5; +uniform float center_y< + string label = "Center y"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.5; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +uniform float point_y< + string label = "Point y"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; + +uniform bool flip; + +uniform float rotate< + string label = "Rotate"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; + +uniform float repeat< + string label = "Repeat"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 20.0; + float step = 0.001; +> = 1.0; + +uniform float scale< + string label = "Scale"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 2.0; + float step = 0.001; +> = 0.5; + +float4 mainImage(VertData v_in) : TARGET +{ + float2 uv = v_in.uv; + uv.x -= center_x ; + uv.y -= center_y ; + uv.x = uv.x * ( uv_size.x / uv_size.y); + float pixel_angle = atan2(uv.x,uv.y)/PI_2+0.5; + if(repeat < 1.0){ + pixel_angle = mod(pixel_angle+rotate,1.0); + if(pixel_angle > repeat) + return float4(0,0,0,0); + pixel_angle = mod(pixel_angle/repeat,1.0); + } else { + pixel_angle = mod(pixel_angle*repeat+rotate, 1.0); + } + float pixel_distance = length(uv)/ scale - point_y; + float2 uv2 = float2(pixel_angle , pixel_distance); + if(flip) + uv2 = float2(1.0,1.0) - uv2; + return image.Sample(textureSampler,uv2); +} +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -49736,122 +48582,259 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSceneItemId { - +function Get-OBSPulseShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneItemId')] -[Alias('obs.powershell.websocket.GetSceneItemId')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSPulseShader','Add-OBSPulseShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, - +# Set the ViewProj of OBSPulseShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the image of OBSPulseShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the elapsed_time of OBSPulseShader +[Alias('elapsed_time')] +[ComponentModel.DefaultBindingProperty('elapsed_time')] +[Single] +$ElapsedTime, +# Set the uv_offset of OBSPulseShader +[Alias('uv_offset')] +[ComponentModel.DefaultBindingProperty('uv_offset')] +[Single[]] +$UvOffset, +# Set the uv_scale of OBSPulseShader +[Alias('uv_scale')] +[ComponentModel.DefaultBindingProperty('uv_scale')] +[Single[]] +$UvScale, +# Set the uv_pixel_interval of OBSPulseShader +[Alias('uv_pixel_interval')] +[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +[Single[]] +$UvPixelInterval, +# Set the rand_f of OBSPulseShader +[Alias('rand_f')] +[ComponentModel.DefaultBindingProperty('rand_f')] +[Single] +$RandF, +# Set the uv_size of OBSPulseShader +[Alias('uv_size')] +[ComponentModel.DefaultBindingProperty('uv_size')] +[Single[]] +$UvSize, +# Set the speed of OBSPulseShader +[ComponentModel.DefaultBindingProperty('speed')] +[Single] +$Speed, +# Set the min_growth_pixels of OBSPulseShader +[Alias('min_growth_pixels')] +[ComponentModel.DefaultBindingProperty('min_growth_pixels')] +[Single] +$MinGrowthPixels, +# Set the max_growth_pixels of OBSPulseShader +[Alias('max_growth_pixels')] +[ComponentModel.DefaultBindingProperty('max_growth_pixels')] +[Single] +$MaxGrowthPixels, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceName')] -[string] +[Alias('SceneItemName')] +[String] $SourceName, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('searchOffset')] -[ValidateRange(-1,[int]::MaxValue)] -[double] -$SearchOffset, -# If set, will return the information that would otherwise be sent to OBS. +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'pulse' +$ShaderNoun = 'OBSPulseShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform float4x4 ViewProj; +uniform texture2d image; +uniform float elapsed_time; +uniform float2 uv_offset; +uniform float2 uv_scale; +uniform float2 uv_pixel_interval; +uniform float rand_f; +uniform float2 uv_size; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +uniform float speed< + string label = "Speed"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.1; +> = 1.0; +uniform float min_growth_pixels< + string label = "min growth pixels"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1000.0; + float step = 0.1; +> = 0.0; +uniform float max_growth_pixels< + string label = "max growth pixels"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1000.0; + float step = 0.1; +> = 200.0; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +sampler_state textureSampler { + Filter = Linear; + AddressU = Border; + AddressV = Border; + BorderColor = 00000000; +}; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } +struct VertData { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; + +VertData mainTransform(VertData v_in) +{ + VertData vert_out; + + float3 pos = v_in.pos.xyz; + float3 direction_from_center = float3((v_in.uv.x - 0.5) * uv_pixel_interval.y / uv_pixel_interval.x, v_in.uv.y - 0.5, 0); + float3 min_pos = pos + direction_from_center * min_growth_pixels / 2; + float3 max_pos = pos + direction_from_center * max_growth_pixels / 2; + + float t = (1 + sin(elapsed_time * speed)) / 2; + float3 current_pos = min_pos * (1 - t) + max_pos * t; + + vert_out.pos = mul(float4(current_pos, 1.0), ViewProj); + vert_out.uv = v_in.uv * uv_scale + uv_offset; + return vert_out; +} + +float4 mainImage(VertData v_in) : TARGET +{ + return image.Sample(textureSampler, v_in.uv); +} + +technique Draw +{ + pass + { + vertex_shader = mainTransform(v_in); + pixel_shader = mainImage(v_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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -49860,117 +48843,247 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSceneItemIndex { +function Get-OBSQuadrilateralCropShader { - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneItemIndex')] -[Alias('obs.powershell.websocket.GetSceneItemIndex')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSQuadrilateralCropShader','Add-OBSQuadrilateralCropShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, - +# Set the Top_Left_X of OBSQuadrilateralCropShader +[Alias('Top_Left_X')] +[ComponentModel.DefaultBindingProperty('Top_Left_X')] +[Single] +$TopLeftX, +# Set the Top_Left_Y of OBSQuadrilateralCropShader +[Alias('Top_Left_Y')] +[ComponentModel.DefaultBindingProperty('Top_Left_Y')] +[Single] +$TopLeftY, +# Set the Top_Right_X of OBSQuadrilateralCropShader +[Alias('Top_Right_X')] +[ComponentModel.DefaultBindingProperty('Top_Right_X')] +[Single] +$TopRightX, +# Set the Top_Right_Y of OBSQuadrilateralCropShader +[Alias('Top_Right_Y')] +[ComponentModel.DefaultBindingProperty('Top_Right_Y')] +[Single] +$TopRightY, +# Set the Bottom_Left_X of OBSQuadrilateralCropShader +[Alias('Bottom_Left_X')] +[ComponentModel.DefaultBindingProperty('Bottom_Left_X')] +[Single] +$BottomLeftX, +# Set the Bottom_Left_Y of OBSQuadrilateralCropShader +[Alias('Bottom_Left_Y')] +[ComponentModel.DefaultBindingProperty('Bottom_Left_Y')] +[Single] +$BottomLeftY, +# Set the Bottom_Right_X of OBSQuadrilateralCropShader +[Alias('Bottom_Right_X')] +[ComponentModel.DefaultBindingProperty('Bottom_Right_X')] +[Single] +$BottomRightX, +# Set the Bottom_Right_Y of OBSQuadrilateralCropShader +[Alias('Bottom_Right_Y')] +[ComponentModel.DefaultBindingProperty('Bottom_Right_Y')] +[Single] +$BottomRightY, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemId')] -[ValidateRange(0,[int]::MaxValue)] -[double] -$SceneItemId, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'quadrilateral_crop' +$ShaderNoun = 'OBSQuadrilateralCropShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Quadrilateral Crop shader (inverse of a corner pin): transform a 4 points polygon to the corners of the source. +// Useful to revert perspective. +uniform float Top_Left_X< + string label = "Top Left X"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 100.0; + float step = 0.01; +> = 0; +uniform float Top_Left_Y< + string label = "Top Left Y"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 100.0; + float step = 0.01; +> = 0; +uniform float Top_Right_X< + string label = "Top Right X"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 100.0; + float step = 0.01; +> = 100.; +uniform float Top_Right_Y< + string label = "Top Right Y"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 100.0; + float step = 0.01; +> = 0; +uniform float Bottom_Left_X< + string label = "Bottom Left X"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 100.0; + float step = 0.01; +> = 0; +uniform float Bottom_Left_Y< + string label = "Bottom Left Y"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 100.0; + float step = 0.01; +> = 100.; +uniform float Bottom_Right_X< + string label = "Bottom Right X"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 100.0; + float step = 0.01; +> = 100.; +uniform float Bottom_Right_Y< + string label = "Bottom Right Y"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 100.0; + float step = 0.01; +> = 100.; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float4 mainImage( VertData v_in ) : TARGET { + + float2 tl = float2(Top_Left_X, Top_Left_Y) * .01; + float2 tr = float2(Top_Right_X, Top_Right_Y) * .01; + float2 bl = float2(Bottom_Left_X, Bottom_Left_Y) * .01; + float2 br = float2(Bottom_Right_X, Bottom_Right_Y) * .01; + + float2 t = lerp(tl, tr, v_in.uv[0]); + float2 b = lerp(bl, br, v_in.uv[0]); + float2 uv = lerp(t, b, v_in.uv[1]); - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + return image.Sample(textureSampler, uv); +} - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } +' +} +$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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -49979,117 +49092,331 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSceneItemLocked { - +function Get-OBSRainbowShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneItemLocked')] -[Alias('obs.powershell.websocket.GetSceneItemLocked')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSRainbowShader','Add-OBSRainbowShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, - +# Set the Saturation of OBSRainbowShader +[ComponentModel.DefaultBindingProperty('Saturation')] +[Single] +$Saturation, +# Set the Luminosity of OBSRainbowShader +[ComponentModel.DefaultBindingProperty('Luminosity')] +[Single] +$Luminosity, +# Set the Spread of OBSRainbowShader +[ComponentModel.DefaultBindingProperty('Spread')] +[Single] +$Spread, +# Set the Speed of OBSRainbowShader +[ComponentModel.DefaultBindingProperty('Speed')] +[Single] +$Speed, +# Set the Alpha_Percentage of OBSRainbowShader +[Alias('Alpha_Percentage')] +[ComponentModel.DefaultBindingProperty('Alpha_Percentage')] +[Single] +$AlphaPercentage, +# Set the Vertical of OBSRainbowShader +[ComponentModel.DefaultBindingProperty('Vertical')] +[Management.Automation.SwitchParameter] +$Vertical, +# Set the Rotational of OBSRainbowShader +[ComponentModel.DefaultBindingProperty('Rotational')] +[Management.Automation.SwitchParameter] +$Rotational, +# Set the Rotation_Offset of OBSRainbowShader +[Alias('Rotation_Offset')] +[ComponentModel.DefaultBindingProperty('Rotation_Offset')] +[Single] +$RotationOffset, +# Set the Apply_To_Image of OBSRainbowShader +[Alias('Apply_To_Image')] +[ComponentModel.DefaultBindingProperty('Apply_To_Image')] +[Management.Automation.SwitchParameter] +$ApplyToImage, +# Set the Replace_Image_Color of OBSRainbowShader +[Alias('Replace_Image_Color')] +[ComponentModel.DefaultBindingProperty('Replace_Image_Color')] +[Management.Automation.SwitchParameter] +$ReplaceImageColor, +# Set the Apply_To_Specific_Color of OBSRainbowShader +[Alias('Apply_To_Specific_Color')] +[ComponentModel.DefaultBindingProperty('Apply_To_Specific_Color')] +[Management.Automation.SwitchParameter] +$ApplyToSpecificColor, +# Set the Color_To_Replace of OBSRainbowShader +[Alias('Color_To_Replace')] +[ComponentModel.DefaultBindingProperty('Color_To_Replace')] +[String] +$ColorToReplace, +# Set the Notes of OBSRainbowShader +[ComponentModel.DefaultBindingProperty('Notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemId')] -[ValidateRange(0,[int]::MaxValue)] -[double] -$SceneItemId, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'rainbow' +$ShaderNoun = 'OBSRainbowShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Rainbow shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 +// https://github.com/Oncorporation/obs-shaderfilter +//Converted to OpenGL by Exeldro February 13, 2022 +uniform float Saturation< + string label = "Saturation"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.8; // +uniform float Luminosity< + string label = "Luminosity"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.5; // +uniform float Spread< + string label = "Spread"; + string widget_type = "slider"; + float minimum = 0.5; + float maximum = 10.0; + float step = 0.01; +> = 3.8; // +uniform float Speed< + string label = "Speed"; + string widget_type = "slider"; + float minimum = -10.0; + float maximum = 10.0; + float step = 0.01; +> = 2.4; // +uniform float Alpha_Percentage< + string label = "Rotation Offset"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.1; +> = 100.0; // +uniform bool Vertical; +uniform bool Rotational; +uniform float Rotation_Offset< + string label = "Rotation Offset"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 6.28318531; + float step = 0.001; +> = 0.0; // +uniform bool Apply_To_Image; +uniform bool Replace_Image_Color; +uniform bool Apply_To_Specific_Color; +uniform float4 Color_To_Replace; +uniform string Notes< + string widget_type = "info"; +> = "Spread is wideness of color and is limited between .25 and 10. Edit at your own risk"; + +float hueToRGB(float v1, float v2, float vH) { + vH = frac(vH); + if ((6.0 * vH) < 1.0) return (v1 + (v2 - v1) * 6.0 * vH); + if ((2.0 * vH) < 1.0) return (v2); + if ((3.0 * vH) < 2.0) return (v1 + (v2 - v1) * ((0.6666666666666667) - vH) * 6.0); + return clamp(v1, 0.0, 1.0); +} +float4 HSLtoRGB(float4 hsl) { + float4 rgb = float4(0.0, 0.0, 0.0, hsl.w); + float v1 = 0.0; + float v2 = 0.0; + + if (hsl.y == 0) { + rgb.xyz = hsl.zzz; + } + else { + + if (hsl.z < 0.5) { + v2 = hsl.z * (1 + hsl.y); + } + else { + v2 = (hsl.z + hsl.y) - (hsl.y * hsl.z); + } + + v1 = 2.0 * hsl.z - v2; + + rgb.x = hueToRGB(v1, v2, hsl.x + (0.3333333333333333)); + rgb.y = hueToRGB(v1, v2, hsl.x); + rgb.z = hueToRGB(v1, v2, hsl.x - (0.3333333333333333)); + + } + + return rgb; +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float4 mainImage(VertData v_in) : TARGET +{ + float2 lPos = (v_in.uv * uv_scale + uv_offset)/ clamp(Spread, 0.25, 10.0); + float time = (elapsed_time * clamp(Speed, -5.0, 5.0)) / clamp(Spread, 0.25, 10.0); + + //set colors and direction + float hue = (-1 * lPos.x) / 2.0; + + if (Rotational && (Vertical == false)) + { + float timeWithOffset = time + Rotation_Offset; + float sine = sin(timeWithOffset); + float cosine = cos(timeWithOffset); + hue = (lPos.x * cosine + lPos.y * sine) * 0.5; + } + + if (Vertical && (Rotational == false)) + { + hue = (-1 * lPos.y) * 0.5; + } + + hue += time; + hue = frac(hue); + float4 hsl = float4(hue, clamp(Saturation, 0.0, 1.0), clamp(Luminosity, 0.0, 1.0), 1.0); + float4 rgba = HSLtoRGB(hsl); + + float4 color; + float4 original_color; + if (Apply_To_Image) + { + color = image.Sample(textureSampler, v_in.uv); + original_color = color; + float luma = 0.30*color.r+0.59*color.g+0.11*color.b+1.0*color.a; + float4 luma_color = float4(luma, luma, luma, luma); + if (Replace_Image_Color) + color = luma_color; + rgba = lerp(original_color, rgba * color,clamp(Alpha_Percentage *.01 ,0,1.0)); + + } + if (Apply_To_Specific_Color) + { + color = image.Sample(textureSampler, v_in.uv); + original_color = color; + color = (distance(color.rgb, Color_To_Replace.rgb) <= 0.075) ? rgba : color; + rgba = lerp(original_color, color, clamp(Alpha_Percentage * .01, 0, 1.0)); + } + return rgba; +} + +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -50098,452 +49425,396 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSceneItemSource { - +function Get-OBSRainWindowShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneItemSource')] -[Alias('obs.powershell.websocket.GetSceneItemSource')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSRainWindowShader','Add-OBSRainWindowShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, - +# Set the size of OBSRainWindowShader +[ComponentModel.DefaultBindingProperty('size')] +[Single] +$Size, +# Set the blurSize of OBSRainWindowShader +[ComponentModel.DefaultBindingProperty('blurSize')] +[Single] +$BlurSize, +# Set the trail_strength of OBSRainWindowShader +[Alias('trail_strength')] +[ComponentModel.DefaultBindingProperty('trail_strength')] +[Single] +$TrailStrength, +# Set the trail_color of OBSRainWindowShader +[Alias('trail_color')] +[ComponentModel.DefaultBindingProperty('trail_color')] +[Single] +$TrailColor, +# Set the speed of OBSRainWindowShader +[ComponentModel.DefaultBindingProperty('speed')] +[Single] +$Speed, +# Set the debug of OBSRainWindowShader +[ComponentModel.DefaultBindingProperty('debug')] +[Management.Automation.SwitchParameter] +$DebugShader, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemId')] -[ValidateRange(0,[int]::MaxValue)] -[double] -$SceneItemId, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'rain-window' +$ShaderNoun = 'OBSRainWindowShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// https://www.shadertoy.com/view/slfSzS adopted for OBS by Exeldro +// shader derived from Heartfelt - by Martijn Steinrucken aka BigWings - 2017 +// https://www.shadertoy.com/view/ltffzl +// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. +uniform float size< + string label = "Rain Drop Size"; + string widget_type = "slider"; + float minimum = 0.001; + float maximum = 0.5; + float step = 0.01; +> = 0.2; +uniform float blurSize< + string label = "Blur Radius"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 32.0; // BLUR SIZE (Radius) +uniform float trail_strength< + string label = "Trail Strength"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 100.0; +uniform float trail_color< + string label = "Trail Color"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 40.0; +uniform float speed< + string label = "Speed"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 200.0; + float step = 0.01; +> = 100.0; +uniform bool debug = false; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } +float fract(float v){ + return v - floor(v); } +float2 fract2(float2 v){ + return float2(v.x - floor(v.x), v.y - floor(v.y)); +} -} - - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSSceneItemTransform { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneItemTransform')] -[Alias('obs.powershell.websocket.GetSceneItemTransform')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemId')] -[ValidateRange(0,[int]::MaxValue)] -[double] -$SceneItemId, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - +float3 fract3(float3 v){ + return float3(v.x - floor(v.x), v.y - floor(v.y), v.z - floor(v.z)); +} -process { +float3 fract4(float4 v){ + return float4(v.x - floor(v.x), v.y - floor(v.y), v.z - floor(v.z), v.w - floor(v.w)); +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float3 N13(float p) { + // from DAVE HOSKINS + float3 p3 = fract3(float3(p, p, p) * float3(.1031,.11369,.13787)); + p3 += dot(p3, p3.yzx + 19.19); + return fract3(float3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x)); +} - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +float4 N14(float t) { + return fract4(sin(t*float4(123., 1024., 1456., 264.))*float4(6547., 345., 8799., 1564.)); +} +float N(float t) { + return fract(sin(t*12345.564)*7658.76); +} - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } +float Saw(float b, float t) { + return smoothstep(0., b, t)*smoothstep(1., b, t); +} - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" +float2 Drops(float2 uv, float t) { - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } - + float2 UV = uv; + + // DEFINE GRID + uv.y += t*0.8; + float2 a = float2(6., 1.); + float2 grid = a*2.; + float2 id = floor(uv*grid); + + // RANDOM SHIFT Y + float colShift = N(id.x); + uv.y += colShift; + + // DEFINE SPACES + id = floor(uv*grid); + float3 n = N13(id.x*35.2+id.y*2376.1); + float2 st = fract2(uv*grid)-float2(.5, 0); + + // POSITION DROPS + //clamp(2*x,0,2)+clamp(1-x*.5, -1.5, .5)+1.5-2 + float x = n.x-.5; + + float y = UV.y*20.; + + float distort = sin(y+sin(y)); + x += distort*(.5-abs(x))*(n.z-.5); + x *= .7; + float ti = fract(t+n.z); + y = (Saw(.85, ti)-.5)*.9+.5; + float2 p = float2(x, y); + + // DROPS + float d = length((st-p)*a.yx); + + float dSize = size; + + float Drop = smoothstep(dSize, .0, d); + + + float r = sqrt(smoothstep(1., y, st.y)); + float cd = abs(st.x-x); + + // TRAILS + float trail = smoothstep((dSize*.5+.03)*r, (dSize*.5-.05)*r, cd); + float trailFront = smoothstep(-.02, .02, st.y-y); + trail *= trailFront; + + + // DROPLETS + y = UV.y; + y += N(id.x); + float trail2 = smoothstep(dSize*r, .0, cd); + float droplets = max(0., (sin(y*(1.-y)*120.)-st.y))*trail2*trailFront*n.z; + y = fract(y*10.)+(st.y-.5); + float dd = length(st-float2(x, y)); + droplets = smoothstep(dSize*N(id.x), 0., dd); + float m = Drop+droplets*r*trailFront; + if(debug){ + m += st.x>a.y*.45 || st.y>a.x*.165 ? 1.2 : 0.; //DEBUG SPACES + } + + + return float2(m, trail); } +float StaticDrops(float2 uv, float t) { + uv *= 30.; + + float2 id = floor(uv); + uv = fract2(uv)-.5; + float3 n = N13(id.x*107.45+id.y*3543.654); + float2 p = (n.xy-.5)*0.5; + float d = length(uv-p); + + float fade = Saw(.025, fract(t+n.z)); + float c = smoothstep(size, 0., d)*fract(n.z*10.)*fade; -} + return c; +} - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSSceneSceneTransitionOverride { +float2 Rain(float2 uv, float t) { + //float s = StaticDrops(uv, t); + float2 r1 = Drops(uv, t); + float2 r2 = Drops(uv*1.8, t); + float c; + if(debug){ + c = r1.x; + }else{ + c = r1.x+r2.x;//s+r1.x+r2.x; + } + + c = smoothstep(.3, 1., c); + + if(debug){ + return float2(c, r1.y); + }else{ + return float2(c, max(r1.y, r2.y)); + } +} +float4 mainImage(VertData v_in) : TARGET +{ + float2 uv = v_in.uv;//(fragCoord.xy-.5*iResolution.xy) / iResolution.y; + uv.y = 1.0 - uv.y; + uv = uv * uv_scale; + float2 UV = v_in.uv; + float T = elapsed_time * speed / 100.0; + + float t = T*.2; + + UV = (UV-.5)*(.9)+.5; -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneSceneTransitionOverride')] -[Alias('obs.powershell.websocket.GetSceneSceneTransitionOverride')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( + float2 c = Rain(uv, t); -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, + float2 e = float2(.001, 0.); //pixel offset + float cx = Rain(uv+e, t).x; + float cy = Rain(uv+e.yx, t).x; + float2 n = float2(cx-c.x, cy-c.x); //normals -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + // BLUR derived from existical https://www.shadertoy.com/view/Xltfzj + float Pi = 6.28318530718; // Pi*2 + // GAUSSIAN BLUR SETTINGS {{{ + float Directions = 32.0; // BLUR DIRECTIONS (Default 16.0 - More is better but slower) + float Quality = 8.0; // BLUR QUALITY (Default 4.0 - More is better but slower) + // GAUSSIAN BLUR SETTINGS }}} + float2 Radius = blurSize/uv_size; + float3 col = image.Sample(textureSampler, UV).rgb; -process { + if(blurSize > 0.0){ + // Blur calculations + for(float d=0.0; dAdd|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 ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSSceneTransition { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSceneTransitionList')] -[Alias('obs.powershell.websocket.GetSceneTransitionList')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -50552,111 +49823,199 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSourceActive { - +function Get-OBSRectangularDropShadowShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSourceActive')] -[Alias('obs.powershell.websocket.GetSourceActive')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSRectangularDropShadowShader','Add-OBSRectangularDropShadowShader')] param( - +# Set the shadow_offset_x of OBSRectangularDropShadowShader +[Alias('shadow_offset_x')] +[ComponentModel.DefaultBindingProperty('shadow_offset_x')] +[Int32] +$ShadowOffsetX, +# Set the shadow_offset_y of OBSRectangularDropShadowShader +[Alias('shadow_offset_y')] +[ComponentModel.DefaultBindingProperty('shadow_offset_y')] +[Int32] +$ShadowOffsetY, +# Set the shadow_blur_size of OBSRectangularDropShadowShader +[Alias('shadow_blur_size')] +[ComponentModel.DefaultBindingProperty('shadow_blur_size')] +[Int32] +$ShadowBlurSize, +# Set the shadow_color of OBSRectangularDropShadowShader +[Alias('shadow_color')] +[ComponentModel.DefaultBindingProperty('shadow_color')] +[String] +$ShadowColor, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceName')] -[string] +[Alias('SceneItemName')] +[String] $SourceName, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceUuid')] -[string] -$SourceUuid, -# If set, will return the information that would otherwise be sent to OBS. +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'rectangular_drop_shadow' +$ShaderNoun = 'OBSRectangularDropShadowShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//Converted to OpenGL by Exeldro February 22, 2022 +uniform int shadow_offset_x< + string label = "shadow offset x"; + string widget_type = "slider"; + int minimum = -100; + int maximum = 100; + int step = 1; +>; +uniform int shadow_offset_y< + string label = "shadow offset y"; + string widget_type = "slider"; + int minimum = -100; + int maximum = 100; + int step = 1; +>; +uniform int shadow_blur_size< + string label = "shadow blur size"; + string widget_type = "slider"; + int minimum = 1; + int maximum = 100; + int step = 1; +> = 1; +uniform float4 shadow_color; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float4 mainImage(VertData v_in) : TARGET +{ + int shadow_blur_samples = int(pow(shadow_blur_size * 2 + 1, 2)); + + float4 color = image.Sample(textureSampler, v_in.uv); + float2 shadow_uv = float2(v_in.uv.x - uv_pixel_interval.x * int(shadow_offset_x), + v_in.uv.y - uv_pixel_interval.y * int(shadow_offset_y)); + + float start_of_overlap_x = max(0, shadow_uv.x - shadow_blur_size * uv_pixel_interval.x); + float end_of_overlap_x = min(1, shadow_uv.x + shadow_blur_size * uv_pixel_interval.x); + float x_proportion = (end_of_overlap_x - start_of_overlap_x) / (2 * shadow_blur_size * uv_pixel_interval.x); + + float start_of_overlap_y = max(0, shadow_uv.y - shadow_blur_size * uv_pixel_interval.y); + float end_of_overlap_y = min(1, shadow_uv.y + shadow_blur_size * uv_pixel_interval.y); + float y_proportion = (end_of_overlap_y - start_of_overlap_y) / (2 * shadow_blur_size * uv_pixel_interval.y); + + float4 final_shadow_color = float4(shadow_color.r, shadow_color.g, shadow_color.b, shadow_color.a * x_proportion * y_proportion); + + return final_shadow_color * (1-color.a) + color; +} - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} +' +} +$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 } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } + } + '(?>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 + } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } + 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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -50665,116 +50024,204 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSourceFilter { - +function Get-OBSReflectShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSourceFilter')] -[Alias('obs.powershell.websocket.GetSourceFilter')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSReflectShader','Add-OBSReflectShader')] param( - +# Set the Horizontal of OBSReflectShader +[ComponentModel.DefaultBindingProperty('Horizontal')] +[Management.Automation.SwitchParameter] +$Horizontal, +# Set the Vertical of OBSReflectShader +[ComponentModel.DefaultBindingProperty('Vertical')] +[Management.Automation.SwitchParameter] +$Vertical, +# Set the center_x_percent of OBSReflectShader +[Alias('center_x_percent')] +[ComponentModel.DefaultBindingProperty('center_x_percent')] +[Int32] +$CenterXPercent, +# Set the center_y_percent of OBSReflectShader +[Alias('center_y_percent')] +[ComponentModel.DefaultBindingProperty('center_y_percent')] +[Int32] +$CenterYPercent, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceName')] -[string] +[Alias('SceneItemName')] +[String] $SourceName, - +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceUuid')] -[string] -$SourceUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('filterName')] -[string] +[String] $FilterName, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +# 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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'Reflect' +$ShaderNoun = 'OBSReflectShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Simple Reflect Shader +// Reflects horizontally and/or vertically. - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +uniform bool Horizontal< + string label = "Reflect horizontally"; +> = false; +uniform bool Vertical< + string label = "Reflect vertically"; +> = true; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +uniform int center_x_percent< + string label = "center x percentage"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform int center_y_percent< + string label = "center y percentage"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + +float4 mainImage(VertData v_in) : TARGET +{ + float2 pos = v_in.uv; + float2 center_pos = float2(center_x_percent * .01, center_y_percent * .01); + + if (Horizontal == true) { + if (pos.x < center_pos.x) { + pos.x = center_pos.x - pos.x; + } else if (pos.x == center_pos.x) { + pos.x = pos.x; + } else { + pos.x = pos.x - center_pos.x; + } + } + if (Vertical == true) { + if (pos.y < center_pos.y) { + pos.y = center_pos.y - pos.y; + } else if (pos.y == center_pos.y) { + pos.y = pos.y; + } else { + pos.y = pos.y - center_pos.y; + } + } + + return image.Sample(textureSampler, pos); +} +' +} +$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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -50783,106 +50230,169 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSourceFilterDefaultSettings { - +function Get-OBSRemovePartialPixelsShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSourceFilterDefaultSettings')] -[Alias('obs.powershell.websocket.GetSourceFilterDefaultSettings')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSRemovePartialPixelsShader','Add-OBSRemovePartialPixelsShader')] param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('filterKind')] -[string] -$FilterKind, -# If set, will return the information that would otherwise be sent to OBS. +# Set the minimum_alpha_percent of OBSRemovePartialPixelsShader +[Alias('minimum_alpha_percent')] +[ComponentModel.DefaultBindingProperty('minimum_alpha_percent')] +[Int32] +$MinimumAlphaPercent, +# Set the notes of OBSRemovePartialPixelsShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'remove_partial_pixels' +$ShaderNoun = 'OBSRemovePartialPixelsShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Remove Partial Pixels shader by Charles Fettinger for obs-shaderfilter plugin 8/2020 +// https://github.com/Oncorporation/obs-shaderfilter +//Converted to OpenGL by Exeldro February 21, 2022 +uniform int minimum_alpha_percent< + string label = "minimum alpha percent"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform string notes< + string widget_type = "info"; +> = "Removes partial pixels, excellent for cleaning greenscreen. Default Minimum Alpha Percent is 50%, lowering will reveal more pixels"; - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} +float4 mainImage(VertData v_in) : TARGET +{ + float min_alpha = clamp(minimum_alpha_percent * .01, -1.0, 101.0); + float4 output_color = image.Sample(textureSampler, v_in.uv); + if (output_color.a < min_alpha) + { + return float4(0.0, 0.0, 0.0, 0.0); + } + else + { + return float4(output_color); + } +} +' +} +$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 } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } + } + '(?>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 + } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } + 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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -50891,101 +50401,204 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSourceFilterKind { - +function Get-OBSRepeatGridCenterCropShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSourceFilterKindList')] -[Alias('obs.powershell.websocket.GetSourceFilterKindList')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSRepeatGridCenterCropShader','Add-OBSRepeatGridCenterCropShader')] param( -# If set, will return the information that would otherwise be sent to OBS. +# Set the ViewProj of OBSRepeatGridCenterCropShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the image of OBSRepeatGridCenterCropShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the alpha of OBSRepeatGridCenterCropShader +[ComponentModel.DefaultBindingProperty('alpha')] +[Single] +$Alpha, +# Set the columns of OBSRepeatGridCenterCropShader +[ComponentModel.DefaultBindingProperty('columns')] +[Single] +$Columns, +# Set the rows of OBSRepeatGridCenterCropShader +[ComponentModel.DefaultBindingProperty('rows')] +[Single] +$Rows, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'repeat_grid_center_crop' +$ShaderNoun = 'OBSRepeatGridCenterCropShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// repeat_grid_center_crop.effect +uniform float4x4 ViewProj; +uniform texture2d image; +sampler_state def_sampler { + Filter = Linear; + AddressU = Clamp; + AddressV = Clamp; +}; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +uniform float alpha = 1.0; +uniform float columns = 3.0; +uniform float rows = 1.0; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +struct VertInOut { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } +VertInOut VSDefault(VertInOut vert_in) { + VertInOut vert_out; + vert_out.pos = mul(float4(vert_in.pos.xyz, 1), ViewProj); + vert_out.uv = vert_in.uv * float2(columns, rows); + return vert_out; +} + +float4 PSMain(VertInOut vert_in) : TARGET { + // Calculate fractional UV within grid cell + float2 cell_uv = frac(vert_in.uv); + + // Calculate center crop parameters + float horizontalCropStart = 0.5 - 0.5/columns; + + // Map to centered portion of original image + float2 original_uv = float2( + cell_uv.x / columns + horizontalCropStart, + cell_uv.y / rows + ); + + // Sample the image + float4 col = image.Sample(def_sampler, original_uv); + col.a *= alpha; + return col; +} + +technique Draw { + pass { + vertex_shader = VSDefault(vert_in); + pixel_shader = PSMain(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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -50994,111 +50607,267 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSourceFilterList { - +function Get-OBSRepeatShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSourceFilterList')] -[Alias('obs.powershell.websocket.GetSourceFilterList')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSRepeatShader','Add-OBSRepeatShader')] param( - +# Set the ViewProj of OBSRepeatShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the color_matrix of OBSRepeatShader +[Alias('color_matrix')] +[ComponentModel.DefaultBindingProperty('color_matrix')] +[Single[][]] +$ColorMatrix, +# Set the color_range_min of OBSRepeatShader +[Alias('color_range_min')] +[ComponentModel.DefaultBindingProperty('color_range_min')] +[Single[]] +$ColorRangeMin, +# Set the color_range_max of OBSRepeatShader +[Alias('color_range_max')] +[ComponentModel.DefaultBindingProperty('color_range_max')] +[Single[]] +$ColorRangeMax, +# Set the image of OBSRepeatShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the elapsed_time of OBSRepeatShader +[Alias('elapsed_time')] +[ComponentModel.DefaultBindingProperty('elapsed_time')] +[Single] +$ElapsedTime, +# Set the uv_offset of OBSRepeatShader +[Alias('uv_offset')] +[ComponentModel.DefaultBindingProperty('uv_offset')] +[Single[]] +$UvOffset, +# Set the uv_scale of OBSRepeatShader +[Alias('uv_scale')] +[ComponentModel.DefaultBindingProperty('uv_scale')] +[Single[]] +$UvScale, +# Set the uv_pixel_interval of OBSRepeatShader +[Alias('uv_pixel_interval')] +[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +[Single[]] +$UvPixelInterval, +# Set the uv_size of OBSRepeatShader +[Alias('uv_size')] +[ComponentModel.DefaultBindingProperty('uv_size')] +[Single[]] +$UvSize, +# Set the rand_f of OBSRepeatShader +[Alias('rand_f')] +[ComponentModel.DefaultBindingProperty('rand_f')] +[Single] +$RandF, +# Set the alpha of OBSRepeatShader +[ComponentModel.DefaultBindingProperty('alpha')] +[Single] +$Alpha, +# Set the copies of OBSRepeatShader +[ComponentModel.DefaultBindingProperty('copies')] +[Single] +$Copies, +# Set the notes of OBSRepeatShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceName')] -[string] +[Alias('SceneItemName')] +[String] $SourceName, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceUuid')] -[string] -$SourceUuid, -# If set, will return the information that would otherwise be sent to OBS. +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'repeat' +$ShaderNoun = 'OBSRepeatShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Repeat Effect By Charles Fettinger (https://github.com/Oncorporation) 2/2019 +uniform float4x4 ViewProj; +uniform float4x4 color_matrix; +uniform float3 color_range_min = {0.0, 0.0, 0.0}; +uniform float3 color_range_max = {1.0, 1.0, 1.0}; +uniform texture2d image; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +uniform float elapsed_time; +uniform float2 uv_offset; +uniform float2 uv_scale; +uniform float2 uv_pixel_interval; +uniform float2 uv_size; +uniform float rand_f; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +uniform float alpha< + string label = "Alpha"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 3.0; + float step = 0.001; +> = 1.0; +uniform float copies< + string label = "Copies"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.1; +> = 4.0; +uniform string notes< + string widget_type = "info"; +> = ''copies, use a number that has a square root. Alpha adjusts the alpha level of the copies (recommend 0.5-2.0 recommend)''; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } +sampler_state def_sampler { + Filter = Linear; + AddressU = Repeat; + AddressV = Repeat; +}; + +struct VertInOut { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; + +VertInOut VSDefault(VertInOut vert_in) +{ + VertInOut vert_out; + vert_out.pos = mul(float4(vert_in.pos.xyz, 1 ), ViewProj); + vert_out.uv = vert_in.uv * sqrt(copies); + return vert_out; +} + +float4 PSDrawBare(VertInOut vert_in) : TARGET +{ + float4 rgba = image.Sample(def_sampler, vert_in.uv); + rgba.a *= alpha; + return rgba; +} + +technique Draw +{ + pass + { + vertex_shader = VSDefault(vert_in); + pixel_shader = PSDrawBare(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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -51107,237 +50876,300 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSSourceScreenshot { - +function Get-OBSRepeatTextureShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSourceScreenshot')] -[Alias('obs.powershell.websocket.GetSourceScreenshot')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSRepeatTextureShader','Add-OBSRepeatTextureShader')] param( - +# Set the ViewProj of OBSRepeatTextureShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the color_matrix of OBSRepeatTextureShader +[Alias('color_matrix')] +[ComponentModel.DefaultBindingProperty('color_matrix')] +[Single[][]] +$ColorMatrix, +# Set the color_range_min of OBSRepeatTextureShader +[Alias('color_range_min')] +[ComponentModel.DefaultBindingProperty('color_range_min')] +[Single[]] +$ColorRangeMin, +# Set the color_range_max of OBSRepeatTextureShader +[Alias('color_range_max')] +[ComponentModel.DefaultBindingProperty('color_range_max')] +[Single[]] +$ColorRangeMax, +# Set the image of OBSRepeatTextureShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the tex_image of OBSRepeatTextureShader +[Alias('tex_image')] +[ComponentModel.DefaultBindingProperty('tex_image')] +[String] +$TexImage, +# Set the elapsed_time of OBSRepeatTextureShader +[Alias('elapsed_time')] +[ComponentModel.DefaultBindingProperty('elapsed_time')] +[Single] +$ElapsedTime, +# Set the uv_offset of OBSRepeatTextureShader +[Alias('uv_offset')] +[ComponentModel.DefaultBindingProperty('uv_offset')] +[Single[]] +$UvOffset, +# Set the uv_scale of OBSRepeatTextureShader +[Alias('uv_scale')] +[ComponentModel.DefaultBindingProperty('uv_scale')] +[Single[]] +$UvScale, +# Set the uv_pixel_interval of OBSRepeatTextureShader +[Alias('uv_pixel_interval')] +[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +[Single[]] +$UvPixelInterval, +# Set the uv_size of OBSRepeatTextureShader +[Alias('uv_size')] +[ComponentModel.DefaultBindingProperty('uv_size')] +[Single[]] +$UvSize, +# Set the rand_f of OBSRepeatTextureShader +[Alias('rand_f')] +[ComponentModel.DefaultBindingProperty('rand_f')] +[Single] +$RandF, +# Set the blend of OBSRepeatTextureShader +[ComponentModel.DefaultBindingProperty('blend')] +[Single] +$Blend, +# Set the copies of OBSRepeatTextureShader +[ComponentModel.DefaultBindingProperty('copies')] +[Single] +$Copies, +# Set the notes of OBSRepeatTextureShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# Set the alpha_percentage of OBSRepeatTextureShader +[Alias('alpha_percentage')] +[ComponentModel.DefaultBindingProperty('alpha_percentage')] +[Single] +$AlphaPercentage, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceName')] -[string] +[Alias('SceneItemName')] +[String] $SourceName, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceUuid')] -[string] -$SourceUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('imageFormat')] -[string] -$ImageFormat, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('imageWidth')] -[ValidateRange(8,4096)] -[double] -$ImageWidth, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('imageHeight')] -[ValidateRange(8,4096)] -[double] -$ImageHeight, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('imageCompressionQuality')] -[ValidateRange(-1,100)] -[double] -$ImageCompressionQuality, -# If set, will return the information that would otherwise be sent to OBS. +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'repeat_texture' +$ShaderNoun = 'OBSRepeatTextureShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Repeat Effect By Charles Fettinger (https://github.com/Oncorporation) 2/2019 +uniform float4x4 ViewProj; +uniform float4x4 color_matrix; +uniform float3 color_range_min = {0.0, 0.0, 0.0}; +uniform float3 color_range_max = {1.0, 1.0, 1.0}; +uniform texture2d image; +uniform texture2d tex_image; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } +uniform float elapsed_time; +uniform float2 uv_offset; +uniform float2 uv_scale; +uniform float2 uv_pixel_interval; +uniform float2 uv_size; +uniform float rand_f; -} +uniform float blend< + string label = "Blend"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 3.0; + float step = 0.001; +> = 1.0; +uniform float copies< + string label = "Copies"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.1; +> = 4.0; +uniform string notes< + string widget_type = "info"; +> = ''copies, use a number that has a square root. Blend adjusts the ratio of source and texture''; +uniform float alpha_percentage< + string label = "alpha percentage"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.1; +> = 100.0; +sampler_state tex_sampler { + Filter = Linear; + AddressU = Repeat; + AddressV = Repeat; +}; -} +sampler_state base_sampler { + Filter = Linear; + AddressU = Clamp; + AddressV = Clamp; +}; - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSSpecialInputs { +struct VertIn { + float4 pos : POSITION; + float2 uv_0 : TEXCOORD0; + float2 uv_1 : TEXCOORD1; +}; +struct VertOut { + float4 pos : POSITION; + float2 uv_0 : TEXCOORD0; + float2 uv_1 : TEXCOORD1; +}; -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetSpecialInputs')] -[Alias('obs.powershell.websocket.GetSpecialInputs')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) +VertOut VSDefault(VertIn vert_in) +{ + VertOut vert_out; + vert_out.pos = mul(float4(vert_in.pos.xyz, 1 ), ViewProj); + vert_out.uv_1 = vert_in.uv_0; + vert_out.uv_0 = vert_in.uv_0 * sqrt(copies); + return vert_out; +} +float4 PSDrawBare(VertOut vert_in) : TARGET +{ + float alpha = clamp(alpha_percentage * 0.01 ,-1.0,2.0); + float4 tex = tex_image.Sample(tex_sampler, vert_in.uv_0); + float4 base = image.Sample(base_sampler, vert_in.uv_1); -process { + return (1 - alpha) * base + (alpha) * tex; +} +technique Draw +{ + pass + { + vertex_shader = VSDefault(vert_in); + pixel_shader = PSDrawBare(vert_in); + } +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -51346,101 +51178,199 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSStats { - +function Get-OBSRGBAPercentShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetStats')] -[Alias('obs.powershell.websocket.GetStats')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSRGBAPercentShader','Add-OBSRGBAPercentShader')] param( -# If set, will return the information that would otherwise be sent to OBS. +# Set the RedPercent of OBSRGBAPercentShader +[ComponentModel.DefaultBindingProperty('RedPercent')] +[Single] +$RedPercent, +# Set the GreenPercent of OBSRGBAPercentShader +[ComponentModel.DefaultBindingProperty('GreenPercent')] +[Single] +$GreenPercent, +# Set the BluePercent of OBSRGBAPercentShader +[ComponentModel.DefaultBindingProperty('BluePercent')] +[Single] +$BluePercent, +# Set the AlphaPercent of OBSRGBAPercentShader +[ComponentModel.DefaultBindingProperty('AlphaPercent')] +[Single] +$AlphaPercent, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'RGBA_Percent' +$ShaderNoun = 'OBSRGBAPercentShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Simple RGBA Percent Shader +// Allows Red, Green, or Blue to be adjusted between 0-200% +// Allows Alpha to be adjusted between 0/100% +uniform float RedPercent< + string label = "Red percentage"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 200; + float step = 1.0; +> = 100; + +uniform float GreenPercent< + string label = "Green percentage"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 200; + float step = 1.0; +> = 100; +uniform float BluePercent< + string label = "Blue percentage"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 200; + float step = 1.0; +> = 100.0; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +uniform float AlphaPercent< + string label = "Alpha percentage"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 1.0; +> = 100.0; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } +float4 mainImage(VertData v_in) : TARGET +{ + float2 pos = v_in.uv; + + float4 imageColors = image.Sample(textureSampler, v_in.uv); + float4 adjustedColor = float4( + imageColors.r * (RedPercent * 0.01), + imageColors.g * (GreenPercent * 0.01), + imageColors.b * (BluePercent * 0.01), + imageColors.a * (AlphaPercent * 0.01) + ); + return adjustedColor; +} + +' +} +$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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -51449,101 +51379,268 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSStreamServiceSettings { - +function Get-OBSRgbColorWheelShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetStreamServiceSettings')] -[Alias('obs.powershell.websocket.GetStreamServiceSettings')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSRgbColorWheelShader','Add-OBSRgbColorWheelShader')] param( -# If set, will return the information that would otherwise be sent to OBS. +# Set the speed of OBSRgbColorWheelShader +[ComponentModel.DefaultBindingProperty('speed')] +[Single] +$Speed, +# Set the color_depth of OBSRgbColorWheelShader +[Alias('color_depth')] +[ComponentModel.DefaultBindingProperty('color_depth')] +[Single] +$ColorDepth, +# Set the Apply_To_Image of OBSRgbColorWheelShader +[Alias('Apply_To_Image')] +[ComponentModel.DefaultBindingProperty('Apply_To_Image')] +[Management.Automation.SwitchParameter] +$ApplyToImage, +# Set the Replace_Image_Color of OBSRgbColorWheelShader +[Alias('Replace_Image_Color')] +[ComponentModel.DefaultBindingProperty('Replace_Image_Color')] +[Management.Automation.SwitchParameter] +$ReplaceImageColor, +# Set the Apply_To_Specific_Color of OBSRgbColorWheelShader +[Alias('Apply_To_Specific_Color')] +[ComponentModel.DefaultBindingProperty('Apply_To_Specific_Color')] +[Management.Automation.SwitchParameter] +$ApplyToSpecificColor, +# Set the Color_To_Replace of OBSRgbColorWheelShader +[Alias('Color_To_Replace')] +[ComponentModel.DefaultBindingProperty('Color_To_Replace')] +[String] +$ColorToReplace, +# Set the Alpha_Percentage of OBSRgbColorWheelShader +[Alias('Alpha_Percentage')] +[ComponentModel.DefaultBindingProperty('Alpha_Percentage')] +[Single] +$AlphaPercentage, +# Set the center_width_percentage of OBSRgbColorWheelShader +[Alias('center_width_percentage')] +[ComponentModel.DefaultBindingProperty('center_width_percentage')] +[Int32] +$CenterWidthPercentage, +# Set the center_height_percentage of OBSRgbColorWheelShader +[Alias('center_height_percentage')] +[ComponentModel.DefaultBindingProperty('center_height_percentage')] +[Int32] +$CenterHeightPercentage, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'rgb_color_wheel' +$ShaderNoun = 'OBSRgbColorWheelShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// RGB Color Wheel shader by Charles Fettinger for obs-shaderfilter plugin 5/2020 +// https://github.com/Oncorporation/obs-shaderfilter +//Converted to OpenGl by Q-mii & Exeldro February 25, 2022 +uniform float speed< + string label = "Speed"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 15.0; + float step = 0.1; +> = 2.0; +uniform float color_depth< + string label = "Color Depth"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.1; +> = 2.10; +uniform bool Apply_To_Image; +uniform bool Replace_Image_Color; +uniform bool Apply_To_Specific_Color; +uniform float4 Color_To_Replace; +uniform float Alpha_Percentage< + string label = "Alpha Percentage"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.1; +> = 100; // +uniform int center_width_percentage< + string label = "center width percentage"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform int center_height_percentage< + string label = "center height percentage"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +float3 hsv2rgb(float3 c) +{ + float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y); +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float mod(float x, float y) +{ + return x - y * floor(x / y); +} - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +float4 mainImage(VertData v_in) : TARGET +{ + const float PI = 3.14159265f;//acos(-1); + float PI180th = 0.0174532925; //PI divided by 180 + float4 rgba = image.Sample(textureSampler, v_in.uv); + float2 center_pixel_coordinates = float2((center_width_percentage * 0.01), (center_height_percentage * 0.01) ); + float2 st = v_in.uv* uv_scale; + float2 toCenter = center_pixel_coordinates - st ; + float r = length(toCenter) * color_depth; + float angle = atan2(toCenter.y ,toCenter.x ); + float angleMod = (elapsed_time * mod(speed ,18)) / 18; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + rgba.rgb = hsv2rgb(float3((angle / PI*0.5) + angleMod,r,1.0)); + + float4 color; + float4 original_color; + if (Apply_To_Image) + { + color = image.Sample(textureSampler, v_in.uv); + original_color = color; + float luma = color.r * 0.299 + color.g * 0.587 + color.b * 0.114; + if (Replace_Image_Color) + color = float4(luma, luma, luma, luma); + rgba = lerp(original_color, rgba * color,clamp(Alpha_Percentage *.01 ,0,1.0)); + + } + if (Apply_To_Specific_Color) + { + color = image.Sample(textureSampler, v_in.uv); + original_color = color; + color = (distance(color.rgb, Color_To_Replace.rgb) <= 0.075) ? rgba : color; + rgba = lerp(original_color, color, clamp(Alpha_Percentage * .01, 0, 1.0)); + } + + return rgba; +} +' +} +$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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -51552,101 +51649,212 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSStreamStatus { - +function Get-OBSRgbSplitShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetStreamStatus')] -[Alias('obs.powershell.websocket.GetStreamStatus')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSRgbSplitShader','Add-OBSRgbSplitShader')] param( -# If set, will return the information that would otherwise be sent to OBS. +# Set the redx of OBSRgbSplitShader +[ComponentModel.DefaultBindingProperty('redx')] +[Single] +$Redx, +# Set the redy of OBSRgbSplitShader +[ComponentModel.DefaultBindingProperty('redy')] +[Single] +$Redy, +# Set the greenx of OBSRgbSplitShader +[ComponentModel.DefaultBindingProperty('greenx')] +[Single] +$Greenx, +# Set the greeny of OBSRgbSplitShader +[ComponentModel.DefaultBindingProperty('greeny')] +[Single] +$Greeny, +# Set the bluex of OBSRgbSplitShader +[ComponentModel.DefaultBindingProperty('bluex')] +[Single] +$Bluex, +# Set the bluey of OBSRgbSplitShader +[ComponentModel.DefaultBindingProperty('bluey')] +[Single] +$Bluey, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'rgb_split' +$ShaderNoun = 'OBSRgbSplitShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform float redx< + string label = "Red X"; + string widget_type = "slider"; + float minimum = -10.0; + float maximum = 10.0; + float step = 0.01; +> = 2.00; +uniform float redy< + string label = "Red Y"; + string widget_type = "slider"; + float minimum = -10.0; + float maximum = 10.0; + float step = 0.01; +> = 0.00; +uniform float greenx< + string label = "Green X"; + string widget_type = "slider"; + float minimum = -10.0; + float maximum = 10.0; + float step = 0.01; +> = 0.00; +uniform float greeny< + string label = "Green Y"; + string widget_type = "slider"; + float minimum = -10.0; + float maximum = 10.0; + float step = 0.01; +> = 0.00; +uniform float bluex< + string label = "Blue X"; + string widget_type = "slider"; + float minimum = -10.0; + float maximum = 10.0; + float step = 0.01; +> = -2.00; +uniform float bluey< + string label = "Blue Y"; + string widget_type = "slider"; + float minimum = -10.0; + float maximum = 10.0; + float step = 0.01; +> = 0.00; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float4 mainImage(VertData v_in) : TARGET +{ + float4 c = image.Sample(textureSampler, v_in.uv); + if(redx != 0.0 || redy != 0.0) + c.r = image.Sample(textureSampler, v_in.uv + float2(redx/100.0, redy/100.0)).r; + if(greenx != 0.0 || greeny != 0.0) + c.g = image.Sample(textureSampler, v_in.uv + float2(greenx/100.0, greeny/100.0)).g; + if(bluex != 0.0 || bluey != 0.0) + c.b = image.Sample(textureSampler, v_in.uv + float2(bluex/100.0, bluey/100.0)).b; + return c; +} +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -51655,204 +51863,225 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSStudioModeEnabled { - +function Get-OBSRgbvisibilityShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetStudioModeEnabled')] -[Alias('obs.powershell.websocket.GetStudioModeEnabled')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSRgbvisibilityShader','Add-OBSRgbvisibilityShader')] param( -# If set, will return the information that would otherwise be sent to OBS. +# Set the Red of OBSRgbvisibilityShader +[ComponentModel.DefaultBindingProperty('Red')] +[Single] +$Red, +# Set the Green of OBSRgbvisibilityShader +[ComponentModel.DefaultBindingProperty('Green')] +[Single] +$Green, +# Set the Blue of OBSRgbvisibilityShader +[ComponentModel.DefaultBindingProperty('Blue')] +[Single] +$Blue, +# Set the RedVisibility of OBSRgbvisibilityShader +[ComponentModel.DefaultBindingProperty('RedVisibility')] +[Single] +$RedVisibility, +# Set the GreenVisibility of OBSRgbvisibilityShader +[ComponentModel.DefaultBindingProperty('GreenVisibility')] +[Single] +$GreenVisibility, +# Set the BlueVisibility of OBSRgbvisibilityShader +[ComponentModel.DefaultBindingProperty('BlueVisibility')] +[Single] +$BlueVisibility, +# Set the notes of OBSRgbvisibilityShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'rgbvisibility' +$ShaderNoun = 'OBSRgbvisibilityShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// RGB visibility separation filter, created by EposVox +uniform float Red< + string label = "Red"; + string widget_type = "slider"; + float minimum = 0.1; + float maximum = 10.0; + float step = 0.01; +> = 2.2; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +uniform float Green< + string label = "Green"; + string widget_type = "slider"; + float minimum = 0.1; + float maximum = 10.0; + float step = 0.01; +> = 2.2; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +uniform float Blue< + string label = "Blue"; + string widget_type = "slider"; + float minimum = 0.1; + float maximum = 10.0; + float step = 0.01; +> = 2.2; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } +uniform float RedVisibility< + string label = "Red Visibility"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 1.0; + +uniform float GreenVisibility< + string label = "Green Visibility"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 1.0; + +uniform float BlueVisibility< + string label = "Blue Visibility"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 1.0; + +uniform string notes< + string widget_type = "info"; +> = "Modify Colors to correct for gamma, use equal values for general correction."; + +float4 mainImage(VertData v_in) : TARGET +{ + float4 c = image.Sample(textureSampler, v_in.uv); + float redChannel = pow(c.r, Red) * RedVisibility; + float greenChannel = pow(c.g, Green) * GreenVisibility; + float blueChannel = pow(c.b, Blue) * BlueVisibility; + + return float4(redChannel, greenChannel, blueChannel, c.a); +} + +' +} +$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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + continue nextParameter + } } - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSTransitionKind { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetTransitionKindList')] -[Alias('obs.powershell.websocket.GetTransitionKindList')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -51861,204 +52090,291 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSVersion { - +function Get-OBSRGSSAAShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetVersion')] -[Alias('obs.powershell.websocket.GetVersion')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSRGSSAAShader','Add-OBSRGSSAAShader')] param( -# If set, will return the information that would otherwise be sent to OBS. +# Set the ColorSigma of OBSRGSSAAShader +[ComponentModel.DefaultBindingProperty('ColorSigma')] +[Single] +$ColorSigma, +# Set the SpatialSigma of OBSRGSSAAShader +[ComponentModel.DefaultBindingProperty('SpatialSigma')] +[Single] +$SpatialSigma, +# Set the notes of OBSRGSSAAShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'RGSSAA' +$ShaderNoun = 'OBSRGSSAAShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// RGSSAA shader by Eliseu Amaro for obs-shaderfilter plugin 2/2024 +// https://github.com/exeldro/obs-shaderfilter/tree/master +// Using edge detection shader as a base, created by Hallatore +// https://forums.unrealengine.com/t/sharper-image-without-the-edge-artifacts/108461 +uniform float ColorSigma< + string label = "Color Sigma"; + string widget_type = "slider"; + float minimum = 0.1; + float maximum = 1.0; + float step = 0.1; +> = 1.0; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } +uniform float SpatialSigma< + string label = "Spatial Sigma"; + string widget_type = "slider"; + float minimum = 0.1; + float maximum = 1.0; + float step = 0.1; +> = 1.0; - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } +uniform string notes< + string widget_type = "info"; +> = "Performs RGSSAA, a form of anti-aliasing. Implementation roughly follows the original with color and spatial sigma (or strengths) parameters. Useful to apply before a sharpen pass (e.g on a webcam feed)." +float Luminance(float3 rgb) +{ + return rgb.r * 0.299 + rgb.g * 0.587 + rgb.b * 0.114; } +float4 mainImage(VertData v_in) : TARGET +{ + float3 SceneColor = image.Sample(textureSampler, v_in.uv).rgb; + float2 SceneUV = v_in.uv; + float2 TexelScale = 1.0f/uv_size; -} + const float SQRT2 = 1.4142135624; + const float PI = 3.141592654; + const float angle = PI / 8.0; + const float cs = cos(angle); + const float sn = sin(angle); - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSVideoSettings { + // Rotated grid samples + float3 C1 = + image.Sample(textureSampler, SceneUV + float2(cs, -sn) * TexelScale).rgb; + float3 C2 = + image.Sample(textureSampler, SceneUV + float2(-cs, -sn) * TexelScale).rgb; + float3 C3 = + image.Sample(textureSampler, SceneUV + float2(-sn, cs) * TexelScale).rgb; + float3 C4 = + image.Sample(textureSampler, SceneUV + float2(sn, cs) * TexelScale).rgb; + float3 C5 = + image.Sample(textureSampler, SceneUV + float2(cs * SQRT2, 0) * TexelScale).rgb; + float3 C6 = + image.Sample(textureSampler, SceneUV + float2(0, sn *SQRT2) * TexelScale).rgb; + float3 C7 = + image.Sample(textureSampler, SceneUV + float2(-cs * SQRT2, 0) * TexelScale).rgb; + float3 C8 = + image.Sample(textureSampler, SceneUV + float2(0, -sn *SQRT2) * TexelScale).rgb; + // Luminance edge detection + float A0 = Luminance(SceneColor); + float CL1 = Luminance(C1); + float L1 = ((max(CL1, A0)) / (min(CL1, A0) + 0.001) - 1); + float CL2 = Luminance(C2); + float L2 = ((max(CL2, A0)) / (min(CL2, A0) + 0.001) - 1); + float CL3 = Luminance(C3); + float L3 = ((max(CL3, A0)) / (min(CL3, A0) + 0.001) - 1); + float CL4 = Luminance(C4); + float L4 = ((max(CL4, A0)) / (min(CL4, A0) + 0.001) - 1); + float CL5 = Luminance(C5); + float L5 = ((max(CL5, A0)) / (min(CL5, A0) + 0.001) - 1); + float CL6 = Luminance(C6); + float L6 = ((max(CL6, A0)) / (min(CL6, A0) + 0.001) - 1); + float CL7 = Luminance(C7); + float L7 = ((max(CL7, A0)) / (min(CL7, A0) + 0.001) - 1); + float CL8 = Luminance(C8); + float L8 = ((max(CL8, A0)) / (min(CL8, A0) + 0.001) - 1); + float NeighborDifference = max(max(max(L1, L2), max(L3, L4)), max(max(L5, L6), max(L7, L8))); -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetVideoSettings')] -[Alias('obs.powershell.websocket.GetVideoSettings')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + // Calculate distance-based weights + float2 Dist1 = float2(cs, -sn); + float2 Dist2 = float2(-cs, -sn); + float2 Dist3 = float2(-sn, cs); + float2 Dist4 = float2(sn, cs); + float2 Dist5 = float2(cs * SQRT2, 0); + float2 Dist6 = float2(0, sn * SQRT2); + float2 Dist7 = float2(-cs * SQRT2, 0); + float2 Dist8 = float2(0, -sn * SQRT2); + float SW1 = exp(-dot(Dist1, Dist1) / (2.0 * SpatialSigma * SpatialSigma)); + float SW2 = exp(-dot(Dist2, Dist2) / (2.0 * SpatialSigma * SpatialSigma)); + float SW3 = exp(-dot(Dist3, Dist3) / (2.0 * SpatialSigma * SpatialSigma)); + float SW4 = exp(-dot(Dist4, Dist4) / (2.0 * SpatialSigma * SpatialSigma)); + float SW5 = exp(-dot(Dist5, Dist5) / (2.0 * SpatialSigma * SpatialSigma)); + float SW6 = exp(-dot(Dist6, Dist6) / (2.0 * SpatialSigma * SpatialSigma)); + float SW7 = exp(-dot(Dist7, Dist7) / (2.0 * SpatialSigma * SpatialSigma)); + float SW8 = exp(-dot(Dist8, Dist8) / (2.0 * SpatialSigma * SpatialSigma)); + + // Color weights + float3 ColorDiff1 = SceneColor.rgb - C1; + float3 ColorDiff2 = SceneColor.rgb - C2; + float3 ColorDiff3 = SceneColor.rgb - C3; + float3 ColorDiff4 = SceneColor.rgb - C4; + float3 ColorDiff5 = SceneColor.rgb - C5; + float3 ColorDiff6 = SceneColor.rgb - C6; + float3 ColorDiff7 = SceneColor.rgb - C7; + float3 ColorDiff8 = SceneColor.rgb - C8; + float CW1 = exp(-dot(ColorDiff1, ColorDiff1) / (2.0 * ColorSigma * ColorSigma)); + float CW2 = exp(-dot(ColorDiff2, ColorDiff2) / (2.0 * ColorSigma * ColorSigma)); + float CW3 = exp(-dot(ColorDiff3, ColorDiff3) / (2.0 * ColorSigma * ColorSigma)); + float CW4 = exp(-dot(ColorDiff4, ColorDiff4) / (2.0 * ColorSigma * ColorSigma)); + float CW5 = exp(-dot(ColorDiff5, ColorDiff5) / (2.0 * ColorSigma * ColorSigma)); + float CW6 = exp(-dot(ColorDiff6, ColorDiff6) / (2.0 * ColorSigma * ColorSigma)); + float CW7 = exp(-dot(ColorDiff7, ColorDiff7) / (2.0 * ColorSigma * ColorSigma)); + float CW8 = exp(-dot(ColorDiff8, ColorDiff8) / (2.0 * ColorSigma * ColorSigma)); -process { + // Mixing weights + float W1 = SW1 * CW1; + float W2 = SW2 * CW2; + float W3 = SW3 * CW3; + float W4 = SW4 * CW4; + float W5 = SW5 * CW5; + float W6 = SW6 * CW6; + float W7 = SW7 * CW7; + float W8 = SW8 * CW8; + float TotalWeight = W1 + W2 + W3 + W4 + W5 + W6 + W7 + W8; + // Weighted color + float3 AAResult = (C1 * W1 + C2 * W2 + C3 * W3 + C4 * W4 + C5 * W5 + C6 * W6 + + C7 * W7 + C8 * W8) / + max(TotalWeight, 0.0001); - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + // Blend it + float4 LuminanceNeightbors = float4(CL1, CL2, CL3, CL4); + float4 LuminanceNeightbors2 = float4(CL5, CL6, CL7, CL8); + float4 A0LuminanceNeightbors = abs(A0 - LuminanceNeightbors); + float4 A0LuminanceNeightbors2 = abs(A0 - LuminanceNeightbors2); + float A0Max = max(max(A0LuminanceNeightbors.r, A0LuminanceNeightbors.g), max(A0LuminanceNeightbors.b, A0LuminanceNeightbors.a)); + float A0Max2 = max(max(A0LuminanceNeightbors2.r, A0LuminanceNeightbors2.g), max(A0LuminanceNeightbors2.b, A0LuminanceNeightbors2.a)); + float HDREdge = max(A0Max, A0Max2); + float EdgeMask = saturate(1.0f - HDREdge); - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + return float4(lerp(SceneColor.rgb, AAResult, EdgeMask), 1.0); +} - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } +' +} +$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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -52067,101 +52383,202 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Get-OBSVirtualCamStatus { - +function Get-OBSRippleShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'GetVirtualCamStatus')] -[Alias('obs.powershell.websocket.GetVirtualCamStatus')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] +[Alias('Set-OBSRippleShader','Add-OBSRippleShader')] param( -# If set, will return the information that would otherwise be sent to OBS. +# Set the distance_factor of OBSRippleShader +[Alias('distance_factor')] +[ComponentModel.DefaultBindingProperty('distance_factor')] +[Single] +$DistanceFactor, +# Set the time_factor of OBSRippleShader +[Alias('time_factor')] +[ComponentModel.DefaultBindingProperty('time_factor')] +[Single] +$TimeFactor, +# Set the power_factor of OBSRippleShader +[Alias('power_factor')] +[ComponentModel.DefaultBindingProperty('power_factor')] +[Single] +$PowerFactor, +# Set the center_pos_x of OBSRippleShader +[Alias('center_pos_x')] +[ComponentModel.DefaultBindingProperty('center_pos_x')] +[Single] +$CenterPosX, +# Set the center_pos_y of OBSRippleShader +[Alias('center_pos_y')] +[ComponentModel.DefaultBindingProperty('center_pos_y')] +[Single] +$CenterPosY, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'ripple' +$ShaderNoun = 'OBSRippleShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform float distance_factor< + string label = "distance factor"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.001; +> = 12.0; +uniform float time_factor< + string label = "time factor"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 2.0; +uniform float power_factor< + string label = "power factor"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 3.0; +uniform float center_pos_x< + string label = "center pos x"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; +uniform float center_pos_y< + string label = "center pos y"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; +float4 mainImage(VertData v_in) : TARGET +{ + float2 cPos = (v_in.uv * 2 ) -1; + float2 center_pos = float2(center_pos_x, center_pos_y); + float cLength = distance(cPos, center_pos); + float2 uv = v_in.uv+(cPos/cLength)*cos(cLength*distance_factor-elapsed_time*time_factor) * power_factor / 100.0; + return image.Sample(textureSampler, uv); +} +' +} +$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 + } + } - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -52170,110 +52587,237 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Open-OBSInputFiltersDialog { - +function Get-OBSRotatingSourceShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'OpenInputFiltersDialog')] -[Alias('obs.powershell.websocket.OpenInputFiltersDialog')] +[Alias('Set-OBSRotatingSourceShader','Add-OBSRotatingSourceShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - +# Set the spin_speed of OBSRotatingSourceShader +[Alias('spin_speed')] +[ComponentModel.DefaultBindingProperty('spin_speed')] +[Single] +$SpinSpeed, +# Set the rotation of OBSRotatingSourceShader +[ComponentModel.DefaultBindingProperty('rotation')] +[Single] +$Rotation, +# Set the zoomin of OBSRotatingSourceShader +[ComponentModel.DefaultBindingProperty('zoomin')] +[Single] +$Zoomin, +# Set the keep_aspectratio of OBSRotatingSourceShader +[Alias('keep_aspectratio')] +[ComponentModel.DefaultBindingProperty('keep_aspectratio')] +[Management.Automation.SwitchParameter] +$KeepAspectratio, +# Set the x_center of OBSRotatingSourceShader +[Alias('x_center')] +[ComponentModel.DefaultBindingProperty('x_center')] +[Single] +$XCenter, +# Set the y_center of OBSRotatingSourceShader +[Alias('y_center')] +[ComponentModel.DefaultBindingProperty('y_center')] +[Single] +$YCenter, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'rotating-source' +$ShaderNoun = 'OBSRotatingSourceShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//spin speed higher the slower +uniform float spin_speed< + string label = "Spin Speed"; + string widget_type = "slider"; + float minimum = -10.0; + float maximum = 10.0; + float step = 0.001; +> = 1.0; +uniform float rotation< + string label = "Rotation"; + string widget_type = "slider"; + float minimum = -360.0; + float maximum = 360.0; + float step = 0.1; +> = 0.0; +uniform float zoomin< + string label = "Zoom"; + string widget_type = "slider"; + float minimum = 0.01; + float maximum = 10.0; + float step = 0.01; +> = 1.0; +uniform bool keep_aspectratio = true; +uniform float x_center< + string label = "Center x"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.5; +uniform float y_center< + string label = "Center y"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.5; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} +//main fragment code +//from lioran to nutella with love +float4 mainImage(VertData v_in) : TARGET +{ + float x_aspectratio = keep_aspectratio ? uv_size.x : 1.0; + float y_aspectratio = keep_aspectratio ? uv_size.y : 1.0; + //get position on of the texture and focus on the middle + float i_rotation; + if (spin_speed == 0){ + //turn angle number into pi number + i_rotation = rotation/57.295779513; + }else{ + //use elapsed time for spinning if spin speed is not 0 + i_rotation = elapsed_time * spin_speed; + } + float2 i_point; + i_point.x = (v_in.uv.x * x_aspectratio) - (x_aspectratio * x_center); + i_point.y = (v_in.uv.y * y_aspectratio) - (y_aspectratio * y_center); + + //get the angle from center , returns pi number + float i_dir = atan(i_point.y/i_point.x); + if(i_point.x < 0.0){ + i_dir += 3.14159265359; + } + + //get the distance from the centers + float i_distance = sqrt(pow(i_point.x,2) + pow(i_point.y,2)); + //multiple distance by the zoomin value + i_distance *= zoomin; + + //shift the texture position based on angle and distance from the middle + i_point.x = ((x_aspectratio*x_center)+cos(i_dir-i_rotation)*i_distance)/x_aspectratio; + i_point.y = ((y_aspectratio*y_center)+sin(i_dir-i_rotation)*i_distance)/y_aspectratio; + + //draw normally from new point + return image.Sample(textureSampler, i_point); +} +' +} +$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 } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -52282,222 +52826,374 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Open-OBSInputInteractDialog { - +function Get-OBSRotatoeShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'OpenInputInteractDialog')] -[Alias('obs.powershell.websocket.OpenInputInteractDialog')] +[Alias('Set-OBSRotatoeShader','Add-OBSRotatoeShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - +# Set the ViewProj of OBSRotatoeShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the image of OBSRotatoeShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the elapsed_time of OBSRotatoeShader +[Alias('elapsed_time')] +[ComponentModel.DefaultBindingProperty('elapsed_time')] +[Single] +$ElapsedTime, +# Set the uv_offset of OBSRotatoeShader +[Alias('uv_offset')] +[ComponentModel.DefaultBindingProperty('uv_offset')] +[Single[]] +$UvOffset, +# Set the uv_scale of OBSRotatoeShader +[Alias('uv_scale')] +[ComponentModel.DefaultBindingProperty('uv_scale')] +[Single[]] +$UvScale, +# Set the uv_pixel_interval of OBSRotatoeShader +[Alias('uv_pixel_interval')] +[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +[Single[]] +$UvPixelInterval, +# Set the rand_f of OBSRotatoeShader +[Alias('rand_f')] +[ComponentModel.DefaultBindingProperty('rand_f')] +[Single] +$RandF, +# Set the uv_size of OBSRotatoeShader +[Alias('uv_size')] +[ComponentModel.DefaultBindingProperty('uv_size')] +[Single[]] +$UvSize, +# Set the speed_percent of OBSRotatoeShader +[Alias('speed_percent')] +[ComponentModel.DefaultBindingProperty('speed_percent')] +[Int32] +$SpeedPercent, +# Set the Axis_X of OBSRotatoeShader +[Alias('Axis_X')] +[ComponentModel.DefaultBindingProperty('Axis_X')] +[Single] +$AxisX, +# Set the Axis_Y of OBSRotatoeShader +[Alias('Axis_Y')] +[ComponentModel.DefaultBindingProperty('Axis_Y')] +[Single] +$AxisY, +# Set the Axis_Z of OBSRotatoeShader +[Alias('Axis_Z')] +[ComponentModel.DefaultBindingProperty('Axis_Z')] +[Single] +$AxisZ, +# Set the Angle_Degrees of OBSRotatoeShader +[Alias('Angle_Degrees')] +[ComponentModel.DefaultBindingProperty('Angle_Degrees')] +[Single] +$AngleDegrees, +# Set the Rotate_Transform of OBSRotatoeShader +[Alias('Rotate_Transform')] +[ComponentModel.DefaultBindingProperty('Rotate_Transform')] +[Management.Automation.SwitchParameter] +$RotateTransform, +# Set the Rotate_Pixels of OBSRotatoeShader +[Alias('Rotate_Pixels')] +[ComponentModel.DefaultBindingProperty('Rotate_Pixels')] +[Management.Automation.SwitchParameter] +$RotatePixels, +# Set the Rotate_Colors of OBSRotatoeShader +[Alias('Rotate_Colors')] +[ComponentModel.DefaultBindingProperty('Rotate_Colors')] +[Management.Automation.SwitchParameter] +$RotateColors, +# Set the center_width_percentage of OBSRotatoeShader +[Alias('center_width_percentage')] +[ComponentModel.DefaultBindingProperty('center_width_percentage')] +[Int32] +$CenterWidthPercentage, +# Set the center_height_percentage of OBSRotatoeShader +[Alias('center_height_percentage')] +[ComponentModel.DefaultBindingProperty('center_height_percentage')] +[Int32] +$CenterHeightPercentage, +# Set the notes of OBSRotatoeShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'rotatoe' +$ShaderNoun = 'OBSRotatoeShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Rotation Effect By Charles Fettinger (https://github.com/Oncorporation) 10/2019 +//Converted to OpenGL by Q-mii, Exeldro, & skeletonbow +uniform float4x4 ViewProj; +uniform texture2d image; +uniform float elapsed_time; +uniform float2 uv_offset; +uniform float2 uv_scale; +uniform float2 uv_pixel_interval; +uniform float rand_f; +uniform float2 uv_size; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +uniform int speed_percent< + string label = "speed percentage"; + string widget_type = "slider"; + int minimum = -100; + int maximum = 100; + int step = 1; +> = 50; // +uniform float Axis_X< + string label = "Axis X"; + string widget_type = "slider"; + float minimum = -2.0; + float maximum = 2.0; + float step = 0.1; +> = 0.0; +uniform float Axis_Y< + string label = "Axis Y"; + string widget_type = "slider"; + float minimum = -2.0; + float maximum = 2.0; + float step = 0.01; +> = 0.0; +uniform float Axis_Z< + string label = "Axis Z"; + string widget_type = "slider"; + float minimum = -2.0; + float maximum = 2.0; + float step = 0.01; +> = 1.0; +uniform float Angle_Degrees< + string label = "Angle Degrees"; + string widget_type = "slider"; + float minimum = -180.0; + float maximum = 180.0; + float step = 0.01; +> = 45.0; +uniform bool Rotate_Transform = true; +uniform bool Rotate_Pixels = false; +uniform bool Rotate_Colors = false; +uniform int center_width_percentage< + string label = "center width percentage"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform int center_height_percentage< + string label = "center height percentage"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +uniform string notes< + string widget_type = "info"; +> = " Choose axis, angle and speed, then rotate away! center_width_percentage & center_height_percentage allow you to change the pixel spin axis"; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } +sampler_state textureSampler { + Filter = Linear; + AddressU = Border; + AddressV = Border; + BorderColor = 00000000; +}; - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } +struct VertData { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } +float3x3 rotAxis(float3 axis, float a) { + float s=sin(a); + float c=cos(a); + float oc=1.0-c; -} + float3 as=axis*s; + float3x3 p=float3x3(axis.x*axis,axis.y*axis,axis.z*axis); + float3x3 q=float3x3(c,-as.z,as.y,as.z,c,-as.x,-as.y,as.x,c); + return p*oc+q; +} -} +VertData mainTransform(VertData v_in) +{ + VertData vert_out; + vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); - -#.ExternalHelp obs-powershell-Help.xml -function Open-OBSInputPropertiesDialog { + float speed = speed_percent * 0.01; + // circular easing variable + float PI = 3.1415926535897932384626433832795; //acos(-1); + float PI180th = 0.0174532925; //PI divided by 180 + float direction = abs(sin((elapsed_time - 0.001) * speed)); + float t = sin(elapsed_time * speed); + float angle_degrees = PI180th * Angle_Degrees; + // use matrix to transform rotation + if (Rotate_Transform) + vert_out.pos.xyz = mul(vert_out.pos.xyz,rotAxis(float3(Axis_X,Axis_Y,Axis_Z), (angle_degrees * t))).xyz; -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'OpenInputPropertiesDialog')] -[Alias('obs.powershell.websocket.OpenInputPropertiesDialog')] -param( + vert_out.uv = v_in.uv * uv_scale + uv_offset; -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, + return vert_out; +} -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) +float4 mainImage(VertData v_in) : TARGET +{ + float4 rgba = image.Sample(textureSampler, v_in.uv); + + float speed = speed_percent * 0.01; + // circular easing variable + float PI = 3.1415926535897932384626433832795; //acos(-1); + float PI180th = 0.0174532925; //PI divided by 180 + float direction = abs(sin((elapsed_time - 0.001) * speed)); + float t = sin(elapsed_time * speed); + float angle_degrees = PI180th * Angle_Degrees; -process { + // use matrix to transform pixels + if (Rotate_Pixels) + { + float2 center_pixel_coordinates = float2((center_width_percentage * 0.01), (center_height_percentage * 0.01) ); + rgba = image.Sample(textureSampler, mul(float3(v_in.uv - center_pixel_coordinates, 1.0), rotAxis(float3(Axis_X ,Axis_Y, Axis_Z ), (angle_degrees * t))).xy + center_pixel_coordinates); + } + if (Rotate_Colors) + rgba.rgb = mul(rgba.rgb, rotAxis(float3(Axis_X,Axis_Y,Axis_Z), (angle_degrees * t))).xyz; + return rgba; +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +technique Draw +{ + pass + { + vertex_shader = mainTransform(v_in); + pixel_shader = mainImage(v_in); + } +} - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} +' +} +$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 } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } + } + '(?>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 + } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } + 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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -52506,237 +53202,330 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Open-OBSSourceProjector { - +function Get-OBSRoundedRect2Shader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'OpenSourceProjector')] -[Alias('obs.powershell.websocket.OpenSourceProjector')] +[Alias('Set-OBSRoundedRect2Shader','Add-OBSRoundedRect2Shader')] param( - +# Set the corner_radius of OBSRoundedRect2Shader +[Alias('corner_radius')] +[ComponentModel.DefaultBindingProperty('corner_radius')] +[Int32] +$CornerRadius, +# Set the border_thickness of OBSRoundedRect2Shader +[Alias('border_thickness')] +[ComponentModel.DefaultBindingProperty('border_thickness')] +[Int32] +$BorderThickness, +# Set the border_color of OBSRoundedRect2Shader +[Alias('border_color')] +[ComponentModel.DefaultBindingProperty('border_color')] +[String] +$BorderColor, +# Set the border_alpha_start of OBSRoundedRect2Shader +[Alias('border_alpha_start')] +[ComponentModel.DefaultBindingProperty('border_alpha_start')] +[Single] +$BorderAlphaStart, +# Set the border_alpha_end of OBSRoundedRect2Shader +[Alias('border_alpha_end')] +[ComponentModel.DefaultBindingProperty('border_alpha_end')] +[Single] +$BorderAlphaEnd, +# Set the alpha_cut_off of OBSRoundedRect2Shader +[Alias('alpha_cut_off')] +[ComponentModel.DefaultBindingProperty('alpha_cut_off')] +[Single] +$AlphaCutOff, +# Set the faster_scan of OBSRoundedRect2Shader +[Alias('faster_scan')] +[ComponentModel.DefaultBindingProperty('faster_scan')] +[Management.Automation.SwitchParameter] +$FasterScan, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceName')] -[string] +[Alias('SceneItemName')] +[String] $SourceName, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceUuid')] -[string] -$SourceUuid, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('monitorIndex')] -[double] -$MonitorIndex, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('projectorGeometry')] -[string] -$ProjectorGeometry, -# If set, will return the information that would otherwise be sent to OBS. +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'rounded_rect2' +$ShaderNoun = 'OBSRoundedRect2Shader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform int corner_radius< + string label = "Corner radius"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 0; +uniform int border_thickness< + string label = "Border thickness"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 0; +uniform float4 border_color; +uniform float border_alpha_start< + string label = "Border alpha start"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 1.0; +uniform float border_alpha_end< + string label = "Border alpha end"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.0; +uniform float alpha_cut_off< + string label = "Aplha cut off"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.5; +uniform bool faster_scan = true; - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} +float4 mainImage(VertData v_in) : TARGET +{ + float4 pixel = image.Sample(textureSampler, v_in.uv); + int closedEdgeX = 0; + int closedEdgeY = 0; + if(pixel.a < alpha_cut_off){ + return float4(1.0,0.0,0.0,0.0); + } + float check_dist = float(corner_radius); + if(border_thickness > check_dist) + check_dist = border_thickness; + if(image.Sample(textureSampler, v_in.uv + float2(check_dist*uv_pixel_interval.x,0)).a < alpha_cut_off){ + closedEdgeX = int(check_dist); + }else if(image.Sample(textureSampler, v_in.uv + float2(-check_dist*uv_pixel_interval.x,0)).a < alpha_cut_off){ + closedEdgeX = int(-check_dist); + } + if(image.Sample(textureSampler, v_in.uv + float2(0,check_dist*uv_pixel_interval.y)).a < alpha_cut_off){ + closedEdgeY = int(check_dist); + }else if(image.Sample(textureSampler, v_in.uv + float2(0,-check_dist*uv_pixel_interval.y)).a < alpha_cut_off){ + closedEdgeY = int(-check_dist); + } + if(closedEdgeX == 0 && closedEdgeY == 0){ + return pixel; + } + if(!faster_scan || closedEdgeX != 0){ + [loop] for(int x = 1;float(x) check_dist && border_thickness > corner_radius){ + if(closedEdgeXabs < corner_radius && closedEdgeYabs < corner_radius){ + float cd = distance(float2(closedEdgeXabs, closedEdgeYabs), float2(corner_radius,corner_radius)); + if(floor(cd) > corner_radius) + return float4(0.0,0.0,0.0,0.0); + if(cd > corner_radius){ + d = border_thickness + cd - corner_radius; + } else if(d > border_thickness){ + d = border_thickness; + } + }else if(d > border_thickness){ + d = border_thickness; + } + } + if(floor(d) <= check_dist){ + if(border_thickness > 0){ + if(ceil(check_dist-d) <= border_thickness){ + float4 fade_color = border_color; + fade_color.a = border_alpha_end + ((check_dist-d)/ float(border_thickness))*(border_alpha_start-border_alpha_end); + if(border_alpha_start < border_alpha_end){ + fade_color.rgb = pixel.rgb * (1.0 - fade_color.a) + fade_color.rgb * fade_color.a; + fade_color.a = border_alpha_end + ((check_dist-d) / float(border_thickness))*(pixel.a-border_alpha_end); } + if(d > check_dist) + fade_color.a *= 1.0 -(d - check_dist); + return fade_color; + }else if(d >= 0 && floor(check_dist-d) <= border_thickness && border_alpha_start >= border_alpha_end){ + float4 fade_color = border_color; + float f; + if(border_thickness > (check_dist-d)) + f = border_thickness - (check_dist-d); + else + f = 1.0 -((check_dist-d) - border_thickness); + fade_color.rgb = pixel.rgb * (1.0 - f) + fade_color.rgb * f; + return fade_color; } } + if (d > check_dist) + pixel.a *= 1.0 - (d - check_dist); + return pixel; - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload + } + return float4(0.0,0.0,0.0,0.0); +} +' +} +$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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $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 + } } -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Open-OBSVideoMixProjector { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'OpenVideoMixProjector')] -[Alias('obs.powershell.websocket.OpenVideoMixProjector')] -param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('videoMixType')] -[string] -$VideoMixType, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('monitorIndex')] -[double] -$MonitorIndex, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('projectorGeometry')] -[string] -$ProjectorGeometry, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -52745,217 +53534,354 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Remove-OBSInput { - +function Get-OBSRoundedRectPerCornerShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'RemoveInput')] -[Alias('obs.powershell.websocket.RemoveInput')] +[Alias('Set-OBSRoundedRectPerCornerShader','Add-OBSRoundedRectPerCornerShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - +# Set the corner_radius_tl of OBSRoundedRectPerCornerShader +[Alias('corner_radius_tl')] +[ComponentModel.DefaultBindingProperty('corner_radius_tl')] +[Int32] +$CornerRadiusTl, +# Set the corner_radius_tr of OBSRoundedRectPerCornerShader +[Alias('corner_radius_tr')] +[ComponentModel.DefaultBindingProperty('corner_radius_tr')] +[Int32] +$CornerRadiusTr, +# Set the corner_radius_br of OBSRoundedRectPerCornerShader +[Alias('corner_radius_br')] +[ComponentModel.DefaultBindingProperty('corner_radius_br')] +[Int32] +$CornerRadiusBr, +# Set the corner_radius_bl of OBSRoundedRectPerCornerShader +[Alias('corner_radius_bl')] +[ComponentModel.DefaultBindingProperty('corner_radius_bl')] +[Int32] +$CornerRadiusBl, +# Set the border_thickness of OBSRoundedRectPerCornerShader +[Alias('border_thickness')] +[ComponentModel.DefaultBindingProperty('border_thickness')] +[Int32] +$BorderThickness, +# Set the border_color of OBSRoundedRectPerCornerShader +[Alias('border_color')] +[ComponentModel.DefaultBindingProperty('border_color')] +[String] +$BorderColor, +# Set the border_alpha_start of OBSRoundedRectPerCornerShader +[Alias('border_alpha_start')] +[ComponentModel.DefaultBindingProperty('border_alpha_start')] +[Single] +$BorderAlphaStart, +# Set the border_alpha_end of OBSRoundedRectPerCornerShader +[Alias('border_alpha_end')] +[ComponentModel.DefaultBindingProperty('border_alpha_end')] +[Single] +$BorderAlphaEnd, +# Set the alpha_cut_off of OBSRoundedRectPerCornerShader +[Alias('alpha_cut_off')] +[ComponentModel.DefaultBindingProperty('alpha_cut_off')] +[Single] +$AlphaCutOff, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'rounded_rect_per_corner' +$ShaderNoun = 'OBSRoundedRectPerCornerShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//Converted to OpenGL by Q-mii & Exeldro February 18, 2022 +uniform int corner_radius_tl< + string label = "Corner radius top left"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 200; + int step = 1; +> = 0; +uniform int corner_radius_tr< + string label = "Corner radius top right"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 200; + int step = 1; +> = 0; +uniform int corner_radius_br< + string label = "Corner radius bottom right"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 200; + int step = 1; +> = 0; +uniform int corner_radius_bl< + string label = "Corner radius bottom left"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 200; + int step = 1; +> = 0; +uniform int border_thickness< + string label = "Border thickness"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 0; +uniform float4 border_color; +uniform float border_alpha_start< + string label = "border alpha start"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 1.0; +uniform float border_alpha_end< + string label = "border alpha end"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; +uniform float alpha_cut_off< + string label = "alpha cut off"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.5; - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} +float4 mainImage(VertData v_in) : TARGET +{ + float4 pixel = image.Sample(textureSampler, v_in.uv); + int closedEdgeX = 0; + int closedEdgeY = 0; + if(pixel.a < alpha_cut_off){ + return float4(1.0,0.0,0.0,0.0); + } + int corner_radius_top = corner_radius_tl>corner_radius_tr?corner_radius_tl:corner_radius_tr; + int corner_radius_right = corner_radius_tr>corner_radius_br?corner_radius_tr:corner_radius_br; + int corner_radius_bottom = corner_radius_bl>corner_radius_br?corner_radius_bl:corner_radius_br; + int corner_radius_left = corner_radius_tl>corner_radius_bl?corner_radius_tl:corner_radius_bl; + + if(image.Sample(textureSampler, v_in.uv + float2(corner_radius_right*uv_pixel_interval.x,0)).a < alpha_cut_off){ + closedEdgeX = corner_radius_right; + }else if(image.Sample(textureSampler, v_in.uv + float2(-corner_radius_left*uv_pixel_interval.x,0)).a < alpha_cut_off){ + closedEdgeX = -corner_radius_left; + } + if(image.Sample(textureSampler, v_in.uv + float2(0,corner_radius_bottom*uv_pixel_interval.y)).a < alpha_cut_off){ + closedEdgeY = corner_radius_bottom; + }else if(image.Sample(textureSampler, v_in.uv + float2(0,-corner_radius_top*uv_pixel_interval.y)).a < alpha_cut_off){ + closedEdgeY = -corner_radius_top; + } + if(closedEdgeX == 0 && closedEdgeY == 0){ + return pixel; + } + if(closedEdgeX != 0){ + [loop] for(int x = 1;x 0 && closedEdgeY < 0){ + corner_radius = corner_radius_tr; + }else if(closedEdgeX > 0 && closedEdgeY > 0){ + corner_radius = corner_radius_br; + }else if(closedEdgeX < 0 && closedEdgeY > 0){ + corner_radius = corner_radius_bl; + } + if(closedEdgeXabs > corner_radius && closedEdgeYabs > corner_radius){ + return pixel; + } + if(closedEdgeXabs == 0){ + if(closedEdgeYabs <= border_thickness){ + float4 fade_color = border_color; + fade_color.a = border_alpha_end + (closedEdgeYabs / border_thickness)*(border_alpha_start-border_alpha_end); + return fade_color; + }else{ + return pixel; } - -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Remove-OBSProfile { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'RemoveProfile')] -[Alias('obs.powershell.websocket.RemoveProfile')] -param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('profileName')] -[string] -$ProfileName, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + } + if(closedEdgeYabs == 0){ + if(closedEdgeXabs <= border_thickness){ + float4 fade_color = border_color; + fade_color.a = border_alpha_end + (closedEdgeXabs / border_thickness)*(border_alpha_start-border_alpha_end); + return fade_color; + }else{ + return pixel; } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + } + if(closedEdgeXabs > corner_radius){ + if(closedEdgeYabs <= border_thickness){ + float4 fade_color = border_color; + fade_color.a = border_alpha_end + (closedEdgeYabs / border_thickness)*(border_alpha_start-border_alpha_end); + return fade_color; + }else{ + return pixel; + } + } + if(closedEdgeYabs > corner_radius){ + if(closedEdgeXabs <= border_thickness){ + float4 fade_color = border_color; + fade_color.a = border_alpha_end + (closedEdgeXabs / border_thickness)*(border_alpha_start-border_alpha_end); + return fade_color; + }else{ + return pixel; + } + } + float d = distance(float2(closedEdgeXabs, closedEdgeYabs), float2(corner_radius,corner_radius)); + if(dAdd|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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -52964,228 +53890,331 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Remove-OBSScene { - +function Get-OBSRoundedRectPerSideShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'RemoveScene')] -[Alias('obs.powershell.websocket.RemoveScene')] +[Alias('Set-OBSRoundedRectPerSideShader','Add-OBSRoundedRectPerSideShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, - +# Set the corner_radius_bottom of OBSRoundedRectPerSideShader +[Alias('corner_radius_bottom')] +[ComponentModel.DefaultBindingProperty('corner_radius_bottom')] +[Int32] +$CornerRadiusBottom, +# Set the corner_radius_left of OBSRoundedRectPerSideShader +[Alias('corner_radius_left')] +[ComponentModel.DefaultBindingProperty('corner_radius_left')] +[Int32] +$CornerRadiusLeft, +# Set the corner_radius_top of OBSRoundedRectPerSideShader +[Alias('corner_radius_top')] +[ComponentModel.DefaultBindingProperty('corner_radius_top')] +[Int32] +$CornerRadiusTop, +# Set the corner_radius_right of OBSRoundedRectPerSideShader +[Alias('corner_radius_right')] +[ComponentModel.DefaultBindingProperty('corner_radius_right')] +[Int32] +$CornerRadiusRight, +# Set the border_thickness of OBSRoundedRectPerSideShader +[Alias('border_thickness')] +[ComponentModel.DefaultBindingProperty('border_thickness')] +[Int32] +$BorderThickness, +# Set the border_color of OBSRoundedRectPerSideShader +[Alias('border_color')] +[ComponentModel.DefaultBindingProperty('border_color')] +[String] +$BorderColor, +# Set the border_alpha_start of OBSRoundedRectPerSideShader +[Alias('border_alpha_start')] +[ComponentModel.DefaultBindingProperty('border_alpha_start')] +[Single] +$BorderAlphaStart, +# Set the border_alpha_end of OBSRoundedRectPerSideShader +[Alias('border_alpha_end')] +[ComponentModel.DefaultBindingProperty('border_alpha_end')] +[Single] +$BorderAlphaEnd, +# Set the alpha_cut_off of OBSRoundedRectPerSideShader +[Alias('alpha_cut_off')] +[ComponentModel.DefaultBindingProperty('alpha_cut_off')] +[Single] +$AlphaCutOff, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'rounded_rect_per_side' +$ShaderNoun = 'OBSRoundedRectPerSideShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform int corner_radius_bottom< + string label = "Corner radius bottom"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 200; + int step = 1; +> = 0; +uniform int corner_radius_left< + string label = "Corner radius left"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 200; + int step = 1; +> = 0; +uniform int corner_radius_top< + string label = "Corner radius top"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 200; + int step = 1; +> = 0; +uniform int corner_radius_right< + string label = "Corner radius right"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 200; + int step = 1; +> = 0; +uniform int border_thickness< + string label = "Border thickness"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 0; +uniform float4 border_color; +uniform float border_alpha_start< + string label = "border alpha start"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 1.0; +uniform float border_alpha_end< + string label = "border alpha end"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; +uniform float alpha_cut_off< + string label = "alpha cut off"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.5; - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} +float4 mainImage(VertData v_in) : TARGET +{ + float4 output_color = image.Sample(textureSampler, v_in.uv); + int closedEdgeX = 0; + int closedEdgeY = 0; + if(output_color.a < alpha_cut_off){ + return float4(1.0,0.0,0.0,0.0); + } + if(image.Sample(textureSampler, v_in.uv + float2(corner_radius_right*uv_pixel_interval.x,0)).a < alpha_cut_off){ + closedEdgeX = corner_radius_right; + }else if(image.Sample(textureSampler, v_in.uv + float2(-corner_radius_left*uv_pixel_interval.x,0)).a < alpha_cut_off){ + closedEdgeX = -corner_radius_left; + } + if(image.Sample(textureSampler, v_in.uv + float2(0,corner_radius_bottom*uv_pixel_interval.y)).a < alpha_cut_off){ + closedEdgeY = corner_radius_bottom; + }else if(image.Sample(textureSampler, v_in.uv + float2(0,-corner_radius_top*uv_pixel_interval.y)).a < alpha_cut_off){ + closedEdgeY = -corner_radius_top; + } + if(closedEdgeX == 0 && closedEdgeY == 0){ + return output_color; + } + if(closedEdgeX != 0){ + [loop] for(int x = 1;x corner_radius){ + closedEdgeXabs = 0; + } + if(closedEdgeYabs > corner_radius){ + closedEdgeYabs = 0; + } + if(closedEdgeXabs == 0 && closedEdgeYabs == 0){ + return output_color; + } + if(closedEdgeXabs == 0){ + if(closedEdgeYabs <= border_thickness){ + float4 fade_color = border_color; + fade_color.a = border_alpha_end + (float(closedEdgeYabs) / float(border_thickness))*(border_alpha_start-border_alpha_end); + return fade_color; + }else{ + return output_color; + } + } + if(closedEdgeYabs == 0){ + if(closedEdgeXabs <= border_thickness){ + float4 fade_color = border_color; + fade_color.a = border_alpha_end + (float(closedEdgeXabs) / float(border_thickness))*(border_alpha_start-border_alpha_end); + return fade_color; + }else{ + return output_color; } + } + float closest = closedEdgeXabsAdd|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 + } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + } } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -53194,115 +54223,183 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Remove-OBSSourceFilter { - +function Get-OBSRoundedRectShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'RemoveSourceFilter')] -[Alias('obs.powershell.websocket.RemoveSourceFilter')] +[Alias('Set-OBSRoundedRectShader','Add-OBSRoundedRectShader')] param( - +# Set the corner_radius of OBSRoundedRectShader +[Alias('corner_radius')] +[ComponentModel.DefaultBindingProperty('corner_radius')] +[Int32] +$CornerRadius, +# Set the border_thickness of OBSRoundedRectShader +[Alias('border_thickness')] +[ComponentModel.DefaultBindingProperty('border_thickness')] +[Int32] +$BorderThickness, +# Set the border_color of OBSRoundedRectShader +[Alias('border_color')] +[ComponentModel.DefaultBindingProperty('border_color')] +[String] +$BorderColor, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceName')] -[string] +[Alias('SceneItemName')] +[String] $SourceName, - +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceUuid')] -[string] -$SourceUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('filterName')] -[string] +[String] $FilterName, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +# 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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'rounded_rect' +$ShaderNoun = 'OBSRoundedRectShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//Converted to OpenGl by Q-mii & Exeldro February 21, 2022 +uniform int corner_radius< + string label = "Corner radius"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 200; + int step = 1; +> = 0; +uniform int border_thickness< + string label = "border thickness"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 0; +uniform float4 border_color; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float4 mainImage(VertData v_in) : TARGET +{ + float2 mirrored_tex_coord = float2(0.5, 0.5) - abs(v_in.uv - float2(0.5, 0.5)); + float4 output_color = image.Sample(textureSampler, v_in.uv); + + float2 pixel_position = float2(mirrored_tex_coord.x / uv_pixel_interval.x, mirrored_tex_coord.y / uv_pixel_interval.y); + float pixel_distance_from_center = distance(pixel_position, float2(corner_radius, corner_radius)); + + bool is_in_corner = pixel_position.x < corner_radius && pixel_position.y < corner_radius; + bool is_within_radius = pixel_distance_from_center <= corner_radius; + + bool is_within_edge_border = !is_in_corner && (pixel_position.x < 0 && pixel_position.x >= -border_thickness || pixel_position.y < 0 && pixel_position.y >= -border_thickness); + bool is_within_corner_border = is_in_corner && pixel_distance_from_center > corner_radius && pixel_distance_from_center <= (corner_radius + border_thickness); + + return ((!is_in_corner || is_within_radius)?output_color:float4(0,0,0,0)) + ((is_within_edge_border || is_within_corner_border)?border_color:float4(0,0,0,0)); +} - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} +' +} +$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 } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } + } + '(?>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 + } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } + 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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -53311,202 +54408,365 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Resume-OBSRecord { - +function Get-OBSRoundedStrokeGradientShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'ResumeRecord')] -[Alias('obs.powershell.websocket.ResumeRecord')] +[Alias('Set-OBSRoundedStrokeGradientShader','Add-OBSRoundedStrokeGradientShader')] param( -# If set, will return the information that would otherwise be sent to OBS. +# Set the corner_radius of OBSRoundedStrokeGradientShader +[Alias('corner_radius')] +[ComponentModel.DefaultBindingProperty('corner_radius')] +[Int32] +$CornerRadius, +# Set the border_thickness of OBSRoundedStrokeGradientShader +[Alias('border_thickness')] +[ComponentModel.DefaultBindingProperty('border_thickness')] +[Int32] +$BorderThickness, +# Set the minimum_alpha_percent of OBSRoundedStrokeGradientShader +[Alias('minimum_alpha_percent')] +[ComponentModel.DefaultBindingProperty('minimum_alpha_percent')] +[Int32] +$MinimumAlphaPercent, +# Set the rotation_speed of OBSRoundedStrokeGradientShader +[Alias('rotation_speed')] +[ComponentModel.DefaultBindingProperty('rotation_speed')] +[Int32] +$RotationSpeed, +# Set the border_colorL of OBSRoundedStrokeGradientShader +[Alias('border_colorL')] +[ComponentModel.DefaultBindingProperty('border_colorL')] +[String] +$BorderColorL, +# Set the border_colorR of OBSRoundedStrokeGradientShader +[Alias('border_colorR')] +[ComponentModel.DefaultBindingProperty('border_colorR')] +[String] +$BorderColorR, +# Set the center_width of OBSRoundedStrokeGradientShader +[Alias('center_width')] +[ComponentModel.DefaultBindingProperty('center_width')] +[Int32] +$CenterWidth, +# Set the center_height of OBSRoundedStrokeGradientShader +[Alias('center_height')] +[ComponentModel.DefaultBindingProperty('center_height')] +[Int32] +$CenterHeight, +# Set the notes of OBSRoundedStrokeGradientShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'rounded_stroke_gradient' +$ShaderNoun = 'OBSRoundedStrokeGradientShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//rounded rectange shader from https://raw.githubusercontent.com/exeldro/obs-lua/master/rounded_rect.shader +//modified slightly by Surn +uniform int corner_radius< + string label = "Corner radius"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 200; + int step = 1; +> = 0; +uniform int border_thickness< + string label = "Border thickness"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 0; +uniform int minimum_alpha_percent< + string label = "Minimum alpha percent"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform int rotation_speed< + string label = "rotation speed"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 0; +uniform float4 border_colorL; +uniform float4 border_colorR; +//uniform float color_spread = 2.0; +uniform int center_width< + string label = "center width"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform int center_height< + string label = "center height"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform string notes< + string widget_type = "info"; +> = "Outlines the opaque areas with a rounded border. Default Minimum Alpha Percent is 50%, lowering will reveal more"; +// float3 hsv2rgb(float3 c) +// { +// float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); +// float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www); +// return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y); +// } - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float mod(float x, float y) +{ + return x - y * floor(x/y); +} - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} +float4 gradient(float c) { + c = mod(c , 2.0); + if(c < 0.0f){ + c = c * -1.0; + } + if(c > 1.0){ + c = 1.0 - c; + if(c < 0.0f){ + c = c + 1.0; } + } + return lerp(border_colorL, border_colorR, c); +} - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } +float4 getBorderColor(float2 toCenter){ + float angle = atan2(toCenter.y ,toCenter.x ); + float angleMod = (elapsed_time * mod(float(rotation_speed) , 18.0)) / 9; + return gradient((angle / 3.14159265f) + angleMod); +} + +float4 mainImage(VertData v_in) : TARGET +{ + float2 st = v_in.uv * uv_scale; + float2 center_pixel_coordinates = float2((float(center_width) * 0.01), (float(center_height) * 0.01) ); + float2 toCenter = center_pixel_coordinates - st; + + float min_alpha = clamp(minimum_alpha_percent * .01, -1.0, 101.0); + float4 output_color = image.Sample(textureSampler, v_in.uv); + if (output_color.a < min_alpha) + { + return float4(0.0, 0.0, 0.0, 0.0); + } + int closedEdgeX = 0; + if (image.Sample(textureSampler, v_in.uv + float2(corner_radius * uv_pixel_interval.x, 0)).a < min_alpha) + { + closedEdgeX = corner_radius; + } + else if (image.Sample(textureSampler, v_in.uv + float2(-corner_radius * uv_pixel_interval.x, 0)).a < min_alpha) + { + closedEdgeX = corner_radius; + } + int closedEdgeY = 0; + if (image.Sample(textureSampler, v_in.uv + float2(0, corner_radius * uv_pixel_interval.y)).a < min_alpha) + { + closedEdgeY = corner_radius; + } + else if (image.Sample(textureSampler, v_in.uv + float2(0, -corner_radius * uv_pixel_interval.y)).a < min_alpha) + { + closedEdgeY = corner_radius; + } + if (closedEdgeX == 0 && closedEdgeY == 0) + { + return output_color; + } + if (closedEdgeX != 0) + { + [loop] + for (int x = 1; x < corner_radius; x++) + { + if (image.Sample(textureSampler, v_in.uv + float2(x * uv_pixel_interval.x, 0)).a < min_alpha) + { + closedEdgeX = x; + break; + } + if (image.Sample(textureSampler, v_in.uv + float2(-x * uv_pixel_interval.x, 0)).a < min_alpha) + { + closedEdgeX = x; + break; + } + } + } + if (closedEdgeY != 0) + { + [loop] + for (int y = 1; y < corner_radius; y++) + { + if (image.Sample(textureSampler, v_in.uv + float2(0, y * uv_pixel_interval.y)).a < min_alpha) + { + closedEdgeY = y; + break; } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } + if (image.Sample(textureSampler, v_in.uv + float2(0, -y * uv_pixel_interval.y)).a < min_alpha) + { + closedEdgeY = y; + break; } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + } + if (closedEdgeX == 0) + { + if (closedEdgeY < border_thickness) + { + return getBorderColor(toCenter); } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + else + { + return output_color; + } + } + if (closedEdgeY == 0) + { + if (closedEdgeX < border_thickness) + { + return getBorderColor(toCenter); + } + else + { + return output_color; } + } + float d = distance(float2(closedEdgeX, closedEdgeY), float2(corner_radius, corner_radius)); + if (d < corner_radius) + { + if (corner_radius - d < border_thickness) + { + return getBorderColor(toCenter); + } + else + { + return output_color; + } + } + return float4(0.0, 0.0, 0.0, 0.0); } +' +} +$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 + } + } - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Save-OBSReplayBuffer { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SaveReplayBuffer')] -[Alias('obs.powershell.websocket.SaveReplayBuffer')] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -53515,370 +54775,287 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Save-OBSSourceScreenshot { - +function Get-OBSRoundedStrokeShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SaveSourceScreenshot')] -[Alias('obs.powershell.websocket.SaveSourceScreenshot')] +[Alias('Set-OBSRoundedStrokeShader','Add-OBSRoundedStrokeShader')] param( - +# Set the corner_radius of OBSRoundedStrokeShader +[Alias('corner_radius')] +[ComponentModel.DefaultBindingProperty('corner_radius')] +[Int32] +$CornerRadius, +# Set the border_thickness of OBSRoundedStrokeShader +[Alias('border_thickness')] +[ComponentModel.DefaultBindingProperty('border_thickness')] +[Int32] +$BorderThickness, +# Set the minimum_alpha_percent of OBSRoundedStrokeShader +[Alias('minimum_alpha_percent')] +[ComponentModel.DefaultBindingProperty('minimum_alpha_percent')] +[Int32] +$MinimumAlphaPercent, +# Set the border_color of OBSRoundedStrokeShader +[Alias('border_color')] +[ComponentModel.DefaultBindingProperty('border_color')] +[String] +$BorderColor, +# Set the notes of OBSRoundedStrokeShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceName')] -[string] +[Alias('SceneItemName')] +[String] $SourceName, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceUuid')] -[string] -$SourceUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('imageFormat')] -[string] -$ImageFormat, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('imageFilePath')] -[string] -$ImageFilePath, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('imageWidth')] -[ValidateRange(8,4096)] -[double] -$ImageWidth, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('imageHeight')] -[ValidateRange(8,4096)] -[double] -$ImageHeight, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('imageCompressionQuality')] -[ValidateRange(-1,100)] -[double] -$ImageCompressionQuality, -# If set, will return the information that would otherwise be sent to OBS. +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'rounded_stroke' +$ShaderNoun = 'OBSRoundedStrokeShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//rounded rectange shader from https://raw.githubusercontent.com/exeldro/obs-lua/master/rounded_rect.shader +//modified slightly by Surn +//Converted to OpenGl by Q-mii & Exeldro February 21, 2022 +uniform int corner_radius< + string label = "Corner radius"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 200; + int step = 1; +> = 0; +uniform int border_thickness< + string label = "border thickness"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 0; +uniform int minimum_alpha_percent< + string label = "Minimum alpha percent"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform float4 border_color; +uniform string notes< + string widget_type = "info"; +> = "Outlines the opaque areas with a rounded border. Default Minimum Alpha Percent is 50%, lowering will reveal more"; - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } +float4 mainImage(VertData v_in) : TARGET +{ + float min_alpha = clamp(minimum_alpha_percent * .01, -1.0, 101.0); + float4 output_color = image.Sample(textureSampler, v_in.uv); + if (output_color.a < min_alpha) + { + return float4(0.0, 0.0, 0.0, 0.0); + } + int closedEdgeX = 0; + if (image.Sample(textureSampler, v_in.uv + float2(corner_radius * uv_pixel_interval.x, 0)).a < min_alpha) + { + closedEdgeX = corner_radius; + } + else if (image.Sample(textureSampler, v_in.uv + float2(-corner_radius * uv_pixel_interval.x, 0)).a < min_alpha) + { + closedEdgeX = corner_radius; + } + int closedEdgeY = 0; + if (image.Sample(textureSampler, v_in.uv + float2(0, corner_radius * uv_pixel_interval.y)).a < min_alpha) + { + closedEdgeY = corner_radius; + } + else if (image.Sample(textureSampler, v_in.uv + float2(0, -corner_radius * uv_pixel_interval.y)).a < min_alpha) + { + closedEdgeY = corner_radius; + } + if (closedEdgeX == 0 && closedEdgeY == 0) + { + return float4(output_color); + } + if (closedEdgeX != 0) + { + [loop] + for (int x = 1; x < corner_radius; x++) + { + if (image.Sample(textureSampler, v_in.uv + float2(x * uv_pixel_interval.x, 0)).a < min_alpha) + { + closedEdgeX = x; + break; + } + if (image.Sample(textureSampler, v_in.uv + float2(-x * uv_pixel_interval.x, 0)).a < min_alpha) + { + closedEdgeX = x; + break; } } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } + } + if (closedEdgeY != 0) + { + [loop] + for (int y = 1; y < corner_radius; y++) + { + if (image.Sample(textureSampler, v_in.uv + float2(0, y * uv_pixel_interval.y)).a < min_alpha) + { + closedEdgeY = y; + break; + } + if (image.Sample(textureSampler, v_in.uv + float2(0, -y * uv_pixel_interval.y)).a < min_alpha) + { + closedEdgeY = y; + break; } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + } + if (closedEdgeX == 0) + { + if (closedEdgeY < border_thickness) + { + return border_color; + } + else + { + return float4(output_color); + } + } + if (closedEdgeY == 0) + { + if (closedEdgeX < border_thickness) + { + return border_color; } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + else + { + return float4(output_color); } + } - - Get-Item $paramCopy["imageFilePath"] | - Add-Member NoteProperty InputName $paramCopy["SourceName"] -Force -PassThru | - Add-Member NoteProperty SourceName $paramCopy["SourceName"] -Force -PassThru | - Add-Member NoteProperty ImageWidth $paramCopy["ImageWidth"] -Force -PassThru | - Add-Member NoteProperty ImageHeight $paramCopy["ImageHeight"] -Force -PassThru - -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Send-OBSCallVendorRequest { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'CallVendorRequest')] -[Alias('obs.powershell.websocket.CallVendorRequest')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('vendorName')] -[string] -$VendorName, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('requestType')] -[string] -$RequestType, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('requestData')] -[PSObject] -$RequestData, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + float d = distance(float2(closedEdgeX, closedEdgeY), float2(corner_radius, corner_radius)); + if (d < corner_radius) + { + if (corner_radius - d < border_thickness) + { + return border_color; } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } + else + { + return output_color; } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } + } + return float4(0.0, 0.0, 0.0, 0.0); +} +' +} +$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 } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + } + '(?>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 ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Send-OBSCustomEvent { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'BroadcastCustomEvent')] -[Alias('obs.powershell.websocket.BroadcastCustomEvent')] -param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('eventData')] -[PSObject] -$EventData, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -53887,115 +55064,265 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Send-OBSOffsetMediaInputCursor { - +function Get-OBSScanLineShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'OffsetMediaInputCursor')] -[Alias('obs.powershell.websocket.OffsetMediaInputCursor')] +[Alias('Set-OBSScanLineShader','Add-OBSScanLineShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - +# Set the lengthwise of OBSScanLineShader +[ComponentModel.DefaultBindingProperty('lengthwise')] +[Management.Automation.SwitchParameter] +$Lengthwise, +# Set the animate of OBSScanLineShader +[ComponentModel.DefaultBindingProperty('animate')] +[Management.Automation.SwitchParameter] +$Animate, +# Set the speed of OBSScanLineShader +[ComponentModel.DefaultBindingProperty('speed')] +[Single] +$Speed, +# Set the angle of OBSScanLineShader +[ComponentModel.DefaultBindingProperty('angle')] +[Single] +$Angle, +# Set the shift of OBSScanLineShader +[ComponentModel.DefaultBindingProperty('shift')] +[Management.Automation.SwitchParameter] +$Shift, +# Set the boost of OBSScanLineShader +[ComponentModel.DefaultBindingProperty('boost')] +[Management.Automation.SwitchParameter] +$Boost, +# Set the floor of OBSScanLineShader +[ComponentModel.DefaultBindingProperty('floor')] +[Single] +$Floor, +# Set the period of OBSScanLineShader +[ComponentModel.DefaultBindingProperty('period')] +[Single] +$Period, +# Set the notes of OBSScanLineShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('mediaCursorOffset')] -[double] -$MediaCursorOffset, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'scan_line' +$ShaderNoun = 'OBSScanLineShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Scan Line Effect for OBS Studio +// originally from Andersama (https://github.com/Andersama) +// Modified and improved my Charles Fettinger (https://github.com/Oncorporation) 1/2019 +//Converted to OpenGL by Q-mii & Exeldro February 21, 2022 +//Count the number of scanlines we want via height or width, adjusts the sin wave period +uniform bool lengthwise; +//Do we want the scanlines to move? +uniform bool animate; +//How fast do we want those scanlines to move? +uniform float speed< + string label = "Speed"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10000.0; + float step = 1; +> = 1000; +//What angle should the scanlines come in at (based in degrees) +uniform float angle< + string label = "angle"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 360.0; + float step = 0.1; +> = 45; +//Turns on adjustment of the results, sin returns -1 -> 1 these settings will change the results a bit +//By default values for color range from 0 to 1 +//Boost centers the result of the sin wave on 1*, to help maintain the brightness of the screen +uniform bool shift = true; +uniform bool boost = true; +//Increases the minimum value of the sin wave +uniform float floor< + string label = "Floor"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.001; +> = 0.0; +//final adjustment to the period of the sin wave, we can''t / 0, need to be careful w/ user input +uniform float period< + string label = "Period"; + string widget_type = "slider"; + float minimum = 1.0; + float maximum = 1000.0; + float step = 1.0; +> = 10.0; +uniform string notes< + string widget_type = "info"; +> = "floor affects the minimum opacity of the scan line"; +float4 mainImage(VertData v_in) : TARGET +{ + //3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481 3.141592653589793238462643383279502884197169399375105820974944592307816406286 + // float pix2 = 6.2831853071795864769252;//86766559005768394338798750211641949 + float nfloor = clamp(floor, 0.0, 100.0) * 0.01; + float nperiod = max(period, 1.0); + float gap = 1 - nfloor; + float pi = 3.1415926535897932384626; + float2 direction = float2( cos(angle * pi / 180.0) , sin(angle * pi / 180.0) ); + float nspeed = 0.0; + if(animate){ + nspeed = speed * 0.0001; + } + + float4 color = image.Sample(textureSampler, v_in.uv); + + float t = elapsed_time * nspeed; + + if(!lengthwise){ + float base_height = 1.0 / uv_pixel_interval.y; + float h_interval = pi * base_height; + + float rh_sin = sin(((v_in.uv.y * direction.y + v_in.uv.x * direction.x) + t) * (h_interval / nperiod)); + if(shift){ + rh_sin = ((1.0 + rh_sin) * 0.5) * gap + nfloor; + if(boost){ + rh_sin += gap * 0.5; + } + } + float4 s_mult = float4(rh_sin,rh_sin,rh_sin,1); + return s_mult * color; + } + else{ + float base_width = 1.0 / uv_pixel_interval.x; + float w_interval = pi * base_width; + + float rh_sin = sin(((v_in.uv.y * direction.y + v_in.uv.x * direction.x) + t) * (w_interval / nperiod)); + if(shift){ + rh_sin = ((1.0 + rh_sin) * 0.5) * gap + nfloor; + if(boost){ + rh_sin += gap * 0.5; + } + } + float4 s_mult = float4(rh_sin,rh_sin,rh_sin,1); + return s_mult * color; + } +} +' +} +$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 + } + } - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -54004,331 +55331,449 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Send-OBSPauseRecord { - +function Get-OBSSeascapeShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'PauseRecord')] -[Alias('obs.powershell.websocket.PauseRecord')] +[Alias('Set-OBSSeascapeShader','Add-OBSSeascapeShader')] param( -# If set, will return the information that would otherwise be sent to OBS. +# Set the AA of OBSSeascapeShader +[ComponentModel.DefaultBindingProperty('AA')] +[Management.Automation.SwitchParameter] +$AA, +# Set the SEA_HEIGHT of OBSSeascapeShader +[Alias('SEA_HEIGHT')] +[ComponentModel.DefaultBindingProperty('SEA_HEIGHT')] +[Single] +$SEAHEIGHT, +# Set the SEA_CHOPPY of OBSSeascapeShader +[Alias('SEA_CHOPPY')] +[ComponentModel.DefaultBindingProperty('SEA_CHOPPY')] +[Single] +$SEACHOPPY, +# Set the SEA_SPEED of OBSSeascapeShader +[Alias('SEA_SPEED')] +[ComponentModel.DefaultBindingProperty('SEA_SPEED')] +[Single] +$SEASPEED, +# Set the SEA_FREQ of OBSSeascapeShader +[Alias('SEA_FREQ')] +[ComponentModel.DefaultBindingProperty('SEA_FREQ')] +[Single] +$SEAFREQ, +# Set the SEA_BASE of OBSSeascapeShader +[Alias('SEA_BASE')] +[ComponentModel.DefaultBindingProperty('SEA_BASE')] +[String] +$SEABASE, +# Set the SEA_WATER_COLOR of OBSSeascapeShader +[Alias('SEA_WATER_COLOR')] +[ComponentModel.DefaultBindingProperty('SEA_WATER_COLOR')] +[String] +$SEAWATERCOLOR, +# Set the CAMERA_SPEED of OBSSeascapeShader +[Alias('CAMERA_SPEED')] +[ComponentModel.DefaultBindingProperty('CAMERA_SPEED')] +[Single] +$CAMERASPEED, +# Set the CAMERA_TURN_SPEED of OBSSeascapeShader +[Alias('CAMERA_TURN_SPEED')] +[ComponentModel.DefaultBindingProperty('CAMERA_TURN_SPEED')] +[Single] +$CAMERATURNSPEED, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'seascape' +$ShaderNoun = 'OBSSeascapeShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +/* + * "Seascape" by Alexander Alekseev aka TDM - 2014 + * License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. + * Contact: tdmaav@gmail.com + * https://www.shadertoy.com/view/Ms2SD1 adapted by Exeldro + */ +#define NUM_STEPS 8 +#define PI 3.141592 +#define EPSILON 0.001 +uniform bool AA< + string label = "Smooth (more resources)"; +> = false; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +#ifndef OPENGL +#define mat2 float2x2 +#define mat3 float3x3 +#define fract frac +#define mix lerp +#endif - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +// sea +#define ITER_GEOMETRY 3 +#define ITER_FRAGMENT 5 +uniform float SEA_HEIGHT< + string label = "Sea Height"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.5; + float step = 0.001; +> = 0.6; +uniform float SEA_CHOPPY< + string label = "Sea Choppy"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 4.0; +uniform float SEA_SPEED< + string label = "Sea Speed"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 0.8; +uniform float SEA_FREQ< + string label = "Sea Frequency"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 0.5; + float step = 0.001; +> = 0.16; +uniform float4 SEA_BASE< + string label = "Sea Base"; +> = {0.0,0.09,0.18,1.0}; +uniform float4 SEA_WATER_COLOR< + string label = "Sea Water"; +> = {0.48,0.54,0.36,1.0}; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } +uniform float CAMERA_SPEED< + string label = "Camera Speed"; + string widget_type = "slider"; + float minimum = -10.0; + float maximum = 10.0; + float step = 0.001; +> = 1.0; - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } +uniform float CAMERA_TURN_SPEED< + string label = "Camera Turn Speed"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 1.0; - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } +float SEA_TIME(){ + return 1.0 + elapsed_time * SEA_SPEED; } +// math +mat3 fromEuler(float3 ang) { + float2 a1 = float2(sin(ang.x),cos(ang.x)); + float2 a2 = float2(sin(ang.y),cos(ang.y)); + float2 a3 = float2(sin(ang.z),cos(ang.z)); + return mat3(float3(a1.y*a3.y+a1.x*a2.x*a3.x,a1.y*a2.x*a3.x+a3.y*a1.x,-a2.y*a3.x), + float3(-a2.y*a1.x,a1.y*a2.y,a2.x), + float3(a3.y*a1.x*a2.x+a1.y*a3.x,a1.x*a3.x-a1.y*a3.y*a2.x,a2.y*a3.y)); +} -} - - -#.ExternalHelp obs-powershell-Help.xml -function Send-OBSPressInputPropertiesButton { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'PressInputPropertiesButton')] -[Alias('obs.powershell.websocket.PressInputPropertiesButton')] -param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('propertyName')] -[string] -$PropertyName, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) +float hash(float2 p) { + float h = dot(p,float2(127.1,311.7)); + return fract(sin(h)*43758.5453123); +} +float noise(float2 p) { + float2 i = floor( p ); + float2 f = fract( p ); + float2 u = f*f*(3.0-2.0*f); + return -1.0+2.0*mix( mix( hash( i + float2(0.0,0.0) ), + hash( i + float2(1.0,0.0) ), u.x), + mix( hash( i + float2(0.0,1.0) ), + hash( i + float2(1.0,1.0) ), u.x), u.y); +} -process { +// lighting +float diffuse(float3 n,float3 l,float p) { + return pow(dot(n,l) * 0.4 + 0.6,p); +} +float specular(float3 n,float3 l,float3 e,float s) { + float nrm = (s + 8.0) / (PI * 8.0); + return pow(max(dot(reflect(e,n),l),0.0),s) * nrm; +} +// sky +float3 getSkyColor(float3 e) { + e.y = (max(e.y,0.0)*0.8+0.2)*0.8; + return float3(pow(1.0-e.y,2.0), 1.0-e.y, 0.6+(1.0-e.y)*0.4) * 1.1; +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +// sea +float sea_octave(float2 uv, float choppy) { + uv += noise(uv); + float2 wv = 1.0-abs(sin(uv)); + float2 swv = abs(cos(uv)); + wv = mix(wv,swv,wv); + return pow(1.0-pow(wv.x * wv.y,0.65),choppy); +} - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +float map(float3 p) { + float freq = SEA_FREQ; + float amp = SEA_HEIGHT; + float choppy = SEA_CHOPPY; + float2 uv = p.xz; + uv.x *= 0.75; + mat2 octave_m = mat2(1.6,1.2,-1.2,1.6); - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } + float st = SEA_TIME(); + float d, h = 0.0; + for(int i = 0; i < ITER_GEOMETRY; i++) { + d = sea_octave((uv+float2(st,st))*freq,choppy); + d += sea_octave((uv-float2(st,st))*freq,choppy); + h += d * amp; + uv = mul(uv, octave_m); + freq *= 1.9; + amp *= 0.22; + choppy = mix(choppy,1.0,0.2); + } + return p.y - h; +} - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } +float map_detailed(float3 p) { + float freq = SEA_FREQ; + float amp = SEA_HEIGHT; + float choppy = SEA_CHOPPY; + float2 uv = p.xz; uv.x *= 0.75; + mat2 octave_m = mat2(1.6,1.2,-1.2,1.6); + float st = SEA_TIME(); + float d, h = 0.0; + for(int i = 0; i < ITER_FRAGMENT; i++) { + d = sea_octave((uv+float2(st,st))*freq,choppy); + d += sea_octave((uv-float2(st,st))*freq,choppy); + h += d * amp; + uv = mul(uv, octave_m); + freq *= 1.9; + amp *= 0.22; + choppy = mix(choppy,1.0,0.2); + } + return p.y - h; +} + +float3 getSeaColor(float3 p, float3 n, float3 l, float3 eye, float3 dist) { + float fresnel = clamp(1.0 - dot(n,-eye), 0.0, 1.0); + fresnel = min(pow(fresnel,3.0), 0.5); - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" + float3 reflected = getSkyColor(reflect(eye,n)); + float3 refracted = SEA_BASE.rgb + diffuse(n,l,80.0) * SEA_WATER_COLOR.rgb * 0.12; - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } + float3 color = mix(refracted,reflected,fresnel); + + float atten = max(1.0 - dot(dist,dist) * 0.001, 0.0); + color += SEA_WATER_COLOR.rgb * (p.y - SEA_HEIGHT) * 0.18 * atten; + + float s = specular(n,l,eye,60.0); + color += float3(s,s,s); + + return color; +} - if ($PassThru) { - [PSCustomObject]$requestPayload +// tracing +float3 getNormal(float3 p, float eps) { + float3 n; + n.y = map_detailed(p); + n.x = map_detailed(float3(p.x+eps,p.y,p.z)) - n.y; + n.z = map_detailed(float3(p.x,p.y,p.z+eps)) - n.y; + n.y = eps; + return normalize(n); +} + +float heightMapTracing(float3 ori, float3 dir, out float3 p) { + float tm = 0.0; + float tx = 1000.0; + float hx = map(ori + dir * tx); + if(hx > 0.0) { + p = ori + dir * tx; + return tx; + } + float hm = map(ori + dir * tm); + float tmid = 0.0; + for(int i = 0; i < NUM_STEPS; i++) { + tmid = mix(tm,tx, hm/(hm-hx)); + p = ori + dir * tmid; + float hmid = map(p); + if(hmid < 0.0) { + tx = tmid; + hx = hmid; } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + tm = tmid; + hm = hmid; } - + } + return tmid; } +float3 getPixel(in float2 coord, float time) { + float2 uv = coord / uv_size.xy; + uv = uv * 2.0 - 1.0; + uv.x *= uv_size.x / uv_size.y; + + // ray + float3 ang = float3(sin(time*3.0*CAMERA_TURN_SPEED)*0.1,sin(time*CAMERA_TURN_SPEED)*0.2+0.3,time*CAMERA_TURN_SPEED); + float3 ori = float3(0.0,3.5,time*5.0*CAMERA_SPEED); + float3 dir = normalize(float3(uv.xy,-2.0)); + dir.z += length(uv) * 0.14; + dir = mul(normalize(dir), fromEuler(ang)); + + // tracing + float3 p; + heightMapTracing(ori,dir,p); + float3 dist = p - ori; + float3 n = getNormal(p, dot(dist,dist) * (0.1 / uv_size.x)); + float3 light = normalize(float3(0.0,1.0,0.8)); + + // color + return mix( + getSkyColor(dir), + getSeaColor(p,n,light,dir,dist), + pow(smoothstep(0.0,-0.02,dir.y),0.2)); +} -} - - -#.ExternalHelp obs-powershell-Help.xml -function Send-OBSSleep { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'Sleep')] -[Alias('obs.powershell.websocket.Sleep')] -param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sleepMillis')] -[ValidateRange(0,50000)] -[double] -$SleepMillis, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sleepFrames')] -[ValidateRange(0,10000)] -[double] -$SleepFrames, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +// main +float4 mainImage(VertData v_in) : TARGET +{ + float time = elapsed_time * 0.3; + float2 fragCoord = float2(v_in.uv.x * uv_size.x, (1.0 - v_in.uv.y) * uv_size.y); + + float3 color = float3(0.0,0.0,0.0);; + if (AA){ + for(int i = -1; i <= 1; i++) { + for(int j = -1; j <= 1; j++) { + float2 uv = fragCoord+float2(i,j)/3.0; + color += getPixel(uv, time); + } + } + color /= 9.0; + }else{ + color = getPixel(fragCoord, time); + } + + // post + return float4(pow(color,float3(0.65,0.65,0.65)), 1.0); +} +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -54337,105 +55782,194 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Send-OBSStreamCaption { - +function Get-OBSSeasickShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SendStreamCaption')] -[Alias('obs.powershell.websocket.SendStreamCaption')] +[Alias('Set-OBSSeasickShader','Add-OBSSeasickShader')] param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('captionText')] -[string] -$CaptionText, -# If set, will return the information that would otherwise be sent to OBS. +# Set the notes of OBSSeasickShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# Set the amplitude of OBSSeasickShader +[ComponentModel.DefaultBindingProperty('amplitude')] +[Single] +$Amplitude, +# Set the speed of OBSSeasickShader +[ComponentModel.DefaultBindingProperty('speed')] +[Single] +$Speed, +# Set the frequency of OBSSeasickShader +[ComponentModel.DefaultBindingProperty('frequency')] +[Single] +$Frequency, +# Set the opacity of OBSSeasickShader +[ComponentModel.DefaultBindingProperty('opacity')] +[Single] +$Opacity, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'seasick' +$ShaderNoun = 'OBSSeasickShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Seasick - an effect for OBS Studio +// +uniform string notes< + string widget_type = "info"; +> = "Seasick - from the game Snavenger\n\n(available on Google Play/Amazon Fire)"; +uniform float amplitude< + string label = "amplitude"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.03; +uniform float speed< + string label = "speed"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.01; +> = 1.0; +uniform float frequency< + string label = "frequency"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 6.0; +uniform float opacity< + string label = "opacity"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.5; +float4 mainImage(VertData v_in) : TARGET +{ + float2 pulse = sin(elapsed_time*speed - frequency * v_in.uv); + float2 coord = v_in.uv + amplitude * float2(pulse.x, -pulse.y); + return image.Sample(textureSampler, coord) * opacity; +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} +' +} +$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 } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } + } + '(?>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 + } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] + } } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -54444,130 +55978,305 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Send-OBSTriggerHotkeyByKeySequence { - +function Get-OBSSelectiveColorShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'TriggerHotkeyByKeySequence')] -[Alias('obs.powershell.websocket.TriggerHotkeyByKeySequence')] +[Alias('Set-OBSSelectiveColorShader','Add-OBSSelectiveColorShader')] param( - +# Set the cutoff_Red of OBSSelectiveColorShader +[Alias('cutoff_Red')] +[ComponentModel.DefaultBindingProperty('cutoff_Red')] +[Single] +$CutoffRed, +# Set the cutoff_Green of OBSSelectiveColorShader +[Alias('cutoff_Green')] +[ComponentModel.DefaultBindingProperty('cutoff_Green')] +[Single] +$CutoffGreen, +# Set the cutoff_Blue of OBSSelectiveColorShader +[Alias('cutoff_Blue')] +[ComponentModel.DefaultBindingProperty('cutoff_Blue')] +[Single] +$CutoffBlue, +# Set the cutoff_Yellow of OBSSelectiveColorShader +[Alias('cutoff_Yellow')] +[ComponentModel.DefaultBindingProperty('cutoff_Yellow')] +[Single] +$CutoffYellow, +# Set the acceptance_Amplifier of OBSSelectiveColorShader +[Alias('acceptance_Amplifier')] +[ComponentModel.DefaultBindingProperty('acceptance_Amplifier')] +[Single] +$AcceptanceAmplifier, +# Set the show_Red of OBSSelectiveColorShader +[Alias('show_Red')] +[ComponentModel.DefaultBindingProperty('show_Red')] +[Management.Automation.SwitchParameter] +$ShowRed, +# Set the show_Green of OBSSelectiveColorShader +[Alias('show_Green')] +[ComponentModel.DefaultBindingProperty('show_Green')] +[Management.Automation.SwitchParameter] +$ShowGreen, +# Set the show_Blue of OBSSelectiveColorShader +[Alias('show_Blue')] +[ComponentModel.DefaultBindingProperty('show_Blue')] +[Management.Automation.SwitchParameter] +$ShowBlue, +# Set the show_Yellow of OBSSelectiveColorShader +[Alias('show_Yellow')] +[ComponentModel.DefaultBindingProperty('show_Yellow')] +[Management.Automation.SwitchParameter] +$ShowYellow, +# Set the notes of OBSSelectiveColorShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# Set the background_type of OBSSelectiveColorShader +[Alias('background_type')] +[ComponentModel.DefaultBindingProperty('background_type')] +[Int32] +$BackgroundType, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('keyId')] -[string] -$KeyId, - +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('keyModifiers')] -[PSObject] -$KeyModifiers, +[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 +) -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('keyModifiers.shift')] -[switch] -$KeyModifiersshift, -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('keyModifiers.control')] -[switch] -$KeyModifierscontrol, +process { +$shaderName = 'selective_color' +$ShaderNoun = 'OBSSelectiveColorShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Selective Color shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 +//https://github.com/Oncorporation/obs-shaderfilter +//updated 4/13/2020: take into account the opacity/alpha of input image -thanks Skeletonbow for suggestion +//Converted to OpenGL by Q-mii February 25, 2020 +uniform float cutoff_Red< + string label = "cutoff Red"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.40; +uniform float cutoff_Green< + string label = "cutoff Green"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.025; +uniform float cutoff_Blue< + string label = "cutoff Blue"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.25; +uniform float cutoff_Yellow< + string label = "cutoff Yellow"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.25; +uniform float acceptance_Amplifier< + string label = "acceptance Amplifier"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 20.0; + float step = 0.001; +> = 5.0; -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('keyModifiers.alt')] -[switch] -$KeyModifiersalt, +uniform bool show_Red = true; +uniform bool show_Green = true; +uniform bool show_Blue = true; +uniform bool show_Yellow = true; +uniform string notes< + string widget_type = "info"; +> = "defaults: .4,.03,.25,.25, 5.0, true,true, true, true. cuttoff higher = less color, 0 = all 1 = none."; +uniform int background_type< + string label = "background type"; + string widget_type = "select"; + int option_0_value = 0; + string option_0_label = "Grey"; + int option_1_value = 1; + string option_1_label = "Luma"; + int option_2_value = 2; + string option_2_label = "White"; + int option_3_value = 3; + string option_3_label = "Black"; + int option_4_value = 4; + string option_4_label = "Transparent"; + int option_5_value = 5; + string option_5_label = "Background Color"; +> = 0; -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('keyModifiers.command')] -[switch] -$KeyModifierscommand, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) +float4 mainImage(VertData v_in) : TARGET +{ + const float PI = 3.1415926535897932384626433832795;//acos(-1); + const float3 coefLuma = float3(0.2126, 0.7152, 0.0722); + float4 color = image.Sample(textureSampler, v_in.uv); + float luminance = dot(coefLuma, color.rgb); + float4 gray = float4(luminance, luminance, luminance, 1.0); -process { + if (background_type == 0) + { + luminance = (color.r + color.g + color.b) * 0.3333; + gray = float4(luminance,luminance,luminance, 1.0); + } + //if (background_type == 1) + //{ + // gray = float4(luminance,luminance,luminance, 1.0); + //} + if (background_type == 2) + gray = float4(1.0,1.0,1.0,1.0); + if (background_type == 3) + gray = float4(0.0,0.0,0.0,1.0); + if (background_type == 4) + gray.a = 0.01; + if (background_type == 5) + gray = color; + float redness = max ( min ( color.r - color.g , color.r - color.b ) / color.r , 0); + float greenness = max ( min ( color.g - color.r , color.g - color.b ) / color.g , 0); + float blueness = max ( min ( color.b - color.r , color.b - color.g ) / color.b , 0); + + float rgLuminance = (color.r*1.4 + color.g*0.6)/2; + float rgDiff = abs(color.r-color.g)*1.4; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + float yellowness = 0.1 + rgLuminance * 1.2 - color.b - rgDiff; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + float4 accept; + accept.r = float(show_Red) * (redness - cutoff_Red); + accept.g = float(show_Green) * (greenness - cutoff_Green); + accept.b = float(show_Blue) * (blueness - cutoff_Blue); + accept[3] = float(show_Yellow) * (yellowness - cutoff_Yellow); - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + float acceptance = max (accept.r, max(accept.g, max(accept.b, max(accept[3],0)))); + float modAcceptance = min (acceptance * acceptance_Amplifier, 1); + + float4 result = color; + if (result.a > 0) { + result = modAcceptance * color + (1.0 - modAcceptance) * gray; + //result.a *= gray.a; + } + + return result; +} + +' +} +$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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -54576,227 +56285,346 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Send-OBSTriggerHotkeyByName { - +function Get-OBSShakeShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'TriggerHotkeyByName')] -[Alias('obs.powershell.websocket.TriggerHotkeyByName')] +[Alias('Set-OBSShakeShader','Add-OBSShakeShader')] param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('hotkeyName')] -[string] -$HotkeyName, - +# Set the ViewProj of OBSShakeShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the image of OBSShakeShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the elapsed_time of OBSShakeShader +[Alias('elapsed_time')] +[ComponentModel.DefaultBindingProperty('elapsed_time')] +[Single] +$ElapsedTime, +# Set the uv_offset of OBSShakeShader +[Alias('uv_offset')] +[ComponentModel.DefaultBindingProperty('uv_offset')] +[Single[]] +$UvOffset, +# Set the uv_scale of OBSShakeShader +[Alias('uv_scale')] +[ComponentModel.DefaultBindingProperty('uv_scale')] +[Single[]] +$UvScale, +# Set the uv_pixel_interval of OBSShakeShader +[Alias('uv_pixel_interval')] +[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +[Single[]] +$UvPixelInterval, +# Set the rand_f of OBSShakeShader +[Alias('rand_f')] +[ComponentModel.DefaultBindingProperty('rand_f')] +[Single] +$RandF, +# Set the uv_size of OBSShakeShader +[Alias('uv_size')] +[ComponentModel.DefaultBindingProperty('uv_size')] +[Single[]] +$UvSize, +# Set the local_time of OBSShakeShader +[Alias('local_time')] +[ComponentModel.DefaultBindingProperty('local_time')] +[Single] +$LocalTime, +# Set the random_scale of OBSShakeShader +[Alias('random_scale')] +[ComponentModel.DefaultBindingProperty('random_scale')] +[Single] +$RandomScale, +# Set the worble of OBSShakeShader +[ComponentModel.DefaultBindingProperty('worble')] +[Management.Automation.SwitchParameter] +$Worble, +# Set the speed of OBSShakeShader +[ComponentModel.DefaultBindingProperty('speed')] +[Single] +$Speed, +# Set the min_growth_pixels of OBSShakeShader +[Alias('min_growth_pixels')] +[ComponentModel.DefaultBindingProperty('min_growth_pixels')] +[Single] +$MinGrowthPixels, +# Set the max_growth_pixels of OBSShakeShader +[Alias('max_growth_pixels')] +[ComponentModel.DefaultBindingProperty('max_growth_pixels')] +[Single] +$MaxGrowthPixels, +# Set the randomize_movement of OBSShakeShader +[Alias('randomize_movement')] +[ComponentModel.DefaultBindingProperty('randomize_movement')] +[Management.Automation.SwitchParameter] +$RandomizeMovement, +# Set the notes of OBSShakeShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('contextName')] -[string] -$ContextName, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'shake' +$ShaderNoun = 'OBSShakeShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Shake Effect By Charles Fettinger (https://github.com/Oncorporation) 2/2019 +// Added some randomization based upon random_scale input +// updated for latest version of obs-shaderfilter +uniform float4x4 ViewProj; +uniform texture2d image; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +uniform float elapsed_time; +uniform float2 uv_offset; +uniform float2 uv_scale; +uniform float2 uv_pixel_interval; +uniform float rand_f; +uniform float2 uv_size; +uniform float local_time; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } +uniform float random_scale< + string label = "random scale"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 0.25; +uniform bool worble = false; +uniform float speed< + string label = "Speed"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.001; +> = 1.0; +uniform float min_growth_pixels< + string label = "min growth pixels"; + string widget_type = "slider"; + float minimum = -10.0; + float maximum = 10.0; + float step = 0.001; +> = -2.0; +uniform float max_growth_pixels< + string label = "max growth pixels"; + string widget_type = "slider"; + float minimum = -10.0; + float maximum = 10.0; + float step = 0.001; +> = 2.0; +uniform bool randomize_movement = false; - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } +uniform string notes< + string widget_type = "info"; +> =''keep the random_scale low for small (0.2-1) for small jerky movements and larger for less often big jumps''; - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } +sampler_state textureSampler { + Filter = Linear; + AddressU = Border; + AddressV = Border; + BorderColor = 00000000; +}; -} +struct VertData { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; +//noise values in range if 0.0 to 1.0 -} +float noise3D(float x, float y, float z) { + float ptr = 0.0f; + return frac(sin(x*112.9898f + y*179.233f + z*237.212f) * 43758.5453f); +} - -#.ExternalHelp obs-powershell-Help.xml -function Send-OBSTriggerMediaInputAction { +VertData mainTransform(VertData v_in) +{ + VertData vert_out; + float3 pos = v_in.pos.xyz; + float t; + float s; + float noise; + if (randomize_movement) + { + t = (rand_f * 2) - 1.0f; + s = (1 - rand_f * 2) - 1.0f;; + noise = clamp( rand_f * random_scale,-0.99, 0.99); + } + else + { + t = (1 + sin(elapsed_time * speed)) / 2; + s = (1 + cos(elapsed_time * speed)) / 2; + noise = clamp(noise3D(t,s,100) * random_scale,-0.99, 0.99); + } -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'TriggerMediaInputAction')] -[Alias('obs.powershell.websocket.TriggerMediaInputAction')] -param( + float3 direction_from_center = float3((v_in.uv.x - 0.5 + noise) * uv_pixel_interval.y / uv_pixel_interval.x, v_in.uv.y - 0.5 + noise, 1); + float3 min_pos; + float3 max_pos; + if (worble) + { + min_pos = pos + direction_from_center * min_growth_pixels * 0.5; + max_pos = pos + direction_from_center * max_growth_pixels * 0.5; + } + else + { + min_pos = pos + direction_from_center * 0.5; + max_pos = min_pos; + } -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, + float3 current_pos = min_pos * (1 - t) + max_pos * t; + //current_pos.x = v_in.pos.x + (t * min_pos.x); + current_pos.y = (min_pos.y * (1 - s) + max_pos.y * s); + //current_pos.y = v_in.pos.y + (s * min_pos.y); + //current_pos.z = min_pos.z * (1 - s) + max_pos.z * s; -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, + float2 offset = uv_offset; + offset.x = uv_offset.x * (1 - t + noise); + offset.y = uv_offset.y * (1 - s + noise); -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('mediaAction')] -[string] -$MediaAction, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + vert_out.pos = mul(float4(current_pos, 1), ViewProj); + + //float2 scale = uv_scale; + //scale += dot(pos - current_pos, 1); + vert_out.uv = v_in.uv * uv_scale + offset; + return vert_out; +} -process { +float4 mainImage(VertData v_in) : TARGET +{ + return image.Sample(textureSampler, v_in.uv); +} +technique Draw +{ + pass + { + vertex_shader = mainTransform(v_in); + pixel_shader = mainImage(v_in); + } +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -54805,212 +56633,371 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Send-OBSTriggerStudioModeTransition { +function Get-OBSShineShader { + +[Alias('Set-OBSShineShader','Add-OBSShineShader')] +param( +# Set the l_tex of OBSShineShader +[Alias('l_tex')] +[ComponentModel.DefaultBindingProperty('l_tex')] +[String] +$LTex, +# Set the shine_color of OBSShineShader +[Alias('shine_color')] +[ComponentModel.DefaultBindingProperty('shine_color')] +[String] +$ShineColor, +# Set the speed_percent of OBSShineShader +[Alias('speed_percent')] +[ComponentModel.DefaultBindingProperty('speed_percent')] +[Int32] +$SpeedPercent, +# Set the gradient_percent of OBSShineShader +[Alias('gradient_percent')] +[ComponentModel.DefaultBindingProperty('gradient_percent')] +[Int32] +$GradientPercent, +# Set the delay_percent of OBSShineShader +[Alias('delay_percent')] +[ComponentModel.DefaultBindingProperty('delay_percent')] +[Int32] +$DelayPercent, +# Set the Apply_To_Alpha_Layer of OBSShineShader +[Alias('Apply_To_Alpha_Layer')] +[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] +[Management.Automation.SwitchParameter] +$ApplyToAlphaLayer, +# Set the ease of OBSShineShader +[ComponentModel.DefaultBindingProperty('ease')] +[Management.Automation.SwitchParameter] +$Ease, +# Set the hide of OBSShineShader +[ComponentModel.DefaultBindingProperty('hide')] +[Management.Automation.SwitchParameter] +$Hide, +# Set the reverse of OBSShineShader +[ComponentModel.DefaultBindingProperty('reverse')] +[Management.Automation.SwitchParameter] +$Reverse, +# Set the One_Direction of OBSShineShader +[Alias('One_Direction')] +[ComponentModel.DefaultBindingProperty('One_Direction')] +[Management.Automation.SwitchParameter] +$OneDirection, +# Set the glitch of OBSShineShader +[ComponentModel.DefaultBindingProperty('glitch')] +[Management.Automation.SwitchParameter] +$Glitch, +# Set the notes of OBSShineShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# Set the start_adjust of OBSShineShader +[Alias('start_adjust')] +[ComponentModel.DefaultBindingProperty('start_adjust')] +[Single] +$StartAdjust, +# Set the stop_adjust of OBSShineShader +[Alias('stop_adjust')] +[ComponentModel.DefaultBindingProperty('stop_adjust')] +[Single] +$StopAdjust, +# 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 = 'shine' +$ShaderNoun = 'OBSShineShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Shine Shader By Charles Fettinger (https://github.com/Oncorporation) 3/2019 +// use color to control shine amount, use transition wipes or make your own alpha texture +// slerp not currently used, for circular effects +//Converted to OpenGL by Exeldro February 14, 2022 +uniform texture2d l_tex; +uniform float4 shine_color ; +uniform int speed_percent< + string label = "speed percent"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 25; +uniform int gradient_percent< + string label = "gradient percent"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 20; +uniform int delay_percent< + string label = "delay percent"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform bool Apply_To_Alpha_Layer = false; +uniform bool ease = false; +uniform bool hide = false; +uniform bool reverse = false; +uniform bool One_Direction = true; +uniform bool glitch = false; +uniform string notes< + string widget_type = "info"; +> = "Use Luma Wipes ( data/obs-plugins/obs-transitions/luma_wipes ) ''ease'' makes the animation pause at the begin and end for a moment, ''hide'' will make the image disappear, ''glitch'' is random and amazing, ''reverse'' quickly allows you to test settings, ''One Direction'' only shows the shine as it travels in one direction, ''delay percentage'' adds a delay between shines (requires adjustment to speed: https://www.desmos.com/calculator/wkgbndweyt )"; -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'TriggerStudioModeTransition')] -[Alias('obs.powershell.websocket.TriggerStudioModeTransition')] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) +uniform float start_adjust; +uniform float stop_adjust; +float EaseInOutCircTimer(float t,float b,float c,float d){ + t /= d/2.0; + if (t < 1.0) return -c/2.0 * (sqrt(1.0 - t*t) - 1.0) + b; + t -= 2.0; + return c/2.0 * (sqrt(1.0 - t*t) + 1.0) + b; +} -process { +float Styler(float t,float b,float c,float d,bool ease) +{ + if (ease) return EaseInOutCircTimer(t,0.0,c,d); + return t; +} +float4 convert_pmalpha(float4 c) +{ + float4 ret = c; + if (c.a >= 0.001) + ret.xyz /= c.a; + else + ret = float4(0.0, 0.0, 0.0, 0.0); + return ret; +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float4 slerp(float4 start, float4 end, float percent) +{ + // Dot product - the cosine of the angle between 2 vectors. + float dotf = start.r*end.r+start.g*end.g+start.b*end.b+start.a*end.a; + // Clamp it to be in the range of Acos() + // This may be unnecessary, but floating point + // precision can be a fickle mistress. + dotf = clamp(dotf, -1.0f, 1.0f); + // Acos(dot) returns the angle between start and end, + // And multiplying that by percent returns the angle between + // start and the final result. + float theta = acos(dotf)*percent; + float4 RelativeVec = normalize(end - start * dotf); + + // Orthonormal basis + // The final result. + return ((start*cos(theta)) + (RelativeVec*sin(theta))); +} - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +float4 mainImage(VertData v_in) : TARGET +{ + // convert input for vector math + float4 rgba = convert_pmalpha(image.Sample(textureSampler, v_in.uv)); + float speed = speed_percent * 0.01; + float softness = max(abs(gradient_percent * 0.01), 0.01) * sign(gradient_percent); + float delay = clamp(delay_percent * 0.01, 0.0, 1.0); + - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } + // circular easing variable + float direction = abs(sin((elapsed_time - 0.001) * speed)); + float t = abs(sin(elapsed_time * speed)); - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } + // if time is greater than direction, we are going up! + direction = t - direction; - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } + // split into segments with frac or mod. + // delay is the gap between starting and ending of the sine wave, use speed to compensate + t = (frac(t) - delay) * (1 / (1 - delay)); + t = 1 + max(t,0.0); -} + float s = 0.0; //start value + float c = 2.0; //change value + float d = 2.0; //duration + if (glitch) t = clamp(t + ((rand_f *2) - 1), 0.0,2.0); -} + //if Unidirectional disable on return + if (One_Direction && (direction < 0.0)) + { + s = 0; + } + else + { + s = Styler(t, 0, c, d, ease); + } - -#.ExternalHelp obs-powershell-Help.xml -function Set-OBSCurrentPreviewScene { + // combine luma texture and user defined shine color + float luma = l_tex.Sample(textureSampler, v_in.uv).x; + // - adjust for min and max + if ((luma >= (start_adjust)) && (luma <= (1 - stop_adjust))) + { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetCurrentPreviewScene')] -[Alias('obs.powershell.websocket.SetCurrentPreviewScene')] -param( + if (reverse) + { + luma = 1.0 - luma; + } + + // user color with luma + float4 output_color = float4(shine_color.rgb, luma); -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, + float time = lerp(0.0f, 1.0f + abs(2*softness), s - 1.0); -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + // use luma texture to add alpha and shine + // if behind glow, consider trailing gradient shine then show underlying image + if (luma <= time - softness) + { + float alpha_behind = clamp(1.0 - (time - softness - luma ) / softness, 0.00, 1.0); + if (Apply_To_Alpha_Layer) + alpha_behind *= rgba.a; + return lerp(rgba, rgba + output_color, alpha_behind); + } -process { + // if in front of glow, consider if the underlying image is hidden + if (luma >= time) + { + // if hide, make the transition better + if (hide) + { + return float4(rgba.rgb, lerp(0.0, rgba.a, (time + softness) / (1 + abs(2*softness)))); + } + else + { + return rgba; + } + } + // else show the glow area, with luminance + float alpha_ = (time - luma) / softness; + if (Apply_To_Alpha_Layer) + alpha_ *= rgba.a; + return lerp(rgba, rgba + output_color, alpha_); + } + else + { + return rgba; + } +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -55019,217 +57006,288 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSCurrentProfile { - +function Get-OBSSimpleGradientShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetCurrentProfile')] -[Alias('obs.powershell.websocket.SetCurrentProfile')] +[Alias('Set-OBSSimpleGradientShader','Add-OBSSimpleGradientShader')] param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('profileName')] -[string] -$ProfileName, -# If set, will return the information that would otherwise be sent to OBS. +# Set the speed_percentage of OBSSimpleGradientShader +[Alias('speed_percentage')] +[ComponentModel.DefaultBindingProperty('speed_percentage')] +[Int32] +$SpeedPercentage, +# Set the alpha_percentage of OBSSimpleGradientShader +[Alias('alpha_percentage')] +[ComponentModel.DefaultBindingProperty('alpha_percentage')] +[Int32] +$AlphaPercentage, +# Set the Lens_Flair of OBSSimpleGradientShader +[Alias('Lens_Flair')] +[ComponentModel.DefaultBindingProperty('Lens_Flair')] +[Management.Automation.SwitchParameter] +$LensFlair, +# Set the Animate_Lens_Flair of OBSSimpleGradientShader +[Alias('Animate_Lens_Flair')] +[ComponentModel.DefaultBindingProperty('Animate_Lens_Flair')] +[Management.Automation.SwitchParameter] +$AnimateLensFlair, +# Set the Apply_To_Alpha_Layer of OBSSimpleGradientShader +[Alias('Apply_To_Alpha_Layer')] +[ComponentModel.DefaultBindingProperty('Apply_To_Alpha_Layer')] +[Management.Automation.SwitchParameter] +$ApplyToAlphaLayer, +# Set the Apply_To_Specific_Color of OBSSimpleGradientShader +[Alias('Apply_To_Specific_Color')] +[ComponentModel.DefaultBindingProperty('Apply_To_Specific_Color')] +[Management.Automation.SwitchParameter] +$ApplyToSpecificColor, +# Set the Color_To_Replace of OBSSimpleGradientShader +[Alias('Color_To_Replace')] +[ComponentModel.DefaultBindingProperty('Color_To_Replace')] +[String] +$ColorToReplace, +# Set the notes of OBSSimpleGradientShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'simple_gradient' +$ShaderNoun = 'OBSSimpleGradientShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Simple Gradient shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 +// https://github.com/Oncorporation/obs-shaderfilter +//lots of room to play here +//Converted to OpenGL by Q-mii & Exeldro February 25, 2022 +uniform int speed_percentage< + string label = "speed percentage"; + string widget_type = "slider"; + int minimum = -500; + int maximum = 500; + int step = 1; +> = 240; // +uniform int alpha_percentage< + string label = "aplha percentage"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 90; +uniform bool Lens_Flair = false; +uniform bool Animate_Lens_Flair = false; +uniform bool Apply_To_Alpha_Layer = false; +uniform bool Apply_To_Specific_Color; +uniform float4 Color_To_Replace; +uniform string notes< + string widget_type = "info"; +> = "This gradient is very basic from the top left corner. Red on horizontal, Green vertical, Blue Diagonal. Apply To Alpha Layer will add the gradient colors to the background. Lens Flair will brighten the scene from the bottom right. There is also a lot of unused code to play with in the shader file, delimted by /* ... */"; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } +float4 mainImage(VertData v_in) : TARGET +{ - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } + float4 background_color = image.Sample(textureSampler, v_in.uv); + int no_colors = 4; + float3 colors[4]; + colors[0] = float3(1.0,0.0,0.0); + colors[1] = float3(0.0,1.0,0.0); + colors[2] = float3(0.0,0.0,1.0); + colors[3] = float3(1.0,1.0,1.0); + float alpha = float(alpha_percentage) * 0.01; + float speed = float(speed_percentage) * 0.01; -} + float mx = max(uv_size.x , uv_size.y); + //float2 uv = v_in.uv / mx; + float3 rgb = background_color.rgb; + // skip if (alpha is zero and only apply to alpha layer is true) + if (!(background_color.a <= 0.0 && Apply_To_Alpha_Layer == true)) + { + rgb = float3(v_in.uv.x, v_in.uv.y, 0.10 + 0.85 * sin(elapsed_time * speed)); + } -} + //create lens flare like effect + if (Lens_Flair) + { + float2 lens_flair_coordinates = float2(0.95 ,0.95); + if (Animate_Lens_Flair) + lens_flair_coordinates *= float2(sin(elapsed_time * speed) ,cos(elapsed_time * speed)); - -#.ExternalHelp obs-powershell-Help.xml -function Set-OBSCurrentProgramScene { + float dist = distance(v_in.uv, ( lens_flair_coordinates * uv_scale + uv_offset)); + for (int i = 0; i < no_colors; ++i) { + rgb += lerp(rgb, colors[i], dist * 1.5) * 0.25; + } + } -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetCurrentProgramScene')] -[Alias('obs.powershell.websocket.SetCurrentProgramScene')] -param( + //float3 col = colors[0]; +/* for (int i = 1; i < no_colors; ++i) { + float3 hole = float3( + sin(1.5 - distance(v_in.uv.x / mx, colors[i].x / mx) * 2.5 * speed), + sin(1.5 - distance(v_in.uv.y / mx, colors[i].y / mx) * 2.5 * speed), + colors[i].z); + rgb = lerp(rgb, hole, 0.1); +*/ +/* float3 hole = lerp(colors[i-1], colors[i], sin(elapsed_time * speed)); + col = lerp(col, hole, v_in.uv.x); +*/ + //} +// rgb = fflerp(rgb, col, 0.5); -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + //try prepositioned colors with colors[] array timing + //creates an animated color spotlight +/* int color_index = int(sin(elapsed_time * speed) * no_colors); + float3 start_color = colors[color_index]; + float3 end_color; + if (color_index >= 0) + { + end_color = colors[color_index - 1]; + } + else + { + end_color = colors[no_colors - 1]; + } -process { + rgb = smoothstep(start_color, end_color, distance(v_in.uv , sin(elapsed_time * speed * no_colors) * (float2(1.0,1.0) * uv_scale + uv_offset))); +*/ + float4 rgba; + if (Apply_To_Alpha_Layer == false) + { + rgba = lerp(background_color,float4(rgb, 1.0),alpha); + } + else + { + rgba = lerp(background_color,background_color * float4(rgb,1.0), alpha); + } + if (Apply_To_Specific_Color) + { + float4 original_color = background_color; + background_color = (distance(background_color.rgb, Color_To_Replace.rgb) <= 0.075) ? rgba : background_color; + rgba = lerp(original_color, background_color, clamp(alpha, 0, 1.0)); + } + return rgba; +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -55238,320 +57296,370 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSCurrentSceneCollection { - +function Get-OBSSimplexNoiseShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetCurrentSceneCollection')] -[Alias('obs.powershell.websocket.SetCurrentSceneCollection')] +[Alias('Set-OBSSimplexNoiseShader','Add-OBSSimplexNoiseShader')] param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneCollectionName')] -[string] -$SceneCollectionName, -# If set, will return the information that would otherwise be sent to OBS. +# Set the Snap_Percent of OBSSimplexNoiseShader +[Alias('Snap_Percent')] +[ComponentModel.DefaultBindingProperty('Snap_Percent')] +[Single] +$SnapPercent, +# Set the Speed_Percent of OBSSimplexNoiseShader +[Alias('Speed_Percent')] +[ComponentModel.DefaultBindingProperty('Speed_Percent')] +[Single] +$SpeedPercent, +# Set the Resolution of OBSSimplexNoiseShader +[ComponentModel.DefaultBindingProperty('Resolution')] +[Single] +$Resolution, +# Set the Fractal of OBSSimplexNoiseShader +[ComponentModel.DefaultBindingProperty('Fractal')] +[Management.Automation.SwitchParameter] +$Fractal, +# Set the Use_Alpha_Layer of OBSSimplexNoiseShader +[Alias('Use_Alpha_Layer')] +[ComponentModel.DefaultBindingProperty('Use_Alpha_Layer')] +[Management.Automation.SwitchParameter] +$UseAlphaLayer, +# Set the Fore_Color of OBSSimplexNoiseShader +[Alias('Fore_Color')] +[ComponentModel.DefaultBindingProperty('Fore_Color')] +[String] +$ForeColor, +# Set the Back_Color of OBSSimplexNoiseShader +[Alias('Back_Color')] +[ComponentModel.DefaultBindingProperty('Back_Color')] +[String] +$BackColor, +# Set the Alpha_Percent of OBSSimplexNoiseShader +[Alias('Alpha_Percent')] +[ComponentModel.DefaultBindingProperty('Alpha_Percent')] +[Single] +$AlphaPercent, +# Set the Notes of OBSSimplexNoiseShader +[ComponentModel.DefaultBindingProperty('Notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'simplex_noise' +$ShaderNoun = 'OBSSimplexNoiseShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Simplex Noise shader by Charles Fettinger (https://github.com/Oncorporation) 5/2019 +// for use with obs-shaderfilter 1.0 +//based upon: https://www.shadertoy.com/view/XsX3zB +#ifndef OPENGL +#define fract frac +#endif - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } +uniform float Snap_Percent< + string label = "Snap Percent"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 7.5; +uniform float Speed_Percent< + string label = "Speed Percent"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 2.5; +uniform float Resolution< + string label = "Resolution"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 16.0; +uniform bool Fractal = false; +uniform bool Use_Alpha_Layer = false; +uniform float4 Fore_Color = {0.95,0.95,0.95, 1.0}; +uniform float4 Back_Color = {0.75, 0.75, 0.75, 1.0}; +uniform float Alpha_Percent< + string label = "Alpha Percent"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 100.0; +uniform string Notes< + string widget_type = "info"; +> = "Alpha Percentage applies to the shader, Use_Alpha_Layer applies effect with the image alpha layer, Resolution is the amount of detail of noise created.Fractal is a different algorithm. Snap Percent affects how many updates per second. Default values: 7.5%, 2.5%, 16.0, 100%"; +float dot(float3 a, float3 b){ + return a.r*b.r+a.g*b.g+a.b*b.b; } +float dot4(float4 a, float4 b){ + return a.r*b.r+a.g*b.g+a.b*b.b+a.a*b.a; +} +float snap(float x, float snap) +{ + return snap * round(x / max(0.01,snap)); +} -} - - -#.ExternalHelp obs-powershell-Help.xml -function Set-OBSCurrentSceneTransition { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetCurrentSceneTransition')] -[Alias('obs.powershell.websocket.SetCurrentSceneTransition')] -param( +float3 random3(float3 co) +{ + float j = 4096.0 * sin(dot(co, float3(17.0, 59.4, 15.0))); + float3 result; + result.z = fract(512.0 * j); + j *= .125; + result.x = fract(512.0 * j); + j *= .125; + result.y = fract(512.0 * j); + return result - 0.5; +} -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('transitionName')] -[string] -$TransitionName, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) +/* 3d simplex noise */ +float simplex3d(float3 p) { + /* 1. find current tetrahedron T and it''s four vertices */ + /* s, s+i1, s+i2, s+1.0 - absolute skewed (integer) coordinates of T vertices */ + /* x, x1, x2, x3 - unskewed coordinates of p relative to each of T vertices*/ + + /* skew constants for 3d simplex functions */ + float F3 = 0.3333333; + float G3 = 0.1666667; + /* calculate s and x */ + float3 s = floor(p + dot(p, float3(F3,F3,F3))); + float3 x = p - s + dot(s, float3(G3,G3,G3)); -process { + /* calculate i1 and i2 */ + float3 e = step(float3(0.0,0.0,0.0), x - x.yzx); + float3 i1 = e * (1.0 - e.zxy); + float3 i2 = 1.0 - e.zxy * (1.0 - e); + /* x1, x2, x3 */ + float3 x1 = x - i1 + G3; + float3 x2 = x - i2 + 2.0 * G3; + float3 x3 = x - 1.0 + 3.0 * G3; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + /* 2. find four surflets and store them in d */ + float4 w, d; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + /* calculate surflet weights */ + w.x = dot(x, x); + w.y = dot(x1, x1); + w.z = dot(x2, x2); + w.w = dot(x3, x3); - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } + /* w fades from 0.6 at the center of the surflet to 0.0 at the margin */ + w = max(0.61 - w, 0.0); - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } + /* calculate surflet components */ + d.x = dot(random3(s), x); + d.y = dot(random3(s + i1), x1); + d.z = dot(random3(s + i2), x2); + d.w = dot(random3(s + 1.0), x3); - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } + /* multiply d by w^4 */ + w *= w; + w *= w; + d *= w; + /* 3. return the sum of the four surflets */ + return dot4(d, float4(52.0, 52.0, 52.0, 52.0)); } -} +/* directional artifacts can be reduced by rotating each octave */ +float simplex3d_fractal(float3 m3) { + /* const matrices for 3d rotation */ +#ifdef OPENGL + float3x3 rot1 = float3x3( + float3(-0.37, 0.36, 0.85), + float3(-0.14, -0.93, 0.34), + float3(0.92, 0.01, 0.4 )); + float3x3 rot2 = float3x3( + float3(-0.55, -0.39, 0.74), + float3(0.33, -0.91, -0.24), + float3(0.77, 0.12, 0.63 )); + float3x3 rot3 = float3x3( + float3(-0.71, 0.52, -0.47), + float3(-0.08, -0.72, -0.68), + float3(-0.7, -0.45, 0.56 )); - -#.ExternalHelp obs-powershell-Help.xml -function Set-OBSCurrentSceneTransitionDuration { + float3 m = float3(m3.x, m3.y, m3.z); +#else + float3x3 rot1 = { + -0.37, 0.36, 0.85, + -0.14, -0.93, 0.34, + 0.92, 0.01, 0.4 }; + float3x3 rot2 = { + -0.55, -0.39, 0.74, + 0.33, -0.91, -0.24, + 0.77, 0.12, 0.63 }; + float3x3 rot3 = { + -0.71, 0.52, -0.47, + -0.08, -0.72, -0.68, + -0.7, -0.45, 0.56 }; + float3 m = {m3.x, m3.y, m3.z}; +#endif -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetCurrentSceneTransitionDuration')] -[Alias('obs.powershell.websocket.SetCurrentSceneTransitionDuration')] -param( + return 0.5333333* simplex3d(mul(m, rot1)) + + 0.2666667 * simplex3d(2.0 * mul(m, rot2)) + + 0.1333333 * simplex3d(4.0 * mul(m, rot3)) + + 0.0666667 * simplex3d(8.0 * m); +} -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('transitionDuration')] -[ValidateRange(50,20000)] -[double] -$TransitionDuration, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) +float4 mainImage(VertData v_in) : TARGET +{ + float time = snap(elapsed_time, Snap_Percent * .01); + float4 rgba = image.Sample(textureSampler, v_in.uv); + float2 p = v_in.uv.xy + float2( 0, -0.5); + float3 p3 = float3(p, time * (Speed_Percent * 0.01)); + + float pixel_alpha = 1.0; + // apply to mainImage rgba + if (Use_Alpha_Layer) { + p3 *= rgba.rgb; + pixel_alpha = rgba.a; + } + float value; -process { + if (Fractal) { + value = simplex3d_fractal(p3 * (Resolution * 0.5) + (Resolution * 0.5)); + } + else { + value = simplex3d(p3 * Resolution); + } + //soften color + value = 0.5 + (0.5 * value); + float intensity = dot(float3(value, value, value), float3(0.299, 0.587, 0.114)); - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + //use intensity to apply foreground and background colors + float4 r = lerp(float4(float3(value, value, value), pixel_alpha), Fore_Color, saturate(intensity)); + r = lerp(Back_Color, r, saturate(intensity)); + r.a = pixel_alpha; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + return lerp(rgba, r, Alpha_Percent * 0.01); +} +' +} +$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 } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } + } + '(?>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 + } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } + 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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -55560,228 +57668,222 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSCurrentSceneTransitionSettings { - +function Get-OBSSmartDenoiseShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetCurrentSceneTransitionSettings')] -[Alias('obs.powershell.websocket.SetCurrentSceneTransitionSettings')] +[Alias('Set-OBSSmartDenoiseShader','Add-OBSSmartDenoiseShader')] param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('transitionSettings')] -[PSObject] -$TransitionSettings, - +# Set the uSigma of OBSSmartDenoiseShader +[ComponentModel.DefaultBindingProperty('uSigma')] +[Single] +$USigma, +# Set the uKSigma of OBSSmartDenoiseShader +[ComponentModel.DefaultBindingProperty('uKSigma')] +[Single] +$UKSigma, +# Set the uThreshold of OBSSmartDenoiseShader +[ComponentModel.DefaultBindingProperty('uThreshold')] +[Single] +$UThreshold, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('overlay')] -[switch] -$Overlay, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'smart_denoise' +$ShaderNoun = 'OBSSmartDenoiseShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Smart DeNoise By Michele Morrone (https://github.com/BrutPitt/glslSmartDeNoise) +// Converted to OBS version of HLSL by Euiko on February 10, 2025 +#define INV_SQRT_OF_2PI 0.39894228040143267793994605993439 // 1.0/SQRT_OF_2PI +#define INV_PI 0.31830988618379067153776752674503 - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } - -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Set-OBSInputAudioBalance { - +uniform float uSigma< + string label = "Sigma"; + string widget_type = "slider"; + float minimum = 0.01; + float maximum = 3; // max based on the webgl sample, which is 3 + float step = 0.01; +> = 5.0; // default value based on shadertoy +uniform float uKSigma< + string label = "K-Sigma"; + string widget_type = "slider"; + float minimum = 0.01; + float maximum = 24; // max based on the webgl sample, which is 24 + float step = 0.01; +> = 7.0; // the default value is based on the webgl sample +uniform float uThreshold< + string label = "Edge Threshold"; + string widget_type = "slider"; + float minimum = 0.01; + float maximum = 2; // max based on the webgl sample, which is 2 + float step = 0.01; +> = 0.190; // the default value is based on the webgl sample -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetInputAudioBalance')] -[Alias('obs.powershell.websocket.SetInputAudioBalance')] -param( +// smartDeNoise - parameters +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// float2 uv - actual fragment coord +// float2 size - window size +// float sigma > 0 - sigma Standard Deviation +// float kSigma >= 0 - sigma coefficient +// kSigma * sigma --> radius of the circular kernel +// float threshold - edge sharpening threshold +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// NOTE: image''s texture2d data will be supplied by the OBS shaderfilter by default +float4 smartDeNoise(float2 uv, float2 size, float sigma, float kSigma, float threshold) +{ + float radius = round(kSigma * sigma); + float radQ = radius * radius; -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, + float invSigmaQx2 = 0.5 / (sigma * sigma); // 1.0 / (sigma^2 * 2.0) + float invSigmaQx2PI = INV_PI * invSigmaQx2; // 1/(2 * PI * sigma^2) -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, + float invThresholdSqx2 = 0.5 / (threshold * threshold); // 1.0 / (sigma^2 * 2.0) + float invThresholdSqrt2PI = INV_SQRT_OF_2PI / threshold; // 1.0 / (sqrt(2*PI) * sigma^2) -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputAudioBalance')] -[ValidateRange(0,1)] -[double] -$InputAudioBalance, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + float4 centrPx = image.Sample(textureSampler, uv); + float zBuff = 0.0; + float4 aBuff = float4(0.0, 0.0, 0.0, 0.0); -process { + float2 d; + for (d.x = -radius; d.x <= radius; d.x += 1.0) + { + float pt = sqrt(radQ - (d.x * d.x)); // pt = yRadius: have circular trend + d.y = -pt; + for (; d.y <= pt; d.y += 1.0) + { + float blurFactor = exp((-dot(d, d)) * invSigmaQx2) * invSigmaQx2PI; + float4 walkPx = image.Sample(textureSampler, uv + (d / size)); + float4 dC = walkPx - centrPx; + float deltaFactor = (exp((-dot(dC.xyz, dC.xyz)) * invThresholdSqx2) * invThresholdSqrt2PI) * blurFactor; + zBuff += deltaFactor; + aBuff += (walkPx * deltaFactor); + } + } + return aBuff / float4(zBuff, zBuff, zBuff, zBuff); +} +float4 mainImage(VertData v_in) : TARGET +{ + return smartDeNoise(v_in.uv, uv_size, uSigma, uKSigma, uThreshold); +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -55790,233 +57892,270 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSInputAudioMonitorType { - +function Get-OBSSpecularShineShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetInputAudioMonitorType')] -[Alias('obs.powershell.websocket.SetInputAudioMonitorType')] +[Alias('Set-OBSSpecularShineShader','Add-OBSSpecularShineShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - +# Set the Hint of OBSSpecularShineShader +[ComponentModel.DefaultBindingProperty('Hint')] +[String] +$Hint, +# Set the roughness of OBSSpecularShineShader +[ComponentModel.DefaultBindingProperty('roughness')] +[Single] +$Roughness, +# Set the lightStrength of OBSSpecularShineShader +[ComponentModel.DefaultBindingProperty('lightStrength')] +[Single] +$LightStrength, +# Set the LightPositionX of OBSSpecularShineShader +[ComponentModel.DefaultBindingProperty('LightPositionX')] +[Single] +$LightPositionX, +# Set the LightPositionY of OBSSpecularShineShader +[ComponentModel.DefaultBindingProperty('LightPositionY')] +[Single] +$LightPositionY, +# Set the flattenNormal of OBSSpecularShineShader +[ComponentModel.DefaultBindingProperty('flattenNormal')] +[Single] +$FlattenNormal, +# Set the stretchNormalX of OBSSpecularShineShader +[ComponentModel.DefaultBindingProperty('stretchNormalX')] +[Single] +$StretchNormalX, +# Set the stretchNormalY of OBSSpecularShineShader +[ComponentModel.DefaultBindingProperty('stretchNormalY')] +[Single] +$StretchNormalY, +# Set the Light_Color of OBSSpecularShineShader +[Alias('Light_Color')] +[ComponentModel.DefaultBindingProperty('Light_Color')] +[Single[]] +$LightColor, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('monitorType')] -[string] -$MonitorType, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'specular-shine' +$ShaderNoun = 'OBSSpecularShineShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Specular Shine shader by Andicraft / Andrea Jörgensen - https://github.com/Andicraft +uniform string Hint< + string widget_type = "info"; +> = "Try using a black color source with the additive blend mode!"; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +uniform float roughness< + string label = "Roughness"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.25; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +uniform float lightStrength< + string label = "lightStrength"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 2.0; + float step = 0.001; +> = 0.5; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } +uniform float LightPositionX< + string label = "Light Position X"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } +uniform float LightPositionY< + string label = "Light Position Y"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } +uniform float flattenNormal< + string label = "Flatten Normal"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.1; -} +uniform float stretchNormalX< + string label = "Stretch Normal X"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 4.0; + float step = 0.01; +> = 1; + +uniform float stretchNormalY< + string label = "Stretch Normal Y"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 4.0; + float step = 0.01; +> = 1; +uniform float3 Light_Color = {1,1,1}; -} +float Square(float a) { return a * a; } - -#.ExternalHelp obs-powershell-Help.xml -function Set-OBSInputAudioSyncOffset { +float CookTorrance(float3 lightDir, float3 normal, float roughness) { + float3 h = normalize(lightDir + float3(0,0,1)); + float nh2 = Square(saturate(dot(normal, h))); + float lh2 = Square(saturate(dot(lightDir, h))); + float r2 = Square(roughness); + float d2 = Square(nh2 * (r2 - 1.0) + 1.00001); + float normalization = roughness * 4.0 + 2.0; + return r2 / (d2 * max(0.1, lh2) * normalization); +} +#define PI 3.14159265 -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetInputAudioSyncOffset')] -[Alias('obs.powershell.websocket.SetInputAudioSyncOffset')] -param( +float4 mainImage(VertData v_in) : TARGET +{ -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, + float4 c0 = image.Sample(textureSampler, v_in.uv); -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, + float3 lightDir = normalize(float3(-LightPositionX*5, -LightPositionY*5, 1)); -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputAudioSyncOffset')] -[ValidateRange(-950,20000)] -[double] -$InputAudioSyncOffset, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + float2 normalUV = v_in.uv - 0.5; + normalUV.x /= stretchNormalX; + normalUV.y /= stretchNormalY; + normalUV += 0.5; + + float3 normal = normalize(float3(normalUV.x * 2 - 1,normalUV.y * 2 - 1,-1)); + normal.z *= -1; + normal = lerp(normal, float3(0,0,-1), flattenNormal); -process { + float3 light = CookTorrance(lightDir, normal, roughness)*float3(1,1,1)*lightStrength*Light_Color; + return float4(c0 + light,c0.a); +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -56025,115 +58164,219 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSInputAudioTracks { - +function Get-OBSSpotlightShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetInputAudioTracks')] -[Alias('obs.powershell.websocket.SetInputAudioTracks')] +[Alias('Set-OBSSpotlightShader','Add-OBSSpotlightShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - +# Set the Speed_Percent of OBSSpotlightShader +[Alias('Speed_Percent')] +[ComponentModel.DefaultBindingProperty('Speed_Percent')] +[Single] +$SpeedPercent, +# Set the Focus_Percent of OBSSpotlightShader +[Alias('Focus_Percent')] +[ComponentModel.DefaultBindingProperty('Focus_Percent')] +[Single] +$FocusPercent, +# Set the Glitch of OBSSpotlightShader +[ComponentModel.DefaultBindingProperty('Glitch')] +[Management.Automation.SwitchParameter] +$Glitch, +# Set the Spotlight_Color of OBSSpotlightShader +[Alias('Spotlight_Color')] +[ComponentModel.DefaultBindingProperty('Spotlight_Color')] +[String] +$SpotlightColor, +# Set the Horizontal_Offset of OBSSpotlightShader +[Alias('Horizontal_Offset')] +[ComponentModel.DefaultBindingProperty('Horizontal_Offset')] +[Single] +$HorizontalOffset, +# Set the Vertical_Offset of OBSSpotlightShader +[Alias('Vertical_Offset')] +[ComponentModel.DefaultBindingProperty('Vertical_Offset')] +[Single] +$VerticalOffset, +# Set the Notes of OBSSpotlightShader +[ComponentModel.DefaultBindingProperty('Notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputAudioTracks')] -[PSObject] -$InputAudioTracks, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'spotlight' +$ShaderNoun = 'OBSSpotlightShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Spotlight By Charles Fettinger (https://github.com/Oncorporation) 4/2019 +uniform float Speed_Percent< + string label = "Speed Percent"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 100.0; +uniform float Focus_Percent< + string label = "Focus Percent"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 0.01; +> = 15.0; +uniform bool Glitch; +uniform float4 Spotlight_Color; +uniform float Horizontal_Offset< + string label = "Horizontal Offset"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = 0.0; +uniform float Vertical_Offset< + string label = "Vertical Offset"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.001; +> = -0.5; +uniform string Notes< + string widget_type = "info"; +> = "use negative Focus Percent to create a shade effect, speed zero is a stationary spotlight"; + +float4 mainImage(VertData v_in) : TARGET +{ + float speed = Speed_Percent * 0.01; + float focus = Focus_Percent; + if (Glitch) + { + speed *= ((rand_f * 2) - 1) * 0.01; + focus *= ((rand_f * 1.1) - 0.1); + } + float PI = 3.1415926535897932384626433832795;//acos(-1); + float4 c0 = image.Sample( textureSampler, v_in.uv); + float3 lightsrc = float3(sin(elapsed_time * speed * PI * 0.667) *.5 + .5 + Horizontal_Offset, cos(elapsed_time * speed * PI) *.5 + .5 + Vertical_Offset, 1); + float3 light = normalize(lightsrc - float3( v_in.uv.x + (Horizontal_Offset * speed), v_in.uv.y + (Vertical_Offset * speed), 0)); + c0 *= pow(dot(light, float3(0, 0, 1)), focus) * Spotlight_Color; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + return c0; +} +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -56142,232 +58385,238 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSInputMute { - +function Get-OBSSwirlShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetInputMute')] -[Alias('obs.powershell.websocket.SetInputMute')] +[Alias('Set-OBSSwirlShader','Add-OBSSwirlShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - +# Set the radius of OBSSwirlShader +[ComponentModel.DefaultBindingProperty('radius')] +[Single] +$Radius, +# Set the angle of OBSSwirlShader +[ComponentModel.DefaultBindingProperty('angle')] +[Single] +$Angle, +# Set the center_x of OBSSwirlShader +[Alias('center_x')] +[ComponentModel.DefaultBindingProperty('center_x')] +[Single] +$CenterX, +# Set the center_y of OBSSwirlShader +[Alias('center_y')] +[ComponentModel.DefaultBindingProperty('center_y')] +[Single] +$CenterY, +# Set the animate of OBSSwirlShader +[ComponentModel.DefaultBindingProperty('animate')] +[Management.Automation.SwitchParameter] +$Animate, +# Set the inverse of OBSSwirlShader +[ComponentModel.DefaultBindingProperty('inverse')] +[Management.Automation.SwitchParameter] +$Inverse, +# Set the notes of OBSSwirlShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputMuted')] -[switch] -$InputMuted, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 { +process { +$shaderName = 'Swirl' +$ShaderNoun = 'OBSSwirlShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//Created by Radegast Stravinsky for obs-shaderfilter 9/2020 +uniform float radius< + string label = "Radius"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.5; // +uniform float angle< + string label = "Angle"; + string widget_type = "slider"; + float minimum = -360.0; + float maximum = 360.0; + float step = 0.01; +> = 270.0; // + +uniform float center_x< + string label = "Center x"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 0.5; + float step = 0.001; +> = 0.25; // +uniform float center_y< + string label = "Center y"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 0.5; + float step = 0.001; +> = 0.25; // + +uniform bool animate = false; +uniform bool inverse = false; + +uniform string notes< + string widget_type = "info"; +> = "Distorts the screen, twisting the image in a circular motion." +float4 mainImage(VertData v_in) : TARGET +{ + + float2 center = float2(center_x, center_y); + VertData v_out; + v_out.pos = v_in.pos; + float2 hw = uv_size; + float ar = 1. * hw.y/hw.x; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + v_out.uv = 1. * v_in.uv - center; + + center.x /= ar; + v_out.uv.x /= ar; + + float dist = distance(v_out.uv, center); + if (dist < radius) + { + float percent = (radius-dist)/(radius); + percent = inverse == false ? percent : 1 - percent; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + float theta = percent * percent * radians(angle * (animate == true ? sin(elapsed_time) : 1.0)); + float s = sin(theta); + float c = cos(theta); + v_out.uv = float2(dot(v_out.uv-center, float2(c,-s)), dot(v_out.uv-center, float2(s,c))); + v_out.uv += (2 * center); + + v_out.uv.x *= ar; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } + return image.Sample(textureSampler, v_out.uv); + } + else + { + return image.Sample(textureSampler, v_in.uv ); + } + +} - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } +' +} +$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 } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + } + '(?>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 ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Set-OBSInputName { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetInputName')] -[Alias('obs.powershell.websocket.SetInputName')] -param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('newInputName')] -[string] -$NewInputName, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -56376,244 +58625,400 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSInputSettings { - +function Get-OBSTetraShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetInputSettings')] -[Alias('obs.powershell.websocket.SetInputSettings')] +[Alias('Set-OBSTetraShader','Add-OBSTetraShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputSettings')] -[PSObject] -$InputSettings, - +# Set the redR of OBSTetraShader +[ComponentModel.DefaultBindingProperty('redR')] +[Single] +$RedR, +# Set the redG of OBSTetraShader +[ComponentModel.DefaultBindingProperty('redG')] +[Single] +$RedG, +# Set the redB of OBSTetraShader +[ComponentModel.DefaultBindingProperty('redB')] +[Single] +$RedB, +# Set the yelR of OBSTetraShader +[ComponentModel.DefaultBindingProperty('yelR')] +[Single] +$YelR, +# Set the yelG of OBSTetraShader +[ComponentModel.DefaultBindingProperty('yelG')] +[Single] +$YelG, +# Set the yelB of OBSTetraShader +[ComponentModel.DefaultBindingProperty('yelB')] +[Single] +$YelB, +# Set the grnR of OBSTetraShader +[ComponentModel.DefaultBindingProperty('grnR')] +[Single] +$GrnR, +# Set the grnG of OBSTetraShader +[ComponentModel.DefaultBindingProperty('grnG')] +[Single] +$GrnG, +# Set the grnB of OBSTetraShader +[ComponentModel.DefaultBindingProperty('grnB')] +[Single] +$GrnB, +# Set the cynR of OBSTetraShader +[ComponentModel.DefaultBindingProperty('cynR')] +[Single] +$CynR, +# Set the cynG of OBSTetraShader +[ComponentModel.DefaultBindingProperty('cynG')] +[Single] +$CynG, +# Set the cynB of OBSTetraShader +[ComponentModel.DefaultBindingProperty('cynB')] +[Single] +$CynB, +# Set the bluR of OBSTetraShader +[ComponentModel.DefaultBindingProperty('bluR')] +[Single] +$BluR, +# Set the bluG of OBSTetraShader +[ComponentModel.DefaultBindingProperty('bluG')] +[Single] +$BluG, +# Set the bluB of OBSTetraShader +[ComponentModel.DefaultBindingProperty('bluB')] +[Single] +$BluB, +# Set the magR of OBSTetraShader +[ComponentModel.DefaultBindingProperty('magR')] +[Single] +$MagR, +# Set the magG of OBSTetraShader +[ComponentModel.DefaultBindingProperty('magG')] +[Single] +$MagG, +# Set the magB of OBSTetraShader +[ComponentModel.DefaultBindingProperty('magB')] +[Single] +$MagB, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('overlay')] -[switch] -$Overlay, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'tetra' +$ShaderNoun = 'OBSTetraShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Tetrahedral Interpolation Shader for OBS +uniform float redR< + string label = "Red in Red"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 2.0; + float step = 0.01; +> = 1.0; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +uniform float redG< + string label = "Green in Red"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.01; +> = 0.0; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } +uniform float redB< + string label = "Blue in Red"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.01; +> = 0.0; - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } +uniform float yelR< + string label = "Red in Yellow"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 2.0; + float step = 0.01; +> = 1.0; - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } +uniform float yelG< + string label = "Green in Yellow"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 2.0; + float step = 0.01; +> = 1.0; -} +uniform float yelB< + string label = "Blue in Yellow"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.01; +> = 0.0; +uniform float grnR< + string label = "Red in Green"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.01; +> = 0.0; -} +uniform float grnG< + string label = "Green in Green"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 2.0; + float step = 0.01; +> = 1.0; - -#.ExternalHelp obs-powershell-Help.xml -function Set-OBSInputVolume { +uniform float grnB< + string label = "Blue in Green"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.01; +> = 0.0; +uniform float cynR< + string label = "Red in Cyan"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.01; +> = 0.0; -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetInputVolume')] -[Alias('obs.powershell.websocket.SetInputVolume')] -param( +uniform float cynG< + string label = "Green in Cyan"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 2.0; + float step = 0.01; +> = 1.0; -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, +uniform float cynB< + string label = "Blue in Cyan"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 2.0; + float step = 0.01; +> = 1.0; -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, +uniform float bluR< + string label = "Red in Blue"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.01; +> = 0.0; -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputVolumeMul')] -[ValidateRange(0,20)] -[double] -$InputVolumeMul, +uniform float bluG< + string label = "Green in Blue"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.01; +> = 0.0; -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputVolumeDb')] -[ValidateRange(-100,26)] -[double] -$InputVolumeDb, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) +uniform float bluB< + string label = "Blue in Blue"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 2.0; + float step = 0.01; +> = 1.0; + +uniform float magR< + string label = "Red in Magenta"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 2.0; + float step = 0.01; +> = 1.0; +uniform float magG< + string label = "Green in Magenta"; + string widget_type = "slider"; + float minimum = -1.0; + float maximum = 1.0; + float step = 0.01; +> = 0.0; -process { +uniform float magB< + string label = "Blue in Magenta"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 2.0; + float step = 0.01; +> = 1.0; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float3 tetra(float3 RGBimage, float3 red, float3 yel, float3 grn, float3 cyn, float3 blu, float3 mag) { + float r = RGBimage.x; + float g = RGBimage.y; + float b = RGBimage.z; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + float3 wht = float3(1.0, 1.0, 1.0); + + if (r > g) { + if (g > b) { + // r > g > b + return r * red + g * (yel - red) + b * (wht - yel); + } else if (r > b) { + // r > b > g + return r * red + g * (wht - mag) + b * (mag - red); + } else { + // b > r > g + return r * (mag - blu) + g * (wht - mag) + b * blu; + } + } else { + if (b > g) { + // b > g > r + return r * (wht - cyn) + g * (cyn - blu) + b * blu; + } else if (b > r) { + // g > b > r + return r * (wht - cyn) + g * grn + b * (cyn - grn); + } else { + // g > r > b + return r * (yel - grn) + g * grn + b * (wht - yel); } + } +} - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } +float4 mainImage(VertData v_in) : TARGET +{ + float4 inputColor = image.Sample(textureSampler, v_in.uv); + float alpha = inputColor.a; + + float3 red = float3(redR, redG, redB); + float3 yel = float3(yelR, yelG, yelB); + float3 grn = float3(grnR, grnG, grnB); + float3 cyn = float3(cynR, cynG, cynB); + float3 blu = float3(bluR, bluG, bluB); + float3 mag = float3(magR, magG, magB); + + float3 outputColor = tetra(inputColor.rgb, red, yel, grn, cyn, blu, mag); + return float4(outputColor, alpha); +} + +' +} +$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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -56622,116 +59027,176 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSMediaInputCursor { - +function Get-OBSThermalShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetMediaInputCursor')] -[Alias('obs.powershell.websocket.SetMediaInputCursor')] +[Alias('Set-OBSThermalShader','Add-OBSThermalShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, - +# Set the strength of OBSThermalShader +[ComponentModel.DefaultBindingProperty('strength')] +[Single] +$Strength, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('mediaCursor')] -[ValidateRange(0,[int]::MaxValue)] -[double] -$MediaCursor, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'thermal' +$ShaderNoun = 'OBSThermalShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//based on https://www.shadertoy.com/view/mdKXzG +uniform float strength< + string label = "Strength"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 200.0; + float step = 0.1; +> = 100.0; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float greyScale(float3 c) { + return 0.29 * c.r + 0.60 * c.g + 0.11; +} - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +float3 heatMap(float greyValue) { + float3 heat; + heat.r = smoothstep(0.5, 0.8, greyValue); + if(greyValue >= 0.8333) { + heat.r *= (1.1 - greyValue) * 5.0; + } + if(greyValue > 0.6) { + heat.g = smoothstep(1.0, 0.7, greyValue); + } else { + heat.g = smoothstep(0.0, 0.7, greyValue); + } + heat.b = smoothstep(1.0, 0.0, greyValue); + if(greyValue <= 0.3333) { + heat.b *= greyValue / 0.3; + } + return heat; +} - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } +float4 mainImage(VertData v_in) : TARGET +{ + float4 c = image.Sample(textureSampler, v_in.uv); + float greyValue = greyScale(c.rgb); + float3 h = heatMap(greyValue*(strength/100.0)); + return float4(h.r, h.g, h.b, c.a); +} +' +} +$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] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -56740,110 +59205,219 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSOutputSettings { - +function Get-OBSTvCrtSubpixelShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetOutputSettings')] -[Alias('obs.powershell.websocket.SetOutputSettings')] +[Alias('Set-OBSTvCrtSubpixelShader','Add-OBSTvCrtSubpixelShader')] param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('outputName')] -[string] -$OutputName, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('outputSettings')] -[PSObject] -$OutputSettings, -# If set, will return the information that would otherwise be sent to OBS. +# Set the channelWidth of OBSTvCrtSubpixelShader +[ComponentModel.DefaultBindingProperty('channelWidth')] +[Int32] +$ChannelWidth, +# Set the channelHeight of OBSTvCrtSubpixelShader +[ComponentModel.DefaultBindingProperty('channelHeight')] +[Int32] +$ChannelHeight, +# Set the hGap of OBSTvCrtSubpixelShader +[ComponentModel.DefaultBindingProperty('hGap')] +[Int32] +$HGap, +# Set the vGap of OBSTvCrtSubpixelShader +[ComponentModel.DefaultBindingProperty('vGap')] +[Int32] +$VGap, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'tv-crt-subpixel' +$ShaderNoun = 'OBSTvCrtSubpixelShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// https://www.shadertoy.com/view/dlBBz1 adopted for OBS by Exeldro + +// width of a single color channel in pixels +uniform int channelWidth< + string label = "Channel Width"; + string widget_type = "slider"; + int minimum = 1; + int maximum = 20; + int step = 1; +> = 1; +// height of color channels in pixels +uniform int channelHeight< + string label = "Channel Height"; + string widget_type = "slider"; + int minimum = 1; + int maximum = 20; + int step = 1; +> = 3; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +// horizontal distance between two neighboring pixels +uniform int hGap< + string label = "Horizontal Gap"; + string widget_type = "slider"; + int minimum = 1; + int maximum = 20; + int step = 1; +> = 1; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +// vertical distance between two neighboring pixels +uniform int vGap< + string label = "Vertical Gap"; + string widget_type = "slider"; + int minimum = 1; + int maximum = 20; + int step = 1; +> = 1; - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } +float4 mainImage(VertData v_in) : TARGET +{ + float columns = float(channelWidth * 3 + hGap); + float pixelHeight = float(channelHeight + vGap); + + float2 fragCoord = v_in.uv * uv_size; + float2 sampleRes = float2(uv_size.x / columns, uv_size.y / pixelHeight); + float2 pixel = float2(floor(fragCoord.x / columns), floor(fragCoord.y / pixelHeight)); + float2 sampleUv = pixel / sampleRes; + + // color of sample point + float4 col = image.Sample(textureSampler, sampleUv); + + int column = int(fragCoord.x) % (channelWidth * 3 + hGap); + + // set color based on which channel this fragment corresponds to + if (column < channelWidth * 1) col = float4(col.r, 0.0, 0.0, col.a); + else if (column < channelWidth * 2) col = float4(0.0, col.g, 0.0, col.a); + else if (column < channelWidth * 3) col = float4(0.0, 0.0, col.b, col.a); + else col = float4(0.0, 0.0, 0.0, col.a); + + // offset every other column of pixels + int height = int(pixelHeight); + if (int(pixel.x) % 2 == 0) { + if (int(fragCoord.y) % height >= height - vGap) col = float4(0.0, 0.0, 0.0, col.a); + } else { + if (int(fragCoord.y) % height < vGap) col = float4(0.0, 0.0, 0.0, col.a); + } + + // Output to screen + return col; +} +' +} +$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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -56852,115 +59426,202 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSPersistentData { - +function Get-OBSTwistShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetPersistentData')] -[Alias('obs.powershell.websocket.SetPersistentData')] +[Alias('Set-OBSTwistShader','Add-OBSTwistShader')] param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('realm')] -[string] -$Realm, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('slotName')] -[string] -$SlotName, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('slotValue')] -[PSObject] -$SlotValue, -# If set, will return the information that would otherwise be sent to OBS. +# Set the center_x_percent of OBSTwistShader +[Alias('center_x_percent')] +[ComponentModel.DefaultBindingProperty('center_x_percent')] +[Int32] +$CenterXPercent, +# Set the center_y_percent of OBSTwistShader +[Alias('center_y_percent')] +[ComponentModel.DefaultBindingProperty('center_y_percent')] +[Int32] +$CenterYPercent, +# Set the power of OBSTwistShader +[ComponentModel.DefaultBindingProperty('power')] +[Single] +$Power, +# Set the rotation of OBSTwistShader +[ComponentModel.DefaultBindingProperty('rotation')] +[Single] +$Rotation, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'twist' +$ShaderNoun = 'OBSTwistShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform int center_x_percent< + string label = "center x percentage"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform int center_y_percent< + string label = "center y percentage"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform float power< + string label = "power"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 5.0; + float step = 0.001; +> = 0.3; +uniform float rotation< + string label = "rotation"; + string widget_type = "slider"; + float minimum = -100.0; + float maximum = 100.0; + float step = 0.001; +> = 2.0; +#ifndef OPENGL +#define mat2 float2x2 +#endif - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +mat2 rotate(float angle){ + return mat2(float2(cos(angle), -sin(angle)), float2(sin(angle), cos(angle))); +} - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} +float4 mainImage(VertData v_in) : TARGET +{ + float2 center_pos = float2(center_x_percent * .01, center_y_percent * .01); + float d = distance(center_pos,v_in.uv); + if(d > power){ + return image.Sample(textureSampler, v_in.uv); + } + float r = (cos(d*3.14159265359/power) +1)/2 * rotation; + float2 pos = v_in.uv - center_pos; + pos = mul(pos, rotate(r)); + pos += center_pos; + return image.Sample(textureSampler, pos); +} + +' +} +$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 + } } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -56969,222 +59630,314 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSProfileParameter { - +function Get-OBSTwoPassDropShadowShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetProfileParameter')] -[Alias('obs.powershell.websocket.SetProfileParameter')] +[Alias('Set-OBSTwoPassDropShadowShader','Add-OBSTwoPassDropShadowShader')] param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('parameterCategory')] -[string] -$ParameterCategory, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('parameterName')] -[string] -$ParameterName, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('parameterValue')] -[string] -$ParameterValue, -# If set, will return the information that would otherwise be sent to OBS. +# Set the ViewProj of OBSTwoPassDropShadowShader +[ComponentModel.DefaultBindingProperty('ViewProj')] +[Single[][]] +$ViewProj, +# Set the image of OBSTwoPassDropShadowShader +[ComponentModel.DefaultBindingProperty('image')] +[String] +$Image, +# Set the elapsed_time of OBSTwoPassDropShadowShader +[Alias('elapsed_time')] +[ComponentModel.DefaultBindingProperty('elapsed_time')] +[Single] +$ElapsedTime, +# Set the uv_offset of OBSTwoPassDropShadowShader +[Alias('uv_offset')] +[ComponentModel.DefaultBindingProperty('uv_offset')] +[Single[]] +$UvOffset, +# Set the uv_scale of OBSTwoPassDropShadowShader +[Alias('uv_scale')] +[ComponentModel.DefaultBindingProperty('uv_scale')] +[Single[]] +$UvScale, +# Set the uv_pixel_interval of OBSTwoPassDropShadowShader +[Alias('uv_pixel_interval')] +[ComponentModel.DefaultBindingProperty('uv_pixel_interval')] +[Single[]] +$UvPixelInterval, +# Set the rand_f of OBSTwoPassDropShadowShader +[Alias('rand_f')] +[ComponentModel.DefaultBindingProperty('rand_f')] +[Single] +$RandF, +# Set the uv_size of OBSTwoPassDropShadowShader +[Alias('uv_size')] +[ComponentModel.DefaultBindingProperty('uv_size')] +[Single[]] +$UvSize, +# Set the shadow_offset_x of OBSTwoPassDropShadowShader +[Alias('shadow_offset_x')] +[ComponentModel.DefaultBindingProperty('shadow_offset_x')] +[Int32] +$ShadowOffsetX, +# Set the shadow_offset_y of OBSTwoPassDropShadowShader +[Alias('shadow_offset_y')] +[ComponentModel.DefaultBindingProperty('shadow_offset_y')] +[Int32] +$ShadowOffsetY, +# Set the shadow_blur_size of OBSTwoPassDropShadowShader +[Alias('shadow_blur_size')] +[ComponentModel.DefaultBindingProperty('shadow_blur_size')] +[Int32] +$ShadowBlurSize, +# Set the shadow_color of OBSTwoPassDropShadowShader +[Alias('shadow_color')] +[ComponentModel.DefaultBindingProperty('shadow_color')] +[String] +$ShadowColor, +# Set the is_alpha_premultiplied of OBSTwoPassDropShadowShader +[Alias('is_alpha_premultiplied')] +[ComponentModel.DefaultBindingProperty('is_alpha_premultiplied')] +[Management.Automation.SwitchParameter] +$IsAlphaPremultiplied, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'two-pass-drop-shadow' +$ShaderNoun = 'OBSTwoPassDropShadowShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//Converted to OpenGL by Q-mii & Exeldro February 22, 2022 +uniform float4x4 ViewProj; +uniform texture2d image; +uniform float elapsed_time; +uniform float2 uv_offset; +uniform float2 uv_scale; +uniform float2 uv_pixel_interval; +uniform float rand_f; +uniform float2 uv_size; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } +sampler_state textureSampler { + Filter = Linear; + AddressU = Border; + AddressV = Border; + BorderColor = 00000000; +}; - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } +struct VertData { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; +VertData mainTransform(VertData v_in) +{ + VertData vert_out; + vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); + vert_out.uv = v_in.uv * uv_scale + uv_offset; + return vert_out; } +uniform int shadow_offset_x< + string label = "shadow offset x"; + string widget_type = "slider"; + int minimum = -1000; + int maximum = 1000; + int step = 1; +>; +uniform int shadow_offset_y< + string label = "shadow offset y"; + string widget_type = "slider"; + int minimum = -1000; + int maximum = 1000; + int step = 1; +>; +uniform int shadow_blur_size< + string label = "shadow blur size"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +>; -} - - -#.ExternalHelp obs-powershell-Help.xml -function Set-OBSRecordDirectory { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetRecordDirectory')] -[Alias('obs.powershell.websocket.SetRecordDirectory')] -param( +uniform float4 shadow_color; -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('recordDirectory')] -[string] -$RecordDirectory, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) +uniform bool is_alpha_premultiplied; +float4 mainImage(VertData v_in) : TARGET +{ + int shadow_blur_samples = int(shadow_blur_size + 1);//pow(shadow_blur_size * 2 + 1, 2); + + float4 color = image.Sample(textureSampler, v_in.uv); + float2 shadow_uv = float2(v_in.uv.x - uv_pixel_interval.x * int(shadow_offset_x), + v_in.uv.y - uv_pixel_interval.y * int(shadow_offset_y)); + + float sampled_shadow_alpha = 0; + + for (int blur_x = -shadow_blur_size; blur_x <= shadow_blur_size; blur_x++) + { + float2 blur_uv = shadow_uv + float2(uv_pixel_interval.x * blur_x, 0); + sampled_shadow_alpha += image.Sample(textureSampler, blur_uv).a; + } + + sampled_shadow_alpha /= shadow_blur_samples; + + float4 final_shadow_color = float4(shadow_color.rgb, shadow_color.a * sampled_shadow_alpha); + + return final_shadow_color * (1-color.a) + color * (is_alpha_premultiplied?1.0:color.a); +} -process { +float4 mainImage_2_end(VertData v_in) : TARGET +{ + int shadow_blur_samples = shadow_blur_size + 1;//pow(shadow_blur_size * 2 + 1, 2); + + float4 color = image.Sample(textureSampler, v_in.uv); + float2 shadow_uv = float2(v_in.uv.x - uv_pixel_interval.x * shadow_offset_x, + v_in.uv.y - uv_pixel_interval.y * shadow_offset_y); + + float sampled_shadow_alpha = 0; + + for (int blur_y = -shadow_blur_size; blur_y <= shadow_blur_size; blur_y++) + { + float2 blur_uv = shadow_uv + float2(0, uv_pixel_interval.y * blur_y); + sampled_shadow_alpha += image.Sample(textureSampler, blur_uv).a; + } + + sampled_shadow_alpha /= shadow_blur_samples; + + float4 final_shadow_color = float4(shadow_color.rgb, shadow_color.a * sampled_shadow_alpha); + + return final_shadow_color * (1-color.a) + color * (is_alpha_premultiplied?1.0:color.a); +} +technique Draw +{ + pass p0 + { + vertex_shader = mainTransform(v_in); + pixel_shader = mainImage(v_in); + } + + pass p1 + { + vertex_shader = mainTransform(v_in); + pixel_shader = mainImage_2_end(v_in); + } +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -57193,121 +59946,260 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSSceneItemBlendMode { - +function Get-OBSVCRShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSceneItemBlendMode')] -[Alias('obs.powershell.websocket.SetSceneItemBlendMode')] +[Alias('Set-OBSVCRShader','Add-OBSVCRShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, - +# Set the vertical_shift of OBSVCRShader +[Alias('vertical_shift')] +[ComponentModel.DefaultBindingProperty('vertical_shift')] +[Single] +$VerticalShift, +# Set the distort of OBSVCRShader +[ComponentModel.DefaultBindingProperty('distort')] +[Single] +$Distort, +# Set the vignet of OBSVCRShader +[ComponentModel.DefaultBindingProperty('vignet')] +[Single] +$Vignet, +# Set the stripe of OBSVCRShader +[ComponentModel.DefaultBindingProperty('stripe')] +[Single] +$Stripe, +# Set the vertical_factor of OBSVCRShader +[Alias('vertical_factor')] +[ComponentModel.DefaultBindingProperty('vertical_factor')] +[Single] +$VerticalFactor, +# Set the vertical_height of OBSVCRShader +[Alias('vertical_height')] +[ComponentModel.DefaultBindingProperty('vertical_height')] +[Single] +$VerticalHeight, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemId')] -[ValidateRange(0,[int]::MaxValue)] -[double] -$SceneItemId, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemBlendMode')] -[string] -$SceneItemBlendMode, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'VCR' +$ShaderNoun = 'OBSVCRShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//based on https://www.shadertoy.com/view/ldjGzV +//Converted to OpenGL by Exeldro February 19, 2022 +uniform float vertical_shift< + string label = "vertical shift"; + string widget_type = "slider"; + float minimum = -5.0; + float maximum = 5.0; + float step = 0.001; +> = 0.4; +uniform float distort< + string label = "distort"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 5.0; + float step = 0.001; +> = 1.2; +uniform float vignet< + string label = "vignet"; + string widget_type = "slider"; + float minimum = -5.0; + float maximum = 5.0; + float step = 0.001; +> = 1.0; +uniform float stripe< + string label = "stripe"; + string widget_type = "slider"; + float minimum = -5.0; + float maximum = 5.0; + float step = 0.001; +> = 1.0; +uniform float vertical_factor< + string label = "vertical factor"; + string widget_type = "slider"; + float minimum = -5.0; + float maximum = 5.0; + float step = 0.001; +> = 1.0; +uniform float vertical_height< + string label = "vertical height"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1000.0; + float step = 0.1; +> = 30.0; +float onOff(float a, float b, float c) +{ + return step(c, sin(elapsed_time + a*cos(elapsed_time*b))); +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float ramp(float y, float start, float end) +{ + float inside = step(start,y) - step(end,y); + float fact = (y-start)/(end-start)*inside; + return (1.-fact) * inside; + +} - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } +float modu(float x, float y) +{ + return (x / y) - floor(x / y); +} - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } +float stripes(float2 uv) +{ + return ramp(modu(uv.y*4. + elapsed_time/2.+sin(elapsed_time + sin(elapsed_time*0.63)),1.),0.5,0.6)*stripe; +} + +float4 getVideo(float2 uv) +{ + float2 look = uv; + float window = 1./(1.+20.*(look.y-modu(elapsed_time/4.,1.))*(look.y-modu(elapsed_time/4.,1.))); + look.x = look.x + sin(look.y*10. + elapsed_time)/50.*onOff(4.,4.,.3)*(1.+cos(elapsed_time*80.))*window; + float vShift = vertical_shift*onOff(2.,3.,.9)*(sin(elapsed_time)*sin(elapsed_time*20.) + + (0.5 + 0.1*sin(elapsed_time*200.)*cos(elapsed_time))); + look.y = modu((look.y + vShift) , 1.); + return image.Sample(textureSampler, look); +} + +float2 screenDistort(float2 uv) +{ + uv -= float2(.5,.5); + uv = uv*distort*(1./1.2+2.*uv.x*uv.x*uv.y*uv.y); + uv += float2(.5,.5); + return uv; +} + +float4 mainImage(VertData v_in) : TARGET +{ + float2 uv = v_in.uv; + uv = screenDistort(uv); + float4 video = getVideo(uv); + float vigAmt = 3.+.3*sin(elapsed_time + 5.*cos(elapsed_time*5.)); + float vignette = ((1.-vigAmt*(uv.y-.5)*(uv.y-.5))*(1.-vigAmt*(uv.x-.5)*(uv.x-.5))-1.)*vignet+1.; + video += stripes(uv); + video *= vignette; + video *= (((12.+modu((uv.y*vertical_height+elapsed_time),1.))/13.)-1.)*vertical_factor+1.; + return float4(video.r, video.g, video.b ,1.0); +} + +' +} +$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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -57316,245 +60208,306 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSSceneItemEnabled { - +function Get-OBSVHSShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSceneItemEnabled')] -[Alias('obs.powershell.websocket.SetSceneItemEnabled')] +[Alias('Set-OBSVHSShader','Add-OBSVHSShader')] param( +# Set the range of OBSVHSShader +[ComponentModel.DefaultBindingProperty('range')] +[Single] +$Range, +# Set the offsetIntensity of OBSVHSShader +[ComponentModel.DefaultBindingProperty('offsetIntensity')] +[Single] +$OffsetIntensity, +# Set the noiseQuality of OBSVHSShader +[ComponentModel.DefaultBindingProperty('noiseQuality')] +[Single] +$NoiseQuality, +# Set the noiseIntensity of OBSVHSShader +[ComponentModel.DefaultBindingProperty('noiseIntensity')] +[Single] +$NoiseIntensity, +# Set the colorOffsetIntensity of OBSVHSShader +[ComponentModel.DefaultBindingProperty('colorOffsetIntensity')] +[Single] +$ColorOffsetIntensity, +# Set the Alpha_Percentage of OBSVHSShader +[Alias('Alpha_Percentage')] +[ComponentModel.DefaultBindingProperty('Alpha_Percentage')] +[Single] +$AlphaPercentage, +# Set the Apply_To_Image of OBSVHSShader +[Alias('Apply_To_Image')] +[ComponentModel.DefaultBindingProperty('Apply_To_Image')] +[Management.Automation.SwitchParameter] +$ApplyToImage, +# Set the Replace_Image_Color of OBSVHSShader +[Alias('Replace_Image_Color')] +[ComponentModel.DefaultBindingProperty('Replace_Image_Color')] +[Management.Automation.SwitchParameter] +$ReplaceImageColor, +# Set the Color_To_Replace of OBSVHSShader +[Alias('Color_To_Replace')] +[ComponentModel.DefaultBindingProperty('Color_To_Replace')] +[String] +$ColorToReplace, +# Set the Apply_To_Specific_Color of OBSVHSShader +[Alias('Apply_To_Specific_Color')] +[ComponentModel.DefaultBindingProperty('Apply_To_Specific_Color')] +[Management.Automation.SwitchParameter] +$ApplyToSpecificColor, +# 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 +) -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemId')] -[ValidateRange(0,[int]::MaxValue)] -[double] -$SceneItemId, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemEnabled')] -[switch] -$SceneItemEnabled, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } - -} +process { +$shaderName = 'VHS' +$ShaderNoun = 'OBSVHSShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//based on https://www.shadertoy.com/view/Ms3XWH converted by Exeldro v 1.0 +//updated by Charles ''Surn'' Fettinger for obs-shaderfilter 9/2020 +//Converted to OpenGL by Exeldro February 19, 2022 +//Use improved input fields by Exeldro April 15, 2023 +uniform float range< + string label = "Wave size (0.05)"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 0.20; + float step = 0.01; +> = 0.05; +uniform float offsetIntensity< + string label = "Offset intensity (0.02)"; + string widget_type = "slider"; + float minimum = 0.01; + float maximum = 0.20; + float step = 0.01; +> = 0.02; +uniform float noiseQuality< + string label = "Noise number of lines (250)"; + string widget_type = "slider"; + float minimum = 1.0; + float maximum = 1000.0; + float step = 10.0; +> = 250.0; +uniform float noiseIntensity< + string label = "Noise intensity (0.88)"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.01; +> = 0.88; +uniform float colorOffsetIntensity< + string label = "Color offset intensity (1.3)"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 10.0; + float step = 0.1; +> = 1.3; +uniform float Alpha_Percentage< + string label = "Aplha percentage (100.0)"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 100.0; + float step = 1.0; +> = 100.0; +uniform bool Apply_To_Image; +uniform bool Replace_Image_Color; +uniform float4 Color_To_Replace; +uniform bool Apply_To_Specific_Color; -} +float dot2(float2 a,float2 b){ + return a.x*b.x+a.y*b.y; +} - -#.ExternalHelp obs-powershell-Help.xml -function Set-OBSSceneItemIndex { +float rand(float2 co) +{ + return frac(sin(dot2(co.xy ,float2(12.9898,78.233))) * 43758.5453); +} +float verticalBar(float pos, float uvY, float offset) +{ + float edge0 = (pos - range); + float edge1 = (pos + range); -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSceneItemIndex')] -[Alias('obs.powershell.websocket.SetSceneItemIndex')] -param( + float x = smoothstep(edge0, pos, uvY) * offset; + x -= smoothstep(pos, edge1, uvY) * offset; + return x; +} -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, +float modu(float x, float y) +{ + return (x / y) - floor(x / y); +} -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, +float dot4(float4 a,float4 b){ + return a.r*b.r+a.g*b.g+a.b*b.b+a.a*b.a; +} -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemId')] -[ValidateRange(0,[int]::MaxValue)] -[double] -$SceneItemId, +float4 mainImage(VertData v_in) : TARGET +{ + float2 uv = v_in.uv; + for (float i = 0.0; i < 0.71; i += 0.1313) + { + float d = modu(elapsed_time * i, 1.7); + float o = sin(1.0 - tan(elapsed_time * 0.24 * i)); + o *= offsetIntensity; + uv.x += verticalBar(d, uv.y, o); + } + float uvY = uv.y; + uvY *= noiseQuality; + uvY = float(int(uvY)) * (1.0 / noiseQuality); + float noise = rand(float2(elapsed_time * 0.00001, uvY)); + uv.x += noise * noiseIntensity / 100.0; -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemIndex')] -[ValidateRange(0,[int]::MaxValue)] -[double] -$SceneItemIndex, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + float2 offsetR = float2(0.006 * sin(elapsed_time), 0.0) * colorOffsetIntensity; + float2 offsetG = float2(0.0073 * (cos(elapsed_time * 0.97)), 0.0) * colorOffsetIntensity; + float4 rgba = image.Sample(textureSampler, uv); + float r = image.Sample(textureSampler, uv + offsetR).r; + float g = image.Sample(textureSampler, uv + offsetG).g; + float b = rgba.b; -process { + rgba = float4(r, g, b, rgba.a); + + float4 color; + float4 original_color; + if (Apply_To_Image) + { + color = image.Sample(textureSampler, v_in.uv); + original_color = color; + float luma = dot4(color, float4(0.30, 0.59, 0.11, 1.0)); + if (Replace_Image_Color) + color = float4(luma,luma,luma,luma); + rgba = lerp(original_color, rgba * color, clamp(Alpha_Percentage * .01, 0, 1.0)); + + } + if (Apply_To_Specific_Color) + { + color = image.Sample(textureSampler, v_in.uv); + original_color = color; + color = (distance(color.rgb, Color_To_Replace.rgb) <= 0.075) ? rgba : color; + rgba = lerp(original_color, color, clamp(Alpha_Percentage * .01, 0, 1.0)); + } + return rgba; +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -57563,121 +60516,201 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSSceneItemLocked { - +function Get-OBSVignettingShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSceneItemLocked')] -[Alias('obs.powershell.websocket.SetSceneItemLocked')] +[Alias('Set-OBSVignettingShader','Add-OBSVignettingShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, - +# Set the innerRadius of OBSVignettingShader +[ComponentModel.DefaultBindingProperty('innerRadius')] +[Single] +$InnerRadius, +# Set the outerRadius of OBSVignettingShader +[ComponentModel.DefaultBindingProperty('outerRadius')] +[Single] +$OuterRadius, +# Set the opacity of OBSVignettingShader +[ComponentModel.DefaultBindingProperty('opacity')] +[Single] +$Opacity, +# Set the notes of OBSVignettingShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemId')] -[ValidateRange(0,[int]::MaxValue)] -[double] -$SceneItemId, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemLocked')] -[switch] -$SceneItemLocked, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'vignetting' +$ShaderNoun = 'OBSVignettingShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//Converted to OpenGL by Q-mii & Exeldro February 21, 2022 +uniform float innerRadius< + string label = "inner radius"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 5.0; + float step = 0.001; +> = 0.9; +uniform float outerRadius< + string label = "outer radius"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 5.0; + float step = 0.001; +> = 1.5; +uniform float opacity< + string label = "opacity"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.8; +uniform string notes< + string widget_type = "info"; +> = "inner radius will always be shown, outer radius is the falloff"; +float4 mainImage(VertData v_in) : TARGET +{ + float PI = 3.1415926535897932384626433832795;//acos(-1); - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + float4 c0 = image.Sample(textureSampler, v_in.uv); + float verticalDim = 0.5 + sin (v_in.uv.y * PI) * 0.9 ; + + float xTrans = (v_in.uv.x * 2) - 1; + float yTrans = 1 - (v_in.uv.y * 2); + + float radius = sqrt(pow(xTrans, 2) + pow(yTrans, 2)); + + float subtraction = max(0, radius - innerRadius) / max((outerRadius - innerRadius), 0.01); + float factor = 1 - subtraction; + + float4 vignetColor = c0 * factor; + vignetColor *= verticalDim; + + vignetColor *= opacity; + c0 *= 1-opacity; + + float4 output_color = c0 + vignetColor; + + return float4(output_color); +} + +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -57686,121 +60719,230 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSSceneItemTransform { - +function Get-OBSVoronoiPixelationShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSceneItemTransform')] -[Alias('obs.powershell.websocket.SetSceneItemTransform')] +[Alias('Set-OBSVoronoiPixelationShader','Add-OBSVoronoiPixelationShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, - +# Set the pixH of OBSVoronoiPixelationShader +[ComponentModel.DefaultBindingProperty('pixH')] +[Single] +$PixH, +# Set the alternative of OBSVoronoiPixelationShader +[ComponentModel.DefaultBindingProperty('alternative')] +[Management.Automation.SwitchParameter] +$Alternative, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemId')] -[ValidateRange(0,[int]::MaxValue)] -[double] -$SceneItemId, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneItemTransform')] -[PSObject] -$SceneItemTransform, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'voronoi-pixelation' +$ShaderNoun = 'OBSVoronoiPixelationShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// https://www.shadertoy.com/view/sd3yzn adopted by Exeldro + +uniform float pixH< + string label = "Size"; + string widget_type = "slider"; + float minimum = 4.0; + float maximum = 500.0; + float step = 0.01; +> = 100.0; +uniform bool alternative; +float2 fract2(float2 v){ + return float2(v.x - floor(v.x), v.y - floor(v.y)); +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float2 random2( float2 p ) { + return fract2(sin(float2(dot(p,float2(127.1,311.7)),dot(p,float2(269.5,183.3))))*43758.5453); +} +float2 randomSpin(float2 p, float f){ + return 1.0 * float2( + cos( f * elapsed_time * 3.14159 * sign(random2(p).y - 0.5) + random2(p).y * 3.14159), + sin( f * elapsed_time * 3.14159 * sign(random2(p).x - 0.5) + random2(p).x * 3.14159)); +} +float4 VoronoiPixelation(float2 uv, float pixH ){ + float2 pixInt = fract2(uv * pixH); + float2 pixExt = floor(uv * pixH); + float m_dist = 10.0; + float2 relClos = float2(0.0, 0.0); + float2 relRot = 0.5 * float2(cos(elapsed_time), sin(elapsed_time)); - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + + for (int y= -3; y <= 3; y++) { + for (int x= -3; x <= 3; x++) { + float2 neighbor = float2(float(x),float(y)); + + float2 point1 = random2(pixExt + neighbor); + float2 relRot = randomSpin(pixExt + neighbor, 0.5); + float2 diff = neighbor + relRot + point1 - pixInt; + float dist = length(diff); + if(dist < m_dist){ + m_dist = dist; + relClos = neighbor; + } } + } + float2 nPoint = pixExt + relClos + randomSpin(pixExt + relClos, 0.5) + random2(pixExt + relClos); + nPoint = nPoint / pixH; + nPoint.x = nPoint.x * uv_scale.x ; + + return image.Sample(textureSampler, nPoint); +} +float4 VoronoiPixelation2(float2 uv, float pixH ){ + float2 pixInt = fract2(uv * pixH); + float2 pixExt = floor(uv * pixH); + float m_dist = 10.0; + float2 relClos = float2(0.0, 0.0); + float2 relRot = 0.5 * float2(cos(elapsed_time), sin(elapsed_time)); - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + + for (int y= -3; y <= 3; y++) { + for (int x= -3; x <= 3; x++) { + float2 neighbor = float2(float(x),float(y)); + + float2 point2 = random2(pixExt + neighbor); + float2 relRot = randomSpin(pixExt + neighbor, 0.5); + float2 diff = neighbor + relRot + point2 - pixInt; + float dist = length(diff); + if(dist < m_dist){ + m_dist = dist; + relClos = neighbor; } } + } + float2 nPoint = pixExt + relClos + random2(pixExt + relClos); + nPoint = nPoint / pixH; + nPoint.x = nPoint.x * uv_scale.x; + + return image.Sample(textureSampler, nPoint); +} - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + +float4 mainImage(VertData v_in) : TARGET +{ + if (alternative) { + return VoronoiPixelation2(v_in.uv, pixH); + } else { + return VoronoiPixelation(v_in.uv, pixH); + } +} +' +} +$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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -57809,238 +60951,379 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSSceneName { - +function Get-OBSWalkingDeadPixelFixerShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSceneName')] -[Alias('obs.powershell.websocket.SetSceneName')] +[Alias('Set-OBSWalkingDeadPixelFixerShader','Add-OBSWalkingDeadPixelFixerShader')] param( - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, - +# Set the Scan_Width of OBSWalkingDeadPixelFixerShader +[Alias('Scan_Width')] +[ComponentModel.DefaultBindingProperty('Scan_Width')] +[Int32] +$ScanWidth, +# Set the Scan_Height of OBSWalkingDeadPixelFixerShader +[Alias('Scan_Height')] +[ComponentModel.DefaultBindingProperty('Scan_Height')] +[Int32] +$ScanHeight, +# Set the Scan_Offset_X of OBSWalkingDeadPixelFixerShader +[Alias('Scan_Offset_X')] +[ComponentModel.DefaultBindingProperty('Scan_Offset_X')] +[Int32] +$ScanOffsetX, +# Set the Scan_Offset_Y of OBSWalkingDeadPixelFixerShader +[Alias('Scan_Offset_Y')] +[ComponentModel.DefaultBindingProperty('Scan_Offset_Y')] +[Int32] +$ScanOffsetY, +# Set the Show_Border of OBSWalkingDeadPixelFixerShader +[Alias('Show_Border')] +[ComponentModel.DefaultBindingProperty('Show_Border')] +[Management.Automation.SwitchParameter] +$ShowBorder, +# Set the Contrast_Threshold of OBSWalkingDeadPixelFixerShader +[Alias('Contrast_Threshold')] +[ComponentModel.DefaultBindingProperty('Contrast_Threshold')] +[Single] +$ContrastThreshold, +# Set the Min_Cluster_Size of OBSWalkingDeadPixelFixerShader +[Alias('Min_Cluster_Size')] +[ComponentModel.DefaultBindingProperty('Min_Cluster_Size')] +[Int32] +$MinClusterSize, +# Set the Max_Cluster_Size of OBSWalkingDeadPixelFixerShader +[Alias('Max_Cluster_Size')] +[ComponentModel.DefaultBindingProperty('Max_Cluster_Size')] +[Int32] +$MaxClusterSize, +# Set the Show_Green of OBSWalkingDeadPixelFixerShader +[Alias('Show_Green')] +[ComponentModel.DefaultBindingProperty('Show_Green')] +[Management.Automation.SwitchParameter] +$ShowGreen, +# Set the Bypass of OBSWalkingDeadPixelFixerShader +[ComponentModel.DefaultBindingProperty('Bypass')] +[Management.Automation.SwitchParameter] +$Bypass, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('newSceneName')] -[string] -$NewSceneName, -# If set, will return the information that would otherwise be sent to OBS. +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +[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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'walking-dead-pixel-fixer' +$ShaderNoun = 'OBSWalkingDeadPixelFixerShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Walking Dead Pixel Fixer, Version 0.10, for OBS Shaderfilter +// by Eegee http://github.com/eegee/ +// Based on Dead Pixel Fixer, Version 0.01, for OBS Shaderfilter +// Copyright ©️ 2022 by SkeletonBow +// License: GNU General Public License, version 2 +// Contact info: +// Twitter: +// Twitch: +// +// Description: Intended for use with an input source that has a dead pixel on its sensor such as a webcam. +// The pixels located in the user configured scan area and passing the threshold settings will have its colors +// overridden by taking the average of the colors of the surrounding pixels, effectively hiding the dead pixels. +// +// Changelog: +// 0.01 - Initial release +// 0.10 - Added a pixel scan area and added contrast threshold settings to replace blur size setting. +uniform int Scan_Width< + string label = "Scan area width"; + int minimum = 1; + int maximum = 2560; + int step = 1; +> = 75; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } +uniform int Scan_Height< + string label = "Scan area height"; + int minimum = 1; + int maximum = 1440; + int step = 1; +> = 120; -} +uniform int Scan_Offset_X< + string label = "Scan area offset X"; + int minimum = 0; + int maximum = 2560; + int step = 1; +> = 110; +uniform int Scan_Offset_Y< + string label = "Scan area offset Y"; + int minimum = 0; + int maximum = 1440; + int step = 1; +> = 20; -} +uniform bool Show_Border< + string label = "Show scan area border in red"; + string widget_type = "checkbox"; +> = true; - -#.ExternalHelp obs-powershell-Help.xml -function Set-OBSSceneSceneTransitionOverride { +uniform float Contrast_Threshold< + string label = "Contrast threshold"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.01; +> = 0.05; +uniform int Min_Cluster_Size< + string label = "Min cluster size"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 600; + int step = 2; +> = 324; -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSceneSceneTransitionOverride')] -[Alias('obs.powershell.websocket.SetSceneSceneTransitionOverride')] -param( +uniform int Max_Cluster_Size< + string label = "Max cluster size"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 600; + int step = 2; +> = 400; -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneName')] -[string] -$SceneName, +uniform bool Show_Green< + string label = "Show matches in green"; + string widget_type = "checkbox"; +> = true; -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sceneUuid')] -[string] -$SceneUuid, +uniform bool Bypass< + string label = "Bypass"; + string widget_type = "checkbox"; +> = false; -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('transitionName')] -[string] -$TransitionName, -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('transitionDuration')] -[ValidateRange(50,20000)] -[double] -$TransitionDuration, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) +#define SAMPLE_RADIUS 9 + +float luminance(float3 color) +{ + return dot(color, float3(0.299, 0.587, 0.114)); +} +void sample_average(float2 uv, float2 center_uv, out float3 avgColor, out float avgLuminance, out int contrastCount, float contrastThreshold) +{ + float3 sumColor = float3(0.0, 0.0, 0.0); + float weightSum = 0.0; + contrastCount = 0; -process { + float3 centerColor = image.Sample(textureSampler, uv).rgb; + float centerLum = luminance(centerColor); + for (int y = -SAMPLE_RADIUS; y <= SAMPLE_RADIUS; ++y) + { + for (int x = -SAMPLE_RADIUS; x <= SAMPLE_RADIUS; ++x) + { + if (x == 0 && y == 0) continue; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + float2 offset = float2(x, y) / uv_size; + float2 sample_uv = clamp(uv + offset, float2(0.0, 0.0), float2(1.0, 1.0)); - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + // skip central pixel + if (ceil(sample_uv.x * uv_size.x) == ceil(center_uv.x) && + ceil(sample_uv.y * uv_size.y) == ceil(center_uv.y)) + continue; + + float3 sampleColor = image.Sample(textureSampler, sample_uv).rgb; + float lum = luminance(sampleColor); + + float weight = 1.0; + sumColor += sampleColor * weight; + weightSum += weight; + + if (abs(lum - centerLum) >= contrastThreshold) + contrastCount++; } + } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } + if (weightSum > 0) + { + avgColor = sumColor / weightSum; + } + else + { + avgColor = centerColor; + } + avgLuminance = luminance(avgColor); +} + +float4 mainImage(VertData v_in) : TARGET +{ + float2 uv = v_in.uv; + float2 pos = v_in.pos.xy; + + float4 tex = image.Sample(textureSampler, uv); + float3 color = tex.rgb; + + if (!Bypass) + { + int pixX = (int)round(pos.x); + int pixY = (int)round(pos.y); + + int borderwidth = 2; + + bool insideScan = + (pixX >= Scan_Offset_X && pixX < Scan_Offset_X + Scan_Width) && + (pixY >= Scan_Offset_Y && pixY < Scan_Offset_Y + Scan_Height); + + bool borderingScan = + (pixX >= Scan_Offset_X - borderwidth && pixX < Scan_Offset_X + Scan_Width + borderwidth) && + (pixY >= Scan_Offset_Y - borderwidth && pixY < Scan_Offset_Y + Scan_Height + borderwidth); + + if (insideScan) + { + float3 avgColor; + float avgLum; + int contrastCount; + + sample_average(uv, pos, avgColor, avgLum, contrastCount, Contrast_Threshold); + + if (contrastCount < Max_Cluster_Size && contrastCount >= Min_Cluster_Size) + { + color = avgColor; + + if (Show_Green) + { + int left = pixX - borderwidth; + int right = pixX + borderwidth; + int top = pixY - borderwidth; + int bottom = pixY + borderwidth; + + bool onOutline = + abs(pos.x - left) < borderwidth || abs(pos.x - right) < borderwidth || + abs(pos.y - top) < borderwidth || abs(pos.y - bottom) < borderwidth; + + if (onOutline) + return float4(0.0, 1.0, 0.0, 1.0); } } } + else if (Show_Border && borderingScan) + { + return float4(1.0, 0.0, 0.0, 0.5); + } + } + return float4(color, tex.a); +} - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam +' +} +$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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -58049,120 +61332,283 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSSourceFilterEnabled { - +function Get-OBSZigZagShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSourceFilterEnabled')] -[Alias('obs.powershell.websocket.SetSourceFilterEnabled')] +[Alias('Set-OBSZigZagShader','Add-OBSZigZagShader')] param( - +# Set the radius of OBSZigZagShader +[ComponentModel.DefaultBindingProperty('radius')] +[Single] +$Radius, +# Set the angle of OBSZigZagShader +[ComponentModel.DefaultBindingProperty('angle')] +[Single] +$Angle, +# Set the period of OBSZigZagShader +[ComponentModel.DefaultBindingProperty('period')] +[Single] +$Period, +# Set the amplitude of OBSZigZagShader +[ComponentModel.DefaultBindingProperty('amplitude')] +[Single] +$Amplitude, +# Set the center_x of OBSZigZagShader +[Alias('center_x')] +[ComponentModel.DefaultBindingProperty('center_x')] +[Single] +$CenterX, +# Set the center_y of OBSZigZagShader +[Alias('center_y')] +[ComponentModel.DefaultBindingProperty('center_y')] +[Single] +$CenterY, +# Set the phase of OBSZigZagShader +[ComponentModel.DefaultBindingProperty('phase')] +[Single] +$Phase, +# Set the animate of OBSZigZagShader +[ComponentModel.DefaultBindingProperty('animate')] +[Int32] +$Animate, +# Set the notes of OBSZigZagShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceName')] -[string] +[Alias('SceneItemName')] +[String] $SourceName, - +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceUuid')] -[string] -$SourceUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('filterName')] -[string] +[String] $FilterName, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('filterEnabled')] -[switch] -$FilterEnabled, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +# 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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'ZigZag' +$ShaderNoun = 'OBSZigZagShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//Created by Radegast Stravinsky for obs-shaderfilter 9/2020 +uniform float radius< + string label = "radius"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 5.0; + float step = 0.001; +> = 0.0; +uniform float angle< + string label = "angle"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 360.0; + float step = 0.1; +> = 180.0; +uniform float period< + string label = "period"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 5.0; + float step = 0.001; +> = 0.5; +uniform float amplitude< + string label = "amplitude"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 5.0; + float step = 0.001; +> = 1.0; +uniform float center_x< + string label = "center x"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 0.5; + float step = 0.001; +> = 0.25; +uniform float center_y< + string label = "center y"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 0.5; + float step = 0.001; +> = 0.25; - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +uniform float phase< + string label = "phase"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 5.0; + float step = 0.001; +> = 1.0; +uniform int animate< + string label = "animate"; + string widget_type = "select"; + int option_0_value = 0; + string option_0_label = "No"; + int option_1_value = 1; + string option_1_label = "Amplitude"; + int option_2_value = 2; + string option_2_label = "Time"; +> = 0; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } +uniform string notes = "Distorts the screen, creating a rippling effect that moves clockwise and anticlockwise." + + +float4 mainImage(VertData v_in) : TARGET +{ + float2 center = float2(center_x, center_y); + VertData v_out; + v_out.pos = v_in.pos; + float2 hw = uv_size; + float ar = 1. * hw.y/hw.x; + + v_out.uv = 1. * v_in.uv - center; + + center.x /= ar; + v_out.uv.x /= ar; + + float dist = distance(v_out.uv, center); + if (dist < radius) + { + float percent = (radius-dist)/radius; + float theta = percent * percent * + ( + animate == 1 ? + amplitude * sin(elapsed_time) : + amplitude + ) + * sin(percent * percent / period * radians(angle) + (phase + + ( + animate == 2 ? + elapsed_time : + 0 + ))); + + float s = sin(theta); + float c = cos(theta); + v_out.uv = float2(dot(v_out.uv-center, float2(c,-s)), dot(v_out.uv-center, float2(s,c))); + v_out.uv += (2 * center); + + v_out.uv.x *= ar; + + return image.Sample(textureSampler, v_out.uv); + } + else + { + return image.Sample(textureSampler, v_in.uv); + } + +} +' +} +$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 + } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } + 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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -58171,121 +61617,256 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSSourceFilterIndex { - +function Get-OBSZoomBlurShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSourceFilterIndex')] -[Alias('obs.powershell.websocket.SetSourceFilterIndex')] +[Alias('Set-OBSZoomBlurShader','Add-OBSZoomBlurShader')] param( - +# Set the samples of OBSZoomBlurShader +[ComponentModel.DefaultBindingProperty('samples')] +[Int32] +$Samples, +# Set the magnitude of OBSZoomBlurShader +[ComponentModel.DefaultBindingProperty('magnitude')] +[Single] +$Magnitude, +# Set the speed_percent of OBSZoomBlurShader +[Alias('speed_percent')] +[ComponentModel.DefaultBindingProperty('speed_percent')] +[Int32] +$SpeedPercent, +# Set the ease of OBSZoomBlurShader +[ComponentModel.DefaultBindingProperty('ease')] +[Management.Automation.SwitchParameter] +$Ease, +# Set the glitch of OBSZoomBlurShader +[ComponentModel.DefaultBindingProperty('glitch')] +[Management.Automation.SwitchParameter] +$Glitch, +# Set the notes of OBSZoomBlurShader +[ComponentModel.DefaultBindingProperty('notes')] +[String] +$Notes, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceName')] -[string] +[Alias('SceneItemName')] +[String] $SourceName, - +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceUuid')] -[string] -$SourceUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('filterName')] -[string] +[String] $FilterName, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('filterIndex')] -[ValidateRange(0,[int]::MaxValue)] -[double] -$FilterIndex, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +# 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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'zoom_blur' +$ShaderNoun = 'OBSZoomBlurShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// zoom blur shader by Charles Fettinger for obs-shaderfilter plugin 3/2019 +// https://github.com/Oncorporation/obs-shaderfilter +// https://github.com/dinfinity/mpc-pixel-shaders/blob/master/PS_Zoom%20Blur.hlsl +//for Media Player Classic HC or BE +//Converted to OpenGL by Q-mii & Exeldro February 18, 2022 +uniform int samples < + string label = "Samples"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 32; +uniform float magnitude< + string label = "Magnitude"; + string widget_type = "slider"; + float minimum = 0.0; + float maximum = 1.0; + float step = 0.001; +> = 0.5; +uniform int speed_percent < + string label = "Speed percent"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 0; +uniform bool ease; +uniform bool glitch; +uniform string notes< + string widget_type = "info"; +> = "Speed Percent above zero will animate the zoom. Keep samples low to save power"; + +float EaseInOutCircTimer(float t,float b,float c,float d){ + t /= d/2; + if (t < 1) return -c/2 * (sqrt(1 - t*t) - 1) + b; + t -= 2; + return c/2 * (sqrt(1 - t*t) + 1) + b; +} +float Styler(float t,float b,float c,float d,bool ease) +{ + if (ease) return EaseInOutCircTimer(t,0,c,d); + return t; +} - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float4 mainImage(VertData v_in) : TARGET +{ + float speed = speed_percent * 0.01; - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + // circular easing variable + float t = 1.0 + sin(elapsed_time * speed); + float b = 0.0; //start value + float c = 2.0; //change value + float d = 2.0; //duration - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + if (glitch) t = clamp(t + ((rand_f *2) - 1), 0.0,2.0); + + b = Styler(t, 0, c, d, ease); + float sample_speed = max(samples * b, 1.0); + + float PI = 3.1415926535897932384626433832795;//acos(-1); + float4 c0 = image.Sample(textureSampler, v_in.uv); + + float xTrans = (v_in.uv.x*2)-1; + float yTrans = 1-(v_in.uv.y*2); + + float angle = atan(yTrans/xTrans) + PI; + if (sign(xTrans) == 1) { + angle+= PI; + } + float radius = sqrt(pow(xTrans,2) + pow(yTrans,2)); + + float2 currentCoord; + float4 accumulatedColor = float4(0,0,0,0); + + float4 currentColor = image.Sample(textureSampler, currentCoord); + accumulatedColor = currentColor; + + accumulatedColor = c0/sample_speed; + for(int i = 1; i< sample_speed; i++) { + float currentRadius ; + // Distance to center dependent + currentRadius = max(0,radius - (radius/1000 * i * magnitude * b)); + + // Continuous; + // currentRadius = max(0,radius - (0.0004 * i)); + + currentCoord.x = (currentRadius * cos(angle)+1.0)/2.0; + currentCoord.y = -1* ((currentRadius * sin(angle)-1.0)/2.0); + + float4 currentColor = image.Sample(textureSampler, currentCoord); + accumulatedColor += currentColor/sample_speed; + + } + + return accumulatedColor; +} + +' +} +$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 } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + } + '(?>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] } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - if ($PassThru) { - [PSCustomObject]$requestPayload + 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 { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + $ShaderFilterSplat.ShaderText = $shaderText + } + + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat + } else { + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -58294,120 +61875,229 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSSourceFilterName { +function Get-OBSZoomBlurTransitionShader { - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSourceFilterName')] -[Alias('obs.powershell.websocket.SetSourceFilterName')] +[Alias('Set-OBSZoomBlurTransitionShader','Add-OBSZoomBlurTransitionShader')] param( - +# Set the image_a of OBSZoomBlurTransitionShader +[Alias('image_a')] +[ComponentModel.DefaultBindingProperty('image_a')] +[String] +$ImageA, +# Set the image_b of OBSZoomBlurTransitionShader +[Alias('image_b')] +[ComponentModel.DefaultBindingProperty('image_b')] +[String] +$ImageB, +# Set the transition_time of OBSZoomBlurTransitionShader +[Alias('transition_time')] +[ComponentModel.DefaultBindingProperty('transition_time')] +[Single] +$TransitionTime, +# Set the convert_linear of OBSZoomBlurTransitionShader +[Alias('convert_linear')] +[ComponentModel.DefaultBindingProperty('convert_linear')] +[Management.Automation.SwitchParameter] +$ConvertLinear, +# Set the strength of OBSZoomBlurTransitionShader +[ComponentModel.DefaultBindingProperty('strength')] +[Single] +$Strength, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceName')] -[string] +[Alias('SceneItemName')] +[String] $SourceName, - +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceUuid')] -[string] -$SourceUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('filterName')] -[string] +[String] $FilterName, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('newFilterName')] -[string] -$NewFilterName, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +# 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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'zoom_blur_transition' +$ShaderNoun = 'OBSZoomBlurTransitionShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +//based on https://www.shadertoy.com/view/Ml3XR2 + +uniform texture2d image_a; +uniform texture2d image_b; +uniform float transition_time = 0.5; +uniform bool convert_linear = true; +//modified zoom blur from http://transitions.glsl.io/transition/b86b90161503a0023231 +uniform float strength< + string label = "Strength (0.3)"; + string widget_type = "slider"; + float minimum = 0.00; + float maximum = 1.50; + float step = 0.01; +> = 0.3; +#define PI 3.141592653589793 - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +float Linear_ease(in float begin, in float change, in float duration, in float time) { + return change * time / duration + begin; +} + +float Exponential_easeInOut(in float begin, in float change, in float duration, in float time) { + if (time == 0.0) + return begin; + else if (time == duration) + return begin + change; + time = time / (duration / 2.0); + if (time < 1.0) + return change / 2.0 * pow(2.0, 10.0 * (time - 1.0)) + begin; + return change / 2.0 * (-pow(2.0, -10.0 * (time - 1.0)) + 2.0) + begin; +} + +float Sinusoidal_easeInOut(in float begin, in float change, in float duration, in float time) { + return -change / 2.0 * (cos(PI * time / duration) - 1.0) + begin; +} + +float random(in float3 scale, in float seed) { + return frac(sin(dot(float3(seed, seed, seed), scale)) * 43758.5453 + seed); +} + +float3 crossFade(in float2 uv, in float dissolve) { + return lerp(image_a.Sample(textureSampler, uv).rgb, image_b.Sample(textureSampler, uv).rgb, dissolve); +} + +float4 mainImage(VertData v_in) : TARGET { + float2 texCoord = v_in.uv; + float progress = transition_time; + // Linear interpolate center across center half of the image + float2 center = float2(Linear_ease(0.5, 0.0, 1.0, progress),0.5); + float dissolve = Exponential_easeInOut(0.0, 1.0, 1.0, progress); + + // Mirrored sinusoidal loop. 0->strength then strength->0 + float strength2 = Sinusoidal_easeInOut(0.0, strength, 0.5, progress); + + float3 color = float3(0.0,0.0,0.0); + float total = 0.0; + float2 toCenter = center - texCoord; + + /* randomize the lookup values to hide the fixed float of samples */ + float offset = random(float3(12.9898, 78.233, 151.7182), 0.0)*0.5; + + for (float t = 0.0; t <= 20.0; t++) { + float percent = (t + offset) / 20.0; + float weight = 1.0 * (percent - percent * percent); + color += crossFade(texCoord + toCenter * percent * strength2, dissolve) * weight; + total += weight; + } + float4 rgba = float4(color / total, 1.0); + if (convert_linear) + rgba.rgb = srgb_nonlinear_to_linear(rgba.rgb); + return rgba; +} +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -58416,125 +62106,177 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSSourceFilterSettings { - +function Get-OBSZoomShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetSourceFilterSettings')] -[Alias('obs.powershell.websocket.SetSourceFilterSettings')] +[Alias('Set-OBSZoomShader','Add-OBSZoomShader')] param( - +# Set the center_x_percent of OBSZoomShader +[Alias('center_x_percent')] +[ComponentModel.DefaultBindingProperty('center_x_percent')] +[Int32] +$CenterXPercent, +# Set the center_y_percent of OBSZoomShader +[Alias('center_y_percent')] +[ComponentModel.DefaultBindingProperty('center_y_percent')] +[Int32] +$CenterYPercent, +# Set the power of OBSZoomShader +[ComponentModel.DefaultBindingProperty('power')] +[Single] +$Power, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceName')] -[string] +[Alias('SceneItemName')] +[String] $SourceName, - +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('sourceUuid')] -[string] -$SourceUuid, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('filterName')] -[string] +[String] $FilterName, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('filterSettings')] -[PSObject] -$FilterSettings, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('overlay')] -[switch] -$Overlay, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] +# 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 attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +# 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 = 'zoom' +$ShaderNoun = 'OBSZoomShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +uniform int center_x_percent< + string label = "center x percent"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform int center_y_percent< + string label = "center y percent"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform float power< + string label = "power"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 20.0; + float step = 0.001; +> = 1.0; +float4 mainImage(VertData v_in) : TARGET +{ + float2 center_pos = float2(center_x_percent * .01, center_y_percent * .01); + float2 uv = v_in.uv; + uv.x = (v_in.uv.x - center_pos.x) * power + center_pos.x; + uv.y = (v_in.uv.y - center_pos.y) * power + center_pos.y; + return image.Sample(textureSampler, uv); +} +' +} +$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 + } + } - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -58543,110 +62285,197 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSStreamServiceSettings { - +function Get-OBSZoomXYShader { -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetStreamServiceSettings')] -[Alias('obs.powershell.websocket.SetStreamServiceSettings')] +[Alias('Set-OBSZoomXYShader','Add-OBSZoomXYShader')] param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('streamServiceType')] -[string] -$StreamServiceType, - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('streamServiceSettings')] -[PSObject] -$StreamServiceSettings, -# If set, will return the information that would otherwise be sent to OBS. +# Set the center_x_percent of OBSZoomXYShader +[Alias('center_x_percent')] +[ComponentModel.DefaultBindingProperty('center_x_percent')] +[Int32] +$CenterXPercent, +# Set the center_y_percent of OBSZoomXYShader +[Alias('center_y_percent')] +[ComponentModel.DefaultBindingProperty('center_y_percent')] +[Int32] +$CenterYPercent, +# Set the x_power of OBSZoomXYShader +[Alias('x_power')] +[ComponentModel.DefaultBindingProperty('x_power')] +[Single] +$XPower, +# Set the y_power of OBSZoomXYShader +[Alias('y_power')] +[ComponentModel.DefaultBindingProperty('y_power')] +[Single] +$YPower, +# The name of the source. This must be provided when adding an item for the first time [Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors +[Alias('SceneItemName')] +[String] +$SourceName, +# The name of the filter. If this is not provided, this will default to the shader name. [Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse +[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 = 'Zoom_XY' +$ShaderNoun = 'OBSZoomXYShader' +if (-not $psBoundParameters['ShaderText']) { + $psBoundParameters['ShaderText'] = $ShaderText = ' +// Zoom XY Shader +// A simple twist on the Zoom Shader in https://github.com/exeldro/obs-shaderfilter/ - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand +// The allow for an independent Horizontal and Vertical Zoom. + +uniform int center_x_percent< + string label = "center x percent"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform int center_y_percent< + string label = "center y percent"; + string widget_type = "slider"; + int minimum = 0; + int maximum = 100; + int step = 1; +> = 50; +uniform float x_power< + string label = "x power"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 20.0; + float step = 0.001; +> = 1; + +uniform float y_power< + string label = "y power"; + string widget_type = "slider"; + float minimum = 0; + float maximum = 20.0; + float step = 0.001; +> = 1; + +float4 mainImage(VertData v_in) : TARGET +{ + float2 center_pos = float2(center_x_percent * .01, center_y_percent * .01); + float2 uv = v_in.uv; + uv.x = (v_in.uv.x - center_pos.x) * x_power + center_pos.x; + uv.y = (v_in.uv.y - center_pos.y) * y_power + center_pos.y; + return image.Sample(textureSampler, uv); +} +' +} +$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 + } + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $PSBoundParameters['FilterName']) { + $filterName = $PSBoundParameters['FilterName'] = $shaderName } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + $ShaderFilterSplat = [Ordered]@{ + ShaderSetting = $ShaderSettings + FilterName = $FilterName + SourceName = $SourceName + } + + foreach ($CarryOnParameter in "PassThru", "NoResponse","Force") { + if ($PSBoundParameters.ContainsKey($CarryOnParameter)) { + $ShaderFilterSplat[$CarryOnParameter] = $PSBoundParameters[$CarryOnParameter] } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + if (-not $script:CachedShaderFilesFromCommand) { + $script:CachedShaderFilesFromCommand = @{} } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + + 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 ($PassThru) { - [PSCustomObject]$requestPayload + if ($myVerb -eq 'Add') { + Add-OBSShaderFilter @ShaderFilterSplat } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + Set-OBSShaderFilter @ShaderFilterSplat } + } +} } @@ -58655,2510 +62484,3415 @@ process { #.ExternalHelp obs-powershell-Help.xml -function Set-OBSStudioModeEnabled { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetStudioModeEnabled')] -[Alias('obs.powershell.websocket.SetStudioModeEnabled')] -param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('studioModeEnabled')] -[switch] -$StudioModeEnabled, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) +function Set-OBSAudioOutputSource { + + + #> + [Alias('Add-OBSAudioOutputSource','Get-OBSAudioOutputSource')] + param( + # The name of the audio device. + # This name or device ID of the audio device that should be captured. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('ItemValue','ItemName','DeviceID')] + [string] + $AudioDevice, + # The name of the scene. + # If no scene name is provided, the current program scene will be used. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('SceneName')] + [string] + $Scene, -process { + # The name of the input. + # If no name is provided, "AudioOutput$($AudioDevice)" will be the input source name. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('InputName','SourceName')] + [string] + $Name, + # If set, will check if the source exists in the scene before creating it and removing any existing sources found. + # If not set, you will get an error if a source with the same name exists. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $Force + ) + dynamicParam { + $baseCommand = + if (-not $script:AddOBSInput) { + $script:AddOBSInput = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') + $script:AddOBSInput + } else { + $script:AddOBSInput + } + $IncludeParameter = @() + $ExcludeParameter = 'inputKind','sceneName','inputName' - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() + :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { + if ($ExcludeParameter) { + foreach ($exclude in $ExcludeParameter) { + if ($paramName -like $exclude) { continue nextInputParameter} + } } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } + if ($IncludeParameter) { + $shouldInclude = + foreach ($include in $IncludeParameter) { + if ($paramName -like $include) { $true;break} } - } + if (-not $shouldInclude) { continue nextInputParameter } } + + $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( + $baseCommand.Parameters[$paramName].Name, + $baseCommand.Parameters[$paramName].ParameterType, + $baseCommand.Parameters[$paramName].Attributes + )) + } + $DynamicParameters - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + begin { + # Audio Output sources have an inputKind of 'wasapi_output_capture'. + $inputKind = "wasapi_output_capture" + + } + process { + # Copy the bound parameters + $myParameters = [Ordered]@{} + $PSBoundParameters + # and determine the name of the invocation + $MyInvocationName = "$($MyInvocation.InvocationName)" + # Split it into verb and noun + $myVerb, $myNoun = $MyInvocationName -split '-' + # and get a copy of ourself that we can call with anonymous recursion. + $myScriptBlock = $MyInvocation.MyCommand.ScriptBlock + # Determine if the verb was get, + $IsGet = $myVerb -eq "Get" + # if no verb was used, + $NoVerb = $MyInvocationName -match '^[^\.\&][^-]+$' + # and if there were any other parameters then name + $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' + + # If it is a get or there was no verb + if ($IsGet -or $NoVerb) { + $inputsOfKind = # Get all inputs of this kind + Get-OBSInput -InputKind $InputKind | + Where-Object { + if ($Name) { # If -Name was provided, + $_.InputName -like $Name # filter by name (as a wildcard). + } else { + $_ # otherwise, return every input. + } } - continue nextParam - } + + # If there were parameters other than name, + # and we were not explicitly called Get-* + if ($NonNameParameters -and -not $IsGet) { + # remove the name parameter + if ($myParameters.Name) { $myParameters.Remove('Name') } + # and pipe results back to ourself. + $inputsOfKind | & $myScriptBlock @myParameters + } else { + # Otherwise, we're just getting the list of inputs + $inputsOfKind } + # (either way, if we were called Get- or with no verb, we're done now). + return } - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + if (-not $myParameters["Scene"]) { + $myParameters["Scene"] = Get-OBSCurrentProgramScene | + Select-Object -ExpandProperty currentProgramSceneName } - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + + if (-not $myParameters["AudioDevice"]) { + $myParameters["AudioDevice"] = "default" } -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Set-OBSTBarPosition { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetTBarPosition')] -[Alias('obs.powershell.websocket.SetTBarPosition')] -param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('position')] -[ValidateRange(0,1)] -[double] -$Position, - -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('release')] -[switch] -$Release, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { + # Window capture is a bit of a tricky one. + # In order to get the WindowTitle to match that OBS needs, we need to look thru the input properties list. + # and for that, an input needs to exist. + if (-not $myParameters["Name"]) { + + if ($myParameters["AudioDevice"]) { + $Name = $myParameters["Name"] = "AudioOutput-" + $myParameters["AudioDevice"] + } + else { + $Name = $myParameters["Name"] = "AudioOutput" + } + } - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + + $myParameterData = [Ordered]@{} + foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } + $bindToPropertyName = $null + + foreach ($attribute in $parameter.Attributes) { + if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { + $bindToPropertyName = $attribute.Name + break } } - } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + if (-not $bindToPropertyName) { continue } + if ($myParameters.Contains($parameter.Name)) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] + if ($myParameters[$parameter.Name] -is [switch]) { + $myParameterData[$bindToPropertyName] = $parameter.Name -as [bool] } } + } + + $addSplat = @{ + sceneName = $myParameters["Scene"] + inputName = $myParameters["Name"] + inputKind = $inputKind + inputSettings = $myParameterData + NoResponse = $myParameters["NoResponse"] + } + + # If -SceneItemEnabled was passed, + if ($myParameters.Contains('SceneItemEnabled')) { + # propagate it to Add-OBSInput. + $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] } - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + # Add the input. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + $possibleDevices = Get-OBSInputPropertiesListPropertyItems -InputName $addSplat.inputName -PropertyName device_id + foreach ($deviceInfo in $possibleDevices) { + if ( + ($deviceInfo.itemName -eq $AudioDevice) -or + ($deviceInfo.ItemValue -eq $AudioDevice) -or + ($deviceInfo.ItemName -replace '\[[^\[\]]+\]\:\s' -eq $AudioDevice) -or + ($deviceInfo.ItemValue -like "*$AudioDevice*") -or + ($deviceInfo.ItemName -like "*$AudioDevice*") + ) { + $myParameterData["device_id"] = $deviceInfo.itemValue + break + } } - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + # If -PassThru was passed + if ($MyParameters["PassThru"]) { + # pass it down to each command + # Otherwise, remove SceneItemEnabled, InputKind, and SceneName + $addSplat.PassThru = $true + $addSplat.Remove('SceneItemEnabled') + $addSplat.Remove('inputKind') + $addSplat.Remove('sceneName') + # and passthru Set-OBSInputSettings. + Set-OBSInputSettings @addSplat + + return } + if ($Force) { # If we do, remove the input + Remove-OBSInput -InputName $addSplat.inputName + # and re-add our result. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + # If the output was still an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # use $psCmdlet.WriteError so that it shows the error correctly. + $psCmdlet.WriteError($outputAddedResult) + } + # Otherwise, if we had a result + elseif ($outputAddedResult) { + # get the input from the scene. + Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $myParameters["Scene"] + } + } else { + # Otherwise, get the input from the scene, + $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $myParameters["Name"] + # update the input settings + $sceneItem.Input.Settings = $addSplat.inputSettings + $sceneItem # and return the scene item. + } + + } } + +#.ExternalHelp obs-powershell-Help.xml +function Set-OBSBrowserSource { + + + [Alias('Add-OBSBrowserSource','Get-OBSBrowserSource')] + param( + # The uri or file path to display. + # If the uri points to a local file, this will be preferred + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('Url', 'Href','Path','FilePath','FullName')] + [uri] + $Uri, + # The width of the browser source. + # If none is provided, this will be the output width of the video settings. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("width")] + [int] + $Width, -} + # The width of the browser source. + # If none is provided, this will be the output height of the video settings. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("height")] + [int] + $Height, - -#.ExternalHelp obs-powershell-Help.xml -function Set-OBSVideoSettings { + # The css style used to render the browser page. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("css")] + [string] + $CSS = "body { background-color: rgba(0, 0, 0, 0); margin: 0px auto; overflow: hidden; }", + # If set, the browser source will shutdown when it is hidden + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("shutdown")] + [switch] + $ShutdownWhenHidden, -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'SetVideoSettings')] -[Alias('obs.powershell.websocket.SetVideoSettings')] -param( + # If set, the browser source will restart when it is activated. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("restart_when_active")] + [switch] + $RestartWhenActived, -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('fpsNumerator')] -[ValidateRange(1,[int]::MaxValue)] -[double] -$FpsNumerator, + # If set, audio from the browser source will be rerouted into OBS. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("reroute_audio")] + [switch] + $RerouteAudio, -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('fpsDenominator')] -[ValidateRange(1,[int]::MaxValue)] -[double] -$FpsDenominator, + # If provided, the browser source will render at a custom frame rate. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("fps")] + [Alias('FPS')] + [int] + $FramesPerSecond, -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('baseWidth')] -[ValidateRange(1,4096)] -[double] -$BaseWidth, + # The name of the scene. + # If no scene name is provided, the current program scene will be used. + [Parameter(ValueFromPipelineByPropertyName)] + [string] + $Scene, -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('baseHeight')] -[ValidateRange(1,4096)] -[double] -$BaseHeight, + # The name of the input. + # If no name is provided, the last segment of the URI or file path will be the input name. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('InputName','SourceName')] + [string] + $Name, -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('outputWidth')] -[ValidateRange(1,4096)] -[double] -$OutputWidth, + # If set, will check if the source exists in the scene before creating it and removing any existing sources found. + # If not set, you will get an error if a source with the same name exists. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $Force + ) + dynamicParam { + $baseCommand = + if (-not $script:AddOBSInput) { + $script:AddOBSInput = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') + $script:AddOBSInput + } else { + $script:AddOBSInput + } + $IncludeParameter = @() + $ExcludeParameter = 'inputKind','sceneName','inputName' -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('outputHeight')] -[ValidateRange(1,4096)] -[double] -$OutputHeight, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() + :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { + if ($ExcludeParameter) { + foreach ($exclude in $ExcludeParameter) { + if ($paramName -like $exclude) { continue nextInputParameter} + } + } + if ($IncludeParameter) { + $shouldInclude = + foreach ($include in $IncludeParameter) { + if ($paramName -like $include) { $true;break} + } + if (-not $shouldInclude) { continue nextInputParameter } + } + + $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( + $baseCommand.Parameters[$paramName].Name, + $baseCommand.Parameters[$paramName].ParameterType, + $baseCommand.Parameters[$paramName].Attributes + )) + } + $DynamicParameters -process { + } + begin { + # Browser Sources are built into OBS. Their input kind is browser_source. + $inputKind = "browser_source" + + } + process { + $myParameters = [Ordered]@{} + $PSBoundParameters + + # Copy the bound parameters + $myParameters = [Ordered]@{} + $PSBoundParameters + # and determine the name of the invocation + $MyInvocationName = "$($MyInvocation.InvocationName)" + # Split it into verb and noun + $myVerb, $myNoun = $MyInvocationName -split '-' + # and get a copy of ourself that we can call with anonymous recursion. + $myScriptBlock = $MyInvocation.MyCommand.ScriptBlock + # Determine if the verb was get, + $IsGet = $myVerb -eq "Get" + # if no verb was used, + $NoVerb = $MyInvocationName -match '^[^\.\&][^-]+$' + # and if there were any other parameters then name + $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' + # If it is a get or there was no verb + if ($IsGet -or $NoVerb) { + $inputsOfKind = # Get all inputs of this kind + Get-OBSInput -InputKind $InputKind | + Where-Object { + if ($Name) { # If -Name was provided, + $_.InputName -like $Name # filter by name (as a wildcard). + } else { + $_ # otherwise, return every input. + } + } + + # If there were parameters other than name, + # and we were not explicitly called Get-* + if ($NonNameParameters -and -not $IsGet) { + # remove the name parameter + if ($myParameters.Name) { $myParameters.Remove('Name') } + # and pipe results back to ourself. + $inputsOfKind | & $myScriptBlock @myParameters + } else { + # Otherwise, we're just getting the list of inputs + $inputsOfKind + } + # (either way, if we were called Get- or with no verb, we're done now). + return + } - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + if ((-not $width) -or (-not $height)) { + if (-not $script:CachedOBSVideoSettings) { + $script:CachedOBSVideoSettings = Get-OBSVideoSettings + } + $videoSettings = $script:CachedOBSVideoSettings + $myParameters["Width"] = $width = $videoSettings.outputWidth + $myParameters["Height"] = $height = $videoSettings.outputHeight + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $myParameters["Scene"]) { + $myParameters["Scene"] = Get-OBSCurrentProgramScene | + Select-Object -ExpandProperty currentProgramSceneName } + + $myParameterData = [Ordered]@{} + foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, + $bindToPropertyName = $null + + foreach ($attribute in $parameter.Attributes) { + if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { + $bindToPropertyName = $attribute.Name + break } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } + } + + if (-not $bindToPropertyName) { continue } + if ($myParameters.Contains($parameter.Name)) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] + if ($myParameters[$parameter.Name] -is [switch]) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] -as [bool] } } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } + if ($fps -and $fps -ne 30) { + $myParameterData["custom_fps"] = $true + } + if ($uri.Scheme -eq 'File') { + if (Test-Path $uri.AbsolutePath) { + $myParameterData["local_file"] = "$uri" -replace '[\\/]', '/' -replace '^file:///' + $myParameterData["is_local_file"] = $true } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + else + { + if (Test-Path $uri) { + $rp = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($uri) + $myParameterData["local_file"] = "$rp" -replace '[\\/]', '/' -replace '^file:///' + $myParameterData["is_local_file"] = $true + } else { + $myParameterData["url"] = "$uri" + } } - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } + + if (-not $Name) { + $Name = $myParameters['Name'] = + if ($uri.Segments) { + $uri.Segments[-1] + } elseif ($uri -match '[\\/]') { + @($uri -split '[\\/]')[-1] + } else { + $uri + } + } -} + $addSplat = [Ordered]@{ + sceneName = $myParameters["Scene"] + inputKind = $inputKind + inputSettings = $myParameterData + inputName = $Name + NoResponse = $myParameters["NoResponse"] + } + # If -SceneItemEnabled was passed, + if ($myParameters.Contains('SceneItemEnabled')) { + # propagate it to Add-OBSInput. + $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] + } + # If -PassThru was passed + if ($MyParameters["PassThru"]) { + # pass it down to each command + $addSplat.Passthru = $MyParameters["PassThru"] + # If we were called with Add- + if ($MyInvocation.InvocationName -like 'Add-*') { + Add-OBSInput @addSplat # passthru Add-OBSInput + } else { + # Otherwise, remove SceneItemEnabled, InputKind, and SceneName + $addSplat.Remove('SceneItemEnabled') + $addSplat.Remove('inputKind') + $addSplat.Remove('sceneName') + # and passthru Set-OBSInputSettings. + Set-OBSInputSettings @addSplat + } + return + } + + # Add the input. + $outputAddedResult = Add-OBSInput @addSplat *>&1 -} + # If we got back an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # and that error was saying the source already exists, + if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { + # then check if we use the -Force. + if ($Force) { # If we do, remove the input + Remove-OBSInput -InputName $addSplat.inputName + # and re-add our result. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + } else { + # Otherwise, get the input from the scene, + $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $myParameters["Name"] + # update the input settings + $sceneItem.Input.Settings = $addSplat.inputSettings + $sceneItem # and return the scene item. + $outputAddedResult = $null + } + } + # If the output was still an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # use $psCmdlet.WriteError so that it shows the error correctly. + $psCmdlet.WriteError($outputAddedResult) + } + } + # Otherwise, if we had a result + if ($outputAddedResult -and + $outputAddedResult -isnot [Management.Automation.ErrorRecord]) { + # get the input from the scene. + Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $myParameters["Name"] + } + + } +} #.ExternalHelp obs-powershell-Help.xml -function Start-OBSOutput { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StartOutput')] -[Alias('obs.powershell.websocket.StartOutput')] -param( - -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('outputName')] -[string] -$OutputName, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) +function Set-OBSColorSource { + + + [Alias('Add-OBSColorSource','Get-OBSColorSource')] + param( + # The name of the scene. + # If no scene name is provided, the current program scene will be used. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('SceneName')] + [string] + $Scene, + # The name of the input. + # If no name is provided, "Display $($Monitor + 1)" will be the input source name. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('InputName')] + [string] + $Name, -process { + [ValidatePattern('\#(?>[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{4}|[0-9a-f]{3})')] + [Parameter(ValueFromPipelineByPropertyName)] + [string] + $Color, + # If set, will check if the source exists in the scene before creating it and removing any existing sources found. + # If not set, you will get an error if a source with the same name exists. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $Force + ) + dynamicParam { + $baseCommand = + if (-not $script:AddOBSInput) { + $script:AddOBSInput = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') + $script:AddOBSInput + } else { + $script:AddOBSInput + } + $IncludeParameter = @() + $ExcludeParameter = 'inputKind','sceneName','inputName' - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() + :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { + if ($ExcludeParameter) { + foreach ($exclude in $ExcludeParameter) { + if ($paramName -like $exclude) { continue nextInputParameter} + } } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } + if ($IncludeParameter) { + $shouldInclude = + foreach ($include in $IncludeParameter) { + if ($paramName -like $include) { $true;break} } - } + if (-not $shouldInclude) { continue nextInputParameter } } + + $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( + $baseCommand.Parameters[$paramName].Name, + $baseCommand.Parameters[$paramName].ParameterType, + $baseCommand.Parameters[$paramName].Attributes + )) + } + $DynamicParameters - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + } + begin { + $inputKind = "color_source_v3" + + } + process { + # Copy the bound parameters + $myParameters = [Ordered]@{} + $PSBoundParameters + # and determine the name of the invocation + $MyInvocationName = "$($MyInvocation.InvocationName)" + # Split it into verb and noun + $myVerb, $myNoun = $MyInvocationName -split '-' + # and get a copy of ourself that we can call with anonymous recursion. + $myScriptBlock = $MyInvocation.MyCommand.ScriptBlock + # Determine if the verb was get, + $IsGet = $myVerb -eq "Get" + # if no verb was used, + $NoVerb = $MyInvocationName -match '^[^\.\&][^-]+$' + # and if there were any other parameters then name + $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' + + # If it is a get or there was no verb + if ($IsGet -or $NoVerb) { + $inputsOfKind = # Get all inputs of this kind + Get-OBSInput -InputKind $InputKind | + Where-Object { + if ($Name) { # If -Name was provided, + $_.InputName -like $Name # filter by name (as a wildcard). + } else { + $_ # otherwise, return every input. + } } - continue nextParam - } + + # If there were parameters other than name, + # and we were not explicitly called Get-* + if ($NonNameParameters -and -not $IsGet) { + # remove the name parameter + if ($myParameters.Name) { $myParameters.Remove('Name') } + # and pipe results back to ourself. + $inputsOfKind | & $myScriptBlock @myParameters + } else { + # Otherwise, we're just getting the list of inputs + $inputsOfKind } + # (either way, if we were called Get- or with no verb, we're done now). + return } - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + if (-not $myParameters["Scene"]) { + $myParameters["Scene"] = Get-OBSCurrentProgramScene | + Select-Object -ExpandProperty currentProgramSceneName } -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Start-OBSRecord { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StartRecord')] -[Alias('obs.powershell.websocket.StartRecord')] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - - - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + $hexChar = [Regex]::new('[0-9a-f]') + $hexColors = @($hexChar.Matches($Color)) - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + switch ($hexColors.Length) { + 8 { + #full rgba + $alpha = [byte]::Parse($hexColors[0..1] -join '', 'HexNumber') + $red = [byte]::Parse($hexColors[2..3] -join '', 'HexNumber') + $green = [byte]::Parse($hexColors[4..5] -join '', 'HexNumber') + $blue = [byte]::Parse($hexColors[6..7] -join '', 'HexNumber') + } + 6 { + #rgb only, assume ff for alpha + $alpha = 0xff + $red = [byte]::Parse($hexColors[0..1] -join '', 'HexNumber') + $green = [byte]::Parse($hexColors[2..3] -join '', 'HexNumber') + $blue = [byte]::Parse($hexColors[4..5] -join '', 'HexNumber') + } + 4 { + #short rgba + $alpha = [byte]::Parse(($hexColors[0],$hexColors[0] -join ''), 'HexNumber') + $red = [byte]::Parse(($hexColors[1],$hexColors[1] -join ''), 'HexNumber') + $green = [byte]::Parse(($hexColors[2],$hexColors[2] -join ''), 'HexNumber') + $blue = [byte]::Parse(($hexColors[3],$hexColors[3] -join ''), 'HexNumber') + } + 3 { + #short rgb, assume f for alpha + $alpha = 0xff + $red = [byte]::Parse(($hexColors[0],$hexColors[0] -join ''), 'HexNumber') + $green = [byte]::Parse(($hexColors[1],$hexColors[1] -join ''), 'HexNumber') + $blue = [byte]::Parse(($hexColors[2],$hexColors[2] -join ''), 'HexNumber') + } + 0 { + # No color provided, default to transparent black + $alpha = 0 + $red = 0 + $green = 0 + $blue = 0 + } } + + $hexColor = ("{0:x2}{1:x2}{2:x2}{3:x2}" -f $alpha, $blue, $green, $red) - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } + $realColor = [uint32]::Parse($hexColor,'HexNumber') + + + if (-not $myParameters["Name"]) { + $myParameters["Name"] = "#$hexColor" } + + $myParameterData = [Ordered]@{color=$realColor} - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + $addSplat = @{ + sceneName = $myParameters["Scene"] + inputName = $myParameters["Name"] + inputKind = "color_source_v3" + inputSettings = $myParameterData + NoResponse = $myParameters["NoResponse"] } - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + # If -SceneItemEnabled was passed, + if ($myParameters.Contains('SceneItemEnabled')) { + # propagate it to Add-OBSInput. + $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] } - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + # If -PassThru was passed + if ($MyParameters["PassThru"]) { + # pass it down to each command + $addSplat.Passthru = $MyParameters["PassThru"] + # If we were called with Add- + if ($MyInvocation.InvocationName -like 'Add-*') { + Add-OBSInput @addSplat # passthru Add-OBSInput + } else { + # Otherwise, remove SceneItemEnabled, InputKind, and SceneName + $addSplat.Remove('SceneItemEnabled') + $addSplat.Remove('inputKind') + $addSplat.Remove('sceneName') + # and passthru Set-OBSInputSettings. + Set-OBSInputSettings @addSplat + } + return } -} + # Add the input. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + # If we got back an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # and that error was saying the source already exists, + if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { + # then check if we use the -Force. + if ($Force) { # If we do, remove the input + Remove-OBSInput -InputName $addSplat.inputName + # and re-add our result. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + } else { + # Otherwise, get the input from the scene, + $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $myParameters["Name"] + # update the input settings + $sceneItem.Input.Settings = $addSplat.inputSettings + $sceneItem # and return the scene item. + $outputAddedResult = $null + } + } -} + # If the output was still an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # use $psCmdlet.WriteError so that it shows the error correctly. + $psCmdlet.WriteError($outputAddedResult) + } + } + # Otherwise, if we had a result + if ($outputAddedResult -and + $outputAddedResult -isnot [Management.Automation.ErrorRecord]) { + # get the input from the scene. + Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $myParameters["Name"] + } + + } +} #.ExternalHelp obs-powershell-Help.xml -function Start-OBSReplayBuffer { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StartReplayBuffer')] -[Alias('obs.powershell.websocket.StartReplayBuffer')] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - +function Set-OBSDisplaySource { + + + [Alias('Add-OBSMonitorSource','Set-OBSMonitorSource','Add-OBSDisplaySource')] + param( + # The monitor number. + # This the number of the monitor you would like to capture. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("monitor")] + [Alias('MonitorNumber','Display','DisplayNumber')] + [int] + $Monitor = 1, -process { + # If set, will capture the cursor. + # This will be set by default. + # If explicitly set to false, the cursor will not be captured. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("capture_cursor")] + [switch] + $CaptureCursor, + # The name of the scene. + # If no scene name is provided, the current program scene will be used. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('SceneName')] + [string] + $Scene, - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + # The name of the input. + # If no name is provided, "Display $($Monitor + 1)" will be the input source name. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('InputName')] + [string] + $Name, - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + # If set, will check if the source exists in the scene before creating it and removing any existing sources found. + # If not set, you will get an error if a source with the same name exists. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $Force + ) + dynamicParam { + $baseCommand = + if (-not $script:AddOBSInput) { + $script:AddOBSInput = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') + $script:AddOBSInput + } else { + $script:AddOBSInput } + $IncludeParameter = @() + $ExcludeParameter = 'inputKind','sceneName','inputName' - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + + $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() + :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { + if ($ExcludeParameter) { + foreach ($exclude in $ExcludeParameter) { + if ($paramName -like $exclude) { continue nextInputParameter} } } - - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + if ($IncludeParameter) { + $shouldInclude = + foreach ($include in $IncludeParameter) { + if ($paramName -like $include) { $true;break} } - } + if (-not $shouldInclude) { continue nextInputParameter } } - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } + $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( + $baseCommand.Parameters[$paramName].Name, + $baseCommand.Parameters[$paramName].ParameterType, + $baseCommand.Parameters[$paramName].Attributes + )) + } + $DynamicParameters - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + } + process { + $myParameters = [Ordered]@{} + $PSBoundParameters + + if (-not $myParameters["Scene"]) { + $myParameters["Scene"] = Get-OBSCurrentProgramScene | + Select-Object -ExpandProperty currentProgramSceneName } + + $myParameterData = [Ordered]@{} + foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { -} - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Start-OBSStream { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StartStream')] -[Alias('obs.powershell.websocket.StartStream')] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + $bindToPropertyName = $null + + foreach ($attribute in $parameter.Attributes) { + if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { + $bindToPropertyName = $attribute.Name + break + } + } + if (-not $bindToPropertyName) { continue } + if ($myParameters.Contains($parameter.Name)) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] + if ($myParameters[$parameter.Name] -is [switch]) { + $myParameterData[$bindToPropertyName] = $parameter.Name -as [bool] + } + } + } -process { + # Users like 1 indexed, computers like zero-indexed. + $myParameterData["monitor"] = $Monitor - 1 + if (-not $myParameters["Name"]) { + $myParameters["Name"] = "Display $($Monitor)" + } - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + $addSplat = @{ + sceneName = $myParameters["Scene"] + inputName = $myParameters["Name"] + inputKind = "monitor_capture" + inputSettings = $myParameterData + NoResponse = $myParameters["NoResponse"] + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + # If -SceneItemEnabled was passed, + if ($myParameters.Contains('SceneItemEnabled')) { + # propagate it to Add-OBSInput. + $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + # If -PassThru was passed + if ($MyParameters["PassThru"]) { + # pass it down to each command + $addSplat.Passthru = $MyParameters["PassThru"] + # If we were called with Add- + if ($MyInvocation.InvocationName -like 'Add-*') { + Add-OBSInput @addSplat # passthru Add-OBSInput + } else { + # Otherwise, remove SceneItemEnabled, InputKind, and SceneName + $addSplat.Remove('SceneItemEnabled') + $addSplat.Remove('inputKind') + $addSplat.Remove('sceneName') + # and passthru Set-OBSInputSettings. + Set-OBSInputSettings @addSplat } + return } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + # Add the input. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + + # If we got back an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # and that error was saying the source already exists, + if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { + # then check if we use the -Force. + if ($Force) { # If we do, remove the input + Remove-OBSInput -InputName $addSplat.inputName + # and re-add our result. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + } else { + # Otherwise, get the input from the scene, + $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $myParameters["Name"] + # update the input settings + $sceneItem.Input.Settings = $addSplat.inputSettings + $sceneItem # and return the scene item. + $outputAddedResult = $null } } + + # If the output was still an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # use $psCmdlet.WriteError so that it shows the error correctly. + $psCmdlet.WriteError($outputAddedResult) + } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + # Otherwise, if we had a result + if ($outputAddedResult -and + $outputAddedResult -isnot [Management.Automation.ErrorRecord]) { + # get the input from the scene. + Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $name } + + } +} + +#.ExternalHelp obs-powershell-Help.xml +function Set-OBSMarkdownSource { + + + [Alias('Add-OBSMarkdownSource','Get-OBSMarkdownSource')] + param( + # The markdown text, or the path to a markdown file + [Parameter(ValueFromPipelineByPropertyName)] + [string] + $Markdown, - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } + # The width of the browser source. + # If none is provided, this will be the output width of the video settings. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("width")] + [int] + $Width, -} + # The width of the browser source. + # If none is provided, this will be the output height of the video settings. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("height")] + [int] + $Height, + # The css style used to render the markdown. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("css")] + [string] + $CSS = "body { background-color: rgba(0, 0, 0, 0); margin: 0px auto; overflow: hidden; }", -} + # The name of the scene. + # If no scene name is provided, the current program scene will be used. + [Parameter(ValueFromPipelineByPropertyName)] + [string] + $Scene, - -#.ExternalHelp obs-powershell-Help.xml -function Start-OBSVirtualCam { + # The name of the input. + # If no name is provided, the last segment of the URI or file path will be the input name. + [Parameter(ValueFromPipelineByPropertyName)] + [string] + $Name, + # If set, will check if the source exists in the scene before creating it and removing any existing sources found. + # If not set, you will get an error if a source with the same name exists. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $Force + ) + dynamicParam { + $baseCommand = + if (-not $script:AddOBSInput) { + $script:AddOBSInput = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') + $script:AddOBSInput + } else { + $script:AddOBSInput + } + $IncludeParameter = @() + $ExcludeParameter = 'inputKind','sceneName','inputName' -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StartVirtualCam')] -[Alias('obs.powershell.websocket.StartVirtualCam')] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() + :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { + if ($ExcludeParameter) { + foreach ($exclude in $ExcludeParameter) { + if ($paramName -like $exclude) { continue nextInputParameter} + } + } + if ($IncludeParameter) { + $shouldInclude = + foreach ($include in $IncludeParameter) { + if ($paramName -like $include) { $true;break} + } + if (-not $shouldInclude) { continue nextInputParameter } + } + + $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( + $baseCommand.Parameters[$paramName].Name, + $baseCommand.Parameters[$paramName].ParameterType, + $baseCommand.Parameters[$paramName].Attributes + )) + } + $DynamicParameters -process { + } + begin { + $inputKind = "markdown_source" + + } + process { + $myParameters = [Ordered]@{} + $PSBoundParameters + $IsGet = $MyInvocation.InvocationName -like "Get-*" + $NoVerb = $MyInvocation.InvocationName -match '^[^-]+$' + $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + if ( + $IsGet -or + ($NoVerb -and -not $NonNameParameters) + ) { + Get-OBSInput -InputKind $InputKind | + Where-Object { + if ($Name) { + $_.InputName -like $Name + } else { + $_ + } + } + return + } + + if ((-not $width) -or (-not $height)) { + if (-not $script:CachedOBSVideoSettings) { + $script:CachedOBSVideoSettings = Get-OBSVideoSettings + } + $videoSettings = $script:CachedOBSVideoSettings + $myParameters["Width"] = $width = $videoSettings.outputWidth + $myParameters["Height"] = $height = $videoSettings.outputHeight + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $myParameters["Scene"]) { + $myParameters["Scene"] = Get-OBSCurrentProgramScene | + Select-Object -ExpandProperty currentProgramSceneName } + + $myParameterData = [Ordered]@{} + foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, + $bindToPropertyName = $null + + foreach ($attribute in $parameter.Attributes) { + if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { + $bindToPropertyName = $attribute.Name + break } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } + } + + if (-not $bindToPropertyName) { continue } + if ($myParameters.Contains($parameter.Name)) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] + if ($myParameters[$parameter.Name] -is [switch]) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] -as [bool] } } } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } + $markdownAsUri = $null + if ($Markdown -like '*.md') { + $markdownAsUri = $markdown -as [uri] + if ($markdownAsUri.Scheme -eq 'File') { + $myParameterData["markdown_path"] = "$markdownAsUri" -replace '[\\/]', '/' -replace '^file:///' + $myParameterData["markdown_source"] = 1 + } + else { + } + } else { + $myParameterData["text"] = $Markdown + $myParameterData["markdown_source"] = 0 } - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + if (-not $Name) { + $Name = $myParameters['Name'] = + if ($markdownAsUri.Segments) { + $markdownAsUri.Segments[-1] + } elseif ($markdownAsUri -match '[\\/]') { + @($markdownAsUri -split '[\\/]')[-1] + } elseif ($markdownAsUri) { + $markdownAsUri + } else { + "Markdown" + } + } + + $addSplat = [Ordered]@{ + sceneName = $myParameters["Scene"] + inputKind = "markdown_source" + inputSettings = $myParameterData + inputName = $Name + NoResponse = $myParameters["NoResponse"] + } + # If -SceneItemEnabled was passed, + if ($myParameters.Contains('SceneItemEnabled')) { + # propagate it to Add-OBSInput. + $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] } - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + # If -PassThru was passed + if ($MyParameters["PassThru"]) { + # pass it down to each command + $addSplat.Passthru = $MyParameters["PassThru"] + # If we were called with Add- + if ($MyInvocation.InvocationName -like 'Add-*') { + Add-OBSInput @addSplat # passthru Add-OBSInput + } else { + # Otherwise, remove SceneItemEnabled, InputKind, and SceneName + $addSplat.Remove('SceneItemEnabled') + $addSplat.Remove('inputKind') + $addSplat.Remove('sceneName') + # and passthru Set-OBSInputSettings. + Set-OBSInputSettings @addSplat + } + return } + + # Add the input. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + + # If we got back an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # and that error was saying the source already exists, + if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { + # then check if we use the -Force. + if ($Force) { # If we do, remove the input + Remove-OBSInput -InputName $addSplat.inputName + # and re-add our result. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + } else { + # Otherwise, get the input from the scene, + $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $myParameters["Name"] + # update the input settings + $sceneItem.Input.Settings = $addSplat.inputSettings + $sceneItem # and return the scene item. + $outputAddedResult = $null + } + } + # If the output was still an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # use $psCmdlet.WriteError so that it shows the error correctly. + $psCmdlet.WriteError($outputAddedResult) + } + } + # Otherwise, if we had a result + if ($outputAddedResult -and + $outputAddedResult -isnot [Management.Automation.ErrorRecord]) { + # get the input from the scene. + Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $myParameters["Name"] + } + + } } + +#.ExternalHelp obs-powershell-Help.xml +function Set-OBSMediaSource { + + + [Alias('Add-OBSFFMpegSource','Add-OBSMediaSource','Set-OBSFFMpegSource','Get-OBSFFMpegSource','Get-OBSMediaSource')] + param( + # The path to the media file. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('FullName','LocalFile','local_file')] + [string] + $FilePath, + # If set, the source will close when it is inactive. + # By default, this will be set to true. + # To explicitly set it to false, use -CloseWhenInactive:$false + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("close_when_inactive")] + [switch] + $CloseWhenInactive, -} + # If set, the source will automatically restart. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("looping")] + [Alias('Looping')] + [switch] + $Loop, - -#.ExternalHelp obs-powershell-Help.xml -function Stop-OBSOutput { + # If set, will use hardware decoding, if available. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("hw_decode")] + [Alias('HardwareDecoding','hw_decode')] + [switch] + $UseHardwareDecoding, + # If set, will clear the output on the end of the media. + # If this is set to false, the media will freeze on the last frame. + # This is set to true by default. + # To explicitly set to false, use -ClearMediaEnd:$false + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("clear_on_media_end")] + [Alias('ClearOnEnd','NoFreezeFrameOnEnd')] + [switch] + $ClearOnMediaEnd, -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StopOutput')] -[Alias('obs.powershell.websocket.StopOutput')] -param( + # Any FFMpeg demuxer options. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("ffmpeg_options")] + [Alias('FFMpegOptions', 'FFMpeg_Options')] + [string] + $FFMpegOption, -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('outputName')] -[string] -$OutputName, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + # The name of the scene. + # If no scene name is provided, the current program scene will be used. + [Parameter(ValueFromPipelineByPropertyName)] + [string] + $Scene, + # The name of the input. + # If no name is provided, the last segment of the URI or file path will be the input name. + [Parameter(ValueFromPipelineByPropertyName)] + [string] + $Name, -process { + # If set, will check if the source exists in the scene before creating it and removing any existing sources found. + # If not set, you will get an error if a source with the same name exists. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $Force, + # If set, will fit the input to the screen. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $FitToScreen + ) + dynamicParam { + $baseCommand = + if (-not $script:AddOBSInput) { + $script:AddOBSInput = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') + $script:AddOBSInput + } else { + $script:AddOBSInput + } + $IncludeParameter = @() + $ExcludeParameter = 'inputKind','sceneName','inputName' - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() + :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { + if ($ExcludeParameter) { + foreach ($exclude in $ExcludeParameter) { + if ($paramName -like $exclude) { continue nextInputParameter} + } + } + if ($IncludeParameter) { + $shouldInclude = + foreach ($include in $IncludeParameter) { + if ($paramName -like $include) { $true;break} + } + if (-not $shouldInclude) { continue nextInputParameter } + } + + $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( + $baseCommand.Parameters[$paramName].Name, + $baseCommand.Parameters[$paramName].ParameterType, + $baseCommand.Parameters[$paramName].Attributes + )) + } + $DynamicParameters + + } + begin { + filter OutputAndFitToScreen { + + if ($FitToScreen -and $_.FitToScreen) { + $_.FitToScreen() + } + $_ + + } + $InputKind = "ffmpeg_source" + + } + process { + # Copy the bound parameters + $myParameters = [Ordered]@{} + $PSBoundParameters + # and determine the name of the invocation + $MyInvocationName = "$($MyInvocation.InvocationName)" + # Split it into verb and noun + $myVerb, $myNoun = $MyInvocationName -split '-' + # and get a copy of ourself that we can call with anonymous recursion. + $myScriptBlock = $MyInvocation.MyCommand.ScriptBlock + # Determine if the verb was get, + $IsGet = $myVerb -eq "Get" + # if no verb was used, + $NoVerb = $MyInvocationName -match '^[^\.\&][^-]+$' + # and if there were any other parameters then name + $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' + + # If it is a get or there was no verb + if ($IsGet -or $NoVerb) { + $inputsOfKind = # Get all inputs of this kind + Get-OBSInput -InputKind $InputKind | + Where-Object { + if ($Name) { # If -Name was provided, + $_.InputName -like $Name # filter by name (as a wildcard). + } else { + $_ # otherwise, return every input. + } + } + + # If there were parameters other than name, + # and we were not explicitly called Get-* + if ($NonNameParameters -and -not $IsGet) { + # remove the name parameter + if ($myParameters.Name) { $myParameters.Remove('Name') } + # and pipe results back to ourself. + $inputsOfKind | & $myScriptBlock @myParameters + } else { + # Otherwise, we're just getting the list of inputs + $inputsOfKind + } + # (either way, if we were called Get- or with no verb, we're done now). + return + } + + if (-not $myParameters["Scene"]) { + $myParameters["Scene"] = Get-OBSCurrentProgramScene | + Select-Object -ExpandProperty currentProgramSceneName } + + $myParameterData = [Ordered]@{} + foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } + $bindToPropertyName = $null + + foreach ($attribute in $parameter.Attributes) { + if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { + $bindToPropertyName = $attribute.Name + break } } - } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + if (-not $bindToPropertyName) { continue } + if ($myParameters.Contains($parameter.Name)) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] + if ($myParameters[$parameter.Name] -is [switch]) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] -as [bool] } } } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + if ((Test-Path $FilePath)) { + $FilePathItem = Get-Item -Path $FilePath + $myParameterData['local_file'] = $FilePathItem.FullName -replace '/', '\' } -} + + if ($myParameters['InputSettings']) { + $keys = + @(if ($myParameters['InputSettings'] -is [Collections.IDictionary]) { + $myParameters['InputSettings'].Keys + } else { + foreach ($prop in $myParameters['InputSettings'].PSObject.Properties) { + $prop.Name + } + }) -} + foreach ($key in $keys) { + $myParameterData[$key] = $myParameters['InputSettings'].$key + } + $myParameterData.remove('inputSettings') + } -#.ExternalHelp obs-powershell-Help.xml -function Stop-OBSRecord { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StopRecord')] -[Alias('obs.powershell.websocket.StopRecord')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - + if (-not $Name) { + + $Name = $myParameters["Name"] = + if ($FilePathItem.Name) { + $FilePathItem.Name + } else { + "Media" + } + + } - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + $addSplat = [Ordered]@{ + sceneName = $myParameters["Scene"] + inputKind = $InputKind + inputSettings = $myParameterData + inputName = $Name + NoResponse = $myParameters["NoResponse"] + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if ($myParameters.Contains('SceneItemEnabled')) { + $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + # If -PassThru was passed + if ($MyParameters["PassThru"]) { + # pass it down to each command + $addSplat.Passthru = $MyParameters["PassThru"] + # If we were called with Add- + if ($MyInvocation.InvocationName -like 'Add-*') { + Add-OBSInput @addSplat # passthru Add-OBSInput + } else { + # Otherwise, remove SceneItemEnabled, InputKind, and SceneName + $addSplat.Remove('SceneItemEnabled') + $addSplat.Remove('inputKind') + $addSplat.Remove('sceneName') + # and passthru Set-OBSInputSettings. + Set-OBSInputSettings @addSplat } + return } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + # Add the input. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + + # If we got back an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # and that error was saying the source already exists, + if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { + # then check if we use the -Force. + if ($Force) { # If we do, remove the input + Remove-OBSInput -InputName $addSplat.inputName + # and re-add our result. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + } else { + # Otherwise, get the input from the scene, + $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $myParameters["Name"] + # update the input settings + $sceneItem.Input.Settings = $addSplat.inputSettings + $sceneItem # and return the scene item. + $outputAddedResult = $null } } + + # If the output was still an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # use $psCmdlet.WriteError so that it shows the error correctly. + $psCmdlet.WriteError($outputAddedResult) + } } - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + # Otherwise, if we had a result + if ($outputAddedResult -isnot [Management.Automation.ErrorRecord]) { + # get the input from the scene and optionally fit it to the screen. + Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $name | + OutputAndFitToScreen } - + + } } + +#.ExternalHelp obs-powershell-Help.xml +function Set-OBSSoundCloudSource { + + + [Alias('Add-OBSSoundCloudSource','Get-OBSSoundCloudSource')] + param( + # The uri to display. This must point to a SoundCloud URL. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('Url','SoundCloudUri','SoundCloudUrl')] + [uri] + $Uri, + # If set, will not autoplay. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $NoAutoPlay, -} + # If set, will not display album artwork. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $NoArtwork, - -#.ExternalHelp obs-powershell-Help.xml -function Stop-OBSReplayBuffer { + # If set, will not display play count. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $NoPlayCount, + # If set, will not display uploader info. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $NoUploaderInfo, -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StopReplayBuffer')] -[Alias('obs.powershell.websocket.StopReplayBuffer')] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + # If provided, will start playing at a given track number. + [Parameter(ValueFromPipelineByPropertyName)] + [int] + $TrackNumber, + # If set, will show a share link. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $ShowShare, -process { + # If set, will show a download link. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $ShowDownload, + # If set, will show a buy link. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $ShowBuy, - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + # The color used for the SoundCloud audio bars and buttons. + [Parameter(ValueFromPipelineByPropertyName)] + [string] + $Color, - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + # The width of the browser source. + # If none is provided, this will be the output width of the video settings. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("width")] + [int] + $Width, - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } + # The width of the browser source. + # If none is provided, this will be the output height of the video settings. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("height")] + [int] + $Height, - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } + # The css style used to render the browser page. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("css")] + [string] + $CSS = "body { background-color: rgba(0, 0, 0, 0); margin: 0px auto; overflow: hidden; }", - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } + # If set, the browser source will shutdown when it is hidden + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("shutdown")] + [switch] + $ShutdownWhenHidden, -} + # If set, the browser source will restart when it is activated. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("restart_when_active")] + [switch] + $RestartWhenActived, + # If set, audio from the browser source will be rerouted into OBS. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("reroute_audio")] + [switch] + $RerouteAudio, -} + # If provided, the browser source will render at a custom frame rate. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("fps")] + [Alias('FPS')] + [int] + $FramesPerSecond, - -#.ExternalHelp obs-powershell-Help.xml -function Stop-OBSStream { + # The name of the scene. + # If no scene name is provided, the current program scene will be used. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('SceneName')] + [string] + $Scene, + # The name of the input. + # If no name is provided, then "SoundCloud" will be used. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('InputName','SourceName')] + [string] + $Name, -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StopStream')] -[Alias('obs.powershell.websocket.StopStream')] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + # If set, will check if the source exists in the scene before creating it and removing any existing sources found. + # If not set, you will get an error if a source with the same name exists. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $Force + ) + dynamicParam { + $baseCommand = + if (-not $script:AddOBSInput) { + $script:AddOBSInput = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') + $script:AddOBSInput + } else { + $script:AddOBSInput + } + $IncludeParameter = @() + $ExcludeParameter = 'inputKind','sceneName','inputName' -process { + $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() + :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { + if ($ExcludeParameter) { + foreach ($exclude in $ExcludeParameter) { + if ($paramName -like $exclude) { continue nextInputParameter} + } + } + if ($IncludeParameter) { + $shouldInclude = + foreach ($include in $IncludeParameter) { + if ($paramName -like $include) { $true;break} + } + if (-not $shouldInclude) { continue nextInputParameter } + } + + $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( + $baseCommand.Parameters[$paramName].Name, + $baseCommand.Parameters[$paramName].ParameterType, + $baseCommand.Parameters[$paramName].Attributes + )) + } + $DynamicParameters + } + begin { + # Browser Sources are built into OBS. Their input kind is browser_source. + # Sound Cloud Sources are really Browser Sources. + $inputKind = "browser_source" + + } + process { + # Copy the bound parameters + $myParameters = [Ordered]@{} + $PSBoundParameters + # and determine the name of the invocation + $MyInvocationName = "$($MyInvocation.InvocationName)" + # Split it into verb and noun + $myVerb, $myNoun = $MyInvocationName -split '-' + # and get a copy of ourself that we can call with anonymous recursion. + $myScriptBlock = $MyInvocation.MyCommand.ScriptBlock + # Determine if the verb was get, + $IsGet = $myVerb -eq "Get" + # if no verb was used, + $NoVerb = $MyInvocationName -match '^[^\.\&][^-]+$' + # and if there were any other parameters then name + $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if (-not $uri.DnsSafeHost -or $uri.DnsSafeHost -notmatch 'SoundCloud\.com$') { + Write-Error "URI must be from SoundCloud.com" + return } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } + if ($uri.Query) { + $uri = "https://$($uri.DnsSafeHost)" + $($uri.Segments -join '') } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + # If it is a get or there was no verb + if ($IsGet -or $NoVerb) { + $inputsOfKind = # Get all inputs of this kind + Get-OBSInput -InputKind $InputKind | + Where-Object { + if ($Name) { # If -Name was provided, + $_.InputName -like $Name # filter by name (as a wildcard). + } else { + $_ # otherwise, return every input. + } + } | + Where-Object { + $_.Settings['LocalFile'] -like '*.SoundCloud.*' } - continue nextParam - } + + # If there were parameters other than name, + # and we were not explicitly called Get-* + if ($NonNameParameters -and -not $IsGet) { + # remove the name parameter + if ($myParameters.Name) { $myParameters.Remove('Name') } + # and pipe results back to ourself. + $inputsOfKind | & $myScriptBlock @myParameters + } else { + # Otherwise, we're just getting the list of inputs + $inputsOfKind } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy + # (either way, if we were called Get- or with no verb, we're done now). + return } - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + if ((-not $width) -or (-not $height)) { + if (-not $script:CachedOBSVideoSettings) { + $script:CachedOBSVideoSettings = Get-OBSVideoSettings + } + $videoSettings = $script:CachedOBSVideoSettings + + $myParameters["Width"] = $width = $videoSettings.outputWidth + $myParameters["Height"] = $height = $videoSettings.outputHeight } -} + if (-not $myParameters["Scene"]) { + $myParameters["Scene"] = Get-OBSCurrentProgramScene | + Select-Object -ExpandProperty currentProgramSceneName + } + + $myParameterData = [Ordered]@{} + foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { + $bindToPropertyName = $null + + foreach ($attribute in $parameter.Attributes) { + if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { + $bindToPropertyName = $attribute.Name + break + } + } -} + if (-not $bindToPropertyName) { continue } + if ($myParameters.Contains($parameter.Name)) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] + if ($myParameters[$parameter.Name] -is [switch]) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] -as [bool] + } + } + } - -#.ExternalHelp obs-powershell-Help.xml -function Stop-OBSVirtualCam { + if ($fps -and $fps -ne 30) { + $myParameterData["custom_fps"] = $true + } + $MyObsPowerShellPath = if ($home) { + Join-Path $home ".obs-powershell" + } -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'StopVirtualCam')] -[Alias('obs.powershell.websocket.StopVirtualCam')] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + $ThisSoundCloudSourceFileName = + if ($name) { + "${name}.SoundCloudSource.html" + } else { + "SoundCloudSource.html" + } + $ThisSoundCloudSourceFilePath = Join-Path $MyObsPowerShellPath $ThisSoundCloudSourceFileName + -process { + $soundCloudSrc = @( + "https://w.soundcloud.com/player/?url=" + $Uri + "&" + @( + if ($PSBoundParameters["TrackNumber"]) {"start_track=$trackNumber"} + if ($color) { "color=$color" -replace "\#",'%23'} + if ($NoAutoPlay) { "auto_play=false" } else { "auto_play=true"} + if ($NoArtwork) { "show_artwork=false" } else {"show_artwork=true" } + if ($NoUploaderInfo) { "show_user=false" } else {"show_user=true"} + if ($NoPlayCount) { "show_playcount=false" } else {"show_playcount=true" } + if ($ShowDownload) { "download=true"} else { "download=false" } + if ($ShowBuy) { "buying=true"} else { "buying=false" } + if ($ShowShare) { "sharing=true"} else { "sharing=false" } + ) -join '&' + ) -join '' + + $soundCloudWidget = @( + "" + "" + "" + "" + "" + ) -join ' ' + $newHtmlFile = New-Item -Value $soundCloudWidget -ItemType File -Path $ThisSoundCloudSourceFilePath -Force + + $myParameterData["local_file"] = ([uri]$newHtmlFile.FullName) -replace '[\\/]', '/' -replace '^file:///' + $myParameterData["is_local_file"] = $true - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + if (-not $Name) { + $Name = $myParameters['Name'] = 'SoundCloud' + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + $addSplat = [Ordered]@{ + sceneName = $myParameters["Scene"] + inputKind = $inputKind + inputSettings = $myParameterData + inputName = $Name + NoResponse = $myParameters["NoResponse"] + } + # If -SceneItemEnabled was passed, + if ($myParameters.Contains('SceneItemEnabled')) { + # propagate it to Add-OBSInput. + $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + # If -PassThru was passed + if ($MyParameters["PassThru"]) { + # pass it down to each command + $addSplat.Passthru = $MyParameters["PassThru"] + # If we were called with Add- + if ($MyInvocation.InvocationName -like 'Add-*') { + Add-OBSInput @addSplat # passthru Add-OBSInput + } else { + # Otherwise, remove SceneItemEnabled, InputKind, and SceneName + $addSplat.Remove('SceneItemEnabled') + $addSplat.Remove('inputKind') + $addSplat.Remove('sceneName') + # and passthru Set-OBSInputSettings. + Set-OBSInputSettings @addSplat } + return } + + # Add the input. + $outputAddedResult = Add-OBSInput @addSplat *>&1 - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + # If we got back an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # and that error was saying the source already exists, + if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { + # then check if we use the -Force. + if ($Force) { # If we do, remove the input + Remove-OBSInput -InputName $addSplat.inputName + # and re-add our result. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + } else { + # Otherwise, get the input from the scene, + $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $myParameters["Name"] + # update the input settings + $sceneItem.Input.Settings = $addSplat.inputSettings + $sceneItem # and return the scene item. + $outputAddedResult = $null } } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + # If the output was still an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # use $psCmdlet.WriteError so that it shows the error correctly. + $psCmdlet.WriteError($outputAddedResult) + } } - + # Otherwise, if we had a result + if ($outputAddedResult -and + $outputAddedResult -isnot [Management.Automation.ErrorRecord]) { + # get the input from the scene. + Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $myParameters["Name"] + } + + } } - - -} - #.ExternalHelp obs-powershell-Help.xml -function Switch-OBSInputMute { +function Set-OBSSwitchSource { + + + [Alias('Add-OBSSwitchSource','Get-OBSSwitchSource')] + param( + # The path to the media file. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('Sources')] + [string[]] + $SourceList, + # What to select in the playlist. + # If a number is provided, this will select an index. + # If a string is provided, this will select the whole name or last part of a name, accepting wildcards. + [Parameter(ValueFromPipelineByPropertyName)] + [ValidateScript({ + $validTypeList = [System.Int32],[System.String] + + $thisType = $_.GetType() + $IsTypeOk = + $(@( foreach ($validType in $validTypeList) { + if ($_ -as $validType) { + $true;break + } + })) + + if (-not $isTypeOk) { + throw "Unexpected type '$(@($thisType)[0])'. Must be 'int','string'." + } + return $true + })] + + [Alias('SelectIndex','SelectName')] + $Select, -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'ToggleInputMute')] -[Alias('obs.powershell.websocket.ToggleInputMute')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( + # If set, the list of sources will loop. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("loop")] + [Alias('Looping')] + [switch] + $Loop, -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputName')] -[string] -$InputName, + # If set, will switch between sources. + # Sources will be displayed for a -Duration. + # No source wil be displayed for an -Interval. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("time_switch")] + [switch] + $TimeSwitch, -[Parameter(ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('inputUuid')] -[string] -$InputUuid, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + # The interval between sources + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("time_switch_between")] + [timespan] + $Interval, + # The duration between sources that are switching at a time. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("time_switch_duration")] + [timespan] + $Duration, -process { + # The item that will be switched in a TimeSwitch, after -Duration and -Interval. + [Parameter(ValueFromPipelineByPropertyName)] + [ValidateSet("None","Next","Previous","First","Last","Random")] + [string] + $TimeSwitchTo = "Next", + # If set, will switch on the underlying source's media state events. + # Sources will be displayed for a -Duration. + # No source wil be displayed for an -Interval. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("media_state_switch")] + [switch] + $MediaStateSwitch, - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + # The change in media state that should trigger a switch + [Parameter(ValueFromPipelineByPropertyName)] + [ValidateSet("Playing","Opening","Buffering","Paused","Stopped","Ended", "Error","Playing","NotOpening","NotBuffering","NotPaused","NotStopped","NotEnded", "NotError")] + $MediaStateChange, - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + # When the source switcher is trigger by media end, this determines the next source that will be switched to. + [Parameter(ValueFromPipelineByPropertyName)] + [ValidateSet("None","Next","Previous","First","Last","Random")] + [string] + $MediaSwitchTo = "Next", - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } + # The name of the transition between sources. + [ArgumentCompleter({ + param ( $commandName, + $parameterName, + $wordToComplete, + $commandAst, + $fakeBoundParameters ) + if (-not $script:OBSTransitionKinds) { + $script:OBSTransitionKinds = @(Get-OBSTransitionKind) -replace '_transition$' + } + + if ($wordToComplete) { + $toComplete = $wordToComplete -replace "^'" -replace "'$" + return @($script:OBSTransitionKinds -like "$toComplete*" -replace '^', "'" -replace '$',"'") + } else { + return @($script:OBSTransitionKinds -replace '^', "'" -replace '$',"'") } + })] + [Parameter(ValueFromPipelineByPropertyName)] + [string] + $TransitionName, - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } + # The properties sent to the transition. + # Notice: this current requires confirmation in the UI. + [Parameter(ValueFromPipelineByPropertyName)] + [PSObject] + $TransitionProperty, + + # The name of the transition used to show a source. + [ArgumentCompleter({ + param ( $commandName, + $parameterName, + $wordToComplete, + $commandAst, + $fakeBoundParameters ) + if (-not $script:OBSTransitionKinds) { + $script:OBSTransitionKinds = @(Get-OBSTransitionKind) -replace '_transition$' } - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload + if ($wordToComplete) { + $toComplete = $wordToComplete -replace "^'" -replace "'$" + return @($script:OBSTransitionKinds -like "$toComplete*" -replace '^', "'" -replace '$',"'") } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + return @($script:OBSTransitionKinds -replace '^', "'" -replace '$',"'") } + })] + [Parameter(ValueFromPipelineByPropertyName)] + [string] + $ShowTransition, -} - + # The properties sent to the show transition. + # Notice: this current requires confirmation in the UI. + [Parameter(ValueFromPipelineByPropertyName)] + [PSObject] + $ShowTransitionProperty, -} + # The transition used to hide a source. + [ArgumentCompleter({ + param ( $commandName, + $parameterName, + $wordToComplete, + $commandAst, + $fakeBoundParameters ) + if (-not $script:OBSTransitionKinds) { + $script:OBSTransitionKinds = @(Get-OBSTransitionKind) -replace '_transition$' + } + + if ($wordToComplete) { + $toComplete = $wordToComplete -replace "^'" -replace "'$" + return @($script:OBSTransitionKinds -like "$toComplete*" -replace '^', "'" -replace '$',"'") + } else { + return @($script:OBSTransitionKinds -replace '^', "'" -replace '$',"'") + } + })] + [Parameter(ValueFromPipelineByPropertyName)] + [string] + $HideTransition, - -#.ExternalHelp obs-powershell-Help.xml -function Switch-OBSOutput { + # The properties sent to the hide transition. + # Notice: this current requires confirmation in the UI. + [Parameter(ValueFromPipelineByPropertyName)] + [PSObject] + $HideTransitionProperty, + # The name of the scene. + # If no scene name is provided, the current program scene will be used. + [Parameter(ValueFromPipelineByPropertyName)] + [string] + $Scene, -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'ToggleOutput')] -[Alias('obs.powershell.websocket.ToggleOutput')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( + # The name of the input. + # If no name is provided, the last segment of the URI or file path will be the input name. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('InputName','SourceName')] + [string] + $Name, -[Parameter(Mandatory,ValueFromPipelineByPropertyName)] -[ComponentModel.DefaultBindingProperty('outputName')] -[string] -$OutputName, -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + # If set, will check if the source exists in the scene before creating it and removing any existing sources found. + # If not set, you will get an error if a source with the same name exists. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $Force, + # If set, will fit the input to the screen. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $FitToScreen + ) + dynamicParam { + $baseCommand = + if (-not $script:AddOBSInput) { + $script:AddOBSInput = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') + $script:AddOBSInput + } else { + $script:AddOBSInput + } + $IncludeParameter = @() + $ExcludeParameter = 'inputKind','sceneName','inputName' -process { + $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() + :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { + if ($ExcludeParameter) { + foreach ($exclude in $ExcludeParameter) { + if ($paramName -like $exclude) { continue nextInputParameter} + } + } + if ($IncludeParameter) { + $shouldInclude = + foreach ($include in $IncludeParameter) { + if ($paramName -like $include) { $true;break} + } + if (-not $shouldInclude) { continue nextInputParameter } + } + + $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( + $baseCommand.Parameters[$paramName].Name, + $baseCommand.Parameters[$paramName].ParameterType, + $baseCommand.Parameters[$paramName].Attributes + )) + } + $DynamicParameters - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + } + begin { + filter OutputAndFitToScreen { + + if ($FitToScreen -and $_.FitToScreen) { + $_.FitToScreen() + } + $_ + + } + $InputKind = "source_switcher" + + } + process { + # Copy the bound parameters + $myParameters = [Ordered]@{} + $PSBoundParameters + # and determine the name of the invocation + $MyInvocationName = "$($MyInvocation.InvocationName)" + # Split it into verb and noun + $myVerb, $myNoun = $MyInvocationName -split '-' + # and get a copy of ourself that we can call with anonymous recursion. + $myScriptBlock = $MyInvocation.MyCommand.ScriptBlock + # Determine if the verb was get, + $IsGet = $myVerb -eq "Get" + # if no verb was used, + $NoVerb = $MyInvocationName -match '^[^\.\&][^-]+$' + # and if there were any other parameters then name + $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + # If it is a get or there was no verb + if ($IsGet -or $NoVerb) { + $inputsOfKind = # Get all inputs of this kind + Get-OBSInput -InputKind $InputKind | + Where-Object { + if ($Name) { # If -Name was provided, + $_.InputName -like $Name # filter by name (as a wildcard). + } else { + $_ # otherwise, return every input. + } + } + + # If there were parameters other than name, + # and we were not explicitly called Get-* + if ($NonNameParameters -and -not $IsGet) { + # remove the name parameter + if ($myParameters.Name) { $myParameters.Remove('Name') } + # and pipe results back to ourself. + $inputsOfKind | & $myScriptBlock @myParameters + } else { + # Otherwise, we're just getting the list of inputs + $inputsOfKind + } + # (either way, if we were called Get- or with no verb, we're done now). + return + } + + if (-not $myParameters["Scene"]) { + $myParameters["Scene"] = Get-OBSCurrentProgramScene | + Select-Object -ExpandProperty currentProgramSceneName } + + $myParameterData = [Ordered]@{} + foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } + $bindToPropertyName = $null + + foreach ($attribute in $parameter.Attributes) { + if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { + $bindToPropertyName = $attribute.Name + break } } - } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + if (-not $bindToPropertyName) { continue } + if ($myParameters.Contains($parameter.Name)) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] + if ($myParameters[$parameter.Name] -is [switch]) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] -as [bool] + } + if ($myParameters[$parameter.Name] -is [timespan]) { + $myParameterData[$bindToPropertyName] = [int]$myParameters[$parameter.Name].TotalMilliseconds } } } - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } + + $selectedIndex = -1 + $sourcesObject = @( + $currentIndex = -1 + foreach ($sourceName in $SourceList) { + $currentIndex++ + $selected = ($null -ne $Select) -and ( + ($select -is [int] -and $currentIndex -eq $select) -or + ($select -is [string] -and + ($sourceName -like $select -or ($sourceName | Split-Path -Leaf -ErrorAction Ignore) -like $Select) + ) + ) + if ($selected) { + $selectedIndex = $currentIndex + } + [PSCustomObject][Ordered]@{hidden=$false;selected=$selected;value=$sourceName} + } + ) - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + if ($sourcesObject) { + $myParameterData['sources'] = $sourcesObject + if ($selectedIndex -gt 0) { + $myParameterData["current_index"] = $selectedIndex + } + } + elseif ($Select -is [int]) { + $myParameterData['current_index'] = $Select } + -} + + if ($TransitionName) { + if ($TransitionName -notlike '*_transition') { + $TransitionName = "${TransitionName}_transition" + } + $myParameterData["transition"] = $TransitionName + } + + if ($TransitionProperty) { + $myParameterData["transition_properties"] = $TransitionProperty + } + if ($ShowTransition) { + if ($ShowTransition -notlike '*_transition') { + $ShowTransition = "${ShowTransition}_transition" + } + $myParameterData["show_transition"] = $ShowTransition + } -} + if ($ShowTransitionProperty) { + $myParameterData["show_transition_properties"] = $ShowTransitionProperty + } - -#.ExternalHelp obs-powershell-Help.xml -function Switch-OBSRecord { + if ($HideTransition) { + if ($HideTransition -notlike '*_transition') { + $HideTransition = "${HideTransition}_transition" + } + $myParameterData["hide_transition"] = $ShowTransition + } + if ($HideTransitionProperty) { + $myParameterData["hide_transition_properties"] = $HideTransitionProperty + } -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'ToggleRecord')] -[Alias('obs.powershell.websocket.ToggleRecord')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + if ($TimeSwitchTo) { + $validValues = $MyInvocation.MyCommand.Parameters["TimeSwitchTo"].Attributes.ValidValues + for ($vvi = 0; $vvi -lt $validValues.Length;$vvi++) { + if ($TimeSwitchTo -eq $validValues[$vvi]) { + $myParameterData["time_switch_to"] = $vvi + break + } + } + } + if ($MediaSwitchTo) { + $validValues = $MyInvocation.MyCommand.Parameters["MediaSwitchTo"].Attributes.ValidValues + for ($vvi = 0; $vvi -lt $validValues.Length;$vvi++) { + if ($TimeSwitchTo -eq $validValues[$vvi]) { + $myParameterData["media_state_switch_to"] = $vvi + break + } + } + } -process { + if ($MediaStateChange) { + $validValues = $MyInvocation.MyCommand.Parameters["MediaStateChange"].Attributes.ValidValues + for ($vvi = 0; $vvi -lt $validValues.Length;$vvi++) { + if ($TimeSwitchTo -eq $validValues[$vvi]) { + $myParameterData["media_switch_state"] = $vvi + break + } + } + } + + if (-not $Name) { + $Name = $myParameters["Name"] = "Source Switcher" + } + - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + $addSplat = [Ordered]@{ + sceneName = $myParameters["Scene"] + inputKind = $InputKind + inputSettings = $myParameterData + inputName = $Name + NoResponse = $myParameters["NoResponse"] + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if ($myParameters.Contains('SceneItemEnabled')) { + $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + # If -PassThru was passed + if ($MyParameters["PassThru"]) { + # pass it down to each command + $addSplat.Passthru = $MyParameters["PassThru"] + # If we were called with Add- + if ($MyInvocation.InvocationName -like 'Add-*') { + Add-OBSInput @addSplat # passthru Add-OBSInput + } else { + # Otherwise, remove SceneItemEnabled, InputKind, and SceneName + $addSplat.Remove('SceneItemEnabled') + $addSplat.Remove('inputKind') + $addSplat.Remove('sceneName') + # and passthru Set-OBSInputSettings. + Set-OBSInputSettings @addSplat } + return } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + # Add the input. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + + # If we got back an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # and that error was saying the source already exists, + if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { + # then check if we use the -Force. + if ($Force) { # If we do, remove the input + Remove-OBSInput -InputName $addSplat.inputName + # and re-add our result. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + } else { + # Otherwise, get the input from the scene, + $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $myParameters["Name"] + # update the input settings + if ($sceneItem) { + $sceneItem.Input.Settings = $addSplat.inputSettings + $sceneItem # and return the scene item. + $outputAddedResult = $null + } } } + + # If the output was still an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # use $psCmdlet.WriteError so that it shows the error correctly. + $psCmdlet.WriteError($outputAddedResult) + } } - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" + # Otherwise, if we had a result + if ($outputAddedResult -and + $outputAddedResult -isnot [Management.Automation.ErrorRecord]) { + # get the input from the scene and optionally fit it to the screen. + Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $name | + OutputAndFitToScreen + } + + } +} + +#.ExternalHelp obs-powershell-Help.xml +function Set-OBSVLCSource { + + + [Alias('Add-OBSVLCSource','Set-OBSPlaylistSource','Add-OBSPlaylistSource','Get-OBSVLCSource','Get-OBSPlaylistSource')] + param( + # The path to the media file. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('FullName','LocalFile','local_file','Playlist')] + [string[]] + $FilePath, + + # What to select in the playlist. + # If a number is provided, this will select an index. + # If a string is provided, this will select the whole name or last part of a name, accepting wildcards. + # If an `[IO.FileInfo]` is provided, this will be the exact file. + [Parameter(ValueFromPipelineByPropertyName)] + [ValidateScript({ + $validTypeList = [System.Int32],[System.String],[System.IO.FileInfo] + + $thisType = $_.GetType() + $IsTypeOk = + $(@( foreach ($validType in $validTypeList) { + if ($_ -as $validType) { + $true;break + } + })) - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } + if (-not $isTypeOk) { + throw "Unexpected type '$(@($thisType)[0])'. Must be 'int','string','System.IO.FileInfo'." + } + return $true + })] + + [Alias('SelectIndex','SelectName')] + $Select, -} + # If set, will shuffle the playlist + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("shuffle")] + [switch] + $Shuffle, + # If set, the playlist will loop. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("loop")] + [Alias('Looping')] + [switch] + $Loop, -} + # If set, will show subtitles, if available. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("subtitle_enable")] + [Alias('ShowSubtitles','Subtitles')] + [switch] + $Subtitle, - -#.ExternalHelp obs-powershell-Help.xml -function Switch-OBSRecordPause { + # The selected audio track number. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("track")] + [int] + $AudioTrack, + # The selected subtitle track number. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("subtitle")] + [int] + $SubtitleTrack, -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'ToggleRecordPause')] -[Alias('obs.powershell.websocket.ToggleRecordPause')] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + # The name of the scene. + # If no scene name is provided, the current program scene will be used. + [Parameter(ValueFromPipelineByPropertyName)] + [string] + $Scene, + # The name of the input. + # If no name is provided, the last segment of the URI or file path will be the input name. + [Parameter(ValueFromPipelineByPropertyName)] + [string] + $Name, -process { + # If set, will check if the source exists in the scene before creating it and removing any existing sources found. + # If not set, you will get an error if a source with the same name exists. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $Force, + # If set, will fit the input to the screen. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $FitToScreen + ) + dynamicParam { + $baseCommand = + if (-not $script:AddOBSInput) { + $script:AddOBSInput = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') + $script:AddOBSInput + } else { + $script:AddOBSInput + } + $IncludeParameter = @() + $ExcludeParameter = 'inputKind','sceneName','inputName' - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() + :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { + if ($ExcludeParameter) { + foreach ($exclude in $ExcludeParameter) { + if ($paramName -like $exclude) { continue nextInputParameter} + } } - - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } + if ($IncludeParameter) { + $shouldInclude = + foreach ($include in $IncludeParameter) { + if ($paramName -like $include) { $true;break} } - } + if (-not $shouldInclude) { continue nextInputParameter } } + + $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( + $baseCommand.Parameters[$paramName].Name, + $baseCommand.Parameters[$paramName].ParameterType, + $baseCommand.Parameters[$paramName].Attributes + )) + } + $DynamicParameters - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] + } + begin { + filter OutputAndFitToScreen { + + if ($FitToScreen -and $_.FitToScreen) { + $_.FitToScreen() } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" + $_ + + } + $InputKind = "vlc_source" + + } + process { + # Copy the bound parameters + $myParameters = [Ordered]@{} + $PSBoundParameters + # and determine the name of the invocation + $MyInvocationName = "$($MyInvocation.InvocationName)" + # Split it into verb and noun + $myVerb, $myNoun = $MyInvocationName -split '-' + # and get a copy of ourself that we can call with anonymous recursion. + $myScriptBlock = $MyInvocation.MyCommand.ScriptBlock + # Determine if the verb was get, + $IsGet = $myVerb -eq "Get" + # if no verb was used, + $NoVerb = $MyInvocationName -match '^[^\.\&][^-]+$' + # and if there were any other parameters then name + $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' + + # If it is a get or there was no verb + if ($IsGet -or $NoVerb) { + $inputsOfKind = # Get all inputs of this kind + Get-OBSInput -InputKind $InputKind | + Where-Object { + if ($Name) { # If -Name was provided, + $_.InputName -like $Name # filter by name (as a wildcard). + } else { + $_ # otherwise, return every input. + } } - continue nextParam - } + + # If there were parameters other than name, + # and we were not explicitly called Get-* + if ($NonNameParameters -and -not $IsGet) { + # remove the name parameter + if ($myParameters.Name) { $myParameters.Remove('Name') } + # and pipe results back to ourself. + $inputsOfKind | & $myScriptBlock @myParameters + } else { + # Otherwise, we're just getting the list of inputs + $inputsOfKind } + # (either way, if we were called Get- or with no verb, we're done now). + return } - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + if (-not $myParameters["Scene"]) { + $myParameters["Scene"] = Get-OBSCurrentProgramScene | + Select-Object -ExpandProperty currentProgramSceneName } + + $myParameterData = [Ordered]@{} + foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { -} - - -} + $bindToPropertyName = $null + + foreach ($attribute in $parameter.Attributes) { + if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { + $bindToPropertyName = $attribute.Name + break + } + } + if (-not $bindToPropertyName) { continue } + if ($myParameters.Contains($parameter.Name)) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] + if ($myParameters[$parameter.Name] -is [switch]) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] -as [bool] + } + } + } + + $allPaths = @(foreach ($path in $FilePath) { + foreach ($_ in $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($path)) { + $_.Path + } + }) + $playlistObject = @( + $currentIndex = 0 + foreach ($path in $allPaths) { + $currentIndex++ + $selected = $Select -and ( + ($select -is [int] -and $currentIndex -eq $select) -or + ($select -is [IO.FileInfo] -and $path -eq $select.FullName) -or + ($select -is [string] -and + ($path -like $select -or ($path | Split-Path -Leaf) -like $Select) + ) + ) + [PSCustomObject][Ordered]@{hidden=$false;selected=$selected;value=$path} + } + ) + $myParameterData['playlist'] = $playlistObject -#.ExternalHelp obs-powershell-Help.xml -function Switch-OBSReplayBuffer { - - -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'ToggleReplayBuffer')] -[Alias('obs.powershell.websocket.ToggleReplayBuffer')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) - - -process { - + if (-not $Name) { + $Name = $myParameters["Name"] = $FilePathItem.Name + } - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + $addSplat = [Ordered]@{ + sceneName = $myParameters["Scene"] + inputKind = $InputKind + inputSettings = $myParameterData + inputName = $Name + NoResponse = $myParameters["NoResponse"] + } - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} + if ($myParameters.Contains('SceneItemEnabled')) { + $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] } - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } + # If -PassThru was passed + if ($MyParameters["PassThru"]) { + # pass it down to each command + $addSplat.Passthru = $MyParameters["PassThru"] + # If we were called with Add- + if ($MyInvocation.InvocationName -like 'Add-*') { + Add-OBSInput @addSplat # passthru Add-OBSInput + } else { + # Otherwise, remove SceneItemEnabled, InputKind, and SceneName + $addSplat.Remove('SceneItemEnabled') + $addSplat.Remove('inputKind') + $addSplat.Remove('sceneName') + # and passthru Set-OBSInputSettings. + Set-OBSInputSettings @addSplat } + return } - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam + # Add the input. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + + # If we got back an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # and that error was saying the source already exists, + if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { + # then check if we use the -Force. + if ($Force) { # If we do, remove the input + Remove-OBSInput -InputName $addSplat.inputName + # and re-add our result. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + } else { + # Otherwise, get the input from the scene, + $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $myParameters["Name"] + # update the input settings + $sceneItem.Input.Settings = $addSplat.inputSettings + $sceneItem # and return the scene item. + $outputAddedResult = $null } } + + # If the output was still an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # use $psCmdlet.WriteError so that it shows the error correctly. + $psCmdlet.WriteError($outputAddedResult) + } } - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } - - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse + # Otherwise, if we had a result + if ($outputAddedResult -and + $outputAddedResult -isnot [Management.Automation.ErrorRecord]) { + # get the input from the scene and optionally fit it to the screen. + Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $name | + OutputAndFitToScreen } - + + } } - - -} - #.ExternalHelp obs-powershell-Help.xml -function Switch-OBSStream { +function Set-OBSWaveformSource { + + + [Alias('Add-OBSWaveformSource','Get-OBSWaveformSource')] + param( + # The width of the browser source. + # If none is provided, this will be the output width of the video settings. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("width")] + [int] + $Width, + + # The width of the browser source. + # If none is provided, this will be the output height of the video settings. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("height")] + [int] + $Height, + # The audio source for the waveform. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("audio_source")] + [string] + $AudioSource, -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'ToggleStream')] -[Alias('obs.powershell.websocket.ToggleStream')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + # The display mode for the waveform. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("display_mode")] + [ValidateSet("curve","bars","stepped_bars","level_meter","stepped_level_meter")] + [string] + $DisplayMode, + # The render mode for the waveform. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("render_mode")] + [ValidateSet("line","solid","gradient")] + [string] + $RenderMode, -process { + # The windowing mode for the waveform. + # This is the mathematical function used to determine the current "window" of audio data. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("render_mode")] + [ValidateSet("hann","hamming","blackman","blackman_harris","none")] + [string] + $WindowMode, + + # The color used for the waveform. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("color_base")] + [PSObject] + $Color, + # The crest color used for the waveform. + # This will be ignored if the render mode is not "gradient". + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("color_crest")] + [PSObject] + $CrestColor, - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + # The channel mode for the waveform. + # This can be either mono or stereo. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("channel_mode")] + [ValidateSet("mono","stereo")] + [string] + $ChannelMode, - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + # The number of pixels between each channel in stereo mode + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("channel_spacing")] + [int] + $ChannelSpacing, - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } + # If set, will use a radial layout for the waveform + # Radial layouts will ignore the desired height of the source and instead create a square. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("radial_layout")] + [switch] + $RadialLayout, - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } + # If set, will invert the direction for a radial waveform. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("invert_direction")] + [switch] + $InvertRadialDirection, - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } + # If set, will normalize the volume displayed in the waveform. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("normalize_volume")] + [switch] + $NoramlizeVolume, -} + # If set, will automatically declare an FFTSize + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("auto_fft_size")] + [switch] + $AutoFftSize, + # If set, will attempt to make audio peaks render faster. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("fast_peaks")] + [switch] + $FastPeak, -} + # The width of the waveform bar. + # This is only valid when -DisplayMode is 'bars' or 'stepped_bars' + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("bar_width")] + [int] + $BarWidth, - -#.ExternalHelp obs-powershell-Help.xml -function Switch-OBSVirtualCam { + # The gap between waveform bars. + # This is only valid when -DisplayMode is 'bars' or 'stepped_bars' + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("bar_gap")] + [int] + $BarGap, + # The width of waveform bar step. + # This is only valid when -DisplayMode is 'stepped_bars' + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("step_width")] + [int] + $StepWidth, -[Reflection.AssemblyMetadata('OBS.WebSocket.RequestType', 'ToggleVirtualCam')] -[Alias('obs.powershell.websocket.ToggleVirtualCam')] -[Reflection.AssemblyMetadata('OBS.WebSocket.ExpectingResponse', $true)] -param( -# If set, will return the information that would otherwise be sent to OBS. -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('OutputRequest','OutputInput')] -[switch] -$PassThru, -# If set, will not attempt to receive a response from OBS. -# This can increase performance, and also silently ignore critical errors -[Parameter(ValueFromPipelineByPropertyName)] -[Alias('NoReceive','IgnoreResponse','IgnoreReceive','DoNotReceiveResponse')] -[switch] -$NoResponse -) + # The gap between waveform bar steps. + # This is only valid when -DisplayMode is 'stepped_bars' + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("step_gap")] + [int] + $StepGap, + # The low-frequency cutoff of the waveform. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("cutoff_low")] + [int] + $LowCutoff, -process { + # The high-frequency cutoff of the waveform. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("cutoff_high")] + [int] + $HighCutoff, + # The floor of the waveform. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("floor")] + [int] + $Floor, - # Create a copy of the parameters (that are part of the payload) - $paramCopy = [Ordered]@{} - # get a reference to this command - $myCmd = $MyInvocation.MyCommand + # The ceiling of the waveform. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("ceiling")] + [int] + $Ceiling, - # Keep track of how many requests we have done of a given type - # (this makes creating RequestIDs easy) - if (-not $script:ObsRequestsCounts) { - $script:ObsRequestsCounts = @{} - } + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("slope")] + [double] + $Slope, - # Set my requestType to blank - $myRequestType = '' - # and indicate we are not expecting a response - $responseExpected = $false - # Then walk over this commands' attributes, - foreach ($attr in $myCmd.ScriptBlock.Attributes) { - if ($attr -is [Reflection.AssemblyMetadataAttribute]) { - if ($attr.Key -eq 'OBS.WebSocket.RequestType') { - $myRequestType = $attr.Value # set the requestType, - } - elseif ($attr.Key -eq 'OBS.WebSocket.ExpectingResponse') { - # and determine if we are expecting a response. - $responseExpected = - if ($attr.Value -eq 'false') { - $false - } else { $true } - } - } - } + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("rolloff_q")] + [Alias('RollOffOctaves')] + [double] + $RollOffOctave, - # Walk over each parameter - :nextParam foreach ($keyValue in $PSBoundParameters.GetEnumerator()) { - # and walk over each of it's attributes to see if it part of the payload - foreach ($attr in $myCmd.Parameters[$keyValue.Key].Attributes) { - # If the parameter is bound to part of the payload - if ($attr -is [ComponentModel.DefaultBindingPropertyAttribute]) { - # copy it into our payload dicitionary. - $paramCopy[$attr.Name] = $keyValue.Value - # (don't forget to turn switches into booleans) - if ($paramCopy[$attr.Name] -is [switch]) { - $paramCopy[$attr.Name] = [bool]$paramCopy[$attr.Name] - } - if ($attr.Name -like '*path') { - $paramCopy[$attr.Name] = - "$($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($paramCopy[$attr.Name]))" - } - continue nextParam - } - } - } - - # and make a request ID from that. - $myRequestId = "$myRequestType.$([Guid]::newGuid())" - - # Construct the payload object - $requestPayload = [Ordered]@{ - # It must include a request ID - requestId = $myRequestId - # request type - requestType = $myRequestType - # and optional data - requestData = $paramCopy - } + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("rolloff_rate")] + [double] + $RollOffRate, - if ($PassThru) { - [PSCustomObject]$requestPayload - } else { - [PSCustomObject]$requestPayload | - Send-OBS -NoResponse:$NoResponse - } + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("grad_ratio")] + [double] + $GradientRatio, -} + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("deadzone")] + [double] + $Deadzone, + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("temporal_smoothing")] + [ValidateSet("none","exp_moving_avg")] + [string] + $TemporalSmoothing, -} + # The name of the scene. + # If no scene name is provided, the current program scene will be used. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('SceneName')] + [string] + $Scene, - -#.ExternalHelp obs-powershell-Help.xml -function Get-OBSEffect -{ - - param( - # The name of the effect. + # The name of the input. + # If no name is provided, the last segment of the URI or file path will be the input name. [Parameter(ValueFromPipelineByPropertyName)] - [Alias('EffectName')] + [Alias('InputName')] [string] - $Name - ) + $Name, - begin { - if (-not $script:OBSFX) { - $script:OBSFX = [Ordered]@{} + # If set, will check if the source exists in the scene before creating it and removing any existing sources found. + # If not set, you will get an error if a source with the same name exists. + [Parameter(ValueFromPipelineByPropertyName)] + [switch] + $Force + ) + dynamicParam { + $baseCommand = + if (-not $script:AddOBSInput) { + $script:AddOBSInput = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') + $script:AddOBSInput + } else { + $script:AddOBSInput } - } + $IncludeParameter = @() + $ExcludeParameter = 'inputKind','sceneName','inputName' - process { - if (-not $Name) { - $script:OBSFX.Values - } elseif ($script:OBSFX[$name]) { - $script:OBSFX[$name] + $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() + :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { + if ($ExcludeParameter) { + foreach ($exclude in $ExcludeParameter) { + if ($paramName -like $exclude) { continue nextInputParameter} + } } + if ($IncludeParameter) { + $shouldInclude = + foreach ($include in $IncludeParameter) { + if ($paramName -like $include) { $true;break} + } + if (-not $shouldInclude) { continue nextInputParameter } + } + + $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( + $baseCommand.Parameters[$paramName].Name, + $baseCommand.Parameters[$paramName].ParameterType, + $baseCommand.Parameters[$paramName].Attributes + )) } -} -#.ExternalHelp obs-powershell-Help.xml -function Import-OBSEffect { + $DynamicParameters - - param( - # The source location of the effect. - # This can be a string, file, directory, command, or module. - [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)] - [Alias( - 'FromPath', - 'FromModule', - 'FromScript', - 'FromFunction', - 'FullName', - 'Path', - 'Source' - )] - [ValidateScript({ - $validTypeList = [System.String],[System.IO.FileInfo],[System.IO.DirectoryInfo],[System.Management.Automation.CommandInfo],[System.Management.Automation.PSModuleInfo] - - $thisType = $_.GetType() - $IsTypeOk = - $(@( foreach ($validType in $validTypeList) { - if ($_ -as $validType) { - $true;break - } - })) - - if (-not $isTypeOk) { - throw "Unexpected type '$(@($thisType)[0])'. Must be 'string','System.IO.FileInfo','System.IO.DirectoryInfo','System.Management.Automation.CommandInfo','psmoduleinfo'." } - return $true - })] + begin { + $inputKind = "phandasm_waveform_source" + filter ToOBSColor { + + if ($_ -is [uint32]) { $_ } + elseif ($_ -is [string]) { + if ($_ -match '^\#[a-f0-9]{3,4}$') { + $_ = $_ -replace '[a-f0-9]','$0$0' + } + + if ($_ -match '^#[a-f0-9]{8}$') { + ( + '0x' + + (($_ -replace '#').ToCharArray()[0,1,-1,-2,-3,-4,-5,-6] -join '') + ) -as [UInt32] + } + elseif ($_ -match '^#[a-f0-9]{6}$') { + + ( + '0xff' + + (($_ -replace '#').ToCharArray()[-1..-6] -join '') + ) -as [UInt32] + } + } + + } - $From - ) + } + process { + $myParameters = [Ordered]@{} + $PSBoundParameters - begin { - if (-not $script:OBSFX) { - $script:OBSFX = [Ordered]@{} - } + $MyInvocationName = "$($MyInvocation.InvocationName)" + $myVerb, $myNoun = $MyInvocationName -split '-' + $myScriptBlock = $MyInvocation.MyCommand.ScriptBlock + $IsGet = $myVerb -eq "Get" + $NoVerb = $MyInvocationName -match '^[^\.\&][^-]+$' + $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' - $newEffects = @() - $obsEffectsPattern = [Regex]::new(' - (?> - ^OBS.(?>fx|effects?)\p{P} - | - [\p{P}-[-]]OBS\.(?>fx|effects?)$ - | - \p{P}OBS.(?>fx|effects?)\.(?>ps1|json)$ - ) - ','IgnoreCase,IgnorePatternWhitespace') - } + if ( + $IsGet -or + $NoVerb + ) { + $inputsOfKind = + Get-OBSInput -InputKind $InputKind | + Where-Object { + if ($Name) { + $_.InputName -like $Name + } else { + $_ + } + } + if ($NonNameParameters -and -not $IsGet) { + $paramCopy = [Ordered]@{} + $PSBoundParameters + if ($paramCopy.Name) { $paramCopy.Remove('Name') } + $inputsOfKind | & $myScriptBlock @paramCopy + } else { + $inputsOfKind + } + return + } + + if ((-not $width) -or (-not $height)) { + if (-not $script:CachedOBSVideoSettings) { + $script:CachedOBSVideoSettings = Get-OBSVideoSettings + } + $videoSettings = $script:CachedOBSVideoSettings + $myParameters["Width"] = $width = $videoSettings.outputWidth + $myParameters["Height"] = $height = $videoSettings.outputHeight + } - process { - # Since -From can be many things, but a metric has to be a command, - # the purpose of this function is to essentially resolve many things to a command, - # and then cache that command. + if (-not $myParameters["Scene"]) { + $myParameters["Scene"] = Get-OBSCurrentProgramScene | + Select-Object -ExpandProperty currentProgramSceneName + } + + $myParameterData = [Ordered]@{} + foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { - # If -From was a string - if ($From -is [string]) { - # It could be a module, so check those first. - :ResolveFromString do { - foreach ($loadedModule in @(Get-Module)) { - # If we find the module, don't try to resolve -From as a path - if ($loadedModule.Name -eq $from) { - # (just set -From again and let the function continue) - $from = $fromModule = $loadedModule;break ResolveFromString - } - + $bindToPropertyName = $null + + foreach ($attribute in $parameter.Attributes) { + if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { + $bindToPropertyName = $attribute.Name + break } - # If we think from was a path - $resolvedPath = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($from) - # attempt to resolve it - if ($resolvedPath) { - $from = Get-Item -LiteralPath $resolvedPath + } + + if (-not $bindToPropertyName) { continue } + if ($myParameters.Contains($parameter.Name)) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] + if ($myParameters[$parameter.Name] -is [switch]) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] -as [bool] } - } while ($false) + } } - # If -From is a module - if ($from -is [Management.Automation.PSModuleInfo]) { - # recursively call ourselves with all matching commands - @($from.ExportedCommands.Values) -match $obsEffectsPattern | - Import-OBSEffect - # then, make -From a directory - if ($from.Path) { - $from = Get-Item ($from.Path | Split-Path) -ErrorAction SilentlyContinue - } + + + if (-not $Name) { + $Name = $myParameters['Name'] = + if ($AudioSource) { + "$($AudioSource)-Waveform" + } else { + "Waveform" + } } - # If -From is a directory - if ($from -is [IO.DirectoryInfo]) { - $FromDirectory = $from - # recursively call ourselves with all matching scripts - Get-ChildItem -LiteralPath $from.FullName -Recurse -File | - Where-Object Name -match '\.obs\.(?>fx|effects?).(?>ps1|json)$' | - Import-OBSEffect - return + if ($myParameterData.color_base) { + $myParameterData.color_base = $myParameterData.color_base | ToOBSColor + } + + if ($myParameterData.color_crest) { + $myParameterData.color_crest = $myParameterData.color_crest | ToOBSColor } - # If -From is a file - if ($from -is [IO.FileInfo]) { - # and it matches the naming convention - if ($from.Name -notmatch '\.obs\.(?>fx|effects?).(?>ps1|json)$') { return } - # make -From a command. - $from = $ExecutionContext.SessionState.InvokeCommand.GetCommand($from.FullName, 'ExternalScript,Application') + $addSplat = [Ordered]@{ + sceneName = $myParameters["Scene"] + inputKind = $inputKind + inputSettings = $myParameterData + inputName = $Name + NoResponse = $myParameters["NoResponse"] + } + # If -SceneItemEnabled was passed, + if ($myParameters.Contains('SceneItemEnabled')) { + # propagate it to Add-OBSInput. + $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] } - # If -From is a command - if ($from -is [Management.Automation.CommandInfo]) { - # decorate the command - if ($from.pstypenames -notcontains 'OBS.PowerShell.Effect') { - $from.pstypenames.insert(0,'OBS.PowerShell.Effect') + # If -PassThru was passed + if ($MyParameters["PassThru"]) { + # pass it down to each command + $addSplat.Passthru = $MyParameters["PassThru"] + # If we were called with Add- + if ($MyInvocation.InvocationName -like 'Add-*') { + Add-OBSInput @addSplat # passthru Add-OBSInput + } else { + # Otherwise, remove SceneItemEnabled, InputKind, and SceneName + $addSplat.Remove('SceneItemEnabled') + $addSplat.Remove('inputKind') + $addSplat.Remove('sceneName') + # and passthru Set-OBSInputSettings. + Set-OBSInputSettings @addSplat } + return + } + + # Add the input. + $outputAddedResult = Add-OBSInput @addSplat *>&1 - if ($from -is [Management.Automation.ApplicationInfo]) { - $effectName = $from.Name -replace '\.obs\.(?>fx|effects?).(?>ps1|json)$' - $newEffect = [PSCustomObject][Ordered]@{ - PSTypeName = 'OBS.PowerShell.Effect' - Messages = Get-Content -Raw -Path $From.Source | ConvertFrom-Json - EffectName = $effectName - TypeName = $TypeName - } - $script:OBSFX[$effectName] = $newEffect - $newEffects += $newEffect - $newEffect - } else { - if ($from.pstypenames -notcontains 'OBS.PowerShell.Effect.Command') { - $from.pstypenames.insert(0,'OBS.PowerShell.Effect.Command') + # If we got back an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # and that error was saying the source already exists, + if ($outputAddedResult.TargetObject.d.requestStatus.code -eq 601) { + # then check if we use the -Force. + if ($Force) { # If we do, remove the input + Remove-OBSInput -InputName $addSplat.inputName + # and re-add our result. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + } else { + # Otherwise, get the input from the scene, + $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $myParameters["Name"] + # update the input settings + $sceneItem.Input.Settings = $addSplat.inputSettings + $sceneItem # and return the scene item. + $outputAddedResult = $null } - # and add it to our list of new metrics - $newEffects+= $from - $script:OBSFX[$from.EffectName] = $from - $from - } - } - } - - - -} - - -#.ExternalHelp obs-powershell-Help.xml -function Remove-OBSEffect -{ - - param( - # The name of the effect. - [Parameter(Mandatory,ValueFromPipelineByPropertyName)] - [Alias('Name')] - [string] - $EffectName - ) + } - begin { - if (-not $script:OBSFX) { - $script:OBSFX = [Ordered]@{} + # If the output was still an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # use $psCmdlet.WriteError so that it shows the error correctly. + $psCmdlet.WriteError($outputAddedResult) + } } - } - - process { - if ($script:OBSFX[$name]) { - $script:OBSFX.Stop() - $script:OBSFX.Remove($name) + # Otherwise, if we had a result + if ($outputAddedResult -and + $outputAddedResult -isnot [Management.Automation.ErrorRecord]) { + # get the input from the scene. + Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $myParameters["Name"] } + } } #.ExternalHelp obs-powershell-Help.xml -function Start-OBSEffect -{ +function Set-OBSWindowSource { - [CmdletBinding(PositionalBinding=$false)] + + [Alias('Add-OBSWindowSource','Set-OBSWindowCaptureSource','Add-OBSWindowCaptureSource','Get-OBSWindowSource','Get-OBSWindowCaptureSource')] param( - # The name of the effect. - [ArgumentCompleter({ - param ( $commandName, - $parameterName, - $wordToComplete, - $commandAst, - $fakeBoundParameters ) - $effectNames = @(Get-OBSEffect| - Select-Object -Unique -ExpandProperty EffectName) - if ($wordToComplete) { - $toComplete = $wordToComplete -replace "^'" -replace "'$" - return @($effectNames -like "$toComplete*" -replace '^', "'" -replace '$',"'") - } else { - return @($effectNames -replace '^', "'" -replace '$',"'") - } - })] - [Parameter(Mandatory)] - [string[]] - $EffectName, - - # The duration of the effect. - # If provided, all effects should use this duration. - # If not provided, each effect should use it's own duration. - [Timespan] - $Duration, - - # The parameters passed to the effect. - [Parameter(ValueFromPipelineByPropertyName)] - [Alias('EffectParameters')] - [Collections.IDictionary] - $EffectParameter = @{}, - - # The arguments passed to the effect. - [Parameter(ValueFromRemainingArguments)] - [Alias('EffectArguments')] - [PSObject[]] - $EffectArgument = @(), - - # If provided, will step thru running + # The monitor number. + # This the number of the monitor you would like to capture. [Parameter(ValueFromPipelineByPropertyName)] - [Alias('ticks')] - [int] - $Step, + [Alias('ItemValue','ItemName','WindowName','MainWindowTitle')] + [string] + $WindowTitle, - # The SceneItemID. If this is provided, the effect will be given a target. + # The number of the capture method. By default, automatic (0). [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("method")] [int] - $SceneItemID, + $CaptureMethod, - # The SceneName. If this is provided with a -SceneItemID or -SourceName, the effect will be given a target. + # The capture priority. [Parameter(ValueFromPipelineByPropertyName)] + [ValidateSet('ExactMatch','SameType','SameExecutable')] [string] - $SceneName, + $CapturePriority, - # The Filter Name. If this is provided with a -SourceName, the effect will be given a target. + # If set, will capture the cursor. + # This will be set by default. + # If explicitly set to false, the cursor will not be captured. [Parameter(ValueFromPipelineByPropertyName)] - [string] - $FilterName, + [ComponentModel.DefaultBindingProperty("cursor")] + [switch] + $CaptureCursor, - # The Source Name. If this is provided with a -FitlerName -or -SceneName, the effect will be given a target. + # If set, will capture the client area. + # This will be set by default. [Parameter(ValueFromPipelineByPropertyName)] - [string] - $SourceName, + [ComponentModel.DefaultBindingProperty("client_area")] + [switch] + $ClientArea, - # If set, will loop the effect. + # If set, will force SDR. + [Parameter(ValueFromPipelineByPropertyName)] + [ComponentModel.DefaultBindingProperty("force_sdr")] [switch] - $Loop, + $ForceSDR, - # If provided, will loop the effect a number of times. - [int] - $LoopCount, + # The name of the scene. + # If no scene name is provided, the current program scene will be used. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('SceneName')] + [string] + $Scene, - # If set, will bounce the effect (flip it / reverse it) - [switch] - $Bounce, + # The name of the input. + # If no name is provided, "Display $($Monitor + 1)" will be the input source name. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('InputName')] + [string] + $Name, - # If set, will reverse an effect. + # If set, will check if the source exists in the scene before creating it and removing any existing sources found. + # If not set, you will get an error if a source with the same name exists. + [Parameter(ValueFromPipelineByPropertyName)] [switch] - $Reverse + $Force ) + dynamicParam { + $baseCommand = + if (-not $script:AddOBSInput) { + $script:AddOBSInput = + $executionContext.SessionState.InvokeCommand.GetCommand('Add-OBSInput','Function') + $script:AddOBSInput + } else { + $script:AddOBSInput + } + $IncludeParameter = @() + $ExcludeParameter = 'inputKind','sceneName','inputName' - process { - foreach ($NameOfEffect in $EffectName) { - $obsEffect = Get-OBSEffect -EffectName $NameOfEffect - if (-not $obsEffect) { - Write-Warning "No Effect named '$NameOfEffect'" - continue + $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() + :nextInputParameter foreach ($paramName in ([Management.Automation.CommandMetaData]$baseCommand).Parameters.Keys) { + if ($ExcludeParameter) { + foreach ($exclude in $ExcludeParameter) { + if ($paramName -like $exclude) { continue nextInputParameter} } + } + if ($IncludeParameter) { + $shouldInclude = + foreach ($include in $IncludeParameter) { + if ($paramName -like $include) { $true;break} + } + if (-not $shouldInclude) { continue nextInputParameter } + } + + $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new( + $baseCommand.Parameters[$paramName].Name, + $baseCommand.Parameters[$paramName].ParameterType, + $baseCommand.Parameters[$paramName].Attributes + )) + } + $DynamicParameters - if ($LoopCount) { - $obsEffect | Add-Member -MemberType NoteProperty LoopCount $LoopCount -Force - } + } + begin { + $InputKind = "window_capture" - if ($loop -or $Bounce) { - $obsEffect | Add-Member -MemberType NoteProperty Mode "$(if ($Bounce) {"Bounce"})$(if ($loop) {"Loop"})" -Force - if (-not $LoopCount) { - $obsEffect | Add-Member -MemberType NoteProperty LoopCount -1 -Force - } + } + process { + # Copy the bound parameters + $myParameters = [Ordered]@{} + $PSBoundParameters + # and determine the name of the invocation + $MyInvocationName = "$($MyInvocation.InvocationName)" + # Split it into verb and noun + $myVerb, $myNoun = $MyInvocationName -split '-' + # and get a copy of ourself that we can call with anonymous recursion. + $myScriptBlock = $MyInvocation.MyCommand.ScriptBlock + # Determine if the verb was get, + $IsGet = $myVerb -eq "Get" + # if no verb was used, + $NoVerb = $MyInvocationName -match '^[^\.\&][^-]+$' + # and if there were any other parameters then name + $NonNameParameters = @($PSBoundParameters.Keys) -ne 'Name' + + # If it is a get or there was no verb + if ($IsGet -or $NoVerb) { + $inputsOfKind = # Get all inputs of this kind + Get-OBSInput -InputKind $InputKind | + Where-Object { + if ($Name) { # If -Name was provided, + $_.InputName -like $Name # filter by name (as a wildcard). + } else { + $_ # otherwise, return every input. + } + } + + # If there were parameters other than name, + # and we were not explicitly called Get-* + if ($NonNameParameters -and -not $IsGet) { + # remove the name parameter + if ($myParameters.Name) { $myParameters.Remove('Name') } + # and pipe results back to ourself. + $inputsOfKind | & $myScriptBlock @myParameters } else { - $obsEffect | Add-Member -MemberType NoteProperty Mode "Once" -Force + # Otherwise, we're just getting the list of inputs + $inputsOfKind } + # (either way, if we were called Get- or with no verb, we're done now). + return + } + + if (-not $myParameters["Scene"]) { + $myParameters["Scene"] = Get-OBSCurrentProgramScene | + Select-Object -ExpandProperty currentProgramSceneName + } - if ($Reverse) { - $obsEffect.Reversed = $true + + if (-not $myParameters["WindowTitle"]) { + while ($_ -is [Diagnostics.Process] -and -not $_.MainWindowTitle) { + $_ = $_.Parent } - - if ($obsEffect -isnot [Management.Automation.CommandInfo]) { - if ($step -and $obsEffect.Messages) { - $obsEffect.Step($step) - continue - } - - $obsEffect.Start() - - } else { - if ($step -and $obsEffect.Messages) { - $obsEffect.Step($step) - continue - } - - if (-not $this) { - if ($_.pstypenames -like '*.GetSourceFilter*') { - $this = $_ - } elseif ($FilterName -and $SourceName) { - $this = Get-OBSSourceFilter -SourceName $SourceName -FilterName $FilterName - } - - if ($_.pstypenames -like '*.GetSceneItem*') { - $this = $_ - } elseif ($SceneName -and ($SceneItemID -or $SourceName)) { - $this = - foreach ($sceneItem in Get-OBSSceneItem -SceneName $SceneName) { - if ($SceneItemID -and $sceneItem.SceneItemID -eq $SceneItemID) { - $sceneItem;break - } - elseif ($SceneName -and $sceneItem.SceneName -eq $SceneName) { - $sceneItem;break - } - } - } - } + if ($_.MainWindowTitle) { + $WindowTitle = $myParameters["WindowTitle"] = "$($_.MainWindowTitle)" + } + } - if ($Duration -and $obsEffect.Parameters.Duration) { - $EffectParameter.Duration = $Duration + # Window capture is a bit of a tricky one. + # In order to get the WindowTitle to match that OBS needs, we need to look thru the input properties list. + # and for that, an input needs to exist. + if (-not $myParameters["Name"]) { + if ($myParameters["WindowTitle"]) { + $Name = $myParameters["Name"] = "WindowCapture-" + $myParameters["WindowTitle"] + } + else { + $Name = "WindowCapture" + } + } + + + + + $myParameterData = [Ordered]@{} + foreach ($parameter in $MyInvocation.MyCommand.Parameters.Values) { + + $bindToPropertyName = $null + + foreach ($attribute in $parameter.Attributes) { + if ($attribute -is [ComponentModel.DefaultBindingPropertyAttribute]) { + $bindToPropertyName = $attribute.Name + break } + } - $obsEffectOutput = . $obsEffect @EffectParameter @EffectArgument - if ($obsEffectOutput) { - $obsEffect | Add-Member NoteProperty Messages $obsEffectOutput -Force - if ($step) { - $obsEffect.Step($step) - } else { - $obsEffect.Start() - } + if (-not $bindToPropertyName) { continue } + if ($myParameters.Contains($parameter.Name)) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] + if ($myParameters[$parameter.Name] -is [switch]) { + $myParameterData[$bindToPropertyName] = $myParameters[$parameter.Name] -as [bool] } } - $obsEffect } - - - } -} -#.ExternalHelp obs-powershell-Help.xml -function Stop-OBSEffect -{ - - param( - # The name of the effect. - [Parameter(Mandatory,ValueFromPipelineByPropertyName)] - [string] - $EffectName) - process { - $obsEffect = Get-OBSEffect -EffectName $EffectName + if ($null -ne $CaptureMethod) { + $myParameterData["method"] = $CaptureMethod + } + if ($CapturePriority -eq 'ExactMatch') { + $myParameterData["priority"] = 1 + } + elseif ($CapturePriority -eq 'SameType') { + $myParameterData["priority"] = 0 + } + elseif ($CapturePriority -eq 'SameExecutable') { + $myParameterData["priority"] = 2 + } - if (-not $obsEffect) { return } + $addSplat = @{ + sceneName = $myParameters["Scene"] + inputName = $myParameters["Name"] + inputKind = "window_capture" + inputSettings = $myParameterData + NoResponse = $myParameters["NoResponse"] + } - $obsEffect | Add-Member -MemberType NoteProperty Mode 'Stopped' -Force + # If -SceneItemEnabled was passed, + if ($myParameters.Contains('SceneItemEnabled')) { + # propagate it to Add-OBSInput. + $addSplat.SceneItemEnabled = $myParameters['SceneItemEnabled'] -as [bool] + } + + # Add the input. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + $possibleWindows = Get-OBSInputPropertiesListPropertyItems -InputName $addSplat.inputName -PropertyName window + foreach ($windowInfo in $possibleWindows) { + if (-not $WindowTitle) { continue } + if ( + ($windowInfo.itemName -eq $WindowTitle) -or + ($windowInfo.ItemValue -eq $WindowTitle) -or + ($windowInfo.ItemName -replace '\[[^\[\]]+\]\:\s' -eq $WindowTitle) -or + ($windowInfo.ItemValue -like "*$WindowTitle*") -or + ($windowInfo.ItemName -like "*$WindowTitle*") + ) { + $myParameterData["window"] = $windowInfo.itemValue + break + } + } + + # If -PassThru was passed + if ($MyParameters["PassThru"]) { + # pass it down to each command + # Otherwise, remove SceneItemEnabled, InputKind, and SceneName + $addSplat.PassThru = $true + $addSplat.Remove('SceneItemEnabled') + $addSplat.Remove('inputKind') + $addSplat.Remove('sceneName') + # and passthru Set-OBSInputSettings. + Set-OBSInputSettings @addSplat + + return + } + + if ($Force) { # If we do, remove the input + Remove-OBSInput -InputName $addSplat.inputName + # and re-add our result. + $outputAddedResult = Add-OBSInput @addSplat *>&1 + # If the output was still an error + if ($outputAddedResult -is [Management.Automation.ErrorRecord]) { + # use $psCmdlet.WriteError so that it shows the error correctly. + $psCmdlet.WriteError($outputAddedResult) + } + # Otherwise, if we had a result + elseif ($outputAddedResult) { + # get the input from the scene. + Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $name + } + } else { + # Otherwise, get the input from the scene, + $sceneItem = Get-OBSSceneItem -sceneName $myParameters["Scene"] | + Where-Object SourceName -eq $myParameters["Name"] + # update the input settings + $sceneItem.Input.Settings = $addSplat.inputSettings + $sceneItem # and return the scene item. + } + } -} \ No newline at end of file +} diff --git a/docs/Add-OBS3dPanelShader.md b/docs/Add-OBS3dPanelShader.md new file mode 100644 index 00000000..c72918bf --- /dev/null +++ b/docs/Add-OBS3dPanelShader.md @@ -0,0 +1,149 @@ +Get-OBS3dPanelShader +-------------------- + +### Synopsis +Get-OBS3dPanelShader [[-Credits] ] [[-Scale] ] [[-TiltXDeg] ] [[-TiltYDeg] ] [[-TiltZDeg] ] [[-PosX] ] [[-PosY] ] [[-Thickness] ] [[-RadiusFb] ] [[-Brightness] ] [[-LightPosition] ] [[-Wiggle] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-WiggleRot] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **Brightness** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **Credits** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **LightPosition** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|--------------| +|`[Int]`|false |named |False |light_position| + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PosX** + +|Type |Required|Position|PipelineInput|Aliases| +|---------|--------|--------|-------------|-------| +|`[Float]`|false |named |False |pos_x | + +#### **PosY** + +|Type |Required|Position|PipelineInput|Aliases| +|---------|--------|--------|-------------|-------| +|`[Float]`|false |named |False |pos_y | + +#### **RadiusFb** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------| +|`[Float]`|false |named |False |radius_fb| + +#### **Scale** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Thickness** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **TiltXDeg** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |tilt_x_deg| + +#### **TiltYDeg** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |tilt_y_deg| + +#### **TiltZDeg** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |tilt_z_deg| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Wiggle** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **WiggleRot** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[Switch]`|false |named |False |wiggle_rot| + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBS3dPanelShader [[-Credits] ] [[-Scale] ] [[-TiltXDeg] ] [[-TiltYDeg] ] [[-TiltZDeg] ] [[-PosX] ] [[-PosY] ] [[-Thickness] ] [[-RadiusFb] ] [[-Brightness] ] [[-LightPosition] ] [[-Wiggle] ] [-WiggleRot ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Add-OBSAudioShader.md b/docs/Add-OBSAudioShader.md new file mode 100644 index 00000000..4cc14640 --- /dev/null +++ b/docs/Add-OBSAudioShader.md @@ -0,0 +1,89 @@ +Get-OBSAudioShader +------------------ + +### Synopsis +Get-OBSAudioShader [[-AudioPeak] ] [[-AudioMagnitude] ] [[-Intensity] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **AudioMagnitude** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------------| +|`[Float]`|false |named |False |audio_magnitude| + +#### **AudioPeak** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |audio_peak| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Intensity** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSAudioShader [[-AudioPeak] ] [[-AudioMagnitude] ] [[-Intensity] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Add-OBSCubeRotatingShader.md b/docs/Add-OBSCubeRotatingShader.md new file mode 100644 index 00000000..ca9ab33e --- /dev/null +++ b/docs/Add-OBSCubeRotatingShader.md @@ -0,0 +1,107 @@ +Get-OBSCubeRotatingShader +------------------------- + +### Synopsis +Get-OBSCubeRotatingShader [[-Images] ] [[-Speed] ] [[-Shadow] ] [[-OtherImage1] ] [[-OtherImage2] ] [[-OtherImage3] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Images** + +|Type |Required|Position|PipelineInput| +|-------|--------|--------|-------------| +|`[Int]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **OtherImage1** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|------------| +|`[String]`|false |named |False |other_image1| + +#### **OtherImage2** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|------------| +|`[String]`|false |named |False |other_image2| + +#### **OtherImage3** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|------------| +|`[String]`|false |named |False |other_image3| + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **Shadow** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Speed** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSCubeRotatingShader [[-Images] ] [[-Speed] ] [[-Shadow] ] [[-OtherImage1] ] [[-OtherImage2] ] [[-OtherImage3] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Add-OBSDisplacementMapAdvancedInvertShader.md b/docs/Add-OBSDisplacementMapAdvancedInvertShader.md new file mode 100644 index 00000000..b7e40d58 --- /dev/null +++ b/docs/Add-OBSDisplacementMapAdvancedInvertShader.md @@ -0,0 +1,191 @@ +Get-OBSDisplacementMapAdvancedInvertShader +------------------------------------------ + +### Synopsis +Get-OBSDisplacementMapAdvancedInvertShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-DisplacementCurve] ] [[-BlurInfo] ] [[-BlurSize] ] [[-BlurQuality] ] [[-BlurDirections] ] [[-BlurAngle] ] [[-ChromaticAberrationInfo] ] [[-ChromaticAberration] ] [[-ColorizeInfo] ] [[-ColorizeColor] ] [[-FlagsInfo] ] [[-BackgroundLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-BlueAffectsStrength] [-BlueAffectsColorize] [-BlueAffectsBlur] [-AlphaAffectsStrength] [-ApplyAlpha] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **AlphaAffectsStrength** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------------------| +|`[Switch]`|false |named |False |alpha_affects_strength| + +#### **ApplyAlpha** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------| +|`[Switch]`|false |named |False |apply_alpha| + +#### **BackgroundLayer** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------------| +|`[String]`|false |named |False |background_layer| + +#### **BlueAffectsBlur** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------------| +|`[Switch]`|false |named |False |blue_affects_blur| + +#### **BlueAffectsColorize** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------------------| +|`[Switch]`|false |named |False |blue_affects_colorize| + +#### **BlueAffectsStrength** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------------------| +|`[Switch]`|false |named |False |blue_affects_strength| + +#### **BlurAngle** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |blur_angle| + +#### **BlurDirections** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------------| +|`[Float]`|false |named |False |blur_directions| + +#### **BlurInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------| +|`[String]`|false |named |False |blur_info| + +#### **BlurQuality** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|------------| +|`[Float]`|false |named |False |blur_quality| + +#### **BlurSize** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------| +|`[Float]`|false |named |False |blur_size| + +#### **ChromaticAberration** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------------| +|`[Float]`|false |named |False |chromatic_aberration| + +#### **ChromaticAberrationInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------------------| +|`[String]`|false |named |False |chromatic_aberration_info| + +#### **ColorizeColor** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|--------------| +|`[String]`|false |named |False |colorize_color| + +#### **ColorizeInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |colorize_info| + +#### **DisplacementCurve** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|------------------| +|`[Int]`|false |named |False |displacement_curve| + +#### **DisplacementInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------------| +|`[String]`|false |named |False |displacement_info| + +#### **DisplacementX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_x| + +#### **DisplacementY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_y| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **FlagsInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[String]`|false |named |False |flags_info| + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSDisplacementMapAdvancedInvertShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-DisplacementCurve] ] [[-BlurInfo] ] [[-BlurSize] ] [[-BlurQuality] ] [[-BlurDirections] ] [[-BlurAngle] ] [[-ChromaticAberrationInfo] ] [[-ChromaticAberration] ] [[-ColorizeInfo] ] [[-ColorizeColor] ] [[-FlagsInfo] ] [-BlueAffectsStrength ] [-BlueAffectsColorize ] [-BlueAffectsBlur ] [-AlphaAffectsStrength ] [-ApplyAlpha ] [[-BackgroundLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Add-OBSDisplacementMapAdvancedShader.md b/docs/Add-OBSDisplacementMapAdvancedShader.md new file mode 100644 index 00000000..7d86b0ce --- /dev/null +++ b/docs/Add-OBSDisplacementMapAdvancedShader.md @@ -0,0 +1,191 @@ +Get-OBSDisplacementMapAdvancedShader +------------------------------------ + +### Synopsis +Get-OBSDisplacementMapAdvancedShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-DisplacementCurve] ] [[-BlurInfo] ] [[-BlurSize] ] [[-BlurQuality] ] [[-BlurDirections] ] [[-BlurAngle] ] [[-ChromaticAberrationInfo] ] [[-ChromaticAberration] ] [[-ColorizeInfo] ] [[-ColorizeColor] ] [[-FlagsInfo] ] [[-MaskLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-BlueAffectsStrength] [-BlueAffectsColorize] [-BlueAffectsBlur] [-AlphaAffectsStrength] [-ApplyAlpha] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **AlphaAffectsStrength** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------------------| +|`[Switch]`|false |named |False |alpha_affects_strength| + +#### **ApplyAlpha** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------| +|`[Switch]`|false |named |False |apply_alpha| + +#### **BlueAffectsBlur** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------------| +|`[Switch]`|false |named |False |blue_affects_blur| + +#### **BlueAffectsColorize** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------------------| +|`[Switch]`|false |named |False |blue_affects_colorize| + +#### **BlueAffectsStrength** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------------------| +|`[Switch]`|false |named |False |blue_affects_strength| + +#### **BlurAngle** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |blur_angle| + +#### **BlurDirections** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------------| +|`[Float]`|false |named |False |blur_directions| + +#### **BlurInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------| +|`[String]`|false |named |False |blur_info| + +#### **BlurQuality** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|------------| +|`[Float]`|false |named |False |blur_quality| + +#### **BlurSize** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------| +|`[Float]`|false |named |False |blur_size| + +#### **ChromaticAberration** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------------| +|`[Float]`|false |named |False |chromatic_aberration| + +#### **ChromaticAberrationInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------------------| +|`[String]`|false |named |False |chromatic_aberration_info| + +#### **ColorizeColor** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|--------------| +|`[String]`|false |named |False |colorize_color| + +#### **ColorizeInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |colorize_info| + +#### **DisplacementCurve** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|------------------| +|`[Int]`|false |named |False |displacement_curve| + +#### **DisplacementInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------------| +|`[String]`|false |named |False |displacement_info| + +#### **DisplacementX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_x| + +#### **DisplacementY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_y| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **FlagsInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[String]`|false |named |False |flags_info| + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **MaskLayer** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[String]`|false |named |False |mask_layer| + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSDisplacementMapAdvancedShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-DisplacementCurve] ] [[-BlurInfo] ] [[-BlurSize] ] [[-BlurQuality] ] [[-BlurDirections] ] [[-BlurAngle] ] [[-ChromaticAberrationInfo] ] [[-ChromaticAberration] ] [[-ColorizeInfo] ] [[-ColorizeColor] ] [[-FlagsInfo] ] [-BlueAffectsStrength ] [-BlueAffectsColorize ] [-BlueAffectsBlur ] [-AlphaAffectsStrength ] [-ApplyAlpha ] [[-MaskLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Add-OBSDisplacementMapInvertShader.md b/docs/Add-OBSDisplacementMapInvertShader.md new file mode 100644 index 00000000..c0b10532 --- /dev/null +++ b/docs/Add-OBSDisplacementMapInvertShader.md @@ -0,0 +1,95 @@ +Get-OBSDisplacementMapInvertShader +---------------------------------- + +### Synopsis +Get-OBSDisplacementMapInvertShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-BackgroundLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **BackgroundLayer** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------------| +|`[String]`|false |named |False |background_layer| + +#### **DisplacementInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------------| +|`[String]`|false |named |False |displacement_info| + +#### **DisplacementX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_x| + +#### **DisplacementY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_y| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSDisplacementMapInvertShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-BackgroundLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Add-OBSDisplacementMapShader.md b/docs/Add-OBSDisplacementMapShader.md new file mode 100644 index 00000000..52eaa8b9 --- /dev/null +++ b/docs/Add-OBSDisplacementMapShader.md @@ -0,0 +1,95 @@ +Get-OBSDisplacementMapShader +---------------------------- + +### Synopsis +Get-OBSDisplacementMapShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-MaskLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **DisplacementInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------------| +|`[String]`|false |named |False |displacement_info| + +#### **DisplacementX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_x| + +#### **DisplacementY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_y| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **MaskLayer** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[String]`|false |named |False |mask_layer| + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSDisplacementMapShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-MaskLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Add-OBSGlitchPeriodicShader.md b/docs/Add-OBSGlitchPeriodicShader.md new file mode 100644 index 00000000..14fd3235 --- /dev/null +++ b/docs/Add-OBSGlitchPeriodicShader.md @@ -0,0 +1,95 @@ +Get-OBSGlitchPeriodicShader +--------------------------- + +### Synopsis +Get-OBSGlitchPeriodicShader [[-PERI] ] [[-DURA] ] [[-AMPL] ] [[-SCRA] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **AMPL** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **DURA** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PERI** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **SCRA** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSGlitchPeriodicShader [[-PERI] ] [[-DURA] ] [[-AMPL] ] [[-SCRA] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Add-OBSHardBlinkShader.md b/docs/Add-OBSHardBlinkShader.md new file mode 100644 index 00000000..63748d2e --- /dev/null +++ b/docs/Add-OBSHardBlinkShader.md @@ -0,0 +1,83 @@ +Get-OBSHardBlinkShader +---------------------- + +### Synopsis +Get-OBSHardBlinkShader [[-Timeon] ] [[-Timeoff] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Timeoff** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **Timeon** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSHardBlinkShader [[-Timeon] ] [[-Timeoff] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Add-OBSMotionBlurShader.md b/docs/Add-OBSMotionBlurShader.md new file mode 100644 index 00000000..0291ea14 --- /dev/null +++ b/docs/Add-OBSMotionBlurShader.md @@ -0,0 +1,83 @@ +Get-OBSMotionBlurShader +----------------------- + +### Synopsis +Get-OBSMotionBlurShader [[-PreviousOutput] ] [[-Strength] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PreviousOutput** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------------| +|`[String]`|false |named |False |previous_output| + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Strength** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSMotionBlurShader [[-PreviousOutput] ] [[-Strength] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Add-OBSNoiseShader.md b/docs/Add-OBSNoiseShader.md new file mode 100644 index 00000000..b75ddd04 --- /dev/null +++ b/docs/Add-OBSNoiseShader.md @@ -0,0 +1,101 @@ +Get-OBSNoiseShader +------------------ + +### Synopsis +Get-OBSNoiseShader [[-Speed] ] [[-Scale] ] [[-NoiseLevel] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Monochromatic] [-UseRand] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Monochromatic** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoiseLevel** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Scale** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Speed** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **UseRand** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|--------| +|`[Switch]`|false |named |False |use_rand| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSNoiseShader [[-Speed] ] [[-Scale] ] [[-NoiseLevel] ] [-Monochromatic ] [-UseRand ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Add-OBSNormalMapShader.md b/docs/Add-OBSNormalMapShader.md new file mode 100644 index 00000000..245b4832 --- /dev/null +++ b/docs/Add-OBSNormalMapShader.md @@ -0,0 +1,107 @@ +Get-OBSNormalMapShader +---------------------- + +### Synopsis +Get-OBSNormalMapShader [[-Strength] ] [[-Type] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-OffsetHeight] [-InvertR] [-InvertG] [-InvertH] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **InvertG** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **InvertH** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **InvertR** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **OffsetHeight** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Strength** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **Type** + +|Type |Required|Position|PipelineInput| +|-------|--------|--------|-------------| +|`[Int]`|false |named |False | + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSNormalMapShader [[-Strength] ] [-OffsetHeight ] [-InvertR ] [-InvertG ] [-InvertH ] [[-Type] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Add-OBSPerspectiveShader.md b/docs/Add-OBSPerspectiveShader.md new file mode 100644 index 00000000..3288693b --- /dev/null +++ b/docs/Add-OBSPerspectiveShader.md @@ -0,0 +1,107 @@ +Get-OBSPerspectiveShader +------------------------ + +### Synopsis +Get-OBSPerspectiveShader [[-AngleX] ] [[-AngleY] ] [[-AngleZ] ] [[-Perspective] ] [[-BorderColor] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-ShowBorder] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **AngleX** + +|Type |Required|Position|PipelineInput|Aliases| +|---------|--------|--------|-------------|-------| +|`[Float]`|false |named |False |angle_x| + +#### **AngleY** + +|Type |Required|Position|PipelineInput|Aliases| +|---------|--------|--------|-------------|-------| +|`[Float]`|false |named |False |angle_y| + +#### **AngleZ** + +|Type |Required|Position|PipelineInput|Aliases| +|---------|--------|--------|-------------|-------| +|`[Float]`|false |named |False |angle_z| + +#### **BorderColor** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|------------| +|`[String]`|false |named |False |border_color| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Perspective** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **ShowBorder** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------| +|`[Switch]`|false |named |False |show_border| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSPerspectiveShader [[-AngleX] ] [[-AngleY] ] [[-AngleZ] ] [[-Perspective] ] [[-BorderColor] ] [-ShowBorder ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Add-OBSQuadrilateralCropShader.md b/docs/Add-OBSQuadrilateralCropShader.md new file mode 100644 index 00000000..c5037d7a --- /dev/null +++ b/docs/Add-OBSQuadrilateralCropShader.md @@ -0,0 +1,119 @@ +Get-OBSQuadrilateralCropShader +------------------------------ + +### Synopsis +Get-OBSQuadrilateralCropShader [[-TopLeftX] ] [[-TopLeftY] ] [[-TopRightX] ] [[-TopRightY] ] [[-BottomLeftX] ] [[-BottomLeftY] ] [[-BottomRightX] ] [[-BottomRightY] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **BottomLeftX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|-------------| +|`[Float]`|false |named |False |Bottom_Left_X| + +#### **BottomLeftY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|-------------| +|`[Float]`|false |named |False |Bottom_Left_Y| + +#### **BottomRightX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |Bottom_Right_X| + +#### **BottomRightY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |Bottom_Right_Y| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **TopLeftX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |Top_Left_X| + +#### **TopLeftY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |Top_Left_Y| + +#### **TopRightX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|-----------| +|`[Float]`|false |named |False |Top_Right_X| + +#### **TopRightY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|-----------| +|`[Float]`|false |named |False |Top_Right_Y| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSQuadrilateralCropShader [[-TopLeftX] ] [[-TopLeftY] ] [[-TopRightX] ] [[-TopRightY] ] [[-BottomLeftX] ] [[-BottomLeftY] ] [[-BottomRightX] ] [[-BottomRightY] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Add-OBSRepeatGridCenterCropShader.md b/docs/Add-OBSRepeatGridCenterCropShader.md new file mode 100644 index 00000000..dd7f8e8a --- /dev/null +++ b/docs/Add-OBSRepeatGridCenterCropShader.md @@ -0,0 +1,101 @@ +Get-OBSRepeatGridCenterCropShader +--------------------------------- + +### Synopsis +Get-OBSRepeatGridCenterCropShader [[-ViewProj] ] [[-Image] ] [[-Alpha] ] [[-Columns] ] [[-Rows] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **Alpha** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **Columns** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Image** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Rows** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ViewProj** + +|Type |Required|Position|PipelineInput| +|---------------------|--------|--------|-------------| +|`[System.Single[][]]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSRepeatGridCenterCropShader [[-ViewProj] ] [[-Image] ] [[-Alpha] ] [[-Columns] ] [[-Rows] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Add-OBSWalkingDeadPixelFixerShader.md b/docs/Add-OBSWalkingDeadPixelFixerShader.md new file mode 100644 index 00000000..dab40694 --- /dev/null +++ b/docs/Add-OBSWalkingDeadPixelFixerShader.md @@ -0,0 +1,131 @@ +Get-OBSWalkingDeadPixelFixerShader +---------------------------------- + +### Synopsis +Get-OBSWalkingDeadPixelFixerShader [[-ScanWidth] ] [[-ScanHeight] ] [[-ScanOffsetX] ] [[-ScanOffsetY] ] [[-ContrastThreshold] ] [[-MinClusterSize] ] [[-MaxClusterSize] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-ShowBorder] [-ShowGreen] [-Bypass] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **Bypass** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ContrastThreshold** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|------------------| +|`[Float]`|false |named |False |Contrast_Threshold| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **MaxClusterSize** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|----------------| +|`[Int]`|false |named |False |Max_Cluster_Size| + +#### **MinClusterSize** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|----------------| +|`[Int]`|false |named |False |Min_Cluster_Size| + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ScanHeight** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|-----------| +|`[Int]`|false |named |False |Scan_Height| + +#### **ScanOffsetX** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|-------------| +|`[Int]`|false |named |False |Scan_Offset_X| + +#### **ScanOffsetY** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|-------------| +|`[Int]`|false |named |False |Scan_Offset_Y| + +#### **ScanWidth** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|----------| +|`[Int]`|false |named |False |Scan_Width| + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **ShowBorder** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------| +|`[Switch]`|false |named |False |Show_Border| + +#### **ShowGreen** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[Switch]`|false |named |False |Show_Green| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSWalkingDeadPixelFixerShader [[-ScanWidth] ] [[-ScanHeight] ] [[-ScanOffsetX] ] [[-ScanOffsetY] ] [-ShowBorder ] [[-ContrastThreshold] ] [[-MinClusterSize] ] [[-MaxClusterSize] ] [-ShowGreen ] [-Bypass ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Add-OBSZoomBlurTransitionShader.md b/docs/Add-OBSZoomBlurTransitionShader.md new file mode 100644 index 00000000..b28ab22b --- /dev/null +++ b/docs/Add-OBSZoomBlurTransitionShader.md @@ -0,0 +1,101 @@ +Get-OBSZoomBlurTransitionShader +------------------------------- + +### Synopsis +Get-OBSZoomBlurTransitionShader [[-ImageA] ] [[-ImageB] ] [[-TransitionTime] ] [[-Strength] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-ConvertLinear] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **ConvertLinear** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|--------------| +|`[Switch]`|false |named |False |convert_linear| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ImageA** + +|Type |Required|Position|PipelineInput|Aliases| +|----------|--------|--------|-------------|-------| +|`[String]`|false |named |False |image_a| + +#### **ImageB** + +|Type |Required|Position|PipelineInput|Aliases| +|----------|--------|--------|-------------|-------| +|`[String]`|false |named |False |image_b| + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Strength** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **TransitionTime** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------------| +|`[Float]`|false |named |False |transition_time| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSZoomBlurTransitionShader [[-ImageA] ] [[-ImageB] ] [[-TransitionTime] ] [-ConvertLinear ] [[-Strength] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index c6f75620..54f80ad4 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,6 +1,32 @@ > Like It? [Star It](https://github.com/StartAutomating/obs-powershell) > Love It? [Support It](https://github.com/sponsors/StartAutomating) +## obs-powershell 0.2.1: + +* New General Purpose Commands + * Start-OBS (#220) + * Stop-OBS (#226) +* New Shader Commands: + * Get-OBS3dPanelShader + * Get-OBSAudioShader + * Get-OBSCubeRotatingShader + * Get-OBSDisplacementMapAdvancedInvertShader + * Get-OBSDisplacementMapAdvancedShader + * Get-OBSDisplacementMapInvertShader + * Get-OBSDisplacementMapShader + * Get-OBSGlitchPeriodicShader + * Get-OBSHardBlinkShader + * Get-OBSMotionBlurShader + * Get-OBSNoiseShader + * Get-OBSNormalMapShader + * Get-OBSPerspectiveShader + * Get-OBSQuadrilateralCropShader + * Get-OBSRepeatGridCenterCropShader + * Get-OBSWalkingDeadPixelFixerShader + * Get-OBSZoomBlurTransitionShader + +--- + ## obs-powershell 0.2.0.1: * Fixing `Watch-OBS` (Fixes #216) diff --git a/docs/Get-OBS3dPanelShader.md b/docs/Get-OBS3dPanelShader.md new file mode 100644 index 00000000..c72918bf --- /dev/null +++ b/docs/Get-OBS3dPanelShader.md @@ -0,0 +1,149 @@ +Get-OBS3dPanelShader +-------------------- + +### Synopsis +Get-OBS3dPanelShader [[-Credits] ] [[-Scale] ] [[-TiltXDeg] ] [[-TiltYDeg] ] [[-TiltZDeg] ] [[-PosX] ] [[-PosY] ] [[-Thickness] ] [[-RadiusFb] ] [[-Brightness] ] [[-LightPosition] ] [[-Wiggle] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-WiggleRot] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **Brightness** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **Credits** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **LightPosition** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|--------------| +|`[Int]`|false |named |False |light_position| + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PosX** + +|Type |Required|Position|PipelineInput|Aliases| +|---------|--------|--------|-------------|-------| +|`[Float]`|false |named |False |pos_x | + +#### **PosY** + +|Type |Required|Position|PipelineInput|Aliases| +|---------|--------|--------|-------------|-------| +|`[Float]`|false |named |False |pos_y | + +#### **RadiusFb** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------| +|`[Float]`|false |named |False |radius_fb| + +#### **Scale** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Thickness** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **TiltXDeg** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |tilt_x_deg| + +#### **TiltYDeg** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |tilt_y_deg| + +#### **TiltZDeg** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |tilt_z_deg| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Wiggle** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **WiggleRot** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[Switch]`|false |named |False |wiggle_rot| + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBS3dPanelShader [[-Credits] ] [[-Scale] ] [[-TiltXDeg] ] [[-TiltYDeg] ] [[-TiltZDeg] ] [[-PosX] ] [[-PosY] ] [[-Thickness] ] [[-RadiusFb] ] [[-Brightness] ] [[-LightPosition] ] [[-Wiggle] ] [-WiggleRot ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Get-OBSAudioShader.md b/docs/Get-OBSAudioShader.md new file mode 100644 index 00000000..4cc14640 --- /dev/null +++ b/docs/Get-OBSAudioShader.md @@ -0,0 +1,89 @@ +Get-OBSAudioShader +------------------ + +### Synopsis +Get-OBSAudioShader [[-AudioPeak] ] [[-AudioMagnitude] ] [[-Intensity] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **AudioMagnitude** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------------| +|`[Float]`|false |named |False |audio_magnitude| + +#### **AudioPeak** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |audio_peak| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Intensity** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSAudioShader [[-AudioPeak] ] [[-AudioMagnitude] ] [[-Intensity] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Get-OBSCubeRotatingShader.md b/docs/Get-OBSCubeRotatingShader.md new file mode 100644 index 00000000..ca9ab33e --- /dev/null +++ b/docs/Get-OBSCubeRotatingShader.md @@ -0,0 +1,107 @@ +Get-OBSCubeRotatingShader +------------------------- + +### Synopsis +Get-OBSCubeRotatingShader [[-Images] ] [[-Speed] ] [[-Shadow] ] [[-OtherImage1] ] [[-OtherImage2] ] [[-OtherImage3] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Images** + +|Type |Required|Position|PipelineInput| +|-------|--------|--------|-------------| +|`[Int]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **OtherImage1** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|------------| +|`[String]`|false |named |False |other_image1| + +#### **OtherImage2** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|------------| +|`[String]`|false |named |False |other_image2| + +#### **OtherImage3** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|------------| +|`[String]`|false |named |False |other_image3| + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **Shadow** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Speed** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSCubeRotatingShader [[-Images] ] [[-Speed] ] [[-Shadow] ] [[-OtherImage1] ] [[-OtherImage2] ] [[-OtherImage3] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Get-OBSDisplacementMapAdvancedInvertShader.md b/docs/Get-OBSDisplacementMapAdvancedInvertShader.md new file mode 100644 index 00000000..b7e40d58 --- /dev/null +++ b/docs/Get-OBSDisplacementMapAdvancedInvertShader.md @@ -0,0 +1,191 @@ +Get-OBSDisplacementMapAdvancedInvertShader +------------------------------------------ + +### Synopsis +Get-OBSDisplacementMapAdvancedInvertShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-DisplacementCurve] ] [[-BlurInfo] ] [[-BlurSize] ] [[-BlurQuality] ] [[-BlurDirections] ] [[-BlurAngle] ] [[-ChromaticAberrationInfo] ] [[-ChromaticAberration] ] [[-ColorizeInfo] ] [[-ColorizeColor] ] [[-FlagsInfo] ] [[-BackgroundLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-BlueAffectsStrength] [-BlueAffectsColorize] [-BlueAffectsBlur] [-AlphaAffectsStrength] [-ApplyAlpha] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **AlphaAffectsStrength** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------------------| +|`[Switch]`|false |named |False |alpha_affects_strength| + +#### **ApplyAlpha** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------| +|`[Switch]`|false |named |False |apply_alpha| + +#### **BackgroundLayer** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------------| +|`[String]`|false |named |False |background_layer| + +#### **BlueAffectsBlur** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------------| +|`[Switch]`|false |named |False |blue_affects_blur| + +#### **BlueAffectsColorize** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------------------| +|`[Switch]`|false |named |False |blue_affects_colorize| + +#### **BlueAffectsStrength** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------------------| +|`[Switch]`|false |named |False |blue_affects_strength| + +#### **BlurAngle** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |blur_angle| + +#### **BlurDirections** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------------| +|`[Float]`|false |named |False |blur_directions| + +#### **BlurInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------| +|`[String]`|false |named |False |blur_info| + +#### **BlurQuality** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|------------| +|`[Float]`|false |named |False |blur_quality| + +#### **BlurSize** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------| +|`[Float]`|false |named |False |blur_size| + +#### **ChromaticAberration** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------------| +|`[Float]`|false |named |False |chromatic_aberration| + +#### **ChromaticAberrationInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------------------| +|`[String]`|false |named |False |chromatic_aberration_info| + +#### **ColorizeColor** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|--------------| +|`[String]`|false |named |False |colorize_color| + +#### **ColorizeInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |colorize_info| + +#### **DisplacementCurve** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|------------------| +|`[Int]`|false |named |False |displacement_curve| + +#### **DisplacementInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------------| +|`[String]`|false |named |False |displacement_info| + +#### **DisplacementX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_x| + +#### **DisplacementY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_y| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **FlagsInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[String]`|false |named |False |flags_info| + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSDisplacementMapAdvancedInvertShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-DisplacementCurve] ] [[-BlurInfo] ] [[-BlurSize] ] [[-BlurQuality] ] [[-BlurDirections] ] [[-BlurAngle] ] [[-ChromaticAberrationInfo] ] [[-ChromaticAberration] ] [[-ColorizeInfo] ] [[-ColorizeColor] ] [[-FlagsInfo] ] [-BlueAffectsStrength ] [-BlueAffectsColorize ] [-BlueAffectsBlur ] [-AlphaAffectsStrength ] [-ApplyAlpha ] [[-BackgroundLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Get-OBSDisplacementMapAdvancedShader.md b/docs/Get-OBSDisplacementMapAdvancedShader.md new file mode 100644 index 00000000..7d86b0ce --- /dev/null +++ b/docs/Get-OBSDisplacementMapAdvancedShader.md @@ -0,0 +1,191 @@ +Get-OBSDisplacementMapAdvancedShader +------------------------------------ + +### Synopsis +Get-OBSDisplacementMapAdvancedShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-DisplacementCurve] ] [[-BlurInfo] ] [[-BlurSize] ] [[-BlurQuality] ] [[-BlurDirections] ] [[-BlurAngle] ] [[-ChromaticAberrationInfo] ] [[-ChromaticAberration] ] [[-ColorizeInfo] ] [[-ColorizeColor] ] [[-FlagsInfo] ] [[-MaskLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-BlueAffectsStrength] [-BlueAffectsColorize] [-BlueAffectsBlur] [-AlphaAffectsStrength] [-ApplyAlpha] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **AlphaAffectsStrength** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------------------| +|`[Switch]`|false |named |False |alpha_affects_strength| + +#### **ApplyAlpha** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------| +|`[Switch]`|false |named |False |apply_alpha| + +#### **BlueAffectsBlur** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------------| +|`[Switch]`|false |named |False |blue_affects_blur| + +#### **BlueAffectsColorize** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------------------| +|`[Switch]`|false |named |False |blue_affects_colorize| + +#### **BlueAffectsStrength** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------------------| +|`[Switch]`|false |named |False |blue_affects_strength| + +#### **BlurAngle** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |blur_angle| + +#### **BlurDirections** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------------| +|`[Float]`|false |named |False |blur_directions| + +#### **BlurInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------| +|`[String]`|false |named |False |blur_info| + +#### **BlurQuality** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|------------| +|`[Float]`|false |named |False |blur_quality| + +#### **BlurSize** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------| +|`[Float]`|false |named |False |blur_size| + +#### **ChromaticAberration** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------------| +|`[Float]`|false |named |False |chromatic_aberration| + +#### **ChromaticAberrationInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------------------| +|`[String]`|false |named |False |chromatic_aberration_info| + +#### **ColorizeColor** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|--------------| +|`[String]`|false |named |False |colorize_color| + +#### **ColorizeInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |colorize_info| + +#### **DisplacementCurve** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|------------------| +|`[Int]`|false |named |False |displacement_curve| + +#### **DisplacementInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------------| +|`[String]`|false |named |False |displacement_info| + +#### **DisplacementX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_x| + +#### **DisplacementY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_y| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **FlagsInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[String]`|false |named |False |flags_info| + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **MaskLayer** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[String]`|false |named |False |mask_layer| + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSDisplacementMapAdvancedShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-DisplacementCurve] ] [[-BlurInfo] ] [[-BlurSize] ] [[-BlurQuality] ] [[-BlurDirections] ] [[-BlurAngle] ] [[-ChromaticAberrationInfo] ] [[-ChromaticAberration] ] [[-ColorizeInfo] ] [[-ColorizeColor] ] [[-FlagsInfo] ] [-BlueAffectsStrength ] [-BlueAffectsColorize ] [-BlueAffectsBlur ] [-AlphaAffectsStrength ] [-ApplyAlpha ] [[-MaskLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Get-OBSDisplacementMapInvertShader.md b/docs/Get-OBSDisplacementMapInvertShader.md new file mode 100644 index 00000000..c0b10532 --- /dev/null +++ b/docs/Get-OBSDisplacementMapInvertShader.md @@ -0,0 +1,95 @@ +Get-OBSDisplacementMapInvertShader +---------------------------------- + +### Synopsis +Get-OBSDisplacementMapInvertShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-BackgroundLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **BackgroundLayer** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------------| +|`[String]`|false |named |False |background_layer| + +#### **DisplacementInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------------| +|`[String]`|false |named |False |displacement_info| + +#### **DisplacementX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_x| + +#### **DisplacementY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_y| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSDisplacementMapInvertShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-BackgroundLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Get-OBSDisplacementMapShader.md b/docs/Get-OBSDisplacementMapShader.md new file mode 100644 index 00000000..52eaa8b9 --- /dev/null +++ b/docs/Get-OBSDisplacementMapShader.md @@ -0,0 +1,95 @@ +Get-OBSDisplacementMapShader +---------------------------- + +### Synopsis +Get-OBSDisplacementMapShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-MaskLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **DisplacementInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------------| +|`[String]`|false |named |False |displacement_info| + +#### **DisplacementX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_x| + +#### **DisplacementY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_y| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **MaskLayer** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[String]`|false |named |False |mask_layer| + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSDisplacementMapShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-MaskLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Get-OBSGlitchPeriodicShader.md b/docs/Get-OBSGlitchPeriodicShader.md new file mode 100644 index 00000000..14fd3235 --- /dev/null +++ b/docs/Get-OBSGlitchPeriodicShader.md @@ -0,0 +1,95 @@ +Get-OBSGlitchPeriodicShader +--------------------------- + +### Synopsis +Get-OBSGlitchPeriodicShader [[-PERI] ] [[-DURA] ] [[-AMPL] ] [[-SCRA] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **AMPL** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **DURA** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PERI** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **SCRA** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSGlitchPeriodicShader [[-PERI] ] [[-DURA] ] [[-AMPL] ] [[-SCRA] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Get-OBSHardBlinkShader.md b/docs/Get-OBSHardBlinkShader.md new file mode 100644 index 00000000..63748d2e --- /dev/null +++ b/docs/Get-OBSHardBlinkShader.md @@ -0,0 +1,83 @@ +Get-OBSHardBlinkShader +---------------------- + +### Synopsis +Get-OBSHardBlinkShader [[-Timeon] ] [[-Timeoff] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Timeoff** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **Timeon** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSHardBlinkShader [[-Timeon] ] [[-Timeoff] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Get-OBSMotionBlurShader.md b/docs/Get-OBSMotionBlurShader.md new file mode 100644 index 00000000..0291ea14 --- /dev/null +++ b/docs/Get-OBSMotionBlurShader.md @@ -0,0 +1,83 @@ +Get-OBSMotionBlurShader +----------------------- + +### Synopsis +Get-OBSMotionBlurShader [[-PreviousOutput] ] [[-Strength] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PreviousOutput** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------------| +|`[String]`|false |named |False |previous_output| + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Strength** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSMotionBlurShader [[-PreviousOutput] ] [[-Strength] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Get-OBSNoiseShader.md b/docs/Get-OBSNoiseShader.md new file mode 100644 index 00000000..b75ddd04 --- /dev/null +++ b/docs/Get-OBSNoiseShader.md @@ -0,0 +1,101 @@ +Get-OBSNoiseShader +------------------ + +### Synopsis +Get-OBSNoiseShader [[-Speed] ] [[-Scale] ] [[-NoiseLevel] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Monochromatic] [-UseRand] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Monochromatic** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoiseLevel** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Scale** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Speed** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **UseRand** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|--------| +|`[Switch]`|false |named |False |use_rand| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSNoiseShader [[-Speed] ] [[-Scale] ] [[-NoiseLevel] ] [-Monochromatic ] [-UseRand ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Get-OBSNormalMapShader.md b/docs/Get-OBSNormalMapShader.md new file mode 100644 index 00000000..245b4832 --- /dev/null +++ b/docs/Get-OBSNormalMapShader.md @@ -0,0 +1,107 @@ +Get-OBSNormalMapShader +---------------------- + +### Synopsis +Get-OBSNormalMapShader [[-Strength] ] [[-Type] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-OffsetHeight] [-InvertR] [-InvertG] [-InvertH] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **InvertG** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **InvertH** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **InvertR** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **OffsetHeight** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Strength** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **Type** + +|Type |Required|Position|PipelineInput| +|-------|--------|--------|-------------| +|`[Int]`|false |named |False | + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSNormalMapShader [[-Strength] ] [-OffsetHeight ] [-InvertR ] [-InvertG ] [-InvertH ] [[-Type] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Get-OBSPerspectiveShader.md b/docs/Get-OBSPerspectiveShader.md new file mode 100644 index 00000000..3288693b --- /dev/null +++ b/docs/Get-OBSPerspectiveShader.md @@ -0,0 +1,107 @@ +Get-OBSPerspectiveShader +------------------------ + +### Synopsis +Get-OBSPerspectiveShader [[-AngleX] ] [[-AngleY] ] [[-AngleZ] ] [[-Perspective] ] [[-BorderColor] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-ShowBorder] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **AngleX** + +|Type |Required|Position|PipelineInput|Aliases| +|---------|--------|--------|-------------|-------| +|`[Float]`|false |named |False |angle_x| + +#### **AngleY** + +|Type |Required|Position|PipelineInput|Aliases| +|---------|--------|--------|-------------|-------| +|`[Float]`|false |named |False |angle_y| + +#### **AngleZ** + +|Type |Required|Position|PipelineInput|Aliases| +|---------|--------|--------|-------------|-------| +|`[Float]`|false |named |False |angle_z| + +#### **BorderColor** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|------------| +|`[String]`|false |named |False |border_color| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Perspective** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **ShowBorder** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------| +|`[Switch]`|false |named |False |show_border| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSPerspectiveShader [[-AngleX] ] [[-AngleY] ] [[-AngleZ] ] [[-Perspective] ] [[-BorderColor] ] [-ShowBorder ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Get-OBSQuadrilateralCropShader.md b/docs/Get-OBSQuadrilateralCropShader.md new file mode 100644 index 00000000..c5037d7a --- /dev/null +++ b/docs/Get-OBSQuadrilateralCropShader.md @@ -0,0 +1,119 @@ +Get-OBSQuadrilateralCropShader +------------------------------ + +### Synopsis +Get-OBSQuadrilateralCropShader [[-TopLeftX] ] [[-TopLeftY] ] [[-TopRightX] ] [[-TopRightY] ] [[-BottomLeftX] ] [[-BottomLeftY] ] [[-BottomRightX] ] [[-BottomRightY] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **BottomLeftX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|-------------| +|`[Float]`|false |named |False |Bottom_Left_X| + +#### **BottomLeftY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|-------------| +|`[Float]`|false |named |False |Bottom_Left_Y| + +#### **BottomRightX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |Bottom_Right_X| + +#### **BottomRightY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |Bottom_Right_Y| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **TopLeftX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |Top_Left_X| + +#### **TopLeftY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |Top_Left_Y| + +#### **TopRightX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|-----------| +|`[Float]`|false |named |False |Top_Right_X| + +#### **TopRightY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|-----------| +|`[Float]`|false |named |False |Top_Right_Y| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSQuadrilateralCropShader [[-TopLeftX] ] [[-TopLeftY] ] [[-TopRightX] ] [[-TopRightY] ] [[-BottomLeftX] ] [[-BottomLeftY] ] [[-BottomRightX] ] [[-BottomRightY] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Get-OBSRepeatGridCenterCropShader.md b/docs/Get-OBSRepeatGridCenterCropShader.md new file mode 100644 index 00000000..dd7f8e8a --- /dev/null +++ b/docs/Get-OBSRepeatGridCenterCropShader.md @@ -0,0 +1,101 @@ +Get-OBSRepeatGridCenterCropShader +--------------------------------- + +### Synopsis +Get-OBSRepeatGridCenterCropShader [[-ViewProj] ] [[-Image] ] [[-Alpha] ] [[-Columns] ] [[-Rows] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **Alpha** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **Columns** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Image** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Rows** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ViewProj** + +|Type |Required|Position|PipelineInput| +|---------------------|--------|--------|-------------| +|`[System.Single[][]]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSRepeatGridCenterCropShader [[-ViewProj] ] [[-Image] ] [[-Alpha] ] [[-Columns] ] [[-Rows] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Get-OBSWalkingDeadPixelFixerShader.md b/docs/Get-OBSWalkingDeadPixelFixerShader.md new file mode 100644 index 00000000..dab40694 --- /dev/null +++ b/docs/Get-OBSWalkingDeadPixelFixerShader.md @@ -0,0 +1,131 @@ +Get-OBSWalkingDeadPixelFixerShader +---------------------------------- + +### Synopsis +Get-OBSWalkingDeadPixelFixerShader [[-ScanWidth] ] [[-ScanHeight] ] [[-ScanOffsetX] ] [[-ScanOffsetY] ] [[-ContrastThreshold] ] [[-MinClusterSize] ] [[-MaxClusterSize] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-ShowBorder] [-ShowGreen] [-Bypass] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **Bypass** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ContrastThreshold** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|------------------| +|`[Float]`|false |named |False |Contrast_Threshold| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **MaxClusterSize** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|----------------| +|`[Int]`|false |named |False |Max_Cluster_Size| + +#### **MinClusterSize** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|----------------| +|`[Int]`|false |named |False |Min_Cluster_Size| + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ScanHeight** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|-----------| +|`[Int]`|false |named |False |Scan_Height| + +#### **ScanOffsetX** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|-------------| +|`[Int]`|false |named |False |Scan_Offset_X| + +#### **ScanOffsetY** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|-------------| +|`[Int]`|false |named |False |Scan_Offset_Y| + +#### **ScanWidth** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|----------| +|`[Int]`|false |named |False |Scan_Width| + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **ShowBorder** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------| +|`[Switch]`|false |named |False |Show_Border| + +#### **ShowGreen** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[Switch]`|false |named |False |Show_Green| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSWalkingDeadPixelFixerShader [[-ScanWidth] ] [[-ScanHeight] ] [[-ScanOffsetX] ] [[-ScanOffsetY] ] [-ShowBorder ] [[-ContrastThreshold] ] [[-MinClusterSize] ] [[-MaxClusterSize] ] [-ShowGreen ] [-Bypass ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Get-OBSZoomBlurTransitionShader.md b/docs/Get-OBSZoomBlurTransitionShader.md new file mode 100644 index 00000000..b28ab22b --- /dev/null +++ b/docs/Get-OBSZoomBlurTransitionShader.md @@ -0,0 +1,101 @@ +Get-OBSZoomBlurTransitionShader +------------------------------- + +### Synopsis +Get-OBSZoomBlurTransitionShader [[-ImageA] ] [[-ImageB] ] [[-TransitionTime] ] [[-Strength] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-ConvertLinear] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **ConvertLinear** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|--------------| +|`[Switch]`|false |named |False |convert_linear| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ImageA** + +|Type |Required|Position|PipelineInput|Aliases| +|----------|--------|--------|-------------|-------| +|`[String]`|false |named |False |image_a| + +#### **ImageB** + +|Type |Required|Position|PipelineInput|Aliases| +|----------|--------|--------|-------------|-------| +|`[String]`|false |named |False |image_b| + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Strength** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **TransitionTime** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------------| +|`[Float]`|false |named |False |transition_time| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSZoomBlurTransitionShader [[-ImageA] ] [[-ImageB] ] [[-TransitionTime] ] [-ConvertLinear ] [[-Strength] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Set-OBS3dPanelShader.md b/docs/Set-OBS3dPanelShader.md new file mode 100644 index 00000000..c72918bf --- /dev/null +++ b/docs/Set-OBS3dPanelShader.md @@ -0,0 +1,149 @@ +Get-OBS3dPanelShader +-------------------- + +### Synopsis +Get-OBS3dPanelShader [[-Credits] ] [[-Scale] ] [[-TiltXDeg] ] [[-TiltYDeg] ] [[-TiltZDeg] ] [[-PosX] ] [[-PosY] ] [[-Thickness] ] [[-RadiusFb] ] [[-Brightness] ] [[-LightPosition] ] [[-Wiggle] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-WiggleRot] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **Brightness** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **Credits** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **LightPosition** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|--------------| +|`[Int]`|false |named |False |light_position| + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PosX** + +|Type |Required|Position|PipelineInput|Aliases| +|---------|--------|--------|-------------|-------| +|`[Float]`|false |named |False |pos_x | + +#### **PosY** + +|Type |Required|Position|PipelineInput|Aliases| +|---------|--------|--------|-------------|-------| +|`[Float]`|false |named |False |pos_y | + +#### **RadiusFb** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------| +|`[Float]`|false |named |False |radius_fb| + +#### **Scale** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Thickness** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **TiltXDeg** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |tilt_x_deg| + +#### **TiltYDeg** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |tilt_y_deg| + +#### **TiltZDeg** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |tilt_z_deg| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Wiggle** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **WiggleRot** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[Switch]`|false |named |False |wiggle_rot| + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBS3dPanelShader [[-Credits] ] [[-Scale] ] [[-TiltXDeg] ] [[-TiltYDeg] ] [[-TiltZDeg] ] [[-PosX] ] [[-PosY] ] [[-Thickness] ] [[-RadiusFb] ] [[-Brightness] ] [[-LightPosition] ] [[-Wiggle] ] [-WiggleRot ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Set-OBSAudioShader.md b/docs/Set-OBSAudioShader.md new file mode 100644 index 00000000..4cc14640 --- /dev/null +++ b/docs/Set-OBSAudioShader.md @@ -0,0 +1,89 @@ +Get-OBSAudioShader +------------------ + +### Synopsis +Get-OBSAudioShader [[-AudioPeak] ] [[-AudioMagnitude] ] [[-Intensity] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **AudioMagnitude** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------------| +|`[Float]`|false |named |False |audio_magnitude| + +#### **AudioPeak** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |audio_peak| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Intensity** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSAudioShader [[-AudioPeak] ] [[-AudioMagnitude] ] [[-Intensity] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Set-OBSCubeRotatingShader.md b/docs/Set-OBSCubeRotatingShader.md new file mode 100644 index 00000000..ca9ab33e --- /dev/null +++ b/docs/Set-OBSCubeRotatingShader.md @@ -0,0 +1,107 @@ +Get-OBSCubeRotatingShader +------------------------- + +### Synopsis +Get-OBSCubeRotatingShader [[-Images] ] [[-Speed] ] [[-Shadow] ] [[-OtherImage1] ] [[-OtherImage2] ] [[-OtherImage3] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Images** + +|Type |Required|Position|PipelineInput| +|-------|--------|--------|-------------| +|`[Int]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **OtherImage1** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|------------| +|`[String]`|false |named |False |other_image1| + +#### **OtherImage2** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|------------| +|`[String]`|false |named |False |other_image2| + +#### **OtherImage3** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|------------| +|`[String]`|false |named |False |other_image3| + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **Shadow** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Speed** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSCubeRotatingShader [[-Images] ] [[-Speed] ] [[-Shadow] ] [[-OtherImage1] ] [[-OtherImage2] ] [[-OtherImage3] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Set-OBSDisplacementMapAdvancedInvertShader.md b/docs/Set-OBSDisplacementMapAdvancedInvertShader.md new file mode 100644 index 00000000..b7e40d58 --- /dev/null +++ b/docs/Set-OBSDisplacementMapAdvancedInvertShader.md @@ -0,0 +1,191 @@ +Get-OBSDisplacementMapAdvancedInvertShader +------------------------------------------ + +### Synopsis +Get-OBSDisplacementMapAdvancedInvertShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-DisplacementCurve] ] [[-BlurInfo] ] [[-BlurSize] ] [[-BlurQuality] ] [[-BlurDirections] ] [[-BlurAngle] ] [[-ChromaticAberrationInfo] ] [[-ChromaticAberration] ] [[-ColorizeInfo] ] [[-ColorizeColor] ] [[-FlagsInfo] ] [[-BackgroundLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-BlueAffectsStrength] [-BlueAffectsColorize] [-BlueAffectsBlur] [-AlphaAffectsStrength] [-ApplyAlpha] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **AlphaAffectsStrength** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------------------| +|`[Switch]`|false |named |False |alpha_affects_strength| + +#### **ApplyAlpha** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------| +|`[Switch]`|false |named |False |apply_alpha| + +#### **BackgroundLayer** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------------| +|`[String]`|false |named |False |background_layer| + +#### **BlueAffectsBlur** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------------| +|`[Switch]`|false |named |False |blue_affects_blur| + +#### **BlueAffectsColorize** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------------------| +|`[Switch]`|false |named |False |blue_affects_colorize| + +#### **BlueAffectsStrength** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------------------| +|`[Switch]`|false |named |False |blue_affects_strength| + +#### **BlurAngle** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |blur_angle| + +#### **BlurDirections** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------------| +|`[Float]`|false |named |False |blur_directions| + +#### **BlurInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------| +|`[String]`|false |named |False |blur_info| + +#### **BlurQuality** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|------------| +|`[Float]`|false |named |False |blur_quality| + +#### **BlurSize** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------| +|`[Float]`|false |named |False |blur_size| + +#### **ChromaticAberration** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------------| +|`[Float]`|false |named |False |chromatic_aberration| + +#### **ChromaticAberrationInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------------------| +|`[String]`|false |named |False |chromatic_aberration_info| + +#### **ColorizeColor** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|--------------| +|`[String]`|false |named |False |colorize_color| + +#### **ColorizeInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |colorize_info| + +#### **DisplacementCurve** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|------------------| +|`[Int]`|false |named |False |displacement_curve| + +#### **DisplacementInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------------| +|`[String]`|false |named |False |displacement_info| + +#### **DisplacementX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_x| + +#### **DisplacementY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_y| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **FlagsInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[String]`|false |named |False |flags_info| + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSDisplacementMapAdvancedInvertShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-DisplacementCurve] ] [[-BlurInfo] ] [[-BlurSize] ] [[-BlurQuality] ] [[-BlurDirections] ] [[-BlurAngle] ] [[-ChromaticAberrationInfo] ] [[-ChromaticAberration] ] [[-ColorizeInfo] ] [[-ColorizeColor] ] [[-FlagsInfo] ] [-BlueAffectsStrength ] [-BlueAffectsColorize ] [-BlueAffectsBlur ] [-AlphaAffectsStrength ] [-ApplyAlpha ] [[-BackgroundLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Set-OBSDisplacementMapAdvancedShader.md b/docs/Set-OBSDisplacementMapAdvancedShader.md new file mode 100644 index 00000000..7d86b0ce --- /dev/null +++ b/docs/Set-OBSDisplacementMapAdvancedShader.md @@ -0,0 +1,191 @@ +Get-OBSDisplacementMapAdvancedShader +------------------------------------ + +### Synopsis +Get-OBSDisplacementMapAdvancedShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-DisplacementCurve] ] [[-BlurInfo] ] [[-BlurSize] ] [[-BlurQuality] ] [[-BlurDirections] ] [[-BlurAngle] ] [[-ChromaticAberrationInfo] ] [[-ChromaticAberration] ] [[-ColorizeInfo] ] [[-ColorizeColor] ] [[-FlagsInfo] ] [[-MaskLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-BlueAffectsStrength] [-BlueAffectsColorize] [-BlueAffectsBlur] [-AlphaAffectsStrength] [-ApplyAlpha] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **AlphaAffectsStrength** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------------------| +|`[Switch]`|false |named |False |alpha_affects_strength| + +#### **ApplyAlpha** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------| +|`[Switch]`|false |named |False |apply_alpha| + +#### **BlueAffectsBlur** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------------| +|`[Switch]`|false |named |False |blue_affects_blur| + +#### **BlueAffectsColorize** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------------------| +|`[Switch]`|false |named |False |blue_affects_colorize| + +#### **BlueAffectsStrength** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------------------| +|`[Switch]`|false |named |False |blue_affects_strength| + +#### **BlurAngle** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |blur_angle| + +#### **BlurDirections** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------------| +|`[Float]`|false |named |False |blur_directions| + +#### **BlurInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------| +|`[String]`|false |named |False |blur_info| + +#### **BlurQuality** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|------------| +|`[Float]`|false |named |False |blur_quality| + +#### **BlurSize** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------| +|`[Float]`|false |named |False |blur_size| + +#### **ChromaticAberration** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------------| +|`[Float]`|false |named |False |chromatic_aberration| + +#### **ChromaticAberrationInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------------------| +|`[String]`|false |named |False |chromatic_aberration_info| + +#### **ColorizeColor** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|--------------| +|`[String]`|false |named |False |colorize_color| + +#### **ColorizeInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |colorize_info| + +#### **DisplacementCurve** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|------------------| +|`[Int]`|false |named |False |displacement_curve| + +#### **DisplacementInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------------| +|`[String]`|false |named |False |displacement_info| + +#### **DisplacementX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_x| + +#### **DisplacementY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_y| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **FlagsInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[String]`|false |named |False |flags_info| + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **MaskLayer** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[String]`|false |named |False |mask_layer| + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSDisplacementMapAdvancedShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-DisplacementCurve] ] [[-BlurInfo] ] [[-BlurSize] ] [[-BlurQuality] ] [[-BlurDirections] ] [[-BlurAngle] ] [[-ChromaticAberrationInfo] ] [[-ChromaticAberration] ] [[-ColorizeInfo] ] [[-ColorizeColor] ] [[-FlagsInfo] ] [-BlueAffectsStrength ] [-BlueAffectsColorize ] [-BlueAffectsBlur ] [-AlphaAffectsStrength ] [-ApplyAlpha ] [[-MaskLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Set-OBSDisplacementMapInvertShader.md b/docs/Set-OBSDisplacementMapInvertShader.md new file mode 100644 index 00000000..c0b10532 --- /dev/null +++ b/docs/Set-OBSDisplacementMapInvertShader.md @@ -0,0 +1,95 @@ +Get-OBSDisplacementMapInvertShader +---------------------------------- + +### Synopsis +Get-OBSDisplacementMapInvertShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-BackgroundLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **BackgroundLayer** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------------| +|`[String]`|false |named |False |background_layer| + +#### **DisplacementInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------------| +|`[String]`|false |named |False |displacement_info| + +#### **DisplacementX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_x| + +#### **DisplacementY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_y| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSDisplacementMapInvertShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-BackgroundLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Set-OBSDisplacementMapShader.md b/docs/Set-OBSDisplacementMapShader.md new file mode 100644 index 00000000..52eaa8b9 --- /dev/null +++ b/docs/Set-OBSDisplacementMapShader.md @@ -0,0 +1,95 @@ +Get-OBSDisplacementMapShader +---------------------------- + +### Synopsis +Get-OBSDisplacementMapShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-MaskLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **DisplacementInfo** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------------| +|`[String]`|false |named |False |displacement_info| + +#### **DisplacementX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_x| + +#### **DisplacementY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |displacement_y| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **MaskLayer** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[String]`|false |named |False |mask_layer| + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSDisplacementMapShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-MaskLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Set-OBSGlitchPeriodicShader.md b/docs/Set-OBSGlitchPeriodicShader.md new file mode 100644 index 00000000..14fd3235 --- /dev/null +++ b/docs/Set-OBSGlitchPeriodicShader.md @@ -0,0 +1,95 @@ +Get-OBSGlitchPeriodicShader +--------------------------- + +### Synopsis +Get-OBSGlitchPeriodicShader [[-PERI] ] [[-DURA] ] [[-AMPL] ] [[-SCRA] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **AMPL** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **DURA** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PERI** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **SCRA** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSGlitchPeriodicShader [[-PERI] ] [[-DURA] ] [[-AMPL] ] [[-SCRA] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Set-OBSHardBlinkShader.md b/docs/Set-OBSHardBlinkShader.md new file mode 100644 index 00000000..63748d2e --- /dev/null +++ b/docs/Set-OBSHardBlinkShader.md @@ -0,0 +1,83 @@ +Get-OBSHardBlinkShader +---------------------- + +### Synopsis +Get-OBSHardBlinkShader [[-Timeon] ] [[-Timeoff] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Timeoff** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **Timeon** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSHardBlinkShader [[-Timeon] ] [[-Timeoff] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Set-OBSMotionBlurShader.md b/docs/Set-OBSMotionBlurShader.md new file mode 100644 index 00000000..0291ea14 --- /dev/null +++ b/docs/Set-OBSMotionBlurShader.md @@ -0,0 +1,83 @@ +Get-OBSMotionBlurShader +----------------------- + +### Synopsis +Get-OBSMotionBlurShader [[-PreviousOutput] ] [[-Strength] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PreviousOutput** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|---------------| +|`[String]`|false |named |False |previous_output| + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Strength** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSMotionBlurShader [[-PreviousOutput] ] [[-Strength] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Set-OBSNoiseShader.md b/docs/Set-OBSNoiseShader.md new file mode 100644 index 00000000..b75ddd04 --- /dev/null +++ b/docs/Set-OBSNoiseShader.md @@ -0,0 +1,101 @@ +Get-OBSNoiseShader +------------------ + +### Synopsis +Get-OBSNoiseShader [[-Speed] ] [[-Scale] ] [[-NoiseLevel] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Monochromatic] [-UseRand] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Monochromatic** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoiseLevel** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Scale** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Speed** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **UseRand** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|--------| +|`[Switch]`|false |named |False |use_rand| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSNoiseShader [[-Speed] ] [[-Scale] ] [[-NoiseLevel] ] [-Monochromatic ] [-UseRand ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Set-OBSNormalMapShader.md b/docs/Set-OBSNormalMapShader.md new file mode 100644 index 00000000..245b4832 --- /dev/null +++ b/docs/Set-OBSNormalMapShader.md @@ -0,0 +1,107 @@ +Get-OBSNormalMapShader +---------------------- + +### Synopsis +Get-OBSNormalMapShader [[-Strength] ] [[-Type] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-OffsetHeight] [-InvertR] [-InvertG] [-InvertH] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **InvertG** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **InvertH** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **InvertR** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **OffsetHeight** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Strength** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **Type** + +|Type |Required|Position|PipelineInput| +|-------|--------|--------|-------------| +|`[Int]`|false |named |False | + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSNormalMapShader [[-Strength] ] [-OffsetHeight ] [-InvertR ] [-InvertG ] [-InvertH ] [[-Type] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Set-OBSPerspectiveShader.md b/docs/Set-OBSPerspectiveShader.md new file mode 100644 index 00000000..3288693b --- /dev/null +++ b/docs/Set-OBSPerspectiveShader.md @@ -0,0 +1,107 @@ +Get-OBSPerspectiveShader +------------------------ + +### Synopsis +Get-OBSPerspectiveShader [[-AngleX] ] [[-AngleY] ] [[-AngleZ] ] [[-Perspective] ] [[-BorderColor] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-ShowBorder] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **AngleX** + +|Type |Required|Position|PipelineInput|Aliases| +|---------|--------|--------|-------------|-------| +|`[Float]`|false |named |False |angle_x| + +#### **AngleY** + +|Type |Required|Position|PipelineInput|Aliases| +|---------|--------|--------|-------------|-------| +|`[Float]`|false |named |False |angle_y| + +#### **AngleZ** + +|Type |Required|Position|PipelineInput|Aliases| +|---------|--------|--------|-------------|-------| +|`[Float]`|false |named |False |angle_z| + +#### **BorderColor** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|------------| +|`[String]`|false |named |False |border_color| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Perspective** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **ShowBorder** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------| +|`[Switch]`|false |named |False |show_border| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSPerspectiveShader [[-AngleX] ] [[-AngleY] ] [[-AngleZ] ] [[-Perspective] ] [[-BorderColor] ] [-ShowBorder ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Set-OBSQuadrilateralCropShader.md b/docs/Set-OBSQuadrilateralCropShader.md new file mode 100644 index 00000000..c5037d7a --- /dev/null +++ b/docs/Set-OBSQuadrilateralCropShader.md @@ -0,0 +1,119 @@ +Get-OBSQuadrilateralCropShader +------------------------------ + +### Synopsis +Get-OBSQuadrilateralCropShader [[-TopLeftX] ] [[-TopLeftY] ] [[-TopRightX] ] [[-TopRightY] ] [[-BottomLeftX] ] [[-BottomLeftY] ] [[-BottomRightX] ] [[-BottomRightY] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **BottomLeftX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|-------------| +|`[Float]`|false |named |False |Bottom_Left_X| + +#### **BottomLeftY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|-------------| +|`[Float]`|false |named |False |Bottom_Left_Y| + +#### **BottomRightX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |Bottom_Right_X| + +#### **BottomRightY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|--------------| +|`[Float]`|false |named |False |Bottom_Right_Y| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **TopLeftX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |Top_Left_X| + +#### **TopLeftY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|----------| +|`[Float]`|false |named |False |Top_Left_Y| + +#### **TopRightX** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|-----------| +|`[Float]`|false |named |False |Top_Right_X| + +#### **TopRightY** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|-----------| +|`[Float]`|false |named |False |Top_Right_Y| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSQuadrilateralCropShader [[-TopLeftX] ] [[-TopLeftY] ] [[-TopRightX] ] [[-TopRightY] ] [[-BottomLeftX] ] [[-BottomLeftY] ] [[-BottomRightX] ] [[-BottomRightY] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Set-OBSRepeatGridCenterCropShader.md b/docs/Set-OBSRepeatGridCenterCropShader.md new file mode 100644 index 00000000..dd7f8e8a --- /dev/null +++ b/docs/Set-OBSRepeatGridCenterCropShader.md @@ -0,0 +1,101 @@ +Get-OBSRepeatGridCenterCropShader +--------------------------------- + +### Synopsis +Get-OBSRepeatGridCenterCropShader [[-ViewProj] ] [[-Image] ] [[-Alpha] ] [[-Columns] ] [[-Rows] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **Alpha** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **Columns** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Image** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **Rows** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ViewProj** + +|Type |Required|Position|PipelineInput| +|---------------------|--------|--------|-------------| +|`[System.Single[][]]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSRepeatGridCenterCropShader [[-ViewProj] ] [[-Image] ] [[-Alpha] ] [[-Columns] ] [[-Rows] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Set-OBSWalkingDeadPixelFixerShader.md b/docs/Set-OBSWalkingDeadPixelFixerShader.md new file mode 100644 index 00000000..dab40694 --- /dev/null +++ b/docs/Set-OBSWalkingDeadPixelFixerShader.md @@ -0,0 +1,131 @@ +Get-OBSWalkingDeadPixelFixerShader +---------------------------------- + +### Synopsis +Get-OBSWalkingDeadPixelFixerShader [[-ScanWidth] ] [[-ScanHeight] ] [[-ScanOffsetX] ] [[-ScanOffsetY] ] [[-ContrastThreshold] ] [[-MinClusterSize] ] [[-MaxClusterSize] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-ShowBorder] [-ShowGreen] [-Bypass] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **Bypass** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ContrastThreshold** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|------------------| +|`[Float]`|false |named |False |Contrast_Threshold| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **MaxClusterSize** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|----------------| +|`[Int]`|false |named |False |Max_Cluster_Size| + +#### **MinClusterSize** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|----------------| +|`[Int]`|false |named |False |Min_Cluster_Size| + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ScanHeight** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|-----------| +|`[Int]`|false |named |False |Scan_Height| + +#### **ScanOffsetX** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|-------------| +|`[Int]`|false |named |False |Scan_Offset_X| + +#### **ScanOffsetY** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|-------------| +|`[Int]`|false |named |False |Scan_Offset_Y| + +#### **ScanWidth** + +|Type |Required|Position|PipelineInput|Aliases | +|-------|--------|--------|-------------|----------| +|`[Int]`|false |named |False |Scan_Width| + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **ShowBorder** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-----------| +|`[Switch]`|false |named |False |Show_Border| + +#### **ShowGreen** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[Switch]`|false |named |False |Show_Green| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSWalkingDeadPixelFixerShader [[-ScanWidth] ] [[-ScanHeight] ] [[-ScanOffsetX] ] [[-ScanOffsetY] ] [-ShowBorder ] [[-ContrastThreshold] ] [[-MinClusterSize] ] [[-MaxClusterSize] ] [-ShowGreen ] [-Bypass ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Set-OBSZoomBlurTransitionShader.md b/docs/Set-OBSZoomBlurTransitionShader.md new file mode 100644 index 00000000..b28ab22b --- /dev/null +++ b/docs/Set-OBSZoomBlurTransitionShader.md @@ -0,0 +1,101 @@ +Get-OBSZoomBlurTransitionShader +------------------------------- + +### Synopsis +Get-OBSZoomBlurTransitionShader [[-ImageA] ] [[-ImageB] ] [[-TransitionTime] ] [[-Strength] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-ConvertLinear] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [] + +--- + +### Description + +--- + +### Parameters +#### **ConvertLinear** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|--------------| +|`[Switch]`|false |named |False |convert_linear| + +#### **FilterName** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[String]`|false |named |False | + +#### **Force** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ImageA** + +|Type |Required|Position|PipelineInput|Aliases| +|----------|--------|--------|-------------|-------| +|`[String]`|false |named |False |image_a| + +#### **ImageB** + +|Type |Required|Position|PipelineInput|Aliases| +|----------|--------|--------|-------------|-------| +|`[String]`|false |named |False |image_b| + +#### **NoResponse** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **PassThru** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +#### **ShaderText** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |ShaderContent| + +#### **SourceName** + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|-------------| +|`[String]`|false |named |False |SceneItemName| + +#### **Strength** + +|Type |Required|Position|PipelineInput| +|---------|--------|--------|-------------| +|`[Float]`|false |named |False | + +#### **TransitionTime** + +|Type |Required|Position|PipelineInput|Aliases | +|---------|--------|--------|-------------|---------------| +|`[Float]`|false |named |False |transition_time| + +#### **UseShaderTime** + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |False | + +--- + +### Inputs +System.String + +--- + +### Outputs +* [Object](https://learn.microsoft.com/en-us/dotnet/api/System.Object) + +--- + +### Syntax +```PowerShell +Get-OBSZoomBlurTransitionShader [[-ImageA] ] [[-ImageB] ] [[-TransitionTime] ] [-ConvertLinear ] [[-Strength] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force ] [-PassThru ] [-NoResponse ] [-UseShaderTime ] [] +``` diff --git a/docs/Start-OBS.md b/docs/Start-OBS.md new file mode 100644 index 00000000..05d4e87f --- /dev/null +++ b/docs/Start-OBS.md @@ -0,0 +1,96 @@ +Start-OBS +--------- + +### Synopsis +Start OBS + +--- + +### Description + +Starts OBS + +Without any parameters, will attempt to start the obs process. + +If OBS is already running, will output the current obs process. + +* If `-Recording` is passed, will start recording +* If `-Streaming` is passed, will start streaming +* If `-StudioMode` is passed, will start studio mode +* If `-VirtualCamera` is passed, will start the virtual camera + +If additional arguments are passed, will pass them thru to a new obs process. + +--- + +### Related Links +* [Stop-OBS](Stop-OBS.md) + +* [Start-OBSRecord](Start-OBSRecord.md) + +* [Start-OBSStream](Start-OBSStream.md) + +* [Start-OBSVirtualCam](Start-OBSVirtualCam.md) + +--- + +### Parameters +#### **ArgumentList** +A list of arguments. These will be passed to a new obs process. + +|Type |Required|Position|PipelineInput|Aliases | +|--------------|--------|--------|-------------|-------------------------------| +|`[PSObject[]]`|false |named |false |Arguments
Argument
Args| + +#### **InputObject** +Any input object. This will currently be ignored. + +|Type |Required|Position|PipelineInput | +|--------------|--------|--------|--------------| +|`[PSObject[]]`|false |named |true (ByValue)| + +#### **Recording** +If set, will start recording. + +|Type |Required|Position|PipelineInput|Aliases| +|----------|--------|--------|-------------|-------| +|`[Switch]`|false |named |false |Record | + +#### **Streaming** +If set, will start streaming. + +|Type |Required|Position|PipelineInput|Aliases| +|----------|--------|--------|-------------|-------| +|`[Switch]`|false |named |false |Stream | + +#### **StudioMode** +If set, will start studio mode. + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |false | + +#### **VirtualCamera** +If set, will start the virtual camera + +|Type |Required|Position|PipelineInput|Aliases | +|----------|--------|--------|-------------|----------| +|`[Switch]`|false |named |false |VirtualCam| + +#### **WhatIf** +-WhatIf is an automatic variable that is created when a command has ```[CmdletBinding(SupportsShouldProcess)]```. +-WhatIf is used to see what would happen, or return operations without executing them +#### **Confirm** +-Confirm is an automatic variable that is created when a command has ```[CmdletBinding(SupportsShouldProcess)]```. +-Confirm is used to -Confirm each operation. + +If you pass ```-Confirm:$false``` you will not be prompted. + +If the command sets a ```[ConfirmImpact("Medium")]``` which is lower than ```$confirmImpactPreference```, you will not be prompted unless -Confirm is passed. + +--- + +### Syntax +```PowerShell +Start-OBS [-ArgumentList ] [-InputObject ] [-Recording] [-Streaming] [-StudioMode] [-VirtualCamera] [-WhatIf] [-Confirm] [] +``` diff --git a/docs/Stop-OBS.md b/docs/Stop-OBS.md new file mode 100644 index 00000000..64e40861 --- /dev/null +++ b/docs/Stop-OBS.md @@ -0,0 +1,130 @@ +Stop-OBS +-------- + +### Synopsis +Stops OBS + +--- + +### Description + +Stops OBS. + +By default, stops recording and streaming. + +If -Process is provided, will stop all running OBS processes + +If -Recording is provided, will stop recording +If -Streaming if provided, will stop obs streaming +If -VirtualCamera is provided, will stop the virtual camera + +--- + +### Related Links +* [Stop-OBSRecord](Stop-OBSRecord.md) + +* [Stop-OBSStream](Stop-OBSStream.md) + +* [Stop-OBSVirtualCam](Stop-OBSVirtualCam.md) + +* [Set-OBSStudioModeEnabled](Set-OBSStudioModeEnabled.md) + +--- + +### Examples +Stop Streaming and Recording + +```PowerShell +Stop-OBS +``` +Stops obs recording + +```PowerShell +Stop-OBS -Recording +``` +Stop Streaming + +```PowerShell +Stop-OBS -Streaming +``` +Stop OBS Virtual Camera + +```PowerShell +Stop-OBS -VirtualCamera +``` +Stop OBS Virtual Camera without prompting + +```PowerShell +Stop-OBS -VirtualCamera -Confirm:$false +``` +> EXAMPLE 6 + +```PowerShell +Stop-OBS -StudioMode +``` + +--- + +### Parameters +#### **Recording** +If set, will stop recording. + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |false | + +#### **Streaming** +If set, will stop streaming + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |false | + +#### **VirtualCamera** +If set, will stop the virtual camera. + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |false | + +#### **Process** +If set, will stop the OBS process. + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |false | + +#### **StudioMode** +If set, will enable studio mode. + +|Type |Required|Position|PipelineInput| +|----------|--------|--------|-------------| +|`[Switch]`|false |named |false | + +#### **WhatIf** +-WhatIf is an automatic variable that is created when a command has ```[CmdletBinding(SupportsShouldProcess)]```. +-WhatIf is used to see what would happen, or return operations without executing them +#### **Confirm** +-Confirm is an automatic variable that is created when a command has ```[CmdletBinding(SupportsShouldProcess)]```. +-Confirm is used to -Confirm each operation. + +If you pass ```-Confirm:$false``` you will not be prompted. + +If the command sets a ```[ConfirmImpact("Medium")]``` which is lower than ```$confirmImpactPreference```, you will not be prompted unless -Confirm is passed. + +--- + +### Notes +This command Supports Should Process and has a ConfirmImpact of 'High' + +In an interactive session, this command prompt by default. + +If `-WhatIf` is passed, will output what happen if this ran +If `-Confirm:$false`, confirmation will be skipped. + +--- + +### Syntax +```PowerShell +Stop-OBS [-Recording] [-Streaming] [-VirtualCamera] [-Process] [-StudioMode] [-WhatIf] [-Confirm] [] +``` diff --git a/docs/_data/Help/Add-OBS3dPanelShader.json b/docs/_data/Help/Add-OBS3dPanelShader.json new file mode 100644 index 00000000..3e26a529 --- /dev/null +++ b/docs/_data/Help/Add-OBS3dPanelShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBS3dPanelShader [[-Credits] ] [[-Scale] ] [[-TiltXDeg] ] [[-TiltYDeg] ] [[-TiltZDeg] ] [[-PosX] ] [[-PosY] ] [[-Thickness] ] [[-RadiusFb] ] [[-Brightness] ] [[-LightPosition] ] [[-Wiggle] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-WiggleRot] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Add-OBSAudioShader.json b/docs/_data/Help/Add-OBSAudioShader.json new file mode 100644 index 00000000..e116c8b5 --- /dev/null +++ b/docs/_data/Help/Add-OBSAudioShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSAudioShader [[-AudioPeak] ] [[-AudioMagnitude] ] [[-Intensity] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Add-OBSCubeRotatingShader.json b/docs/_data/Help/Add-OBSCubeRotatingShader.json new file mode 100644 index 00000000..39b20764 --- /dev/null +++ b/docs/_data/Help/Add-OBSCubeRotatingShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSCubeRotatingShader [[-Images] ] [[-Speed] ] [[-Shadow] ] [[-OtherImage1] ] [[-OtherImage2] ] [[-OtherImage3] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Add-OBSDisplacementMapAdvancedInvertShader.json b/docs/_data/Help/Add-OBSDisplacementMapAdvancedInvertShader.json new file mode 100644 index 00000000..46bf6ed5 --- /dev/null +++ b/docs/_data/Help/Add-OBSDisplacementMapAdvancedInvertShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSDisplacementMapAdvancedInvertShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-DisplacementCurve] ] [[-BlurInfo] ] [[-BlurSize] ] [[-BlurQuality] ] [[-BlurDirections] ] [[-BlurAngle] ] [[-ChromaticAberrationInfo] ] [[-ChromaticAberration] ] [[-ColorizeInfo] ] [[-ColorizeColor] ] [[-FlagsInfo] ] [[-BackgroundLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-BlueAffectsStrength] [-BlueAffectsColorize] [-BlueAffectsBlur] [-AlphaAffectsStrength] [-ApplyAlpha] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Add-OBSDisplacementMapAdvancedShader.json b/docs/_data/Help/Add-OBSDisplacementMapAdvancedShader.json new file mode 100644 index 00000000..2eb87e91 --- /dev/null +++ b/docs/_data/Help/Add-OBSDisplacementMapAdvancedShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSDisplacementMapAdvancedShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-DisplacementCurve] ] [[-BlurInfo] ] [[-BlurSize] ] [[-BlurQuality] ] [[-BlurDirections] ] [[-BlurAngle] ] [[-ChromaticAberrationInfo] ] [[-ChromaticAberration] ] [[-ColorizeInfo] ] [[-ColorizeColor] ] [[-FlagsInfo] ] [[-MaskLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-BlueAffectsStrength] [-BlueAffectsColorize] [-BlueAffectsBlur] [-AlphaAffectsStrength] [-ApplyAlpha] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Add-OBSDisplacementMapInvertShader.json b/docs/_data/Help/Add-OBSDisplacementMapInvertShader.json new file mode 100644 index 00000000..de771ff7 --- /dev/null +++ b/docs/_data/Help/Add-OBSDisplacementMapInvertShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSDisplacementMapInvertShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-BackgroundLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Add-OBSDisplacementMapShader.json b/docs/_data/Help/Add-OBSDisplacementMapShader.json new file mode 100644 index 00000000..a49bf9e4 --- /dev/null +++ b/docs/_data/Help/Add-OBSDisplacementMapShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSDisplacementMapShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-MaskLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Add-OBSGlitchPeriodicShader.json b/docs/_data/Help/Add-OBSGlitchPeriodicShader.json new file mode 100644 index 00000000..7e4a2349 --- /dev/null +++ b/docs/_data/Help/Add-OBSGlitchPeriodicShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSGlitchPeriodicShader [[-PERI] ] [[-DURA] ] [[-AMPL] ] [[-SCRA] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Add-OBSHardBlinkShader.json b/docs/_data/Help/Add-OBSHardBlinkShader.json new file mode 100644 index 00000000..cf41ebe3 --- /dev/null +++ b/docs/_data/Help/Add-OBSHardBlinkShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSHardBlinkShader [[-Timeon] ] [[-Timeoff] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Add-OBSMotionBlurShader.json b/docs/_data/Help/Add-OBSMotionBlurShader.json new file mode 100644 index 00000000..183df040 --- /dev/null +++ b/docs/_data/Help/Add-OBSMotionBlurShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSMotionBlurShader [[-PreviousOutput] ] [[-Strength] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Add-OBSNoiseShader.json b/docs/_data/Help/Add-OBSNoiseShader.json new file mode 100644 index 00000000..075a0ecc --- /dev/null +++ b/docs/_data/Help/Add-OBSNoiseShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSNoiseShader [[-Speed] ] [[-Scale] ] [[-NoiseLevel] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Monochromatic] [-UseRand] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Add-OBSNormalMapShader.json b/docs/_data/Help/Add-OBSNormalMapShader.json new file mode 100644 index 00000000..7464c72a --- /dev/null +++ b/docs/_data/Help/Add-OBSNormalMapShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSNormalMapShader [[-Strength] ] [[-Type] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-OffsetHeight] [-InvertR] [-InvertG] [-InvertH] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Add-OBSPerspectiveShader.json b/docs/_data/Help/Add-OBSPerspectiveShader.json new file mode 100644 index 00000000..c0615f02 --- /dev/null +++ b/docs/_data/Help/Add-OBSPerspectiveShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSPerspectiveShader [[-AngleX] ] [[-AngleY] ] [[-AngleZ] ] [[-Perspective] ] [[-BorderColor] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-ShowBorder] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Add-OBSQuadrilateralCropShader.json b/docs/_data/Help/Add-OBSQuadrilateralCropShader.json new file mode 100644 index 00000000..bf3337fe --- /dev/null +++ b/docs/_data/Help/Add-OBSQuadrilateralCropShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSQuadrilateralCropShader [[-TopLeftX] ] [[-TopLeftY] ] [[-TopRightX] ] [[-TopRightY] ] [[-BottomLeftX] ] [[-BottomLeftY] ] [[-BottomRightX] ] [[-BottomRightY] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Add-OBSRepeatGridCenterCropShader.json b/docs/_data/Help/Add-OBSRepeatGridCenterCropShader.json new file mode 100644 index 00000000..25e86ac4 --- /dev/null +++ b/docs/_data/Help/Add-OBSRepeatGridCenterCropShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSRepeatGridCenterCropShader [[-ViewProj] ] [[-Image] ] [[-Alpha] ] [[-Columns] ] [[-Rows] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Add-OBSWalkingDeadPixelFixerShader.json b/docs/_data/Help/Add-OBSWalkingDeadPixelFixerShader.json new file mode 100644 index 00000000..64dbd980 --- /dev/null +++ b/docs/_data/Help/Add-OBSWalkingDeadPixelFixerShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSWalkingDeadPixelFixerShader [[-ScanWidth] ] [[-ScanHeight] ] [[-ScanOffsetX] ] [[-ScanOffsetY] ] [[-ContrastThreshold] ] [[-MinClusterSize] ] [[-MaxClusterSize] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-ShowBorder] [-ShowGreen] [-Bypass] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Add-OBSZoomBlurTransitionShader.json b/docs/_data/Help/Add-OBSZoomBlurTransitionShader.json new file mode 100644 index 00000000..a23dbcaf --- /dev/null +++ b/docs/_data/Help/Add-OBSZoomBlurTransitionShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSZoomBlurTransitionShader [[-ImageA] ] [[-ImageB] ] [[-TransitionTime] ] [[-Strength] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-ConvertLinear] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Get-OBS3dPanelShader.json b/docs/_data/Help/Get-OBS3dPanelShader.json new file mode 100644 index 00000000..3e26a529 --- /dev/null +++ b/docs/_data/Help/Get-OBS3dPanelShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBS3dPanelShader [[-Credits] ] [[-Scale] ] [[-TiltXDeg] ] [[-TiltYDeg] ] [[-TiltZDeg] ] [[-PosX] ] [[-PosY] ] [[-Thickness] ] [[-RadiusFb] ] [[-Brightness] ] [[-LightPosition] ] [[-Wiggle] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-WiggleRot] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Get-OBSAudioShader.json b/docs/_data/Help/Get-OBSAudioShader.json new file mode 100644 index 00000000..e116c8b5 --- /dev/null +++ b/docs/_data/Help/Get-OBSAudioShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSAudioShader [[-AudioPeak] ] [[-AudioMagnitude] ] [[-Intensity] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Get-OBSCubeRotatingShader.json b/docs/_data/Help/Get-OBSCubeRotatingShader.json new file mode 100644 index 00000000..39b20764 --- /dev/null +++ b/docs/_data/Help/Get-OBSCubeRotatingShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSCubeRotatingShader [[-Images] ] [[-Speed] ] [[-Shadow] ] [[-OtherImage1] ] [[-OtherImage2] ] [[-OtherImage3] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Get-OBSDisplacementMapAdvancedInvertShader.json b/docs/_data/Help/Get-OBSDisplacementMapAdvancedInvertShader.json new file mode 100644 index 00000000..46bf6ed5 --- /dev/null +++ b/docs/_data/Help/Get-OBSDisplacementMapAdvancedInvertShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSDisplacementMapAdvancedInvertShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-DisplacementCurve] ] [[-BlurInfo] ] [[-BlurSize] ] [[-BlurQuality] ] [[-BlurDirections] ] [[-BlurAngle] ] [[-ChromaticAberrationInfo] ] [[-ChromaticAberration] ] [[-ColorizeInfo] ] [[-ColorizeColor] ] [[-FlagsInfo] ] [[-BackgroundLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-BlueAffectsStrength] [-BlueAffectsColorize] [-BlueAffectsBlur] [-AlphaAffectsStrength] [-ApplyAlpha] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Get-OBSDisplacementMapAdvancedShader.json b/docs/_data/Help/Get-OBSDisplacementMapAdvancedShader.json new file mode 100644 index 00000000..2eb87e91 --- /dev/null +++ b/docs/_data/Help/Get-OBSDisplacementMapAdvancedShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSDisplacementMapAdvancedShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-DisplacementCurve] ] [[-BlurInfo] ] [[-BlurSize] ] [[-BlurQuality] ] [[-BlurDirections] ] [[-BlurAngle] ] [[-ChromaticAberrationInfo] ] [[-ChromaticAberration] ] [[-ColorizeInfo] ] [[-ColorizeColor] ] [[-FlagsInfo] ] [[-MaskLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-BlueAffectsStrength] [-BlueAffectsColorize] [-BlueAffectsBlur] [-AlphaAffectsStrength] [-ApplyAlpha] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Get-OBSDisplacementMapInvertShader.json b/docs/_data/Help/Get-OBSDisplacementMapInvertShader.json new file mode 100644 index 00000000..de771ff7 --- /dev/null +++ b/docs/_data/Help/Get-OBSDisplacementMapInvertShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSDisplacementMapInvertShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-BackgroundLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Get-OBSDisplacementMapShader.json b/docs/_data/Help/Get-OBSDisplacementMapShader.json new file mode 100644 index 00000000..a49bf9e4 --- /dev/null +++ b/docs/_data/Help/Get-OBSDisplacementMapShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSDisplacementMapShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-MaskLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Get-OBSGlitchPeriodicShader.json b/docs/_data/Help/Get-OBSGlitchPeriodicShader.json new file mode 100644 index 00000000..7e4a2349 --- /dev/null +++ b/docs/_data/Help/Get-OBSGlitchPeriodicShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSGlitchPeriodicShader [[-PERI] ] [[-DURA] ] [[-AMPL] ] [[-SCRA] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Get-OBSHardBlinkShader.json b/docs/_data/Help/Get-OBSHardBlinkShader.json new file mode 100644 index 00000000..cf41ebe3 --- /dev/null +++ b/docs/_data/Help/Get-OBSHardBlinkShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSHardBlinkShader [[-Timeon] ] [[-Timeoff] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Get-OBSMotionBlurShader.json b/docs/_data/Help/Get-OBSMotionBlurShader.json new file mode 100644 index 00000000..183df040 --- /dev/null +++ b/docs/_data/Help/Get-OBSMotionBlurShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSMotionBlurShader [[-PreviousOutput] ] [[-Strength] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Get-OBSNoiseShader.json b/docs/_data/Help/Get-OBSNoiseShader.json new file mode 100644 index 00000000..075a0ecc --- /dev/null +++ b/docs/_data/Help/Get-OBSNoiseShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSNoiseShader [[-Speed] ] [[-Scale] ] [[-NoiseLevel] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Monochromatic] [-UseRand] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Get-OBSNormalMapShader.json b/docs/_data/Help/Get-OBSNormalMapShader.json new file mode 100644 index 00000000..7464c72a --- /dev/null +++ b/docs/_data/Help/Get-OBSNormalMapShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSNormalMapShader [[-Strength] ] [[-Type] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-OffsetHeight] [-InvertR] [-InvertG] [-InvertH] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Get-OBSPerspectiveShader.json b/docs/_data/Help/Get-OBSPerspectiveShader.json new file mode 100644 index 00000000..c0615f02 --- /dev/null +++ b/docs/_data/Help/Get-OBSPerspectiveShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSPerspectiveShader [[-AngleX] ] [[-AngleY] ] [[-AngleZ] ] [[-Perspective] ] [[-BorderColor] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-ShowBorder] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Get-OBSQuadrilateralCropShader.json b/docs/_data/Help/Get-OBSQuadrilateralCropShader.json new file mode 100644 index 00000000..bf3337fe --- /dev/null +++ b/docs/_data/Help/Get-OBSQuadrilateralCropShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSQuadrilateralCropShader [[-TopLeftX] ] [[-TopLeftY] ] [[-TopRightX] ] [[-TopRightY] ] [[-BottomLeftX] ] [[-BottomLeftY] ] [[-BottomRightX] ] [[-BottomRightY] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Get-OBSRepeatGridCenterCropShader.json b/docs/_data/Help/Get-OBSRepeatGridCenterCropShader.json new file mode 100644 index 00000000..25e86ac4 --- /dev/null +++ b/docs/_data/Help/Get-OBSRepeatGridCenterCropShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSRepeatGridCenterCropShader [[-ViewProj] ] [[-Image] ] [[-Alpha] ] [[-Columns] ] [[-Rows] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Get-OBSWalkingDeadPixelFixerShader.json b/docs/_data/Help/Get-OBSWalkingDeadPixelFixerShader.json new file mode 100644 index 00000000..64dbd980 --- /dev/null +++ b/docs/_data/Help/Get-OBSWalkingDeadPixelFixerShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSWalkingDeadPixelFixerShader [[-ScanWidth] ] [[-ScanHeight] ] [[-ScanOffsetX] ] [[-ScanOffsetY] ] [[-ContrastThreshold] ] [[-MinClusterSize] ] [[-MaxClusterSize] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-ShowBorder] [-ShowGreen] [-Bypass] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Get-OBSZoomBlurTransitionShader.json b/docs/_data/Help/Get-OBSZoomBlurTransitionShader.json new file mode 100644 index 00000000..a23dbcaf --- /dev/null +++ b/docs/_data/Help/Get-OBSZoomBlurTransitionShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSZoomBlurTransitionShader [[-ImageA] ] [[-ImageB] ] [[-TransitionTime] ] [[-Strength] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-ConvertLinear] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Set-OBS3dPanelShader.json b/docs/_data/Help/Set-OBS3dPanelShader.json new file mode 100644 index 00000000..3e26a529 --- /dev/null +++ b/docs/_data/Help/Set-OBS3dPanelShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBS3dPanelShader [[-Credits] ] [[-Scale] ] [[-TiltXDeg] ] [[-TiltYDeg] ] [[-TiltZDeg] ] [[-PosX] ] [[-PosY] ] [[-Thickness] ] [[-RadiusFb] ] [[-Brightness] ] [[-LightPosition] ] [[-Wiggle] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-WiggleRot] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Set-OBSAudioShader.json b/docs/_data/Help/Set-OBSAudioShader.json new file mode 100644 index 00000000..e116c8b5 --- /dev/null +++ b/docs/_data/Help/Set-OBSAudioShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSAudioShader [[-AudioPeak] ] [[-AudioMagnitude] ] [[-Intensity] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Set-OBSCubeRotatingShader.json b/docs/_data/Help/Set-OBSCubeRotatingShader.json new file mode 100644 index 00000000..39b20764 --- /dev/null +++ b/docs/_data/Help/Set-OBSCubeRotatingShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSCubeRotatingShader [[-Images] ] [[-Speed] ] [[-Shadow] ] [[-OtherImage1] ] [[-OtherImage2] ] [[-OtherImage3] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Set-OBSDisplacementMapAdvancedInvertShader.json b/docs/_data/Help/Set-OBSDisplacementMapAdvancedInvertShader.json new file mode 100644 index 00000000..46bf6ed5 --- /dev/null +++ b/docs/_data/Help/Set-OBSDisplacementMapAdvancedInvertShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSDisplacementMapAdvancedInvertShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-DisplacementCurve] ] [[-BlurInfo] ] [[-BlurSize] ] [[-BlurQuality] ] [[-BlurDirections] ] [[-BlurAngle] ] [[-ChromaticAberrationInfo] ] [[-ChromaticAberration] ] [[-ColorizeInfo] ] [[-ColorizeColor] ] [[-FlagsInfo] ] [[-BackgroundLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-BlueAffectsStrength] [-BlueAffectsColorize] [-BlueAffectsBlur] [-AlphaAffectsStrength] [-ApplyAlpha] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Set-OBSDisplacementMapAdvancedShader.json b/docs/_data/Help/Set-OBSDisplacementMapAdvancedShader.json new file mode 100644 index 00000000..2eb87e91 --- /dev/null +++ b/docs/_data/Help/Set-OBSDisplacementMapAdvancedShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSDisplacementMapAdvancedShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-DisplacementCurve] ] [[-BlurInfo] ] [[-BlurSize] ] [[-BlurQuality] ] [[-BlurDirections] ] [[-BlurAngle] ] [[-ChromaticAberrationInfo] ] [[-ChromaticAberration] ] [[-ColorizeInfo] ] [[-ColorizeColor] ] [[-FlagsInfo] ] [[-MaskLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-BlueAffectsStrength] [-BlueAffectsColorize] [-BlueAffectsBlur] [-AlphaAffectsStrength] [-ApplyAlpha] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Set-OBSDisplacementMapInvertShader.json b/docs/_data/Help/Set-OBSDisplacementMapInvertShader.json new file mode 100644 index 00000000..de771ff7 --- /dev/null +++ b/docs/_data/Help/Set-OBSDisplacementMapInvertShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSDisplacementMapInvertShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-BackgroundLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Set-OBSDisplacementMapShader.json b/docs/_data/Help/Set-OBSDisplacementMapShader.json new file mode 100644 index 00000000..a49bf9e4 --- /dev/null +++ b/docs/_data/Help/Set-OBSDisplacementMapShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSDisplacementMapShader [[-DisplacementInfo] ] [[-DisplacementX] ] [[-DisplacementY] ] [[-MaskLayer] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Set-OBSGlitchPeriodicShader.json b/docs/_data/Help/Set-OBSGlitchPeriodicShader.json new file mode 100644 index 00000000..7e4a2349 --- /dev/null +++ b/docs/_data/Help/Set-OBSGlitchPeriodicShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSGlitchPeriodicShader [[-PERI] ] [[-DURA] ] [[-AMPL] ] [[-SCRA] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Set-OBSHardBlinkShader.json b/docs/_data/Help/Set-OBSHardBlinkShader.json new file mode 100644 index 00000000..cf41ebe3 --- /dev/null +++ b/docs/_data/Help/Set-OBSHardBlinkShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSHardBlinkShader [[-Timeon] ] [[-Timeoff] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Set-OBSMotionBlurShader.json b/docs/_data/Help/Set-OBSMotionBlurShader.json new file mode 100644 index 00000000..183df040 --- /dev/null +++ b/docs/_data/Help/Set-OBSMotionBlurShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSMotionBlurShader [[-PreviousOutput] ] [[-Strength] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Set-OBSNoiseShader.json b/docs/_data/Help/Set-OBSNoiseShader.json new file mode 100644 index 00000000..075a0ecc --- /dev/null +++ b/docs/_data/Help/Set-OBSNoiseShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSNoiseShader [[-Speed] ] [[-Scale] ] [[-NoiseLevel] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Monochromatic] [-UseRand] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Set-OBSNormalMapShader.json b/docs/_data/Help/Set-OBSNormalMapShader.json new file mode 100644 index 00000000..7464c72a --- /dev/null +++ b/docs/_data/Help/Set-OBSNormalMapShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSNormalMapShader [[-Strength] ] [[-Type] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-OffsetHeight] [-InvertR] [-InvertG] [-InvertH] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Set-OBSPerspectiveShader.json b/docs/_data/Help/Set-OBSPerspectiveShader.json new file mode 100644 index 00000000..c0615f02 --- /dev/null +++ b/docs/_data/Help/Set-OBSPerspectiveShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSPerspectiveShader [[-AngleX] ] [[-AngleY] ] [[-AngleZ] ] [[-Perspective] ] [[-BorderColor] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-ShowBorder] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Set-OBSQuadrilateralCropShader.json b/docs/_data/Help/Set-OBSQuadrilateralCropShader.json new file mode 100644 index 00000000..bf3337fe --- /dev/null +++ b/docs/_data/Help/Set-OBSQuadrilateralCropShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSQuadrilateralCropShader [[-TopLeftX] ] [[-TopLeftY] ] [[-TopRightX] ] [[-TopRightY] ] [[-BottomLeftX] ] [[-BottomLeftY] ] [[-BottomRightX] ] [[-BottomRightY] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Set-OBSRepeatGridCenterCropShader.json b/docs/_data/Help/Set-OBSRepeatGridCenterCropShader.json new file mode 100644 index 00000000..25e86ac4 --- /dev/null +++ b/docs/_data/Help/Set-OBSRepeatGridCenterCropShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSRepeatGridCenterCropShader [[-ViewProj] ] [[-Image] ] [[-Alpha] ] [[-Columns] ] [[-Rows] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Set-OBSWalkingDeadPixelFixerShader.json b/docs/_data/Help/Set-OBSWalkingDeadPixelFixerShader.json new file mode 100644 index 00000000..64dbd980 --- /dev/null +++ b/docs/_data/Help/Set-OBSWalkingDeadPixelFixerShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSWalkingDeadPixelFixerShader [[-ScanWidth] ] [[-ScanHeight] ] [[-ScanOffsetX] ] [[-ScanOffsetY] ] [[-ContrastThreshold] ] [[-MinClusterSize] ] [[-MaxClusterSize] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-ShowBorder] [-ShowGreen] [-Bypass] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Set-OBSZoomBlurTransitionShader.json b/docs/_data/Help/Set-OBSZoomBlurTransitionShader.json new file mode 100644 index 00000000..a23dbcaf --- /dev/null +++ b/docs/_data/Help/Set-OBSZoomBlurTransitionShader.json @@ -0,0 +1,33 @@ +{ + "Synopsis": "Get-OBSZoomBlurTransitionShader [[-ImageA] ] [[-ImageB] ] [[-TransitionTime] ] [[-Strength] ] [[-SourceName] ] [[-FilterName] ] [[-ShaderText] ] [-ConvertLinear] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] []", + "Description": "", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + "System.String" + ], + "Outputs": [ + "System.Object" + ], + "Links": [], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Start-OBS.json b/docs/_data/Help/Start-OBS.json new file mode 100644 index 00000000..8b1741d8 --- /dev/null +++ b/docs/_data/Help/Start-OBS.json @@ -0,0 +1,38 @@ +{ + "Synopsis": "Start OBS", + "Description": "Starts OBS\n\nWithout any parameters, will attempt to start the obs process.\n\nIf OBS is already running, will output the current obs process.\n\n* If `-Recording` is passed, will start recording\n* If `-Streaming` is passed, will start streaming\n* If `-StudioMode` is passed, will start studio mode\n* If `-VirtualCamera` is passed, will start the virtual camera\n\nIf additional arguments are passed, will pass them thru to a new obs process.", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + null + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + null + ], + "Outputs": [ + null + ], + "Links": [ + null, + null, + null, + null + ], + "Examples": [] +} \ No newline at end of file diff --git a/docs/_data/Help/Stop-OBS.json b/docs/_data/Help/Stop-OBS.json new file mode 100644 index 00000000..dbe33e14 --- /dev/null +++ b/docs/_data/Help/Stop-OBS.json @@ -0,0 +1,69 @@ +{ + "Synopsis": "Stops OBS", + "Description": "Stops OBS.\n\nBy default, stops recording and streaming.\n\nIf -Process is provided, will stop all running OBS processes\n\nIf -Recording is provided, will stop recording\nIf -Streaming if provided, will stop obs streaming\nIf -VirtualCamera is provided, will stop the virtual camera", + "Parameters": [ + { + "Name": null, + "Type": null, + "Description": "", + "Required": false, + "Position": 0, + "Aliases": null, + "DefaultValue": null, + "Globbing": false, + "PipelineInput": null, + "variableLength": false + } + ], + "Notes": [ + "This command Supports Should Process and has a ConfirmImpact of 'High'\n\nIn an interactive session, this command prompt by default.\n\nIf `-WhatIf` is passed, will output what happen if this ran\nIf `-Confirm:$false`, confirmation will be skipped." + ], + "CommandType": "Function", + "Component": [ + null + ], + "Inputs": [ + null + ], + "Outputs": [ + null + ], + "Links": [ + null, + null, + null, + null + ], + "Examples": [ + { + "Title": "EXAMPLE 1", + "Markdown": "Stop Streaming and Recording", + "Code": "Stop-OBS" + }, + { + "Title": "EXAMPLE 2", + "Markdown": "Stops obs recording", + "Code": "Stop-OBS -Recording" + }, + { + "Title": "EXAMPLE 3", + "Markdown": "Stop Streaming ", + "Code": "Stop-OBS -Streaming" + }, + { + "Title": "EXAMPLE 4", + "Markdown": "Stop OBS Virtual Camera", + "Code": "Stop-OBS -VirtualCamera" + }, + { + "Title": "EXAMPLE 5", + "Markdown": "Stop OBS Virtual Camera without prompting", + "Code": "Stop-OBS -VirtualCamera -Confirm:$false" + }, + { + "Title": "EXAMPLE 6", + "Markdown": "", + "Code": "Stop-OBS -StudioMode" + } + ] +} \ No newline at end of file diff --git a/docs/obs-powershell-commands.md b/docs/obs-powershell-commands.md index 552443d8..43aeb69d 100644 --- a/docs/obs-powershell-commands.md +++ b/docs/obs-powershell-commands.md @@ -1,8 +1,8 @@ obs-powershell-commands ----------------------- -obs-powershell exports 787 commands -(316 functions and 471 aliases) +obs-powershell exports 840 commands +(335 functions and 505 aliases) A good number of these commands directly correspond to an obs-websocket message. For a complete list, see [obs-powershell-websocket-commands](obs-powershell-websocket-commands.md). @@ -12,324 +12,343 @@ Functions ========= -|Name |Synopsis| -|------------------------------------------------------------------------------------------|--------| -|[Add-OBSInput](Add-OBSInput.md) | -|[Add-OBSProfile](Add-OBSProfile.md) | -|[Add-OBSScene](Add-OBSScene.md) | -|[Add-OBSSceneCollection](Add-OBSSceneCollection.md) | -|[Add-OBSSceneItem](Add-OBSSceneItem.md) | -|[Add-OBSSourceFilter](Add-OBSSourceFilter.md) | -|[Clear-OBSScene](Clear-OBSScene.md) | -|[Connect-OBS](Connect-OBS.md) | -|[Copy-OBSSceneItem](Copy-OBSSceneItem.md) | -|[Disconnect-OBS](Disconnect-OBS.md) | -|[Get-OBS](Get-OBS.md) | -|[Get-OBS3dSwapTransitionShader](Get-OBS3dSwapTransitionShader.md) | -|[Get-OBSAddShader](Get-OBSAddShader.md) | -|[Get-OBSAlphaBorderShader](Get-OBSAlphaBorderShader.md) | -|[Get-OBSAlphaGamingBentCameraShader](Get-OBSAlphaGamingBentCameraShader.md) | -|[Get-OBSAnimatedPathShader](Get-OBSAnimatedPathShader.md) | -|[Get-OBSAnimatedTextureShader](Get-OBSAnimatedTextureShader.md) | -|[Get-OBSAsciiShader](Get-OBSAsciiShader.md) | -|[Get-OBSAspectRatioShader](Get-OBSAspectRatioShader.md) | -|[Get-OBSBackgroundRemovalShader](Get-OBSBackgroundRemovalShader.md) | -|[Get-OBSBlendOpacityShader](Get-OBSBlendOpacityShader.md) | -|[Get-OBSBlinkShader](Get-OBSBlinkShader.md) | -|[Get-OBSBloomShader](Get-OBSBloomShader.md) | -|[Get-OBSBorderShader](Get-OBSBorderShader.md) | -|[Get-OBSBoxBlurShader](Get-OBSBoxBlurShader.md) | -|[Get-OBSBulgePinchShader](Get-OBSBulgePinchShader.md) | -|[Get-OBSBurnShader](Get-OBSBurnShader.md) | -|[Get-OBSCartoonShader](Get-OBSCartoonShader.md) | -|[Get-OBSCellShadedShader](Get-OBSCellShadedShader.md) | -|[Get-OBSChromaticAberrationShader](Get-OBSChromaticAberrationShader.md) | -|[Get-OBSChromaUVDistortionShader](Get-OBSChromaUVDistortionShader.md) | -|[Get-OBSCircleMaskFilterShader](Get-OBSCircleMaskFilterShader.md) | -|[Get-OBSClockAnalogShader](Get-OBSClockAnalogShader.md) | -|[Get-OBSClockDigitalLedShader](Get-OBSClockDigitalLedShader.md) | -|[Get-OBSClockDigitalNixieShader](Get-OBSClockDigitalNixieShader.md) | -|[Get-OBSColorDepthShader](Get-OBSColorDepthShader.md) | -|[Get-OBSColorGradeFilterShader](Get-OBSColorGradeFilterShader.md) | -|[Get-OBSCornerPinShader](Get-OBSCornerPinShader.md) | -|[Get-OBSCrtCurvatureShader](Get-OBSCrtCurvatureShader.md) | -|[Get-OBSCurrentPreviewScene](Get-OBSCurrentPreviewScene.md) | -|[Get-OBSCurrentProgramScene](Get-OBSCurrentProgramScene.md) | -|[Get-OBSCurrentSceneTransition](Get-OBSCurrentSceneTransition.md) | -|[Get-OBSCurrentSceneTransitionCursor](Get-OBSCurrentSceneTransitionCursor.md) | -|[Get-OBSCurveShader](Get-OBSCurveShader.md) | -|[Get-OBSCutRectPerCornerShader](Get-OBSCutRectPerCornerShader.md) | -|[Get-OBSCylinderShader](Get-OBSCylinderShader.md) | -|[Get-OBSDarkenShader](Get-OBSDarkenShader.md) | -|[Get-OBSDeadPixelFixerShader](Get-OBSDeadPixelFixerShader.md) | -|[Get-OBSDensitySatHueShader](Get-OBSDensitySatHueShader.md) | -|[Get-OBSDiffuseTransitionShader](Get-OBSDiffuseTransitionShader.md) | -|[Get-OBSDigitalRainShader](Get-OBSDigitalRainShader.md) | -|[Get-OBSDivideRotateShader](Get-OBSDivideRotateShader.md) | -|[Get-OBSDoodleShader](Get-OBSDoodleShader.md) | -|[Get-OBSDrawingsShader](Get-OBSDrawingsShader.md) | -|[Get-OBSDropShadowShader](Get-OBSDropShadowShader.md) | -|[Get-OBSDrunkShader](Get-OBSDrunkShader.md) | -|[Get-OBSDynamicMaskShader](Get-OBSDynamicMaskShader.md) | -|[Get-OBSEdgeDetectionShader](Get-OBSEdgeDetectionShader.md) | -|[Get-OBSEffect](Get-OBSEffect.md) | -|[Get-OBSEmbersShader](Get-OBSEmbersShader.md) | -|[Get-OBSEmbossColorShader](Get-OBSEmbossColorShader.md) | -|[Get-OBSEmbossShader](Get-OBSEmbossShader.md) | -|[Get-OBSExeldroBentCameraShader](Get-OBSExeldroBentCameraShader.md) | -|[Get-OBSFadeTransitionShader](Get-OBSFadeTransitionShader.md) | -|[Get-OBSFillColorGradientShader](Get-OBSFillColorGradientShader.md) | -|[Get-OBSFillColorLinearShader](Get-OBSFillColorLinearShader.md) | -|[Get-OBSFillColorRadialDegreesShader](Get-OBSFillColorRadialDegreesShader.md) | -|[Get-OBSFillColorRadialPercentageShader](Get-OBSFillColorRadialPercentageShader.md) | -|[Get-OBSFilterTemplateShader](Get-OBSFilterTemplateShader.md) | -|[Get-OBSFire3Shader](Get-OBSFire3Shader.md) | -|[Get-OBSFireShader](Get-OBSFireShader.md) | -|[Get-OBSFireworks2Shader](Get-OBSFireworks2Shader.md) | -|[Get-OBSFireworksShader](Get-OBSFireworksShader.md) | -|[Get-OBSFisheyeShader](Get-OBSFisheyeShader.md) | -|[Get-OBSFisheyeXyShader](Get-OBSFisheyeXyShader.md) | -|[Get-OBSFlipShader](Get-OBSFlipShader.md) | -|[Get-OBSFrostedGlassShader](Get-OBSFrostedGlassShader.md) | -|[Get-OBSGammaCorrectionShader](Get-OBSGammaCorrectionShader.md) | -|[Get-OBSGaussianBlurAdvancedShader](Get-OBSGaussianBlurAdvancedShader.md) | -|[Get-OBSGaussianBlurShader](Get-OBSGaussianBlurShader.md) | -|[Get-OBSGaussianBlurSimpleShader](Get-OBSGaussianBlurSimpleShader.md) | -|[Get-OBSGaussianExampleShader](Get-OBSGaussianExampleShader.md) | -|[Get-OBSGaussianSimpleShader](Get-OBSGaussianSimpleShader.md) | -|[Get-OBSGbCameraShader](Get-OBSGbCameraShader.md) | -|[Get-OBSGlassShader](Get-OBSGlassShader.md) | -|[Get-OBSGlitchAnalogShader](Get-OBSGlitchAnalogShader.md) | -|[Get-OBSGlitchShader](Get-OBSGlitchShader.md) | -|[Get-OBSGlowShader](Get-OBSGlowShader.md) | -|[Get-OBSGradientShader](Get-OBSGradientShader.md) | -|[Get-OBSGroup](Get-OBSGroup.md) | -|[Get-OBSGroupSceneItem](Get-OBSGroupSceneItem.md) | -|[Get-OBSHalftoneShader](Get-OBSHalftoneShader.md) | -|[Get-OBSHeatWaveSimpleShader](Get-OBSHeatWaveSimpleShader.md) | -|[Get-OBSHexagonShader](Get-OBSHexagonShader.md) | -|[Get-OBSHotkey](Get-OBSHotkey.md) | -|[Get-OBSHslHsvSaturationShader](Get-OBSHslHsvSaturationShader.md) | -|[Get-OBSHueRotatonShader](Get-OBSHueRotatonShader.md) | -|[Get-OBSInput](Get-OBSInput.md) | -|[Get-OBSInputAudioBalance](Get-OBSInputAudioBalance.md) | -|[Get-OBSInputAudioMonitorType](Get-OBSInputAudioMonitorType.md) | -|[Get-OBSInputAudioSyncOffset](Get-OBSInputAudioSyncOffset.md) | -|[Get-OBSInputAudioTracks](Get-OBSInputAudioTracks.md) | -|[Get-OBSInputDefaultSettings](Get-OBSInputDefaultSettings.md) | -|[Get-OBSInputKind](Get-OBSInputKind.md) | -|[Get-OBSInputMute](Get-OBSInputMute.md) | -|[Get-OBSInputPropertiesListPropertyItems](Get-OBSInputPropertiesListPropertyItems.md)| -|[Get-OBSInputSettings](Get-OBSInputSettings.md) | -|[Get-OBSInputVolume](Get-OBSInputVolume.md) | -|[Get-OBSIntensityScopeShader](Get-OBSIntensityScopeShader.md) | -|[Get-OBSInvertLumaShader](Get-OBSInvertLumaShader.md) | -|[Get-OBSLastReplayBufferReplay](Get-OBSLastReplayBufferReplay.md) | -|[Get-OBSLuminance2Shader](Get-OBSLuminance2Shader.md) | -|[Get-OBSLuminanceAlphaShader](Get-OBSLuminanceAlphaShader.md) | -|[Get-OBSLuminanceShader](Get-OBSLuminanceShader.md) | -|[Get-OBSMatrixShader](Get-OBSMatrixShader.md) | -|[Get-OBSMediaInputStatus](Get-OBSMediaInputStatus.md) | -|[Get-OBSMonitor](Get-OBSMonitor.md) | -|[Get-OBSMultiplyShader](Get-OBSMultiplyShader.md) | -|[Get-OBSNightSkyShader](Get-OBSNightSkyShader.md) | -|[Get-OBSOpacityShader](Get-OBSOpacityShader.md) | -|[Get-OBSOutput](Get-OBSOutput.md) | -|[Get-OBSOutputSettings](Get-OBSOutputSettings.md) | -|[Get-OBSOutputStatus](Get-OBSOutputStatus.md) | -|[Get-OBSPagePeelShader](Get-OBSPagePeelShader.md) | -|[Get-OBSPagePeelTransitionShader](Get-OBSPagePeelTransitionShader.md) | -|[Get-OBSPerlinNoiseShader](Get-OBSPerlinNoiseShader.md) | -|[Get-OBSPersistentData](Get-OBSPersistentData.md) | -|[Get-OBSPieChartShader](Get-OBSPieChartShader.md) | -|[Get-OBSPixelationShader](Get-OBSPixelationShader.md) | -|[Get-OBSPixelationTransitionShader](Get-OBSPixelationTransitionShader.md) | -|[Get-OBSPolarShader](Get-OBSPolarShader.md) | -|[Get-OBSProfile](Get-OBSProfile.md) | -|[Get-OBSProfileParameter](Get-OBSProfileParameter.md) | -|[Get-OBSPulseShader](Get-OBSPulseShader.md) | -|[Get-OBSRainbowShader](Get-OBSRainbowShader.md) | -|[Get-OBSRainWindowShader](Get-OBSRainWindowShader.md) | -|[Get-OBSRecordDirectory](Get-OBSRecordDirectory.md) | -|[Get-OBSRecordStatus](Get-OBSRecordStatus.md) | -|[Get-OBSRectangularDropShadowShader](Get-OBSRectangularDropShadowShader.md) | -|[Get-OBSReflectShader](Get-OBSReflectShader.md) | -|[Get-OBSRemovePartialPixelsShader](Get-OBSRemovePartialPixelsShader.md) | -|[Get-OBSRepeatShader](Get-OBSRepeatShader.md) | -|[Get-OBSRepeatTextureShader](Get-OBSRepeatTextureShader.md) | -|[Get-OBSReplayBufferStatus](Get-OBSReplayBufferStatus.md) | -|[Get-OBSRGBAPercentShader](Get-OBSRGBAPercentShader.md) | -|[Get-OBSRgbColorWheelShader](Get-OBSRgbColorWheelShader.md) | -|[Get-OBSRgbSplitShader](Get-OBSRgbSplitShader.md) | -|[Get-OBSRgbvisibilityShader](Get-OBSRgbvisibilityShader.md) | -|[Get-OBSRGSSAAShader](Get-OBSRGSSAAShader.md) | -|[Get-OBSRippleShader](Get-OBSRippleShader.md) | -|[Get-OBSRotatingSourceShader](Get-OBSRotatingSourceShader.md) | -|[Get-OBSRotatoeShader](Get-OBSRotatoeShader.md) | -|[Get-OBSRoundedRect2Shader](Get-OBSRoundedRect2Shader.md) | -|[Get-OBSRoundedRectPerCornerShader](Get-OBSRoundedRectPerCornerShader.md) | -|[Get-OBSRoundedRectPerSideShader](Get-OBSRoundedRectPerSideShader.md) | -|[Get-OBSRoundedRectShader](Get-OBSRoundedRectShader.md) | -|[Get-OBSRoundedStrokeGradientShader](Get-OBSRoundedStrokeGradientShader.md) | -|[Get-OBSRoundedStrokeShader](Get-OBSRoundedStrokeShader.md) | -|[Get-OBSScanLineShader](Get-OBSScanLineShader.md) | -|[Get-OBSScene](Get-OBSScene.md) | -|[Get-OBSSceneCollection](Get-OBSSceneCollection.md) | -|[Get-OBSSceneItem](Get-OBSSceneItem.md) | -|[Get-OBSSceneItemBlendMode](Get-OBSSceneItemBlendMode.md) | -|[Get-OBSSceneItemEnabled](Get-OBSSceneItemEnabled.md) | -|[Get-OBSSceneItemId](Get-OBSSceneItemId.md) | -|[Get-OBSSceneItemIndex](Get-OBSSceneItemIndex.md) | -|[Get-OBSSceneItemLocked](Get-OBSSceneItemLocked.md) | -|[Get-OBSSceneItemSource](Get-OBSSceneItemSource.md) | -|[Get-OBSSceneItemTransform](Get-OBSSceneItemTransform.md) | -|[Get-OBSSceneSceneTransitionOverride](Get-OBSSceneSceneTransitionOverride.md) | -|[Get-OBSSceneTransition](Get-OBSSceneTransition.md) | -|[Get-OBSSeascapeShader](Get-OBSSeascapeShader.md) | -|[Get-OBSSeasickShader](Get-OBSSeasickShader.md) | -|[Get-OBSSelectiveColorShader](Get-OBSSelectiveColorShader.md) | -|[Get-OBSShakeShader](Get-OBSShakeShader.md) | -|[Get-OBSShineShader](Get-OBSShineShader.md) | -|[Get-OBSSimpleGradientShader](Get-OBSSimpleGradientShader.md) | -|[Get-OBSSimplexNoiseShader](Get-OBSSimplexNoiseShader.md) | -|[Get-OBSSmartDenoiseShader](Get-OBSSmartDenoiseShader.md) | -|[Get-OBSSourceActive](Get-OBSSourceActive.md) | -|[Get-OBSSourceFilter](Get-OBSSourceFilter.md) | -|[Get-OBSSourceFilterDefaultSettings](Get-OBSSourceFilterDefaultSettings.md) | -|[Get-OBSSourceFilterKind](Get-OBSSourceFilterKind.md) | -|[Get-OBSSourceFilterList](Get-OBSSourceFilterList.md) | -|[Get-OBSSourceScreenshot](Get-OBSSourceScreenshot.md) | -|[Get-OBSSpecialInputs](Get-OBSSpecialInputs.md) | -|[Get-OBSSpecularShineShader](Get-OBSSpecularShineShader.md) | -|[Get-OBSSpotlightShader](Get-OBSSpotlightShader.md) | -|[Get-OBSStats](Get-OBSStats.md) | -|[Get-OBSStreamServiceSettings](Get-OBSStreamServiceSettings.md) | -|[Get-OBSStreamStatus](Get-OBSStreamStatus.md) | -|[Get-OBSStudioModeEnabled](Get-OBSStudioModeEnabled.md) | -|[Get-OBSSwirlShader](Get-OBSSwirlShader.md) | -|[Get-OBSTetraShader](Get-OBSTetraShader.md) | -|[Get-OBSThermalShader](Get-OBSThermalShader.md) | -|[Get-OBSTransitionKind](Get-OBSTransitionKind.md) | -|[Get-OBSTvCrtSubpixelShader](Get-OBSTvCrtSubpixelShader.md) | -|[Get-OBSTwistShader](Get-OBSTwistShader.md) | -|[Get-OBSTwoPassDropShadowShader](Get-OBSTwoPassDropShadowShader.md) | -|[Get-OBSVCRShader](Get-OBSVCRShader.md) | -|[Get-OBSVersion](Get-OBSVersion.md) | -|[Get-OBSVHSShader](Get-OBSVHSShader.md) | -|[Get-OBSVideoSettings](Get-OBSVideoSettings.md) | -|[Get-OBSVignettingShader](Get-OBSVignettingShader.md) | -|[Get-OBSVirtualCamStatus](Get-OBSVirtualCamStatus.md) | -|[Get-OBSVoronoiPixelationShader](Get-OBSVoronoiPixelationShader.md) | -|[Get-OBSZigZagShader](Get-OBSZigZagShader.md) | -|[Get-OBSZoomBlurShader](Get-OBSZoomBlurShader.md) | -|[Get-OBSZoomShader](Get-OBSZoomShader.md) | -|[Get-OBSZoomXYShader](Get-OBSZoomXYShader.md) | -|[Hide-OBS](Hide-OBS.md) | -|[Import-OBSEffect](Import-OBSEffect.md) | -|[Open-OBSInputFiltersDialog](Open-OBSInputFiltersDialog.md) | -|[Open-OBSInputInteractDialog](Open-OBSInputInteractDialog.md) | -|[Open-OBSInputPropertiesDialog](Open-OBSInputPropertiesDialog.md) | -|[Open-OBSSourceProjector](Open-OBSSourceProjector.md) | -|[Open-OBSVideoMixProjector](Open-OBSVideoMixProjector.md) | -|[Receive-OBS](Receive-OBS.md) | -|[Remove-OBS](Remove-OBS.md) | -|[Remove-OBSEffect](Remove-OBSEffect.md) | -|[Remove-OBSInput](Remove-OBSInput.md) | -|[Remove-OBSProfile](Remove-OBSProfile.md) | -|[Remove-OBSScene](Remove-OBSScene.md) | -|[Remove-OBSSceneItem](Remove-OBSSceneItem.md) | -|[Remove-OBSSourceFilter](Remove-OBSSourceFilter.md) | -|[Resume-OBSRecord](Resume-OBSRecord.md) | -|[Save-OBSReplayBuffer](Save-OBSReplayBuffer.md) | -|[Save-OBSSourceScreenshot](Save-OBSSourceScreenshot.md) | -|[Send-OBS](Send-OBS.md) | -|[Send-OBSCallVendorRequest](Send-OBSCallVendorRequest.md) | -|[Send-OBSCustomEvent](Send-OBSCustomEvent.md) | -|[Send-OBSOffsetMediaInputCursor](Send-OBSOffsetMediaInputCursor.md) | -|[Send-OBSPauseRecord](Send-OBSPauseRecord.md) | -|[Send-OBSPressInputPropertiesButton](Send-OBSPressInputPropertiesButton.md) | -|[Send-OBSSleep](Send-OBSSleep.md) | -|[Send-OBSStreamCaption](Send-OBSStreamCaption.md) | -|[Send-OBSTriggerHotkeyByKeySequence](Send-OBSTriggerHotkeyByKeySequence.md) | -|[Send-OBSTriggerHotkeyByName](Send-OBSTriggerHotkeyByName.md) | -|[Send-OBSTriggerMediaInputAction](Send-OBSTriggerMediaInputAction.md) | -|[Send-OBSTriggerStudioModeTransition](Send-OBSTriggerStudioModeTransition.md) | -|[Set-OBS3DFilter](Set-OBS3DFilter.md) | -|[Set-OBSAudioOutputSource](Set-OBSAudioOutputSource.md) | -|[Set-OBSBrowserSource](Set-OBSBrowserSource.md) | -|[Set-OBSColorFilter](Set-OBSColorFilter.md) | -|[Set-OBSColorSource](Set-OBSColorSource.md) | -|[Set-OBSCurrentPreviewScene](Set-OBSCurrentPreviewScene.md) | -|[Set-OBSCurrentProfile](Set-OBSCurrentProfile.md) | -|[Set-OBSCurrentProgramScene](Set-OBSCurrentProgramScene.md) | -|[Set-OBSCurrentSceneCollection](Set-OBSCurrentSceneCollection.md) | -|[Set-OBSCurrentSceneTransition](Set-OBSCurrentSceneTransition.md) | -|[Set-OBSCurrentSceneTransitionDuration](Set-OBSCurrentSceneTransitionDuration.md) | -|[Set-OBSCurrentSceneTransitionSettings](Set-OBSCurrentSceneTransitionSettings.md) | -|[Set-OBSDisplaySource](Set-OBSDisplaySource.md) | -|[Set-OBSEqualizerFilter](Set-OBSEqualizerFilter.md) | -|[Set-OBSGainFilter](Set-OBSGainFilter.md) | -|[Set-OBSInputAudioBalance](Set-OBSInputAudioBalance.md) | -|[Set-OBSInputAudioMonitorType](Set-OBSInputAudioMonitorType.md) | -|[Set-OBSInputAudioSyncOffset](Set-OBSInputAudioSyncOffset.md) | -|[Set-OBSInputAudioTracks](Set-OBSInputAudioTracks.md) | -|[Set-OBSInputMute](Set-OBSInputMute.md) | -|[Set-OBSInputName](Set-OBSInputName.md) | -|[Set-OBSInputSettings](Set-OBSInputSettings.md) | -|[Set-OBSInputVolume](Set-OBSInputVolume.md) | -|[Set-OBSMarkdownSource](Set-OBSMarkdownSource.md) | -|[Set-OBSMediaInputCursor](Set-OBSMediaInputCursor.md) | -|[Set-OBSMediaSource](Set-OBSMediaSource.md) | -|[Set-OBSOutputSettings](Set-OBSOutputSettings.md) | -|[Set-OBSPersistentData](Set-OBSPersistentData.md) | -|[Set-OBSProfileParameter](Set-OBSProfileParameter.md) | -|[Set-OBSRecordDirectory](Set-OBSRecordDirectory.md) | -|[Set-OBSRenderDelayFilter](Set-OBSRenderDelayFilter.md) | -|[Set-OBSScaleFilter](Set-OBSScaleFilter.md) | -|[Set-OBSSceneItemBlendMode](Set-OBSSceneItemBlendMode.md) | -|[Set-OBSSceneItemEnabled](Set-OBSSceneItemEnabled.md) | -|[Set-OBSSceneItemIndex](Set-OBSSceneItemIndex.md) | -|[Set-OBSSceneItemLocked](Set-OBSSceneItemLocked.md) | -|[Set-OBSSceneItemTransform](Set-OBSSceneItemTransform.md) | -|[Set-OBSSceneName](Set-OBSSceneName.md) | -|[Set-OBSSceneSceneTransitionOverride](Set-OBSSceneSceneTransitionOverride.md) | -|[Set-OBSScrollFilter](Set-OBSScrollFilter.md) | -|[Set-OBSShaderFilter](Set-OBSShaderFilter.md) | -|[Set-OBSSharpnessFilter](Set-OBSSharpnessFilter.md) | -|[Set-OBSSoundCloudSource](Set-OBSSoundCloudSource.md) | -|[Set-OBSSourceFilterEnabled](Set-OBSSourceFilterEnabled.md) | -|[Set-OBSSourceFilterIndex](Set-OBSSourceFilterIndex.md) | -|[Set-OBSSourceFilterName](Set-OBSSourceFilterName.md) | -|[Set-OBSSourceFilterSettings](Set-OBSSourceFilterSettings.md) | -|[Set-OBSStreamServiceSettings](Set-OBSStreamServiceSettings.md) | -|[Set-OBSStudioModeEnabled](Set-OBSStudioModeEnabled.md) | -|[Set-OBSSwitchSource](Set-OBSSwitchSource.md) | -|[Set-OBSTBarPosition](Set-OBSTBarPosition.md) | -|[Set-OBSVideoSettings](Set-OBSVideoSettings.md) | -|[Set-OBSVLCSource](Set-OBSVLCSource.md) | -|[Set-OBSWaveformSource](Set-OBSWaveformSource.md) | -|[Set-OBSWindowSource](Set-OBSWindowSource.md) | -|[Show-OBS](Show-OBS.md) | -|[Start-OBSEffect](Start-OBSEffect.md) | -|[Start-OBSOutput](Start-OBSOutput.md) | -|[Start-OBSRecord](Start-OBSRecord.md) | -|[Start-OBSReplayBuffer](Start-OBSReplayBuffer.md) | -|[Start-OBSStream](Start-OBSStream.md) | -|[Start-OBSVirtualCam](Start-OBSVirtualCam.md) | -|[Stop-OBSEffect](Stop-OBSEffect.md) | -|[Stop-OBSOutput](Stop-OBSOutput.md) | -|[Stop-OBSRecord](Stop-OBSRecord.md) | -|[Stop-OBSReplayBuffer](Stop-OBSReplayBuffer.md) | -|[Stop-OBSStream](Stop-OBSStream.md) | -|[Stop-OBSVirtualCam](Stop-OBSVirtualCam.md) | -|[Switch-OBSInputMute](Switch-OBSInputMute.md) | -|[Switch-OBSOutput](Switch-OBSOutput.md) | -|[Switch-OBSRecord](Switch-OBSRecord.md) | -|[Switch-OBSRecordPause](Switch-OBSRecordPause.md) | -|[Switch-OBSReplayBuffer](Switch-OBSReplayBuffer.md) | -|[Switch-OBSStream](Switch-OBSStream.md) | -|[Switch-OBSVirtualCam](Switch-OBSVirtualCam.md) | -|[Watch-OBS](Watch-OBS.md) | +|Name |Synopsis| +|------------------------------------------------------------------------------------------------|--------| +|[Add-OBSInput](Add-OBSInput.md) | +|[Add-OBSProfile](Add-OBSProfile.md) | +|[Add-OBSScene](Add-OBSScene.md) | +|[Add-OBSSceneCollection](Add-OBSSceneCollection.md) | +|[Add-OBSSceneItem](Add-OBSSceneItem.md) | +|[Add-OBSSourceFilter](Add-OBSSourceFilter.md) | +|[Clear-OBSScene](Clear-OBSScene.md) | +|[Connect-OBS](Connect-OBS.md) | +|[Copy-OBSSceneItem](Copy-OBSSceneItem.md) | +|[Disconnect-OBS](Disconnect-OBS.md) | +|[Get-OBS](Get-OBS.md) | +|[Get-OBS3dPanelShader](Get-OBS3dPanelShader.md) | +|[Get-OBS3dSwapTransitionShader](Get-OBS3dSwapTransitionShader.md) | +|[Get-OBSAddShader](Get-OBSAddShader.md) | +|[Get-OBSAlphaBorderShader](Get-OBSAlphaBorderShader.md) | +|[Get-OBSAlphaGamingBentCameraShader](Get-OBSAlphaGamingBentCameraShader.md) | +|[Get-OBSAnimatedPathShader](Get-OBSAnimatedPathShader.md) | +|[Get-OBSAnimatedTextureShader](Get-OBSAnimatedTextureShader.md) | +|[Get-OBSAsciiShader](Get-OBSAsciiShader.md) | +|[Get-OBSAspectRatioShader](Get-OBSAspectRatioShader.md) | +|[Get-OBSAudioShader](Get-OBSAudioShader.md) | +|[Get-OBSBackgroundRemovalShader](Get-OBSBackgroundRemovalShader.md) | +|[Get-OBSBlendOpacityShader](Get-OBSBlendOpacityShader.md) | +|[Get-OBSBlinkShader](Get-OBSBlinkShader.md) | +|[Get-OBSBloomShader](Get-OBSBloomShader.md) | +|[Get-OBSBorderShader](Get-OBSBorderShader.md) | +|[Get-OBSBoxBlurShader](Get-OBSBoxBlurShader.md) | +|[Get-OBSBulgePinchShader](Get-OBSBulgePinchShader.md) | +|[Get-OBSBurnShader](Get-OBSBurnShader.md) | +|[Get-OBSCartoonShader](Get-OBSCartoonShader.md) | +|[Get-OBSCellShadedShader](Get-OBSCellShadedShader.md) | +|[Get-OBSChromaticAberrationShader](Get-OBSChromaticAberrationShader.md) | +|[Get-OBSChromaUVDistortionShader](Get-OBSChromaUVDistortionShader.md) | +|[Get-OBSCircleMaskFilterShader](Get-OBSCircleMaskFilterShader.md) | +|[Get-OBSClockAnalogShader](Get-OBSClockAnalogShader.md) | +|[Get-OBSClockDigitalLedShader](Get-OBSClockDigitalLedShader.md) | +|[Get-OBSClockDigitalNixieShader](Get-OBSClockDigitalNixieShader.md) | +|[Get-OBSColorDepthShader](Get-OBSColorDepthShader.md) | +|[Get-OBSColorGradeFilterShader](Get-OBSColorGradeFilterShader.md) | +|[Get-OBSCornerPinShader](Get-OBSCornerPinShader.md) | +|[Get-OBSCrtCurvatureShader](Get-OBSCrtCurvatureShader.md) | +|[Get-OBSCubeRotatingShader](Get-OBSCubeRotatingShader.md) | +|[Get-OBSCurrentPreviewScene](Get-OBSCurrentPreviewScene.md) | +|[Get-OBSCurrentProgramScene](Get-OBSCurrentProgramScene.md) | +|[Get-OBSCurrentSceneTransition](Get-OBSCurrentSceneTransition.md) | +|[Get-OBSCurrentSceneTransitionCursor](Get-OBSCurrentSceneTransitionCursor.md) | +|[Get-OBSCurveShader](Get-OBSCurveShader.md) | +|[Get-OBSCutRectPerCornerShader](Get-OBSCutRectPerCornerShader.md) | +|[Get-OBSCylinderShader](Get-OBSCylinderShader.md) | +|[Get-OBSDarkenShader](Get-OBSDarkenShader.md) | +|[Get-OBSDeadPixelFixerShader](Get-OBSDeadPixelFixerShader.md) | +|[Get-OBSDensitySatHueShader](Get-OBSDensitySatHueShader.md) | +|[Get-OBSDiffuseTransitionShader](Get-OBSDiffuseTransitionShader.md) | +|[Get-OBSDigitalRainShader](Get-OBSDigitalRainShader.md) | +|[Get-OBSDisplacementMapAdvancedInvertShader](Get-OBSDisplacementMapAdvancedInvertShader.md)| +|[Get-OBSDisplacementMapAdvancedShader](Get-OBSDisplacementMapAdvancedShader.md) | +|[Get-OBSDisplacementMapInvertShader](Get-OBSDisplacementMapInvertShader.md) | +|[Get-OBSDisplacementMapShader](Get-OBSDisplacementMapShader.md) | +|[Get-OBSDivideRotateShader](Get-OBSDivideRotateShader.md) | +|[Get-OBSDoodleShader](Get-OBSDoodleShader.md) | +|[Get-OBSDrawingsShader](Get-OBSDrawingsShader.md) | +|[Get-OBSDropShadowShader](Get-OBSDropShadowShader.md) | +|[Get-OBSDrunkShader](Get-OBSDrunkShader.md) | +|[Get-OBSDynamicMaskShader](Get-OBSDynamicMaskShader.md) | +|[Get-OBSEdgeDetectionShader](Get-OBSEdgeDetectionShader.md) | +|[Get-OBSEffect](Get-OBSEffect.md) | +|[Get-OBSEmbersShader](Get-OBSEmbersShader.md) | +|[Get-OBSEmbossColorShader](Get-OBSEmbossColorShader.md) | +|[Get-OBSEmbossShader](Get-OBSEmbossShader.md) | +|[Get-OBSExeldroBentCameraShader](Get-OBSExeldroBentCameraShader.md) | +|[Get-OBSFadeTransitionShader](Get-OBSFadeTransitionShader.md) | +|[Get-OBSFillColorGradientShader](Get-OBSFillColorGradientShader.md) | +|[Get-OBSFillColorLinearShader](Get-OBSFillColorLinearShader.md) | +|[Get-OBSFillColorRadialDegreesShader](Get-OBSFillColorRadialDegreesShader.md) | +|[Get-OBSFillColorRadialPercentageShader](Get-OBSFillColorRadialPercentageShader.md) | +|[Get-OBSFilterTemplateShader](Get-OBSFilterTemplateShader.md) | +|[Get-OBSFire3Shader](Get-OBSFire3Shader.md) | +|[Get-OBSFireShader](Get-OBSFireShader.md) | +|[Get-OBSFireworks2Shader](Get-OBSFireworks2Shader.md) | +|[Get-OBSFireworksShader](Get-OBSFireworksShader.md) | +|[Get-OBSFisheyeShader](Get-OBSFisheyeShader.md) | +|[Get-OBSFisheyeXyShader](Get-OBSFisheyeXyShader.md) | +|[Get-OBSFlipShader](Get-OBSFlipShader.md) | +|[Get-OBSFrostedGlassShader](Get-OBSFrostedGlassShader.md) | +|[Get-OBSGammaCorrectionShader](Get-OBSGammaCorrectionShader.md) | +|[Get-OBSGaussianBlurAdvancedShader](Get-OBSGaussianBlurAdvancedShader.md) | +|[Get-OBSGaussianBlurShader](Get-OBSGaussianBlurShader.md) | +|[Get-OBSGaussianBlurSimpleShader](Get-OBSGaussianBlurSimpleShader.md) | +|[Get-OBSGaussianExampleShader](Get-OBSGaussianExampleShader.md) | +|[Get-OBSGaussianSimpleShader](Get-OBSGaussianSimpleShader.md) | +|[Get-OBSGbCameraShader](Get-OBSGbCameraShader.md) | +|[Get-OBSGlassShader](Get-OBSGlassShader.md) | +|[Get-OBSGlitchAnalogShader](Get-OBSGlitchAnalogShader.md) | +|[Get-OBSGlitchPeriodicShader](Get-OBSGlitchPeriodicShader.md) | +|[Get-OBSGlitchShader](Get-OBSGlitchShader.md) | +|[Get-OBSGlowShader](Get-OBSGlowShader.md) | +|[Get-OBSGradientShader](Get-OBSGradientShader.md) | +|[Get-OBSGroup](Get-OBSGroup.md) | +|[Get-OBSGroupSceneItem](Get-OBSGroupSceneItem.md) | +|[Get-OBSHalftoneShader](Get-OBSHalftoneShader.md) | +|[Get-OBSHardBlinkShader](Get-OBSHardBlinkShader.md) | +|[Get-OBSHeatWaveSimpleShader](Get-OBSHeatWaveSimpleShader.md) | +|[Get-OBSHexagonShader](Get-OBSHexagonShader.md) | +|[Get-OBSHotkey](Get-OBSHotkey.md) | +|[Get-OBSHslHsvSaturationShader](Get-OBSHslHsvSaturationShader.md) | +|[Get-OBSHueRotatonShader](Get-OBSHueRotatonShader.md) | +|[Get-OBSInput](Get-OBSInput.md) | +|[Get-OBSInputAudioBalance](Get-OBSInputAudioBalance.md) | +|[Get-OBSInputAudioMonitorType](Get-OBSInputAudioMonitorType.md) | +|[Get-OBSInputAudioSyncOffset](Get-OBSInputAudioSyncOffset.md) | +|[Get-OBSInputAudioTracks](Get-OBSInputAudioTracks.md) | +|[Get-OBSInputDefaultSettings](Get-OBSInputDefaultSettings.md) | +|[Get-OBSInputKind](Get-OBSInputKind.md) | +|[Get-OBSInputMute](Get-OBSInputMute.md) | +|[Get-OBSInputPropertiesListPropertyItems](Get-OBSInputPropertiesListPropertyItems.md) | +|[Get-OBSInputSettings](Get-OBSInputSettings.md) | +|[Get-OBSInputVolume](Get-OBSInputVolume.md) | +|[Get-OBSIntensityScopeShader](Get-OBSIntensityScopeShader.md) | +|[Get-OBSInvertLumaShader](Get-OBSInvertLumaShader.md) | +|[Get-OBSLastReplayBufferReplay](Get-OBSLastReplayBufferReplay.md) | +|[Get-OBSLuminance2Shader](Get-OBSLuminance2Shader.md) | +|[Get-OBSLuminanceAlphaShader](Get-OBSLuminanceAlphaShader.md) | +|[Get-OBSLuminanceShader](Get-OBSLuminanceShader.md) | +|[Get-OBSMatrixShader](Get-OBSMatrixShader.md) | +|[Get-OBSMediaInputStatus](Get-OBSMediaInputStatus.md) | +|[Get-OBSMonitor](Get-OBSMonitor.md) | +|[Get-OBSMotionBlurShader](Get-OBSMotionBlurShader.md) | +|[Get-OBSMultiplyShader](Get-OBSMultiplyShader.md) | +|[Get-OBSNightSkyShader](Get-OBSNightSkyShader.md) | +|[Get-OBSNoiseShader](Get-OBSNoiseShader.md) | +|[Get-OBSNormalMapShader](Get-OBSNormalMapShader.md) | +|[Get-OBSOpacityShader](Get-OBSOpacityShader.md) | +|[Get-OBSOutput](Get-OBSOutput.md) | +|[Get-OBSOutputSettings](Get-OBSOutputSettings.md) | +|[Get-OBSOutputStatus](Get-OBSOutputStatus.md) | +|[Get-OBSPagePeelShader](Get-OBSPagePeelShader.md) | +|[Get-OBSPagePeelTransitionShader](Get-OBSPagePeelTransitionShader.md) | +|[Get-OBSPerlinNoiseShader](Get-OBSPerlinNoiseShader.md) | +|[Get-OBSPersistentData](Get-OBSPersistentData.md) | +|[Get-OBSPerspectiveShader](Get-OBSPerspectiveShader.md) | +|[Get-OBSPieChartShader](Get-OBSPieChartShader.md) | +|[Get-OBSPixelationShader](Get-OBSPixelationShader.md) | +|[Get-OBSPixelationTransitionShader](Get-OBSPixelationTransitionShader.md) | +|[Get-OBSPolarShader](Get-OBSPolarShader.md) | +|[Get-OBSProfile](Get-OBSProfile.md) | +|[Get-OBSProfileParameter](Get-OBSProfileParameter.md) | +|[Get-OBSPulseShader](Get-OBSPulseShader.md) | +|[Get-OBSQuadrilateralCropShader](Get-OBSQuadrilateralCropShader.md) | +|[Get-OBSRainbowShader](Get-OBSRainbowShader.md) | +|[Get-OBSRainWindowShader](Get-OBSRainWindowShader.md) | +|[Get-OBSRecordDirectory](Get-OBSRecordDirectory.md) | +|[Get-OBSRecordStatus](Get-OBSRecordStatus.md) | +|[Get-OBSRectangularDropShadowShader](Get-OBSRectangularDropShadowShader.md) | +|[Get-OBSReflectShader](Get-OBSReflectShader.md) | +|[Get-OBSRemovePartialPixelsShader](Get-OBSRemovePartialPixelsShader.md) | +|[Get-OBSRepeatGridCenterCropShader](Get-OBSRepeatGridCenterCropShader.md) | +|[Get-OBSRepeatShader](Get-OBSRepeatShader.md) | +|[Get-OBSRepeatTextureShader](Get-OBSRepeatTextureShader.md) | +|[Get-OBSReplayBufferStatus](Get-OBSReplayBufferStatus.md) | +|[Get-OBSRGBAPercentShader](Get-OBSRGBAPercentShader.md) | +|[Get-OBSRgbColorWheelShader](Get-OBSRgbColorWheelShader.md) | +|[Get-OBSRgbSplitShader](Get-OBSRgbSplitShader.md) | +|[Get-OBSRgbvisibilityShader](Get-OBSRgbvisibilityShader.md) | +|[Get-OBSRGSSAAShader](Get-OBSRGSSAAShader.md) | +|[Get-OBSRippleShader](Get-OBSRippleShader.md) | +|[Get-OBSRotatingSourceShader](Get-OBSRotatingSourceShader.md) | +|[Get-OBSRotatoeShader](Get-OBSRotatoeShader.md) | +|[Get-OBSRoundedRect2Shader](Get-OBSRoundedRect2Shader.md) | +|[Get-OBSRoundedRectPerCornerShader](Get-OBSRoundedRectPerCornerShader.md) | +|[Get-OBSRoundedRectPerSideShader](Get-OBSRoundedRectPerSideShader.md) | +|[Get-OBSRoundedRectShader](Get-OBSRoundedRectShader.md) | +|[Get-OBSRoundedStrokeGradientShader](Get-OBSRoundedStrokeGradientShader.md) | +|[Get-OBSRoundedStrokeShader](Get-OBSRoundedStrokeShader.md) | +|[Get-OBSScanLineShader](Get-OBSScanLineShader.md) | +|[Get-OBSScene](Get-OBSScene.md) | +|[Get-OBSSceneCollection](Get-OBSSceneCollection.md) | +|[Get-OBSSceneItem](Get-OBSSceneItem.md) | +|[Get-OBSSceneItemBlendMode](Get-OBSSceneItemBlendMode.md) | +|[Get-OBSSceneItemEnabled](Get-OBSSceneItemEnabled.md) | +|[Get-OBSSceneItemId](Get-OBSSceneItemId.md) | +|[Get-OBSSceneItemIndex](Get-OBSSceneItemIndex.md) | +|[Get-OBSSceneItemLocked](Get-OBSSceneItemLocked.md) | +|[Get-OBSSceneItemSource](Get-OBSSceneItemSource.md) | +|[Get-OBSSceneItemTransform](Get-OBSSceneItemTransform.md) | +|[Get-OBSSceneSceneTransitionOverride](Get-OBSSceneSceneTransitionOverride.md) | +|[Get-OBSSceneTransition](Get-OBSSceneTransition.md) | +|[Get-OBSSeascapeShader](Get-OBSSeascapeShader.md) | +|[Get-OBSSeasickShader](Get-OBSSeasickShader.md) | +|[Get-OBSSelectiveColorShader](Get-OBSSelectiveColorShader.md) | +|[Get-OBSShakeShader](Get-OBSShakeShader.md) | +|[Get-OBSShineShader](Get-OBSShineShader.md) | +|[Get-OBSSimpleGradientShader](Get-OBSSimpleGradientShader.md) | +|[Get-OBSSimplexNoiseShader](Get-OBSSimplexNoiseShader.md) | +|[Get-OBSSmartDenoiseShader](Get-OBSSmartDenoiseShader.md) | +|[Get-OBSSourceActive](Get-OBSSourceActive.md) | +|[Get-OBSSourceFilter](Get-OBSSourceFilter.md) | +|[Get-OBSSourceFilterDefaultSettings](Get-OBSSourceFilterDefaultSettings.md) | +|[Get-OBSSourceFilterKind](Get-OBSSourceFilterKind.md) | +|[Get-OBSSourceFilterList](Get-OBSSourceFilterList.md) | +|[Get-OBSSourceScreenshot](Get-OBSSourceScreenshot.md) | +|[Get-OBSSpecialInputs](Get-OBSSpecialInputs.md) | +|[Get-OBSSpecularShineShader](Get-OBSSpecularShineShader.md) | +|[Get-OBSSpotlightShader](Get-OBSSpotlightShader.md) | +|[Get-OBSStats](Get-OBSStats.md) | +|[Get-OBSStreamServiceSettings](Get-OBSStreamServiceSettings.md) | +|[Get-OBSStreamStatus](Get-OBSStreamStatus.md) | +|[Get-OBSStudioModeEnabled](Get-OBSStudioModeEnabled.md) | +|[Get-OBSSwirlShader](Get-OBSSwirlShader.md) | +|[Get-OBSTetraShader](Get-OBSTetraShader.md) | +|[Get-OBSThermalShader](Get-OBSThermalShader.md) | +|[Get-OBSTransitionKind](Get-OBSTransitionKind.md) | +|[Get-OBSTvCrtSubpixelShader](Get-OBSTvCrtSubpixelShader.md) | +|[Get-OBSTwistShader](Get-OBSTwistShader.md) | +|[Get-OBSTwoPassDropShadowShader](Get-OBSTwoPassDropShadowShader.md) | +|[Get-OBSVCRShader](Get-OBSVCRShader.md) | +|[Get-OBSVersion](Get-OBSVersion.md) | +|[Get-OBSVHSShader](Get-OBSVHSShader.md) | +|[Get-OBSVideoSettings](Get-OBSVideoSettings.md) | +|[Get-OBSVignettingShader](Get-OBSVignettingShader.md) | +|[Get-OBSVirtualCamStatus](Get-OBSVirtualCamStatus.md) | +|[Get-OBSVoronoiPixelationShader](Get-OBSVoronoiPixelationShader.md) | +|[Get-OBSWalkingDeadPixelFixerShader](Get-OBSWalkingDeadPixelFixerShader.md) | +|[Get-OBSZigZagShader](Get-OBSZigZagShader.md) | +|[Get-OBSZoomBlurShader](Get-OBSZoomBlurShader.md) | +|[Get-OBSZoomBlurTransitionShader](Get-OBSZoomBlurTransitionShader.md) | +|[Get-OBSZoomShader](Get-OBSZoomShader.md) | +|[Get-OBSZoomXYShader](Get-OBSZoomXYShader.md) | +|[Hide-OBS](Hide-OBS.md) | +|[Import-OBSEffect](Import-OBSEffect.md) | +|[Open-OBSInputFiltersDialog](Open-OBSInputFiltersDialog.md) | +|[Open-OBSInputInteractDialog](Open-OBSInputInteractDialog.md) | +|[Open-OBSInputPropertiesDialog](Open-OBSInputPropertiesDialog.md) | +|[Open-OBSSourceProjector](Open-OBSSourceProjector.md) | +|[Open-OBSVideoMixProjector](Open-OBSVideoMixProjector.md) | +|[Receive-OBS](Receive-OBS.md) | +|[Remove-OBS](Remove-OBS.md) | +|[Remove-OBSEffect](Remove-OBSEffect.md) | +|[Remove-OBSInput](Remove-OBSInput.md) | +|[Remove-OBSProfile](Remove-OBSProfile.md) | +|[Remove-OBSScene](Remove-OBSScene.md) | +|[Remove-OBSSceneItem](Remove-OBSSceneItem.md) | +|[Remove-OBSSourceFilter](Remove-OBSSourceFilter.md) | +|[Resume-OBSRecord](Resume-OBSRecord.md) | +|[Save-OBSReplayBuffer](Save-OBSReplayBuffer.md) | +|[Save-OBSSourceScreenshot](Save-OBSSourceScreenshot.md) | +|[Send-OBS](Send-OBS.md) | +|[Send-OBSCallVendorRequest](Send-OBSCallVendorRequest.md) | +|[Send-OBSCustomEvent](Send-OBSCustomEvent.md) | +|[Send-OBSOffsetMediaInputCursor](Send-OBSOffsetMediaInputCursor.md) | +|[Send-OBSPauseRecord](Send-OBSPauseRecord.md) | +|[Send-OBSPressInputPropertiesButton](Send-OBSPressInputPropertiesButton.md) | +|[Send-OBSSleep](Send-OBSSleep.md) | +|[Send-OBSStreamCaption](Send-OBSStreamCaption.md) | +|[Send-OBSTriggerHotkeyByKeySequence](Send-OBSTriggerHotkeyByKeySequence.md) | +|[Send-OBSTriggerHotkeyByName](Send-OBSTriggerHotkeyByName.md) | +|[Send-OBSTriggerMediaInputAction](Send-OBSTriggerMediaInputAction.md) | +|[Send-OBSTriggerStudioModeTransition](Send-OBSTriggerStudioModeTransition.md) | +|[Set-OBS3DFilter](Set-OBS3DFilter.md) | +|[Set-OBSAudioOutputSource](Set-OBSAudioOutputSource.md) | +|[Set-OBSBrowserSource](Set-OBSBrowserSource.md) | +|[Set-OBSColorFilter](Set-OBSColorFilter.md) | +|[Set-OBSColorSource](Set-OBSColorSource.md) | +|[Set-OBSCurrentPreviewScene](Set-OBSCurrentPreviewScene.md) | +|[Set-OBSCurrentProfile](Set-OBSCurrentProfile.md) | +|[Set-OBSCurrentProgramScene](Set-OBSCurrentProgramScene.md) | +|[Set-OBSCurrentSceneCollection](Set-OBSCurrentSceneCollection.md) | +|[Set-OBSCurrentSceneTransition](Set-OBSCurrentSceneTransition.md) | +|[Set-OBSCurrentSceneTransitionDuration](Set-OBSCurrentSceneTransitionDuration.md) | +|[Set-OBSCurrentSceneTransitionSettings](Set-OBSCurrentSceneTransitionSettings.md) | +|[Set-OBSDisplaySource](Set-OBSDisplaySource.md) | +|[Set-OBSEqualizerFilter](Set-OBSEqualizerFilter.md) | +|[Set-OBSGainFilter](Set-OBSGainFilter.md) | +|[Set-OBSInputAudioBalance](Set-OBSInputAudioBalance.md) | +|[Set-OBSInputAudioMonitorType](Set-OBSInputAudioMonitorType.md) | +|[Set-OBSInputAudioSyncOffset](Set-OBSInputAudioSyncOffset.md) | +|[Set-OBSInputAudioTracks](Set-OBSInputAudioTracks.md) | +|[Set-OBSInputMute](Set-OBSInputMute.md) | +|[Set-OBSInputName](Set-OBSInputName.md) | +|[Set-OBSInputSettings](Set-OBSInputSettings.md) | +|[Set-OBSInputVolume](Set-OBSInputVolume.md) | +|[Set-OBSMarkdownSource](Set-OBSMarkdownSource.md) | +|[Set-OBSMediaInputCursor](Set-OBSMediaInputCursor.md) | +|[Set-OBSMediaSource](Set-OBSMediaSource.md) | +|[Set-OBSOutputSettings](Set-OBSOutputSettings.md) | +|[Set-OBSPersistentData](Set-OBSPersistentData.md) | +|[Set-OBSProfileParameter](Set-OBSProfileParameter.md) | +|[Set-OBSRecordDirectory](Set-OBSRecordDirectory.md) | +|[Set-OBSRenderDelayFilter](Set-OBSRenderDelayFilter.md) | +|[Set-OBSScaleFilter](Set-OBSScaleFilter.md) | +|[Set-OBSSceneItemBlendMode](Set-OBSSceneItemBlendMode.md) | +|[Set-OBSSceneItemEnabled](Set-OBSSceneItemEnabled.md) | +|[Set-OBSSceneItemIndex](Set-OBSSceneItemIndex.md) | +|[Set-OBSSceneItemLocked](Set-OBSSceneItemLocked.md) | +|[Set-OBSSceneItemTransform](Set-OBSSceneItemTransform.md) | +|[Set-OBSSceneName](Set-OBSSceneName.md) | +|[Set-OBSSceneSceneTransitionOverride](Set-OBSSceneSceneTransitionOverride.md) | +|[Set-OBSScrollFilter](Set-OBSScrollFilter.md) | +|[Set-OBSShaderFilter](Set-OBSShaderFilter.md) | +|[Set-OBSSharpnessFilter](Set-OBSSharpnessFilter.md) | +|[Set-OBSSoundCloudSource](Set-OBSSoundCloudSource.md) | +|[Set-OBSSourceFilterEnabled](Set-OBSSourceFilterEnabled.md) | +|[Set-OBSSourceFilterIndex](Set-OBSSourceFilterIndex.md) | +|[Set-OBSSourceFilterName](Set-OBSSourceFilterName.md) | +|[Set-OBSSourceFilterSettings](Set-OBSSourceFilterSettings.md) | +|[Set-OBSStreamServiceSettings](Set-OBSStreamServiceSettings.md) | +|[Set-OBSStudioModeEnabled](Set-OBSStudioModeEnabled.md) | +|[Set-OBSSwitchSource](Set-OBSSwitchSource.md) | +|[Set-OBSTBarPosition](Set-OBSTBarPosition.md) | +|[Set-OBSVideoSettings](Set-OBSVideoSettings.md) | +|[Set-OBSVLCSource](Set-OBSVLCSource.md) | +|[Set-OBSWaveformSource](Set-OBSWaveformSource.md) | +|[Set-OBSWindowSource](Set-OBSWindowSource.md) | +|[Show-OBS](Show-OBS.md) | +|[Start-OBS](Start-OBS.md) | +|[Start-OBSEffect](Start-OBSEffect.md) | +|[Start-OBSOutput](Start-OBSOutput.md) | +|[Start-OBSRecord](Start-OBSRecord.md) | +|[Start-OBSReplayBuffer](Start-OBSReplayBuffer.md) | +|[Start-OBSStream](Start-OBSStream.md) | +|[Start-OBSVirtualCam](Start-OBSVirtualCam.md) | +|[Stop-OBS](Stop-OBS.md) | +|[Stop-OBSEffect](Stop-OBSEffect.md) | +|[Stop-OBSOutput](Stop-OBSOutput.md) | +|[Stop-OBSRecord](Stop-OBSRecord.md) | +|[Stop-OBSReplayBuffer](Stop-OBSReplayBuffer.md) | +|[Stop-OBSStream](Stop-OBSStream.md) | +|[Stop-OBSVirtualCam](Stop-OBSVirtualCam.md) | +|[Switch-OBSInputMute](Switch-OBSInputMute.md) | +|[Switch-OBSOutput](Switch-OBSOutput.md) | +|[Switch-OBSRecord](Switch-OBSRecord.md) | +|[Switch-OBSRecordPause](Switch-OBSRecordPause.md) | +|[Switch-OBSReplayBuffer](Switch-OBSReplayBuffer.md) | +|[Switch-OBSStream](Switch-OBSStream.md) | +|[Switch-OBSVirtualCam](Switch-OBSVirtualCam.md) | +|[Watch-OBS](Watch-OBS.md) | @@ -337,321 +356,340 @@ Functions Aliases ======= -|Name |ResolvedCommand| -|------------------------------------------------------------------------------------------|---------------| -|[Add-OBSInput](Add-OBSInput.md) | -|[Add-OBSProfile](Add-OBSProfile.md) | -|[Add-OBSScene](Add-OBSScene.md) | -|[Add-OBSSceneCollection](Add-OBSSceneCollection.md) | -|[Add-OBSSceneItem](Add-OBSSceneItem.md) | -|[Add-OBSSourceFilter](Add-OBSSourceFilter.md) | -|[Clear-OBSScene](Clear-OBSScene.md) | -|[Connect-OBS](Connect-OBS.md) | -|[Copy-OBSSceneItem](Copy-OBSSceneItem.md) | -|[Disconnect-OBS](Disconnect-OBS.md) | -|[Get-OBS](Get-OBS.md) | -|[Get-OBS3dSwapTransitionShader](Get-OBS3dSwapTransitionShader.md) | -|[Get-OBSAddShader](Get-OBSAddShader.md) | -|[Get-OBSAlphaBorderShader](Get-OBSAlphaBorderShader.md) | -|[Get-OBSAlphaGamingBentCameraShader](Get-OBSAlphaGamingBentCameraShader.md) | -|[Get-OBSAnimatedPathShader](Get-OBSAnimatedPathShader.md) | -|[Get-OBSAnimatedTextureShader](Get-OBSAnimatedTextureShader.md) | -|[Get-OBSAsciiShader](Get-OBSAsciiShader.md) | -|[Get-OBSAspectRatioShader](Get-OBSAspectRatioShader.md) | -|[Get-OBSBackgroundRemovalShader](Get-OBSBackgroundRemovalShader.md) | -|[Get-OBSBlendOpacityShader](Get-OBSBlendOpacityShader.md) | -|[Get-OBSBlinkShader](Get-OBSBlinkShader.md) | -|[Get-OBSBloomShader](Get-OBSBloomShader.md) | -|[Get-OBSBorderShader](Get-OBSBorderShader.md) | -|[Get-OBSBoxBlurShader](Get-OBSBoxBlurShader.md) | -|[Get-OBSBulgePinchShader](Get-OBSBulgePinchShader.md) | -|[Get-OBSBurnShader](Get-OBSBurnShader.md) | -|[Get-OBSCartoonShader](Get-OBSCartoonShader.md) | -|[Get-OBSCellShadedShader](Get-OBSCellShadedShader.md) | -|[Get-OBSChromaticAberrationShader](Get-OBSChromaticAberrationShader.md) | -|[Get-OBSChromaUVDistortionShader](Get-OBSChromaUVDistortionShader.md) | -|[Get-OBSCircleMaskFilterShader](Get-OBSCircleMaskFilterShader.md) | -|[Get-OBSClockAnalogShader](Get-OBSClockAnalogShader.md) | -|[Get-OBSClockDigitalLedShader](Get-OBSClockDigitalLedShader.md) | -|[Get-OBSClockDigitalNixieShader](Get-OBSClockDigitalNixieShader.md) | -|[Get-OBSColorDepthShader](Get-OBSColorDepthShader.md) | -|[Get-OBSColorGradeFilterShader](Get-OBSColorGradeFilterShader.md) | -|[Get-OBSCornerPinShader](Get-OBSCornerPinShader.md) | -|[Get-OBSCrtCurvatureShader](Get-OBSCrtCurvatureShader.md) | -|[Get-OBSCurrentPreviewScene](Get-OBSCurrentPreviewScene.md) | -|[Get-OBSCurrentProgramScene](Get-OBSCurrentProgramScene.md) | -|[Get-OBSCurrentSceneTransition](Get-OBSCurrentSceneTransition.md) | -|[Get-OBSCurrentSceneTransitionCursor](Get-OBSCurrentSceneTransitionCursor.md) | -|[Get-OBSCurveShader](Get-OBSCurveShader.md) | -|[Get-OBSCutRectPerCornerShader](Get-OBSCutRectPerCornerShader.md) | -|[Get-OBSCylinderShader](Get-OBSCylinderShader.md) | -|[Get-OBSDarkenShader](Get-OBSDarkenShader.md) | -|[Get-OBSDeadPixelFixerShader](Get-OBSDeadPixelFixerShader.md) | -|[Get-OBSDensitySatHueShader](Get-OBSDensitySatHueShader.md) | -|[Get-OBSDiffuseTransitionShader](Get-OBSDiffuseTransitionShader.md) | -|[Get-OBSDigitalRainShader](Get-OBSDigitalRainShader.md) | -|[Get-OBSDivideRotateShader](Get-OBSDivideRotateShader.md) | -|[Get-OBSDoodleShader](Get-OBSDoodleShader.md) | -|[Get-OBSDrawingsShader](Get-OBSDrawingsShader.md) | -|[Get-OBSDropShadowShader](Get-OBSDropShadowShader.md) | -|[Get-OBSDrunkShader](Get-OBSDrunkShader.md) | -|[Get-OBSDynamicMaskShader](Get-OBSDynamicMaskShader.md) | -|[Get-OBSEdgeDetectionShader](Get-OBSEdgeDetectionShader.md) | -|[Get-OBSEffect](Get-OBSEffect.md) | -|[Get-OBSEmbersShader](Get-OBSEmbersShader.md) | -|[Get-OBSEmbossColorShader](Get-OBSEmbossColorShader.md) | -|[Get-OBSEmbossShader](Get-OBSEmbossShader.md) | -|[Get-OBSExeldroBentCameraShader](Get-OBSExeldroBentCameraShader.md) | -|[Get-OBSFadeTransitionShader](Get-OBSFadeTransitionShader.md) | -|[Get-OBSFillColorGradientShader](Get-OBSFillColorGradientShader.md) | -|[Get-OBSFillColorLinearShader](Get-OBSFillColorLinearShader.md) | -|[Get-OBSFillColorRadialDegreesShader](Get-OBSFillColorRadialDegreesShader.md) | -|[Get-OBSFillColorRadialPercentageShader](Get-OBSFillColorRadialPercentageShader.md) | -|[Get-OBSFilterTemplateShader](Get-OBSFilterTemplateShader.md) | -|[Get-OBSFire3Shader](Get-OBSFire3Shader.md) | -|[Get-OBSFireShader](Get-OBSFireShader.md) | -|[Get-OBSFireworks2Shader](Get-OBSFireworks2Shader.md) | -|[Get-OBSFireworksShader](Get-OBSFireworksShader.md) | -|[Get-OBSFisheyeShader](Get-OBSFisheyeShader.md) | -|[Get-OBSFisheyeXyShader](Get-OBSFisheyeXyShader.md) | -|[Get-OBSFlipShader](Get-OBSFlipShader.md) | -|[Get-OBSFrostedGlassShader](Get-OBSFrostedGlassShader.md) | -|[Get-OBSGammaCorrectionShader](Get-OBSGammaCorrectionShader.md) | -|[Get-OBSGaussianBlurAdvancedShader](Get-OBSGaussianBlurAdvancedShader.md) | -|[Get-OBSGaussianBlurShader](Get-OBSGaussianBlurShader.md) | -|[Get-OBSGaussianBlurSimpleShader](Get-OBSGaussianBlurSimpleShader.md) | -|[Get-OBSGaussianExampleShader](Get-OBSGaussianExampleShader.md) | -|[Get-OBSGaussianSimpleShader](Get-OBSGaussianSimpleShader.md) | -|[Get-OBSGbCameraShader](Get-OBSGbCameraShader.md) | -|[Get-OBSGlassShader](Get-OBSGlassShader.md) | -|[Get-OBSGlitchAnalogShader](Get-OBSGlitchAnalogShader.md) | -|[Get-OBSGlitchShader](Get-OBSGlitchShader.md) | -|[Get-OBSGlowShader](Get-OBSGlowShader.md) | -|[Get-OBSGradientShader](Get-OBSGradientShader.md) | -|[Get-OBSGroup](Get-OBSGroup.md) | -|[Get-OBSGroupSceneItem](Get-OBSGroupSceneItem.md) | -|[Get-OBSHalftoneShader](Get-OBSHalftoneShader.md) | -|[Get-OBSHeatWaveSimpleShader](Get-OBSHeatWaveSimpleShader.md) | -|[Get-OBSHexagonShader](Get-OBSHexagonShader.md) | -|[Get-OBSHotkey](Get-OBSHotkey.md) | -|[Get-OBSHslHsvSaturationShader](Get-OBSHslHsvSaturationShader.md) | -|[Get-OBSHueRotatonShader](Get-OBSHueRotatonShader.md) | -|[Get-OBSInput](Get-OBSInput.md) | -|[Get-OBSInputAudioBalance](Get-OBSInputAudioBalance.md) | -|[Get-OBSInputAudioMonitorType](Get-OBSInputAudioMonitorType.md) | -|[Get-OBSInputAudioSyncOffset](Get-OBSInputAudioSyncOffset.md) | -|[Get-OBSInputAudioTracks](Get-OBSInputAudioTracks.md) | -|[Get-OBSInputDefaultSettings](Get-OBSInputDefaultSettings.md) | -|[Get-OBSInputKind](Get-OBSInputKind.md) | -|[Get-OBSInputMute](Get-OBSInputMute.md) | -|[Get-OBSInputPropertiesListPropertyItems](Get-OBSInputPropertiesListPropertyItems.md)| -|[Get-OBSInputSettings](Get-OBSInputSettings.md) | -|[Get-OBSInputVolume](Get-OBSInputVolume.md) | -|[Get-OBSIntensityScopeShader](Get-OBSIntensityScopeShader.md) | -|[Get-OBSInvertLumaShader](Get-OBSInvertLumaShader.md) | -|[Get-OBSLastReplayBufferReplay](Get-OBSLastReplayBufferReplay.md) | -|[Get-OBSLuminance2Shader](Get-OBSLuminance2Shader.md) | -|[Get-OBSLuminanceAlphaShader](Get-OBSLuminanceAlphaShader.md) | -|[Get-OBSLuminanceShader](Get-OBSLuminanceShader.md) | -|[Get-OBSMatrixShader](Get-OBSMatrixShader.md) | -|[Get-OBSMediaInputStatus](Get-OBSMediaInputStatus.md) | -|[Get-OBSMonitor](Get-OBSMonitor.md) | -|[Get-OBSMultiplyShader](Get-OBSMultiplyShader.md) | -|[Get-OBSNightSkyShader](Get-OBSNightSkyShader.md) | -|[Get-OBSOpacityShader](Get-OBSOpacityShader.md) | -|[Get-OBSOutput](Get-OBSOutput.md) | -|[Get-OBSOutputSettings](Get-OBSOutputSettings.md) | -|[Get-OBSOutputStatus](Get-OBSOutputStatus.md) | -|[Get-OBSPagePeelShader](Get-OBSPagePeelShader.md) | -|[Get-OBSPagePeelTransitionShader](Get-OBSPagePeelTransitionShader.md) | -|[Get-OBSPerlinNoiseShader](Get-OBSPerlinNoiseShader.md) | -|[Get-OBSPersistentData](Get-OBSPersistentData.md) | -|[Get-OBSPieChartShader](Get-OBSPieChartShader.md) | -|[Get-OBSPixelationShader](Get-OBSPixelationShader.md) | -|[Get-OBSPixelationTransitionShader](Get-OBSPixelationTransitionShader.md) | -|[Get-OBSPolarShader](Get-OBSPolarShader.md) | -|[Get-OBSProfile](Get-OBSProfile.md) | -|[Get-OBSProfileParameter](Get-OBSProfileParameter.md) | -|[Get-OBSPulseShader](Get-OBSPulseShader.md) | -|[Get-OBSRainbowShader](Get-OBSRainbowShader.md) | -|[Get-OBSRainWindowShader](Get-OBSRainWindowShader.md) | -|[Get-OBSRecordDirectory](Get-OBSRecordDirectory.md) | -|[Get-OBSRecordStatus](Get-OBSRecordStatus.md) | -|[Get-OBSRectangularDropShadowShader](Get-OBSRectangularDropShadowShader.md) | -|[Get-OBSReflectShader](Get-OBSReflectShader.md) | -|[Get-OBSRemovePartialPixelsShader](Get-OBSRemovePartialPixelsShader.md) | -|[Get-OBSRepeatShader](Get-OBSRepeatShader.md) | -|[Get-OBSRepeatTextureShader](Get-OBSRepeatTextureShader.md) | -|[Get-OBSReplayBufferStatus](Get-OBSReplayBufferStatus.md) | -|[Get-OBSRGBAPercentShader](Get-OBSRGBAPercentShader.md) | -|[Get-OBSRgbColorWheelShader](Get-OBSRgbColorWheelShader.md) | -|[Get-OBSRgbSplitShader](Get-OBSRgbSplitShader.md) | -|[Get-OBSRgbvisibilityShader](Get-OBSRgbvisibilityShader.md) | -|[Get-OBSRGSSAAShader](Get-OBSRGSSAAShader.md) | -|[Get-OBSRippleShader](Get-OBSRippleShader.md) | -|[Get-OBSRotatingSourceShader](Get-OBSRotatingSourceShader.md) | -|[Get-OBSRotatoeShader](Get-OBSRotatoeShader.md) | -|[Get-OBSRoundedRect2Shader](Get-OBSRoundedRect2Shader.md) | -|[Get-OBSRoundedRectPerCornerShader](Get-OBSRoundedRectPerCornerShader.md) | -|[Get-OBSRoundedRectPerSideShader](Get-OBSRoundedRectPerSideShader.md) | -|[Get-OBSRoundedRectShader](Get-OBSRoundedRectShader.md) | -|[Get-OBSRoundedStrokeGradientShader](Get-OBSRoundedStrokeGradientShader.md) | -|[Get-OBSRoundedStrokeShader](Get-OBSRoundedStrokeShader.md) | -|[Get-OBSScanLineShader](Get-OBSScanLineShader.md) | -|[Get-OBSScene](Get-OBSScene.md) | -|[Get-OBSSceneCollection](Get-OBSSceneCollection.md) | -|[Get-OBSSceneItem](Get-OBSSceneItem.md) | -|[Get-OBSSceneItemBlendMode](Get-OBSSceneItemBlendMode.md) | -|[Get-OBSSceneItemEnabled](Get-OBSSceneItemEnabled.md) | -|[Get-OBSSceneItemId](Get-OBSSceneItemId.md) | -|[Get-OBSSceneItemIndex](Get-OBSSceneItemIndex.md) | -|[Get-OBSSceneItemLocked](Get-OBSSceneItemLocked.md) | -|[Get-OBSSceneItemSource](Get-OBSSceneItemSource.md) | -|[Get-OBSSceneItemTransform](Get-OBSSceneItemTransform.md) | -|[Get-OBSSceneSceneTransitionOverride](Get-OBSSceneSceneTransitionOverride.md) | -|[Get-OBSSceneTransition](Get-OBSSceneTransition.md) | -|[Get-OBSSeascapeShader](Get-OBSSeascapeShader.md) | -|[Get-OBSSeasickShader](Get-OBSSeasickShader.md) | -|[Get-OBSSelectiveColorShader](Get-OBSSelectiveColorShader.md) | -|[Get-OBSShakeShader](Get-OBSShakeShader.md) | -|[Get-OBSShineShader](Get-OBSShineShader.md) | -|[Get-OBSSimpleGradientShader](Get-OBSSimpleGradientShader.md) | -|[Get-OBSSimplexNoiseShader](Get-OBSSimplexNoiseShader.md) | -|[Get-OBSSmartDenoiseShader](Get-OBSSmartDenoiseShader.md) | -|[Get-OBSSourceActive](Get-OBSSourceActive.md) | -|[Get-OBSSourceFilter](Get-OBSSourceFilter.md) | -|[Get-OBSSourceFilterDefaultSettings](Get-OBSSourceFilterDefaultSettings.md) | -|[Get-OBSSourceFilterKind](Get-OBSSourceFilterKind.md) | -|[Get-OBSSourceFilterList](Get-OBSSourceFilterList.md) | -|[Get-OBSSourceScreenshot](Get-OBSSourceScreenshot.md) | -|[Get-OBSSpecialInputs](Get-OBSSpecialInputs.md) | -|[Get-OBSSpecularShineShader](Get-OBSSpecularShineShader.md) | -|[Get-OBSSpotlightShader](Get-OBSSpotlightShader.md) | -|[Get-OBSStats](Get-OBSStats.md) | -|[Get-OBSStreamServiceSettings](Get-OBSStreamServiceSettings.md) | -|[Get-OBSStreamStatus](Get-OBSStreamStatus.md) | -|[Get-OBSStudioModeEnabled](Get-OBSStudioModeEnabled.md) | -|[Get-OBSSwirlShader](Get-OBSSwirlShader.md) | -|[Get-OBSTetraShader](Get-OBSTetraShader.md) | -|[Get-OBSThermalShader](Get-OBSThermalShader.md) | -|[Get-OBSTransitionKind](Get-OBSTransitionKind.md) | -|[Get-OBSTvCrtSubpixelShader](Get-OBSTvCrtSubpixelShader.md) | -|[Get-OBSTwistShader](Get-OBSTwistShader.md) | -|[Get-OBSTwoPassDropShadowShader](Get-OBSTwoPassDropShadowShader.md) | -|[Get-OBSVCRShader](Get-OBSVCRShader.md) | -|[Get-OBSVersion](Get-OBSVersion.md) | -|[Get-OBSVHSShader](Get-OBSVHSShader.md) | -|[Get-OBSVideoSettings](Get-OBSVideoSettings.md) | -|[Get-OBSVignettingShader](Get-OBSVignettingShader.md) | -|[Get-OBSVirtualCamStatus](Get-OBSVirtualCamStatus.md) | -|[Get-OBSVoronoiPixelationShader](Get-OBSVoronoiPixelationShader.md) | -|[Get-OBSZigZagShader](Get-OBSZigZagShader.md) | -|[Get-OBSZoomBlurShader](Get-OBSZoomBlurShader.md) | -|[Get-OBSZoomShader](Get-OBSZoomShader.md) | -|[Get-OBSZoomXYShader](Get-OBSZoomXYShader.md) | -|[Hide-OBS](Hide-OBS.md) | -|[Import-OBSEffect](Import-OBSEffect.md) | -|[Open-OBSInputFiltersDialog](Open-OBSInputFiltersDialog.md) | -|[Open-OBSInputInteractDialog](Open-OBSInputInteractDialog.md) | -|[Open-OBSInputPropertiesDialog](Open-OBSInputPropertiesDialog.md) | -|[Open-OBSSourceProjector](Open-OBSSourceProjector.md) | -|[Open-OBSVideoMixProjector](Open-OBSVideoMixProjector.md) | -|[Receive-OBS](Receive-OBS.md) | -|[Remove-OBS](Remove-OBS.md) | -|[Remove-OBSEffect](Remove-OBSEffect.md) | -|[Remove-OBSInput](Remove-OBSInput.md) | -|[Remove-OBSProfile](Remove-OBSProfile.md) | -|[Remove-OBSScene](Remove-OBSScene.md) | -|[Remove-OBSSceneItem](Remove-OBSSceneItem.md) | -|[Remove-OBSSourceFilter](Remove-OBSSourceFilter.md) | -|[Resume-OBSRecord](Resume-OBSRecord.md) | -|[Save-OBSReplayBuffer](Save-OBSReplayBuffer.md) | -|[Save-OBSSourceScreenshot](Save-OBSSourceScreenshot.md) | -|[Send-OBS](Send-OBS.md) | -|[Send-OBSCallVendorRequest](Send-OBSCallVendorRequest.md) | -|[Send-OBSCustomEvent](Send-OBSCustomEvent.md) | -|[Send-OBSOffsetMediaInputCursor](Send-OBSOffsetMediaInputCursor.md) | -|[Send-OBSPauseRecord](Send-OBSPauseRecord.md) | -|[Send-OBSPressInputPropertiesButton](Send-OBSPressInputPropertiesButton.md) | -|[Send-OBSSleep](Send-OBSSleep.md) | -|[Send-OBSStreamCaption](Send-OBSStreamCaption.md) | -|[Send-OBSTriggerHotkeyByKeySequence](Send-OBSTriggerHotkeyByKeySequence.md) | -|[Send-OBSTriggerHotkeyByName](Send-OBSTriggerHotkeyByName.md) | -|[Send-OBSTriggerMediaInputAction](Send-OBSTriggerMediaInputAction.md) | -|[Send-OBSTriggerStudioModeTransition](Send-OBSTriggerStudioModeTransition.md) | -|[Set-OBS3DFilter](Set-OBS3DFilter.md) | -|[Set-OBSAudioOutputSource](Set-OBSAudioOutputSource.md) | -|[Set-OBSBrowserSource](Set-OBSBrowserSource.md) | -|[Set-OBSColorFilter](Set-OBSColorFilter.md) | -|[Set-OBSColorSource](Set-OBSColorSource.md) | -|[Set-OBSCurrentPreviewScene](Set-OBSCurrentPreviewScene.md) | -|[Set-OBSCurrentProfile](Set-OBSCurrentProfile.md) | -|[Set-OBSCurrentProgramScene](Set-OBSCurrentProgramScene.md) | -|[Set-OBSCurrentSceneCollection](Set-OBSCurrentSceneCollection.md) | -|[Set-OBSCurrentSceneTransition](Set-OBSCurrentSceneTransition.md) | -|[Set-OBSCurrentSceneTransitionDuration](Set-OBSCurrentSceneTransitionDuration.md) | -|[Set-OBSCurrentSceneTransitionSettings](Set-OBSCurrentSceneTransitionSettings.md) | -|[Set-OBSDisplaySource](Set-OBSDisplaySource.md) | -|[Set-OBSEqualizerFilter](Set-OBSEqualizerFilter.md) | -|[Set-OBSGainFilter](Set-OBSGainFilter.md) | -|[Set-OBSInputAudioBalance](Set-OBSInputAudioBalance.md) | -|[Set-OBSInputAudioMonitorType](Set-OBSInputAudioMonitorType.md) | -|[Set-OBSInputAudioSyncOffset](Set-OBSInputAudioSyncOffset.md) | -|[Set-OBSInputAudioTracks](Set-OBSInputAudioTracks.md) | -|[Set-OBSInputMute](Set-OBSInputMute.md) | -|[Set-OBSInputName](Set-OBSInputName.md) | -|[Set-OBSInputSettings](Set-OBSInputSettings.md) | -|[Set-OBSInputVolume](Set-OBSInputVolume.md) | -|[Set-OBSMarkdownSource](Set-OBSMarkdownSource.md) | -|[Set-OBSMediaInputCursor](Set-OBSMediaInputCursor.md) | -|[Set-OBSMediaSource](Set-OBSMediaSource.md) | -|[Set-OBSOutputSettings](Set-OBSOutputSettings.md) | -|[Set-OBSPersistentData](Set-OBSPersistentData.md) | -|[Set-OBSProfileParameter](Set-OBSProfileParameter.md) | -|[Set-OBSRecordDirectory](Set-OBSRecordDirectory.md) | -|[Set-OBSRenderDelayFilter](Set-OBSRenderDelayFilter.md) | -|[Set-OBSScaleFilter](Set-OBSScaleFilter.md) | -|[Set-OBSSceneItemBlendMode](Set-OBSSceneItemBlendMode.md) | -|[Set-OBSSceneItemEnabled](Set-OBSSceneItemEnabled.md) | -|[Set-OBSSceneItemIndex](Set-OBSSceneItemIndex.md) | -|[Set-OBSSceneItemLocked](Set-OBSSceneItemLocked.md) | -|[Set-OBSSceneItemTransform](Set-OBSSceneItemTransform.md) | -|[Set-OBSSceneName](Set-OBSSceneName.md) | -|[Set-OBSSceneSceneTransitionOverride](Set-OBSSceneSceneTransitionOverride.md) | -|[Set-OBSScrollFilter](Set-OBSScrollFilter.md) | -|[Set-OBSShaderFilter](Set-OBSShaderFilter.md) | -|[Set-OBSSharpnessFilter](Set-OBSSharpnessFilter.md) | -|[Set-OBSSoundCloudSource](Set-OBSSoundCloudSource.md) | -|[Set-OBSSourceFilterEnabled](Set-OBSSourceFilterEnabled.md) | -|[Set-OBSSourceFilterIndex](Set-OBSSourceFilterIndex.md) | -|[Set-OBSSourceFilterName](Set-OBSSourceFilterName.md) | -|[Set-OBSSourceFilterSettings](Set-OBSSourceFilterSettings.md) | -|[Set-OBSStreamServiceSettings](Set-OBSStreamServiceSettings.md) | -|[Set-OBSStudioModeEnabled](Set-OBSStudioModeEnabled.md) | -|[Set-OBSSwitchSource](Set-OBSSwitchSource.md) | -|[Set-OBSTBarPosition](Set-OBSTBarPosition.md) | -|[Set-OBSVideoSettings](Set-OBSVideoSettings.md) | -|[Set-OBSVLCSource](Set-OBSVLCSource.md) | -|[Set-OBSWaveformSource](Set-OBSWaveformSource.md) | -|[Set-OBSWindowSource](Set-OBSWindowSource.md) | -|[Show-OBS](Show-OBS.md) | -|[Start-OBSEffect](Start-OBSEffect.md) | -|[Start-OBSOutput](Start-OBSOutput.md) | -|[Start-OBSRecord](Start-OBSRecord.md) | -|[Start-OBSReplayBuffer](Start-OBSReplayBuffer.md) | -|[Start-OBSStream](Start-OBSStream.md) | -|[Start-OBSVirtualCam](Start-OBSVirtualCam.md) | -|[Stop-OBSEffect](Stop-OBSEffect.md) | -|[Stop-OBSOutput](Stop-OBSOutput.md) | -|[Stop-OBSRecord](Stop-OBSRecord.md) | -|[Stop-OBSReplayBuffer](Stop-OBSReplayBuffer.md) | -|[Stop-OBSStream](Stop-OBSStream.md) | -|[Stop-OBSVirtualCam](Stop-OBSVirtualCam.md) | -|[Switch-OBSInputMute](Switch-OBSInputMute.md) | -|[Switch-OBSOutput](Switch-OBSOutput.md) | -|[Switch-OBSRecord](Switch-OBSRecord.md) | -|[Switch-OBSRecordPause](Switch-OBSRecordPause.md) | -|[Switch-OBSReplayBuffer](Switch-OBSReplayBuffer.md) | -|[Switch-OBSStream](Switch-OBSStream.md) | -|[Switch-OBSVirtualCam](Switch-OBSVirtualCam.md) | -|[Watch-OBS](Watch-OBS.md) | +|Name |ResolvedCommand| +|------------------------------------------------------------------------------------------------|---------------| +|[Add-OBSInput](Add-OBSInput.md) | +|[Add-OBSProfile](Add-OBSProfile.md) | +|[Add-OBSScene](Add-OBSScene.md) | +|[Add-OBSSceneCollection](Add-OBSSceneCollection.md) | +|[Add-OBSSceneItem](Add-OBSSceneItem.md) | +|[Add-OBSSourceFilter](Add-OBSSourceFilter.md) | +|[Clear-OBSScene](Clear-OBSScene.md) | +|[Connect-OBS](Connect-OBS.md) | +|[Copy-OBSSceneItem](Copy-OBSSceneItem.md) | +|[Disconnect-OBS](Disconnect-OBS.md) | +|[Get-OBS](Get-OBS.md) | +|[Get-OBS3dPanelShader](Get-OBS3dPanelShader.md) | +|[Get-OBS3dSwapTransitionShader](Get-OBS3dSwapTransitionShader.md) | +|[Get-OBSAddShader](Get-OBSAddShader.md) | +|[Get-OBSAlphaBorderShader](Get-OBSAlphaBorderShader.md) | +|[Get-OBSAlphaGamingBentCameraShader](Get-OBSAlphaGamingBentCameraShader.md) | +|[Get-OBSAnimatedPathShader](Get-OBSAnimatedPathShader.md) | +|[Get-OBSAnimatedTextureShader](Get-OBSAnimatedTextureShader.md) | +|[Get-OBSAsciiShader](Get-OBSAsciiShader.md) | +|[Get-OBSAspectRatioShader](Get-OBSAspectRatioShader.md) | +|[Get-OBSAudioShader](Get-OBSAudioShader.md) | +|[Get-OBSBackgroundRemovalShader](Get-OBSBackgroundRemovalShader.md) | +|[Get-OBSBlendOpacityShader](Get-OBSBlendOpacityShader.md) | +|[Get-OBSBlinkShader](Get-OBSBlinkShader.md) | +|[Get-OBSBloomShader](Get-OBSBloomShader.md) | +|[Get-OBSBorderShader](Get-OBSBorderShader.md) | +|[Get-OBSBoxBlurShader](Get-OBSBoxBlurShader.md) | +|[Get-OBSBulgePinchShader](Get-OBSBulgePinchShader.md) | +|[Get-OBSBurnShader](Get-OBSBurnShader.md) | +|[Get-OBSCartoonShader](Get-OBSCartoonShader.md) | +|[Get-OBSCellShadedShader](Get-OBSCellShadedShader.md) | +|[Get-OBSChromaticAberrationShader](Get-OBSChromaticAberrationShader.md) | +|[Get-OBSChromaUVDistortionShader](Get-OBSChromaUVDistortionShader.md) | +|[Get-OBSCircleMaskFilterShader](Get-OBSCircleMaskFilterShader.md) | +|[Get-OBSClockAnalogShader](Get-OBSClockAnalogShader.md) | +|[Get-OBSClockDigitalLedShader](Get-OBSClockDigitalLedShader.md) | +|[Get-OBSClockDigitalNixieShader](Get-OBSClockDigitalNixieShader.md) | +|[Get-OBSColorDepthShader](Get-OBSColorDepthShader.md) | +|[Get-OBSColorGradeFilterShader](Get-OBSColorGradeFilterShader.md) | +|[Get-OBSCornerPinShader](Get-OBSCornerPinShader.md) | +|[Get-OBSCrtCurvatureShader](Get-OBSCrtCurvatureShader.md) | +|[Get-OBSCubeRotatingShader](Get-OBSCubeRotatingShader.md) | +|[Get-OBSCurrentPreviewScene](Get-OBSCurrentPreviewScene.md) | +|[Get-OBSCurrentProgramScene](Get-OBSCurrentProgramScene.md) | +|[Get-OBSCurrentSceneTransition](Get-OBSCurrentSceneTransition.md) | +|[Get-OBSCurrentSceneTransitionCursor](Get-OBSCurrentSceneTransitionCursor.md) | +|[Get-OBSCurveShader](Get-OBSCurveShader.md) | +|[Get-OBSCutRectPerCornerShader](Get-OBSCutRectPerCornerShader.md) | +|[Get-OBSCylinderShader](Get-OBSCylinderShader.md) | +|[Get-OBSDarkenShader](Get-OBSDarkenShader.md) | +|[Get-OBSDeadPixelFixerShader](Get-OBSDeadPixelFixerShader.md) | +|[Get-OBSDensitySatHueShader](Get-OBSDensitySatHueShader.md) | +|[Get-OBSDiffuseTransitionShader](Get-OBSDiffuseTransitionShader.md) | +|[Get-OBSDigitalRainShader](Get-OBSDigitalRainShader.md) | +|[Get-OBSDisplacementMapAdvancedInvertShader](Get-OBSDisplacementMapAdvancedInvertShader.md)| +|[Get-OBSDisplacementMapAdvancedShader](Get-OBSDisplacementMapAdvancedShader.md) | +|[Get-OBSDisplacementMapInvertShader](Get-OBSDisplacementMapInvertShader.md) | +|[Get-OBSDisplacementMapShader](Get-OBSDisplacementMapShader.md) | +|[Get-OBSDivideRotateShader](Get-OBSDivideRotateShader.md) | +|[Get-OBSDoodleShader](Get-OBSDoodleShader.md) | +|[Get-OBSDrawingsShader](Get-OBSDrawingsShader.md) | +|[Get-OBSDropShadowShader](Get-OBSDropShadowShader.md) | +|[Get-OBSDrunkShader](Get-OBSDrunkShader.md) | +|[Get-OBSDynamicMaskShader](Get-OBSDynamicMaskShader.md) | +|[Get-OBSEdgeDetectionShader](Get-OBSEdgeDetectionShader.md) | +|[Get-OBSEffect](Get-OBSEffect.md) | +|[Get-OBSEmbersShader](Get-OBSEmbersShader.md) | +|[Get-OBSEmbossColorShader](Get-OBSEmbossColorShader.md) | +|[Get-OBSEmbossShader](Get-OBSEmbossShader.md) | +|[Get-OBSExeldroBentCameraShader](Get-OBSExeldroBentCameraShader.md) | +|[Get-OBSFadeTransitionShader](Get-OBSFadeTransitionShader.md) | +|[Get-OBSFillColorGradientShader](Get-OBSFillColorGradientShader.md) | +|[Get-OBSFillColorLinearShader](Get-OBSFillColorLinearShader.md) | +|[Get-OBSFillColorRadialDegreesShader](Get-OBSFillColorRadialDegreesShader.md) | +|[Get-OBSFillColorRadialPercentageShader](Get-OBSFillColorRadialPercentageShader.md) | +|[Get-OBSFilterTemplateShader](Get-OBSFilterTemplateShader.md) | +|[Get-OBSFire3Shader](Get-OBSFire3Shader.md) | +|[Get-OBSFireShader](Get-OBSFireShader.md) | +|[Get-OBSFireworks2Shader](Get-OBSFireworks2Shader.md) | +|[Get-OBSFireworksShader](Get-OBSFireworksShader.md) | +|[Get-OBSFisheyeShader](Get-OBSFisheyeShader.md) | +|[Get-OBSFisheyeXyShader](Get-OBSFisheyeXyShader.md) | +|[Get-OBSFlipShader](Get-OBSFlipShader.md) | +|[Get-OBSFrostedGlassShader](Get-OBSFrostedGlassShader.md) | +|[Get-OBSGammaCorrectionShader](Get-OBSGammaCorrectionShader.md) | +|[Get-OBSGaussianBlurAdvancedShader](Get-OBSGaussianBlurAdvancedShader.md) | +|[Get-OBSGaussianBlurShader](Get-OBSGaussianBlurShader.md) | +|[Get-OBSGaussianBlurSimpleShader](Get-OBSGaussianBlurSimpleShader.md) | +|[Get-OBSGaussianExampleShader](Get-OBSGaussianExampleShader.md) | +|[Get-OBSGaussianSimpleShader](Get-OBSGaussianSimpleShader.md) | +|[Get-OBSGbCameraShader](Get-OBSGbCameraShader.md) | +|[Get-OBSGlassShader](Get-OBSGlassShader.md) | +|[Get-OBSGlitchAnalogShader](Get-OBSGlitchAnalogShader.md) | +|[Get-OBSGlitchPeriodicShader](Get-OBSGlitchPeriodicShader.md) | +|[Get-OBSGlitchShader](Get-OBSGlitchShader.md) | +|[Get-OBSGlowShader](Get-OBSGlowShader.md) | +|[Get-OBSGradientShader](Get-OBSGradientShader.md) | +|[Get-OBSGroup](Get-OBSGroup.md) | +|[Get-OBSGroupSceneItem](Get-OBSGroupSceneItem.md) | +|[Get-OBSHalftoneShader](Get-OBSHalftoneShader.md) | +|[Get-OBSHardBlinkShader](Get-OBSHardBlinkShader.md) | +|[Get-OBSHeatWaveSimpleShader](Get-OBSHeatWaveSimpleShader.md) | +|[Get-OBSHexagonShader](Get-OBSHexagonShader.md) | +|[Get-OBSHotkey](Get-OBSHotkey.md) | +|[Get-OBSHslHsvSaturationShader](Get-OBSHslHsvSaturationShader.md) | +|[Get-OBSHueRotatonShader](Get-OBSHueRotatonShader.md) | +|[Get-OBSInput](Get-OBSInput.md) | +|[Get-OBSInputAudioBalance](Get-OBSInputAudioBalance.md) | +|[Get-OBSInputAudioMonitorType](Get-OBSInputAudioMonitorType.md) | +|[Get-OBSInputAudioSyncOffset](Get-OBSInputAudioSyncOffset.md) | +|[Get-OBSInputAudioTracks](Get-OBSInputAudioTracks.md) | +|[Get-OBSInputDefaultSettings](Get-OBSInputDefaultSettings.md) | +|[Get-OBSInputKind](Get-OBSInputKind.md) | +|[Get-OBSInputMute](Get-OBSInputMute.md) | +|[Get-OBSInputPropertiesListPropertyItems](Get-OBSInputPropertiesListPropertyItems.md) | +|[Get-OBSInputSettings](Get-OBSInputSettings.md) | +|[Get-OBSInputVolume](Get-OBSInputVolume.md) | +|[Get-OBSIntensityScopeShader](Get-OBSIntensityScopeShader.md) | +|[Get-OBSInvertLumaShader](Get-OBSInvertLumaShader.md) | +|[Get-OBSLastReplayBufferReplay](Get-OBSLastReplayBufferReplay.md) | +|[Get-OBSLuminance2Shader](Get-OBSLuminance2Shader.md) | +|[Get-OBSLuminanceAlphaShader](Get-OBSLuminanceAlphaShader.md) | +|[Get-OBSLuminanceShader](Get-OBSLuminanceShader.md) | +|[Get-OBSMatrixShader](Get-OBSMatrixShader.md) | +|[Get-OBSMediaInputStatus](Get-OBSMediaInputStatus.md) | +|[Get-OBSMonitor](Get-OBSMonitor.md) | +|[Get-OBSMotionBlurShader](Get-OBSMotionBlurShader.md) | +|[Get-OBSMultiplyShader](Get-OBSMultiplyShader.md) | +|[Get-OBSNightSkyShader](Get-OBSNightSkyShader.md) | +|[Get-OBSNoiseShader](Get-OBSNoiseShader.md) | +|[Get-OBSNormalMapShader](Get-OBSNormalMapShader.md) | +|[Get-OBSOpacityShader](Get-OBSOpacityShader.md) | +|[Get-OBSOutput](Get-OBSOutput.md) | +|[Get-OBSOutputSettings](Get-OBSOutputSettings.md) | +|[Get-OBSOutputStatus](Get-OBSOutputStatus.md) | +|[Get-OBSPagePeelShader](Get-OBSPagePeelShader.md) | +|[Get-OBSPagePeelTransitionShader](Get-OBSPagePeelTransitionShader.md) | +|[Get-OBSPerlinNoiseShader](Get-OBSPerlinNoiseShader.md) | +|[Get-OBSPersistentData](Get-OBSPersistentData.md) | +|[Get-OBSPerspectiveShader](Get-OBSPerspectiveShader.md) | +|[Get-OBSPieChartShader](Get-OBSPieChartShader.md) | +|[Get-OBSPixelationShader](Get-OBSPixelationShader.md) | +|[Get-OBSPixelationTransitionShader](Get-OBSPixelationTransitionShader.md) | +|[Get-OBSPolarShader](Get-OBSPolarShader.md) | +|[Get-OBSProfile](Get-OBSProfile.md) | +|[Get-OBSProfileParameter](Get-OBSProfileParameter.md) | +|[Get-OBSPulseShader](Get-OBSPulseShader.md) | +|[Get-OBSQuadrilateralCropShader](Get-OBSQuadrilateralCropShader.md) | +|[Get-OBSRainbowShader](Get-OBSRainbowShader.md) | +|[Get-OBSRainWindowShader](Get-OBSRainWindowShader.md) | +|[Get-OBSRecordDirectory](Get-OBSRecordDirectory.md) | +|[Get-OBSRecordStatus](Get-OBSRecordStatus.md) | +|[Get-OBSRectangularDropShadowShader](Get-OBSRectangularDropShadowShader.md) | +|[Get-OBSReflectShader](Get-OBSReflectShader.md) | +|[Get-OBSRemovePartialPixelsShader](Get-OBSRemovePartialPixelsShader.md) | +|[Get-OBSRepeatGridCenterCropShader](Get-OBSRepeatGridCenterCropShader.md) | +|[Get-OBSRepeatShader](Get-OBSRepeatShader.md) | +|[Get-OBSRepeatTextureShader](Get-OBSRepeatTextureShader.md) | +|[Get-OBSReplayBufferStatus](Get-OBSReplayBufferStatus.md) | +|[Get-OBSRGBAPercentShader](Get-OBSRGBAPercentShader.md) | +|[Get-OBSRgbColorWheelShader](Get-OBSRgbColorWheelShader.md) | +|[Get-OBSRgbSplitShader](Get-OBSRgbSplitShader.md) | +|[Get-OBSRgbvisibilityShader](Get-OBSRgbvisibilityShader.md) | +|[Get-OBSRGSSAAShader](Get-OBSRGSSAAShader.md) | +|[Get-OBSRippleShader](Get-OBSRippleShader.md) | +|[Get-OBSRotatingSourceShader](Get-OBSRotatingSourceShader.md) | +|[Get-OBSRotatoeShader](Get-OBSRotatoeShader.md) | +|[Get-OBSRoundedRect2Shader](Get-OBSRoundedRect2Shader.md) | +|[Get-OBSRoundedRectPerCornerShader](Get-OBSRoundedRectPerCornerShader.md) | +|[Get-OBSRoundedRectPerSideShader](Get-OBSRoundedRectPerSideShader.md) | +|[Get-OBSRoundedRectShader](Get-OBSRoundedRectShader.md) | +|[Get-OBSRoundedStrokeGradientShader](Get-OBSRoundedStrokeGradientShader.md) | +|[Get-OBSRoundedStrokeShader](Get-OBSRoundedStrokeShader.md) | +|[Get-OBSScanLineShader](Get-OBSScanLineShader.md) | +|[Get-OBSScene](Get-OBSScene.md) | +|[Get-OBSSceneCollection](Get-OBSSceneCollection.md) | +|[Get-OBSSceneItem](Get-OBSSceneItem.md) | +|[Get-OBSSceneItemBlendMode](Get-OBSSceneItemBlendMode.md) | +|[Get-OBSSceneItemEnabled](Get-OBSSceneItemEnabled.md) | +|[Get-OBSSceneItemId](Get-OBSSceneItemId.md) | +|[Get-OBSSceneItemIndex](Get-OBSSceneItemIndex.md) | +|[Get-OBSSceneItemLocked](Get-OBSSceneItemLocked.md) | +|[Get-OBSSceneItemSource](Get-OBSSceneItemSource.md) | +|[Get-OBSSceneItemTransform](Get-OBSSceneItemTransform.md) | +|[Get-OBSSceneSceneTransitionOverride](Get-OBSSceneSceneTransitionOverride.md) | +|[Get-OBSSceneTransition](Get-OBSSceneTransition.md) | +|[Get-OBSSeascapeShader](Get-OBSSeascapeShader.md) | +|[Get-OBSSeasickShader](Get-OBSSeasickShader.md) | +|[Get-OBSSelectiveColorShader](Get-OBSSelectiveColorShader.md) | +|[Get-OBSShakeShader](Get-OBSShakeShader.md) | +|[Get-OBSShineShader](Get-OBSShineShader.md) | +|[Get-OBSSimpleGradientShader](Get-OBSSimpleGradientShader.md) | +|[Get-OBSSimplexNoiseShader](Get-OBSSimplexNoiseShader.md) | +|[Get-OBSSmartDenoiseShader](Get-OBSSmartDenoiseShader.md) | +|[Get-OBSSourceActive](Get-OBSSourceActive.md) | +|[Get-OBSSourceFilter](Get-OBSSourceFilter.md) | +|[Get-OBSSourceFilterDefaultSettings](Get-OBSSourceFilterDefaultSettings.md) | +|[Get-OBSSourceFilterKind](Get-OBSSourceFilterKind.md) | +|[Get-OBSSourceFilterList](Get-OBSSourceFilterList.md) | +|[Get-OBSSourceScreenshot](Get-OBSSourceScreenshot.md) | +|[Get-OBSSpecialInputs](Get-OBSSpecialInputs.md) | +|[Get-OBSSpecularShineShader](Get-OBSSpecularShineShader.md) | +|[Get-OBSSpotlightShader](Get-OBSSpotlightShader.md) | +|[Get-OBSStats](Get-OBSStats.md) | +|[Get-OBSStreamServiceSettings](Get-OBSStreamServiceSettings.md) | +|[Get-OBSStreamStatus](Get-OBSStreamStatus.md) | +|[Get-OBSStudioModeEnabled](Get-OBSStudioModeEnabled.md) | +|[Get-OBSSwirlShader](Get-OBSSwirlShader.md) | +|[Get-OBSTetraShader](Get-OBSTetraShader.md) | +|[Get-OBSThermalShader](Get-OBSThermalShader.md) | +|[Get-OBSTransitionKind](Get-OBSTransitionKind.md) | +|[Get-OBSTvCrtSubpixelShader](Get-OBSTvCrtSubpixelShader.md) | +|[Get-OBSTwistShader](Get-OBSTwistShader.md) | +|[Get-OBSTwoPassDropShadowShader](Get-OBSTwoPassDropShadowShader.md) | +|[Get-OBSVCRShader](Get-OBSVCRShader.md) | +|[Get-OBSVersion](Get-OBSVersion.md) | +|[Get-OBSVHSShader](Get-OBSVHSShader.md) | +|[Get-OBSVideoSettings](Get-OBSVideoSettings.md) | +|[Get-OBSVignettingShader](Get-OBSVignettingShader.md) | +|[Get-OBSVirtualCamStatus](Get-OBSVirtualCamStatus.md) | +|[Get-OBSVoronoiPixelationShader](Get-OBSVoronoiPixelationShader.md) | +|[Get-OBSWalkingDeadPixelFixerShader](Get-OBSWalkingDeadPixelFixerShader.md) | +|[Get-OBSZigZagShader](Get-OBSZigZagShader.md) | +|[Get-OBSZoomBlurShader](Get-OBSZoomBlurShader.md) | +|[Get-OBSZoomBlurTransitionShader](Get-OBSZoomBlurTransitionShader.md) | +|[Get-OBSZoomShader](Get-OBSZoomShader.md) | +|[Get-OBSZoomXYShader](Get-OBSZoomXYShader.md) | +|[Hide-OBS](Hide-OBS.md) | +|[Import-OBSEffect](Import-OBSEffect.md) | +|[Open-OBSInputFiltersDialog](Open-OBSInputFiltersDialog.md) | +|[Open-OBSInputInteractDialog](Open-OBSInputInteractDialog.md) | +|[Open-OBSInputPropertiesDialog](Open-OBSInputPropertiesDialog.md) | +|[Open-OBSSourceProjector](Open-OBSSourceProjector.md) | +|[Open-OBSVideoMixProjector](Open-OBSVideoMixProjector.md) | +|[Receive-OBS](Receive-OBS.md) | +|[Remove-OBS](Remove-OBS.md) | +|[Remove-OBSEffect](Remove-OBSEffect.md) | +|[Remove-OBSInput](Remove-OBSInput.md) | +|[Remove-OBSProfile](Remove-OBSProfile.md) | +|[Remove-OBSScene](Remove-OBSScene.md) | +|[Remove-OBSSceneItem](Remove-OBSSceneItem.md) | +|[Remove-OBSSourceFilter](Remove-OBSSourceFilter.md) | +|[Resume-OBSRecord](Resume-OBSRecord.md) | +|[Save-OBSReplayBuffer](Save-OBSReplayBuffer.md) | +|[Save-OBSSourceScreenshot](Save-OBSSourceScreenshot.md) | +|[Send-OBS](Send-OBS.md) | +|[Send-OBSCallVendorRequest](Send-OBSCallVendorRequest.md) | +|[Send-OBSCustomEvent](Send-OBSCustomEvent.md) | +|[Send-OBSOffsetMediaInputCursor](Send-OBSOffsetMediaInputCursor.md) | +|[Send-OBSPauseRecord](Send-OBSPauseRecord.md) | +|[Send-OBSPressInputPropertiesButton](Send-OBSPressInputPropertiesButton.md) | +|[Send-OBSSleep](Send-OBSSleep.md) | +|[Send-OBSStreamCaption](Send-OBSStreamCaption.md) | +|[Send-OBSTriggerHotkeyByKeySequence](Send-OBSTriggerHotkeyByKeySequence.md) | +|[Send-OBSTriggerHotkeyByName](Send-OBSTriggerHotkeyByName.md) | +|[Send-OBSTriggerMediaInputAction](Send-OBSTriggerMediaInputAction.md) | +|[Send-OBSTriggerStudioModeTransition](Send-OBSTriggerStudioModeTransition.md) | +|[Set-OBS3DFilter](Set-OBS3DFilter.md) | +|[Set-OBSAudioOutputSource](Set-OBSAudioOutputSource.md) | +|[Set-OBSBrowserSource](Set-OBSBrowserSource.md) | +|[Set-OBSColorFilter](Set-OBSColorFilter.md) | +|[Set-OBSColorSource](Set-OBSColorSource.md) | +|[Set-OBSCurrentPreviewScene](Set-OBSCurrentPreviewScene.md) | +|[Set-OBSCurrentProfile](Set-OBSCurrentProfile.md) | +|[Set-OBSCurrentProgramScene](Set-OBSCurrentProgramScene.md) | +|[Set-OBSCurrentSceneCollection](Set-OBSCurrentSceneCollection.md) | +|[Set-OBSCurrentSceneTransition](Set-OBSCurrentSceneTransition.md) | +|[Set-OBSCurrentSceneTransitionDuration](Set-OBSCurrentSceneTransitionDuration.md) | +|[Set-OBSCurrentSceneTransitionSettings](Set-OBSCurrentSceneTransitionSettings.md) | +|[Set-OBSDisplaySource](Set-OBSDisplaySource.md) | +|[Set-OBSEqualizerFilter](Set-OBSEqualizerFilter.md) | +|[Set-OBSGainFilter](Set-OBSGainFilter.md) | +|[Set-OBSInputAudioBalance](Set-OBSInputAudioBalance.md) | +|[Set-OBSInputAudioMonitorType](Set-OBSInputAudioMonitorType.md) | +|[Set-OBSInputAudioSyncOffset](Set-OBSInputAudioSyncOffset.md) | +|[Set-OBSInputAudioTracks](Set-OBSInputAudioTracks.md) | +|[Set-OBSInputMute](Set-OBSInputMute.md) | +|[Set-OBSInputName](Set-OBSInputName.md) | +|[Set-OBSInputSettings](Set-OBSInputSettings.md) | +|[Set-OBSInputVolume](Set-OBSInputVolume.md) | +|[Set-OBSMarkdownSource](Set-OBSMarkdownSource.md) | +|[Set-OBSMediaInputCursor](Set-OBSMediaInputCursor.md) | +|[Set-OBSMediaSource](Set-OBSMediaSource.md) | +|[Set-OBSOutputSettings](Set-OBSOutputSettings.md) | +|[Set-OBSPersistentData](Set-OBSPersistentData.md) | +|[Set-OBSProfileParameter](Set-OBSProfileParameter.md) | +|[Set-OBSRecordDirectory](Set-OBSRecordDirectory.md) | +|[Set-OBSRenderDelayFilter](Set-OBSRenderDelayFilter.md) | +|[Set-OBSScaleFilter](Set-OBSScaleFilter.md) | +|[Set-OBSSceneItemBlendMode](Set-OBSSceneItemBlendMode.md) | +|[Set-OBSSceneItemEnabled](Set-OBSSceneItemEnabled.md) | +|[Set-OBSSceneItemIndex](Set-OBSSceneItemIndex.md) | +|[Set-OBSSceneItemLocked](Set-OBSSceneItemLocked.md) | +|[Set-OBSSceneItemTransform](Set-OBSSceneItemTransform.md) | +|[Set-OBSSceneName](Set-OBSSceneName.md) | +|[Set-OBSSceneSceneTransitionOverride](Set-OBSSceneSceneTransitionOverride.md) | +|[Set-OBSScrollFilter](Set-OBSScrollFilter.md) | +|[Set-OBSShaderFilter](Set-OBSShaderFilter.md) | +|[Set-OBSSharpnessFilter](Set-OBSSharpnessFilter.md) | +|[Set-OBSSoundCloudSource](Set-OBSSoundCloudSource.md) | +|[Set-OBSSourceFilterEnabled](Set-OBSSourceFilterEnabled.md) | +|[Set-OBSSourceFilterIndex](Set-OBSSourceFilterIndex.md) | +|[Set-OBSSourceFilterName](Set-OBSSourceFilterName.md) | +|[Set-OBSSourceFilterSettings](Set-OBSSourceFilterSettings.md) | +|[Set-OBSStreamServiceSettings](Set-OBSStreamServiceSettings.md) | +|[Set-OBSStudioModeEnabled](Set-OBSStudioModeEnabled.md) | +|[Set-OBSSwitchSource](Set-OBSSwitchSource.md) | +|[Set-OBSTBarPosition](Set-OBSTBarPosition.md) | +|[Set-OBSVideoSettings](Set-OBSVideoSettings.md) | +|[Set-OBSVLCSource](Set-OBSVLCSource.md) | +|[Set-OBSWaveformSource](Set-OBSWaveformSource.md) | +|[Set-OBSWindowSource](Set-OBSWindowSource.md) | +|[Show-OBS](Show-OBS.md) | +|[Start-OBS](Start-OBS.md) | +|[Start-OBSEffect](Start-OBSEffect.md) | +|[Start-OBSOutput](Start-OBSOutput.md) | +|[Start-OBSRecord](Start-OBSRecord.md) | +|[Start-OBSReplayBuffer](Start-OBSReplayBuffer.md) | +|[Start-OBSStream](Start-OBSStream.md) | +|[Start-OBSVirtualCam](Start-OBSVirtualCam.md) | +|[Stop-OBS](Stop-OBS.md) | +|[Stop-OBSEffect](Stop-OBSEffect.md) | +|[Stop-OBSOutput](Stop-OBSOutput.md) | +|[Stop-OBSRecord](Stop-OBSRecord.md) | +|[Stop-OBSReplayBuffer](Stop-OBSReplayBuffer.md) | +|[Stop-OBSStream](Stop-OBSStream.md) | +|[Stop-OBSVirtualCam](Stop-OBSVirtualCam.md) | +|[Switch-OBSInputMute](Switch-OBSInputMute.md) | +|[Switch-OBSOutput](Switch-OBSOutput.md) | +|[Switch-OBSRecord](Switch-OBSRecord.md) | +|[Switch-OBSRecordPause](Switch-OBSRecordPause.md) | +|[Switch-OBSReplayBuffer](Switch-OBSReplayBuffer.md) | +|[Switch-OBSStream](Switch-OBSStream.md) | +|[Switch-OBSVirtualCam](Switch-OBSVirtualCam.md) | +|[Watch-OBS](Watch-OBS.md) | diff --git a/en-us/obs-powershell-commands.help.txt b/en-us/obs-powershell-commands.help.txt index 45ae5b97..f0131b8a 100644 --- a/en-us/obs-powershell-commands.help.txt +++ b/en-us/obs-powershell-commands.help.txt @@ -1,8 +1,8 @@ obs-powershell-commands ----------------------- -obs-powershell exports 787 commands -(316 functions and 471 aliases) +obs-powershell exports 840 commands +(335 functions and 505 aliases) A good number of these commands directly correspond to an obs-websocket message. For a complete list, see [obs-powershell-websocket-commands](docs/obs-powershell-websocket-commands.md). @@ -12,324 +12,343 @@ Functions ========= -|Name |Synopsis| -|------------------------------------------------------------------------------------------|--------| -|[Add-OBSInput](docs/Add-OBSInput.md) | -|[Add-OBSProfile](docs/Add-OBSProfile.md) | -|[Add-OBSScene](docs/Add-OBSScene.md) | -|[Add-OBSSceneCollection](docs/Add-OBSSceneCollection.md) | -|[Add-OBSSceneItem](docs/Add-OBSSceneItem.md) | -|[Add-OBSSourceFilter](docs/Add-OBSSourceFilter.md) | -|[Clear-OBSScene](docs/Clear-OBSScene.md) | -|[Connect-OBS](docs/Connect-OBS.md) | -|[Copy-OBSSceneItem](docs/Copy-OBSSceneItem.md) | -|[Disconnect-OBS](docs/Disconnect-OBS.md) | -|[Get-OBS](docs/Get-OBS.md) | -|[Get-OBS3dSwapTransitionShader](docs/Get-OBS3dSwapTransitionShader.md) | -|[Get-OBSAddShader](docs/Get-OBSAddShader.md) | -|[Get-OBSAlphaBorderShader](docs/Get-OBSAlphaBorderShader.md) | -|[Get-OBSAlphaGamingBentCameraShader](docs/Get-OBSAlphaGamingBentCameraShader.md) | -|[Get-OBSAnimatedPathShader](docs/Get-OBSAnimatedPathShader.md) | -|[Get-OBSAnimatedTextureShader](docs/Get-OBSAnimatedTextureShader.md) | -|[Get-OBSAsciiShader](docs/Get-OBSAsciiShader.md) | -|[Get-OBSAspectRatioShader](docs/Get-OBSAspectRatioShader.md) | -|[Get-OBSBackgroundRemovalShader](docs/Get-OBSBackgroundRemovalShader.md) | -|[Get-OBSBlendOpacityShader](docs/Get-OBSBlendOpacityShader.md) | -|[Get-OBSBlinkShader](docs/Get-OBSBlinkShader.md) | -|[Get-OBSBloomShader](docs/Get-OBSBloomShader.md) | -|[Get-OBSBorderShader](docs/Get-OBSBorderShader.md) | -|[Get-OBSBoxBlurShader](docs/Get-OBSBoxBlurShader.md) | -|[Get-OBSBulgePinchShader](docs/Get-OBSBulgePinchShader.md) | -|[Get-OBSBurnShader](docs/Get-OBSBurnShader.md) | -|[Get-OBSCartoonShader](docs/Get-OBSCartoonShader.md) | -|[Get-OBSCellShadedShader](docs/Get-OBSCellShadedShader.md) | -|[Get-OBSChromaticAberrationShader](docs/Get-OBSChromaticAberrationShader.md) | -|[Get-OBSChromaUVDistortionShader](docs/Get-OBSChromaUVDistortionShader.md) | -|[Get-OBSCircleMaskFilterShader](docs/Get-OBSCircleMaskFilterShader.md) | -|[Get-OBSClockAnalogShader](docs/Get-OBSClockAnalogShader.md) | -|[Get-OBSClockDigitalLedShader](docs/Get-OBSClockDigitalLedShader.md) | -|[Get-OBSClockDigitalNixieShader](docs/Get-OBSClockDigitalNixieShader.md) | -|[Get-OBSColorDepthShader](docs/Get-OBSColorDepthShader.md) | -|[Get-OBSColorGradeFilterShader](docs/Get-OBSColorGradeFilterShader.md) | -|[Get-OBSCornerPinShader](docs/Get-OBSCornerPinShader.md) | -|[Get-OBSCrtCurvatureShader](docs/Get-OBSCrtCurvatureShader.md) | -|[Get-OBSCurrentPreviewScene](docs/Get-OBSCurrentPreviewScene.md) | -|[Get-OBSCurrentProgramScene](docs/Get-OBSCurrentProgramScene.md) | -|[Get-OBSCurrentSceneTransition](docs/Get-OBSCurrentSceneTransition.md) | -|[Get-OBSCurrentSceneTransitionCursor](docs/Get-OBSCurrentSceneTransitionCursor.md) | -|[Get-OBSCurveShader](docs/Get-OBSCurveShader.md) | -|[Get-OBSCutRectPerCornerShader](docs/Get-OBSCutRectPerCornerShader.md) | -|[Get-OBSCylinderShader](docs/Get-OBSCylinderShader.md) | -|[Get-OBSDarkenShader](docs/Get-OBSDarkenShader.md) | -|[Get-OBSDeadPixelFixerShader](docs/Get-OBSDeadPixelFixerShader.md) | -|[Get-OBSDensitySatHueShader](docs/Get-OBSDensitySatHueShader.md) | -|[Get-OBSDiffuseTransitionShader](docs/Get-OBSDiffuseTransitionShader.md) | -|[Get-OBSDigitalRainShader](docs/Get-OBSDigitalRainShader.md) | -|[Get-OBSDivideRotateShader](docs/Get-OBSDivideRotateShader.md) | -|[Get-OBSDoodleShader](docs/Get-OBSDoodleShader.md) | -|[Get-OBSDrawingsShader](docs/Get-OBSDrawingsShader.md) | -|[Get-OBSDropShadowShader](docs/Get-OBSDropShadowShader.md) | -|[Get-OBSDrunkShader](docs/Get-OBSDrunkShader.md) | -|[Get-OBSDynamicMaskShader](docs/Get-OBSDynamicMaskShader.md) | -|[Get-OBSEdgeDetectionShader](docs/Get-OBSEdgeDetectionShader.md) | -|[Get-OBSEffect](docs/Get-OBSEffect.md) | -|[Get-OBSEmbersShader](docs/Get-OBSEmbersShader.md) | -|[Get-OBSEmbossColorShader](docs/Get-OBSEmbossColorShader.md) | -|[Get-OBSEmbossShader](docs/Get-OBSEmbossShader.md) | -|[Get-OBSExeldroBentCameraShader](docs/Get-OBSExeldroBentCameraShader.md) | -|[Get-OBSFadeTransitionShader](docs/Get-OBSFadeTransitionShader.md) | -|[Get-OBSFillColorGradientShader](docs/Get-OBSFillColorGradientShader.md) | -|[Get-OBSFillColorLinearShader](docs/Get-OBSFillColorLinearShader.md) | -|[Get-OBSFillColorRadialDegreesShader](docs/Get-OBSFillColorRadialDegreesShader.md) | -|[Get-OBSFillColorRadialPercentageShader](docs/Get-OBSFillColorRadialPercentageShader.md) | -|[Get-OBSFilterTemplateShader](docs/Get-OBSFilterTemplateShader.md) | -|[Get-OBSFire3Shader](docs/Get-OBSFire3Shader.md) | -|[Get-OBSFireShader](docs/Get-OBSFireShader.md) | -|[Get-OBSFireworks2Shader](docs/Get-OBSFireworks2Shader.md) | -|[Get-OBSFireworksShader](docs/Get-OBSFireworksShader.md) | -|[Get-OBSFisheyeShader](docs/Get-OBSFisheyeShader.md) | -|[Get-OBSFisheyeXyShader](docs/Get-OBSFisheyeXyShader.md) | -|[Get-OBSFlipShader](docs/Get-OBSFlipShader.md) | -|[Get-OBSFrostedGlassShader](docs/Get-OBSFrostedGlassShader.md) | -|[Get-OBSGammaCorrectionShader](docs/Get-OBSGammaCorrectionShader.md) | -|[Get-OBSGaussianBlurAdvancedShader](docs/Get-OBSGaussianBlurAdvancedShader.md) | -|[Get-OBSGaussianBlurShader](docs/Get-OBSGaussianBlurShader.md) | -|[Get-OBSGaussianBlurSimpleShader](docs/Get-OBSGaussianBlurSimpleShader.md) | -|[Get-OBSGaussianExampleShader](docs/Get-OBSGaussianExampleShader.md) | -|[Get-OBSGaussianSimpleShader](docs/Get-OBSGaussianSimpleShader.md) | -|[Get-OBSGbCameraShader](docs/Get-OBSGbCameraShader.md) | -|[Get-OBSGlassShader](docs/Get-OBSGlassShader.md) | -|[Get-OBSGlitchAnalogShader](docs/Get-OBSGlitchAnalogShader.md) | -|[Get-OBSGlitchShader](docs/Get-OBSGlitchShader.md) | -|[Get-OBSGlowShader](docs/Get-OBSGlowShader.md) | -|[Get-OBSGradientShader](docs/Get-OBSGradientShader.md) | -|[Get-OBSGroup](docs/Get-OBSGroup.md) | -|[Get-OBSGroupSceneItem](docs/Get-OBSGroupSceneItem.md) | -|[Get-OBSHalftoneShader](docs/Get-OBSHalftoneShader.md) | -|[Get-OBSHeatWaveSimpleShader](docs/Get-OBSHeatWaveSimpleShader.md) | -|[Get-OBSHexagonShader](docs/Get-OBSHexagonShader.md) | -|[Get-OBSHotkey](docs/Get-OBSHotkey.md) | -|[Get-OBSHslHsvSaturationShader](docs/Get-OBSHslHsvSaturationShader.md) | -|[Get-OBSHueRotatonShader](docs/Get-OBSHueRotatonShader.md) | -|[Get-OBSInput](docs/Get-OBSInput.md) | -|[Get-OBSInputAudioBalance](docs/Get-OBSInputAudioBalance.md) | -|[Get-OBSInputAudioMonitorType](docs/Get-OBSInputAudioMonitorType.md) | -|[Get-OBSInputAudioSyncOffset](docs/Get-OBSInputAudioSyncOffset.md) | -|[Get-OBSInputAudioTracks](docs/Get-OBSInputAudioTracks.md) | -|[Get-OBSInputDefaultSettings](docs/Get-OBSInputDefaultSettings.md) | -|[Get-OBSInputKind](docs/Get-OBSInputKind.md) | -|[Get-OBSInputMute](docs/Get-OBSInputMute.md) | -|[Get-OBSInputPropertiesListPropertyItems](docs/Get-OBSInputPropertiesListPropertyItems.md)| -|[Get-OBSInputSettings](docs/Get-OBSInputSettings.md) | -|[Get-OBSInputVolume](docs/Get-OBSInputVolume.md) | -|[Get-OBSIntensityScopeShader](docs/Get-OBSIntensityScopeShader.md) | -|[Get-OBSInvertLumaShader](docs/Get-OBSInvertLumaShader.md) | -|[Get-OBSLastReplayBufferReplay](docs/Get-OBSLastReplayBufferReplay.md) | -|[Get-OBSLuminance2Shader](docs/Get-OBSLuminance2Shader.md) | -|[Get-OBSLuminanceAlphaShader](docs/Get-OBSLuminanceAlphaShader.md) | -|[Get-OBSLuminanceShader](docs/Get-OBSLuminanceShader.md) | -|[Get-OBSMatrixShader](docs/Get-OBSMatrixShader.md) | -|[Get-OBSMediaInputStatus](docs/Get-OBSMediaInputStatus.md) | -|[Get-OBSMonitor](docs/Get-OBSMonitor.md) | -|[Get-OBSMultiplyShader](docs/Get-OBSMultiplyShader.md) | -|[Get-OBSNightSkyShader](docs/Get-OBSNightSkyShader.md) | -|[Get-OBSOpacityShader](docs/Get-OBSOpacityShader.md) | -|[Get-OBSOutput](docs/Get-OBSOutput.md) | -|[Get-OBSOutputSettings](docs/Get-OBSOutputSettings.md) | -|[Get-OBSOutputStatus](docs/Get-OBSOutputStatus.md) | -|[Get-OBSPagePeelShader](docs/Get-OBSPagePeelShader.md) | -|[Get-OBSPagePeelTransitionShader](docs/Get-OBSPagePeelTransitionShader.md) | -|[Get-OBSPerlinNoiseShader](docs/Get-OBSPerlinNoiseShader.md) | -|[Get-OBSPersistentData](docs/Get-OBSPersistentData.md) | -|[Get-OBSPieChartShader](docs/Get-OBSPieChartShader.md) | -|[Get-OBSPixelationShader](docs/Get-OBSPixelationShader.md) | -|[Get-OBSPixelationTransitionShader](docs/Get-OBSPixelationTransitionShader.md) | -|[Get-OBSPolarShader](docs/Get-OBSPolarShader.md) | -|[Get-OBSProfile](docs/Get-OBSProfile.md) | -|[Get-OBSProfileParameter](docs/Get-OBSProfileParameter.md) | -|[Get-OBSPulseShader](docs/Get-OBSPulseShader.md) | -|[Get-OBSRainbowShader](docs/Get-OBSRainbowShader.md) | -|[Get-OBSRainWindowShader](docs/Get-OBSRainWindowShader.md) | -|[Get-OBSRecordDirectory](docs/Get-OBSRecordDirectory.md) | -|[Get-OBSRecordStatus](docs/Get-OBSRecordStatus.md) | -|[Get-OBSRectangularDropShadowShader](docs/Get-OBSRectangularDropShadowShader.md) | -|[Get-OBSReflectShader](docs/Get-OBSReflectShader.md) | -|[Get-OBSRemovePartialPixelsShader](docs/Get-OBSRemovePartialPixelsShader.md) | -|[Get-OBSRepeatShader](docs/Get-OBSRepeatShader.md) | -|[Get-OBSRepeatTextureShader](docs/Get-OBSRepeatTextureShader.md) | -|[Get-OBSReplayBufferStatus](docs/Get-OBSReplayBufferStatus.md) | -|[Get-OBSRGBAPercentShader](docs/Get-OBSRGBAPercentShader.md) | -|[Get-OBSRgbColorWheelShader](docs/Get-OBSRgbColorWheelShader.md) | -|[Get-OBSRgbSplitShader](docs/Get-OBSRgbSplitShader.md) | -|[Get-OBSRgbvisibilityShader](docs/Get-OBSRgbvisibilityShader.md) | -|[Get-OBSRGSSAAShader](docs/Get-OBSRGSSAAShader.md) | -|[Get-OBSRippleShader](docs/Get-OBSRippleShader.md) | -|[Get-OBSRotatingSourceShader](docs/Get-OBSRotatingSourceShader.md) | -|[Get-OBSRotatoeShader](docs/Get-OBSRotatoeShader.md) | -|[Get-OBSRoundedRect2Shader](docs/Get-OBSRoundedRect2Shader.md) | -|[Get-OBSRoundedRectPerCornerShader](docs/Get-OBSRoundedRectPerCornerShader.md) | -|[Get-OBSRoundedRectPerSideShader](docs/Get-OBSRoundedRectPerSideShader.md) | -|[Get-OBSRoundedRectShader](docs/Get-OBSRoundedRectShader.md) | -|[Get-OBSRoundedStrokeGradientShader](docs/Get-OBSRoundedStrokeGradientShader.md) | -|[Get-OBSRoundedStrokeShader](docs/Get-OBSRoundedStrokeShader.md) | -|[Get-OBSScanLineShader](docs/Get-OBSScanLineShader.md) | -|[Get-OBSScene](docs/Get-OBSScene.md) | -|[Get-OBSSceneCollection](docs/Get-OBSSceneCollection.md) | -|[Get-OBSSceneItem](docs/Get-OBSSceneItem.md) | -|[Get-OBSSceneItemBlendMode](docs/Get-OBSSceneItemBlendMode.md) | -|[Get-OBSSceneItemEnabled](docs/Get-OBSSceneItemEnabled.md) | -|[Get-OBSSceneItemId](docs/Get-OBSSceneItemId.md) | -|[Get-OBSSceneItemIndex](docs/Get-OBSSceneItemIndex.md) | -|[Get-OBSSceneItemLocked](docs/Get-OBSSceneItemLocked.md) | -|[Get-OBSSceneItemSource](docs/Get-OBSSceneItemSource.md) | -|[Get-OBSSceneItemTransform](docs/Get-OBSSceneItemTransform.md) | -|[Get-OBSSceneSceneTransitionOverride](docs/Get-OBSSceneSceneTransitionOverride.md) | -|[Get-OBSSceneTransition](docs/Get-OBSSceneTransition.md) | -|[Get-OBSSeascapeShader](docs/Get-OBSSeascapeShader.md) | -|[Get-OBSSeasickShader](docs/Get-OBSSeasickShader.md) | -|[Get-OBSSelectiveColorShader](docs/Get-OBSSelectiveColorShader.md) | -|[Get-OBSShakeShader](docs/Get-OBSShakeShader.md) | -|[Get-OBSShineShader](docs/Get-OBSShineShader.md) | -|[Get-OBSSimpleGradientShader](docs/Get-OBSSimpleGradientShader.md) | -|[Get-OBSSimplexNoiseShader](docs/Get-OBSSimplexNoiseShader.md) | -|[Get-OBSSmartDenoiseShader](docs/Get-OBSSmartDenoiseShader.md) | -|[Get-OBSSourceActive](docs/Get-OBSSourceActive.md) | -|[Get-OBSSourceFilter](docs/Get-OBSSourceFilter.md) | -|[Get-OBSSourceFilterDefaultSettings](docs/Get-OBSSourceFilterDefaultSettings.md) | -|[Get-OBSSourceFilterKind](docs/Get-OBSSourceFilterKind.md) | -|[Get-OBSSourceFilterList](docs/Get-OBSSourceFilterList.md) | -|[Get-OBSSourceScreenshot](docs/Get-OBSSourceScreenshot.md) | -|[Get-OBSSpecialInputs](docs/Get-OBSSpecialInputs.md) | -|[Get-OBSSpecularShineShader](docs/Get-OBSSpecularShineShader.md) | -|[Get-OBSSpotlightShader](docs/Get-OBSSpotlightShader.md) | -|[Get-OBSStats](docs/Get-OBSStats.md) | -|[Get-OBSStreamServiceSettings](docs/Get-OBSStreamServiceSettings.md) | -|[Get-OBSStreamStatus](docs/Get-OBSStreamStatus.md) | -|[Get-OBSStudioModeEnabled](docs/Get-OBSStudioModeEnabled.md) | -|[Get-OBSSwirlShader](docs/Get-OBSSwirlShader.md) | -|[Get-OBSTetraShader](docs/Get-OBSTetraShader.md) | -|[Get-OBSThermalShader](docs/Get-OBSThermalShader.md) | -|[Get-OBSTransitionKind](docs/Get-OBSTransitionKind.md) | -|[Get-OBSTvCrtSubpixelShader](docs/Get-OBSTvCrtSubpixelShader.md) | -|[Get-OBSTwistShader](docs/Get-OBSTwistShader.md) | -|[Get-OBSTwoPassDropShadowShader](docs/Get-OBSTwoPassDropShadowShader.md) | -|[Get-OBSVCRShader](docs/Get-OBSVCRShader.md) | -|[Get-OBSVersion](docs/Get-OBSVersion.md) | -|[Get-OBSVHSShader](docs/Get-OBSVHSShader.md) | -|[Get-OBSVideoSettings](docs/Get-OBSVideoSettings.md) | -|[Get-OBSVignettingShader](docs/Get-OBSVignettingShader.md) | -|[Get-OBSVirtualCamStatus](docs/Get-OBSVirtualCamStatus.md) | -|[Get-OBSVoronoiPixelationShader](docs/Get-OBSVoronoiPixelationShader.md) | -|[Get-OBSZigZagShader](docs/Get-OBSZigZagShader.md) | -|[Get-OBSZoomBlurShader](docs/Get-OBSZoomBlurShader.md) | -|[Get-OBSZoomShader](docs/Get-OBSZoomShader.md) | -|[Get-OBSZoomXYShader](docs/Get-OBSZoomXYShader.md) | -|[Hide-OBS](docs/Hide-OBS.md) | -|[Import-OBSEffect](docs/Import-OBSEffect.md) | -|[Open-OBSInputFiltersDialog](docs/Open-OBSInputFiltersDialog.md) | -|[Open-OBSInputInteractDialog](docs/Open-OBSInputInteractDialog.md) | -|[Open-OBSInputPropertiesDialog](docs/Open-OBSInputPropertiesDialog.md) | -|[Open-OBSSourceProjector](docs/Open-OBSSourceProjector.md) | -|[Open-OBSVideoMixProjector](docs/Open-OBSVideoMixProjector.md) | -|[Receive-OBS](docs/Receive-OBS.md) | -|[Remove-OBS](docs/Remove-OBS.md) | -|[Remove-OBSEffect](docs/Remove-OBSEffect.md) | -|[Remove-OBSInput](docs/Remove-OBSInput.md) | -|[Remove-OBSProfile](docs/Remove-OBSProfile.md) | -|[Remove-OBSScene](docs/Remove-OBSScene.md) | -|[Remove-OBSSceneItem](docs/Remove-OBSSceneItem.md) | -|[Remove-OBSSourceFilter](docs/Remove-OBSSourceFilter.md) | -|[Resume-OBSRecord](docs/Resume-OBSRecord.md) | -|[Save-OBSReplayBuffer](docs/Save-OBSReplayBuffer.md) | -|[Save-OBSSourceScreenshot](docs/Save-OBSSourceScreenshot.md) | -|[Send-OBS](docs/Send-OBS.md) | -|[Send-OBSCallVendorRequest](docs/Send-OBSCallVendorRequest.md) | -|[Send-OBSCustomEvent](docs/Send-OBSCustomEvent.md) | -|[Send-OBSOffsetMediaInputCursor](docs/Send-OBSOffsetMediaInputCursor.md) | -|[Send-OBSPauseRecord](docs/Send-OBSPauseRecord.md) | -|[Send-OBSPressInputPropertiesButton](docs/Send-OBSPressInputPropertiesButton.md) | -|[Send-OBSSleep](docs/Send-OBSSleep.md) | -|[Send-OBSStreamCaption](docs/Send-OBSStreamCaption.md) | -|[Send-OBSTriggerHotkeyByKeySequence](docs/Send-OBSTriggerHotkeyByKeySequence.md) | -|[Send-OBSTriggerHotkeyByName](docs/Send-OBSTriggerHotkeyByName.md) | -|[Send-OBSTriggerMediaInputAction](docs/Send-OBSTriggerMediaInputAction.md) | -|[Send-OBSTriggerStudioModeTransition](docs/Send-OBSTriggerStudioModeTransition.md) | -|[Set-OBS3DFilter](docs/Set-OBS3DFilter.md) | -|[Set-OBSAudioOutputSource](docs/Set-OBSAudioOutputSource.md) | -|[Set-OBSBrowserSource](docs/Set-OBSBrowserSource.md) | -|[Set-OBSColorFilter](docs/Set-OBSColorFilter.md) | -|[Set-OBSColorSource](docs/Set-OBSColorSource.md) | -|[Set-OBSCurrentPreviewScene](docs/Set-OBSCurrentPreviewScene.md) | -|[Set-OBSCurrentProfile](docs/Set-OBSCurrentProfile.md) | -|[Set-OBSCurrentProgramScene](docs/Set-OBSCurrentProgramScene.md) | -|[Set-OBSCurrentSceneCollection](docs/Set-OBSCurrentSceneCollection.md) | -|[Set-OBSCurrentSceneTransition](docs/Set-OBSCurrentSceneTransition.md) | -|[Set-OBSCurrentSceneTransitionDuration](docs/Set-OBSCurrentSceneTransitionDuration.md) | -|[Set-OBSCurrentSceneTransitionSettings](docs/Set-OBSCurrentSceneTransitionSettings.md) | -|[Set-OBSDisplaySource](docs/Set-OBSDisplaySource.md) | -|[Set-OBSEqualizerFilter](docs/Set-OBSEqualizerFilter.md) | -|[Set-OBSGainFilter](docs/Set-OBSGainFilter.md) | -|[Set-OBSInputAudioBalance](docs/Set-OBSInputAudioBalance.md) | -|[Set-OBSInputAudioMonitorType](docs/Set-OBSInputAudioMonitorType.md) | -|[Set-OBSInputAudioSyncOffset](docs/Set-OBSInputAudioSyncOffset.md) | -|[Set-OBSInputAudioTracks](docs/Set-OBSInputAudioTracks.md) | -|[Set-OBSInputMute](docs/Set-OBSInputMute.md) | -|[Set-OBSInputName](docs/Set-OBSInputName.md) | -|[Set-OBSInputSettings](docs/Set-OBSInputSettings.md) | -|[Set-OBSInputVolume](docs/Set-OBSInputVolume.md) | -|[Set-OBSMarkdownSource](docs/Set-OBSMarkdownSource.md) | -|[Set-OBSMediaInputCursor](docs/Set-OBSMediaInputCursor.md) | -|[Set-OBSMediaSource](docs/Set-OBSMediaSource.md) | -|[Set-OBSOutputSettings](docs/Set-OBSOutputSettings.md) | -|[Set-OBSPersistentData](docs/Set-OBSPersistentData.md) | -|[Set-OBSProfileParameter](docs/Set-OBSProfileParameter.md) | -|[Set-OBSRecordDirectory](docs/Set-OBSRecordDirectory.md) | -|[Set-OBSRenderDelayFilter](docs/Set-OBSRenderDelayFilter.md) | -|[Set-OBSScaleFilter](docs/Set-OBSScaleFilter.md) | -|[Set-OBSSceneItemBlendMode](docs/Set-OBSSceneItemBlendMode.md) | -|[Set-OBSSceneItemEnabled](docs/Set-OBSSceneItemEnabled.md) | -|[Set-OBSSceneItemIndex](docs/Set-OBSSceneItemIndex.md) | -|[Set-OBSSceneItemLocked](docs/Set-OBSSceneItemLocked.md) | -|[Set-OBSSceneItemTransform](docs/Set-OBSSceneItemTransform.md) | -|[Set-OBSSceneName](docs/Set-OBSSceneName.md) | -|[Set-OBSSceneSceneTransitionOverride](docs/Set-OBSSceneSceneTransitionOverride.md) | -|[Set-OBSScrollFilter](docs/Set-OBSScrollFilter.md) | -|[Set-OBSShaderFilter](docs/Set-OBSShaderFilter.md) | -|[Set-OBSSharpnessFilter](docs/Set-OBSSharpnessFilter.md) | -|[Set-OBSSoundCloudSource](docs/Set-OBSSoundCloudSource.md) | -|[Set-OBSSourceFilterEnabled](docs/Set-OBSSourceFilterEnabled.md) | -|[Set-OBSSourceFilterIndex](docs/Set-OBSSourceFilterIndex.md) | -|[Set-OBSSourceFilterName](docs/Set-OBSSourceFilterName.md) | -|[Set-OBSSourceFilterSettings](docs/Set-OBSSourceFilterSettings.md) | -|[Set-OBSStreamServiceSettings](docs/Set-OBSStreamServiceSettings.md) | -|[Set-OBSStudioModeEnabled](docs/Set-OBSStudioModeEnabled.md) | -|[Set-OBSSwitchSource](docs/Set-OBSSwitchSource.md) | -|[Set-OBSTBarPosition](docs/Set-OBSTBarPosition.md) | -|[Set-OBSVideoSettings](docs/Set-OBSVideoSettings.md) | -|[Set-OBSVLCSource](docs/Set-OBSVLCSource.md) | -|[Set-OBSWaveformSource](docs/Set-OBSWaveformSource.md) | -|[Set-OBSWindowSource](docs/Set-OBSWindowSource.md) | -|[Show-OBS](docs/Show-OBS.md) | -|[Start-OBSEffect](docs/Start-OBSEffect.md) | -|[Start-OBSOutput](docs/Start-OBSOutput.md) | -|[Start-OBSRecord](docs/Start-OBSRecord.md) | -|[Start-OBSReplayBuffer](docs/Start-OBSReplayBuffer.md) | -|[Start-OBSStream](docs/Start-OBSStream.md) | -|[Start-OBSVirtualCam](docs/Start-OBSVirtualCam.md) | -|[Stop-OBSEffect](docs/Stop-OBSEffect.md) | -|[Stop-OBSOutput](docs/Stop-OBSOutput.md) | -|[Stop-OBSRecord](docs/Stop-OBSRecord.md) | -|[Stop-OBSReplayBuffer](docs/Stop-OBSReplayBuffer.md) | -|[Stop-OBSStream](docs/Stop-OBSStream.md) | -|[Stop-OBSVirtualCam](docs/Stop-OBSVirtualCam.md) | -|[Switch-OBSInputMute](docs/Switch-OBSInputMute.md) | -|[Switch-OBSOutput](docs/Switch-OBSOutput.md) | -|[Switch-OBSRecord](docs/Switch-OBSRecord.md) | -|[Switch-OBSRecordPause](docs/Switch-OBSRecordPause.md) | -|[Switch-OBSReplayBuffer](docs/Switch-OBSReplayBuffer.md) | -|[Switch-OBSStream](docs/Switch-OBSStream.md) | -|[Switch-OBSVirtualCam](docs/Switch-OBSVirtualCam.md) | -|[Watch-OBS](docs/Watch-OBS.md) | +|Name |Synopsis| +|------------------------------------------------------------------------------------------------|--------| +|[Add-OBSInput](docs/Add-OBSInput.md) | +|[Add-OBSProfile](docs/Add-OBSProfile.md) | +|[Add-OBSScene](docs/Add-OBSScene.md) | +|[Add-OBSSceneCollection](docs/Add-OBSSceneCollection.md) | +|[Add-OBSSceneItem](docs/Add-OBSSceneItem.md) | +|[Add-OBSSourceFilter](docs/Add-OBSSourceFilter.md) | +|[Clear-OBSScene](docs/Clear-OBSScene.md) | +|[Connect-OBS](docs/Connect-OBS.md) | +|[Copy-OBSSceneItem](docs/Copy-OBSSceneItem.md) | +|[Disconnect-OBS](docs/Disconnect-OBS.md) | +|[Get-OBS](docs/Get-OBS.md) | +|[Get-OBS3dPanelShader](docs/Get-OBS3dPanelShader.md) | +|[Get-OBS3dSwapTransitionShader](docs/Get-OBS3dSwapTransitionShader.md) | +|[Get-OBSAddShader](docs/Get-OBSAddShader.md) | +|[Get-OBSAlphaBorderShader](docs/Get-OBSAlphaBorderShader.md) | +|[Get-OBSAlphaGamingBentCameraShader](docs/Get-OBSAlphaGamingBentCameraShader.md) | +|[Get-OBSAnimatedPathShader](docs/Get-OBSAnimatedPathShader.md) | +|[Get-OBSAnimatedTextureShader](docs/Get-OBSAnimatedTextureShader.md) | +|[Get-OBSAsciiShader](docs/Get-OBSAsciiShader.md) | +|[Get-OBSAspectRatioShader](docs/Get-OBSAspectRatioShader.md) | +|[Get-OBSAudioShader](docs/Get-OBSAudioShader.md) | +|[Get-OBSBackgroundRemovalShader](docs/Get-OBSBackgroundRemovalShader.md) | +|[Get-OBSBlendOpacityShader](docs/Get-OBSBlendOpacityShader.md) | +|[Get-OBSBlinkShader](docs/Get-OBSBlinkShader.md) | +|[Get-OBSBloomShader](docs/Get-OBSBloomShader.md) | +|[Get-OBSBorderShader](docs/Get-OBSBorderShader.md) | +|[Get-OBSBoxBlurShader](docs/Get-OBSBoxBlurShader.md) | +|[Get-OBSBulgePinchShader](docs/Get-OBSBulgePinchShader.md) | +|[Get-OBSBurnShader](docs/Get-OBSBurnShader.md) | +|[Get-OBSCartoonShader](docs/Get-OBSCartoonShader.md) | +|[Get-OBSCellShadedShader](docs/Get-OBSCellShadedShader.md) | +|[Get-OBSChromaticAberrationShader](docs/Get-OBSChromaticAberrationShader.md) | +|[Get-OBSChromaUVDistortionShader](docs/Get-OBSChromaUVDistortionShader.md) | +|[Get-OBSCircleMaskFilterShader](docs/Get-OBSCircleMaskFilterShader.md) | +|[Get-OBSClockAnalogShader](docs/Get-OBSClockAnalogShader.md) | +|[Get-OBSClockDigitalLedShader](docs/Get-OBSClockDigitalLedShader.md) | +|[Get-OBSClockDigitalNixieShader](docs/Get-OBSClockDigitalNixieShader.md) | +|[Get-OBSColorDepthShader](docs/Get-OBSColorDepthShader.md) | +|[Get-OBSColorGradeFilterShader](docs/Get-OBSColorGradeFilterShader.md) | +|[Get-OBSCornerPinShader](docs/Get-OBSCornerPinShader.md) | +|[Get-OBSCrtCurvatureShader](docs/Get-OBSCrtCurvatureShader.md) | +|[Get-OBSCubeRotatingShader](docs/Get-OBSCubeRotatingShader.md) | +|[Get-OBSCurrentPreviewScene](docs/Get-OBSCurrentPreviewScene.md) | +|[Get-OBSCurrentProgramScene](docs/Get-OBSCurrentProgramScene.md) | +|[Get-OBSCurrentSceneTransition](docs/Get-OBSCurrentSceneTransition.md) | +|[Get-OBSCurrentSceneTransitionCursor](docs/Get-OBSCurrentSceneTransitionCursor.md) | +|[Get-OBSCurveShader](docs/Get-OBSCurveShader.md) | +|[Get-OBSCutRectPerCornerShader](docs/Get-OBSCutRectPerCornerShader.md) | +|[Get-OBSCylinderShader](docs/Get-OBSCylinderShader.md) | +|[Get-OBSDarkenShader](docs/Get-OBSDarkenShader.md) | +|[Get-OBSDeadPixelFixerShader](docs/Get-OBSDeadPixelFixerShader.md) | +|[Get-OBSDensitySatHueShader](docs/Get-OBSDensitySatHueShader.md) | +|[Get-OBSDiffuseTransitionShader](docs/Get-OBSDiffuseTransitionShader.md) | +|[Get-OBSDigitalRainShader](docs/Get-OBSDigitalRainShader.md) | +|[Get-OBSDisplacementMapAdvancedInvertShader](docs/Get-OBSDisplacementMapAdvancedInvertShader.md)| +|[Get-OBSDisplacementMapAdvancedShader](docs/Get-OBSDisplacementMapAdvancedShader.md) | +|[Get-OBSDisplacementMapInvertShader](docs/Get-OBSDisplacementMapInvertShader.md) | +|[Get-OBSDisplacementMapShader](docs/Get-OBSDisplacementMapShader.md) | +|[Get-OBSDivideRotateShader](docs/Get-OBSDivideRotateShader.md) | +|[Get-OBSDoodleShader](docs/Get-OBSDoodleShader.md) | +|[Get-OBSDrawingsShader](docs/Get-OBSDrawingsShader.md) | +|[Get-OBSDropShadowShader](docs/Get-OBSDropShadowShader.md) | +|[Get-OBSDrunkShader](docs/Get-OBSDrunkShader.md) | +|[Get-OBSDynamicMaskShader](docs/Get-OBSDynamicMaskShader.md) | +|[Get-OBSEdgeDetectionShader](docs/Get-OBSEdgeDetectionShader.md) | +|[Get-OBSEffect](docs/Get-OBSEffect.md) | +|[Get-OBSEmbersShader](docs/Get-OBSEmbersShader.md) | +|[Get-OBSEmbossColorShader](docs/Get-OBSEmbossColorShader.md) | +|[Get-OBSEmbossShader](docs/Get-OBSEmbossShader.md) | +|[Get-OBSExeldroBentCameraShader](docs/Get-OBSExeldroBentCameraShader.md) | +|[Get-OBSFadeTransitionShader](docs/Get-OBSFadeTransitionShader.md) | +|[Get-OBSFillColorGradientShader](docs/Get-OBSFillColorGradientShader.md) | +|[Get-OBSFillColorLinearShader](docs/Get-OBSFillColorLinearShader.md) | +|[Get-OBSFillColorRadialDegreesShader](docs/Get-OBSFillColorRadialDegreesShader.md) | +|[Get-OBSFillColorRadialPercentageShader](docs/Get-OBSFillColorRadialPercentageShader.md) | +|[Get-OBSFilterTemplateShader](docs/Get-OBSFilterTemplateShader.md) | +|[Get-OBSFire3Shader](docs/Get-OBSFire3Shader.md) | +|[Get-OBSFireShader](docs/Get-OBSFireShader.md) | +|[Get-OBSFireworks2Shader](docs/Get-OBSFireworks2Shader.md) | +|[Get-OBSFireworksShader](docs/Get-OBSFireworksShader.md) | +|[Get-OBSFisheyeShader](docs/Get-OBSFisheyeShader.md) | +|[Get-OBSFisheyeXyShader](docs/Get-OBSFisheyeXyShader.md) | +|[Get-OBSFlipShader](docs/Get-OBSFlipShader.md) | +|[Get-OBSFrostedGlassShader](docs/Get-OBSFrostedGlassShader.md) | +|[Get-OBSGammaCorrectionShader](docs/Get-OBSGammaCorrectionShader.md) | +|[Get-OBSGaussianBlurAdvancedShader](docs/Get-OBSGaussianBlurAdvancedShader.md) | +|[Get-OBSGaussianBlurShader](docs/Get-OBSGaussianBlurShader.md) | +|[Get-OBSGaussianBlurSimpleShader](docs/Get-OBSGaussianBlurSimpleShader.md) | +|[Get-OBSGaussianExampleShader](docs/Get-OBSGaussianExampleShader.md) | +|[Get-OBSGaussianSimpleShader](docs/Get-OBSGaussianSimpleShader.md) | +|[Get-OBSGbCameraShader](docs/Get-OBSGbCameraShader.md) | +|[Get-OBSGlassShader](docs/Get-OBSGlassShader.md) | +|[Get-OBSGlitchAnalogShader](docs/Get-OBSGlitchAnalogShader.md) | +|[Get-OBSGlitchPeriodicShader](docs/Get-OBSGlitchPeriodicShader.md) | +|[Get-OBSGlitchShader](docs/Get-OBSGlitchShader.md) | +|[Get-OBSGlowShader](docs/Get-OBSGlowShader.md) | +|[Get-OBSGradientShader](docs/Get-OBSGradientShader.md) | +|[Get-OBSGroup](docs/Get-OBSGroup.md) | +|[Get-OBSGroupSceneItem](docs/Get-OBSGroupSceneItem.md) | +|[Get-OBSHalftoneShader](docs/Get-OBSHalftoneShader.md) | +|[Get-OBSHardBlinkShader](docs/Get-OBSHardBlinkShader.md) | +|[Get-OBSHeatWaveSimpleShader](docs/Get-OBSHeatWaveSimpleShader.md) | +|[Get-OBSHexagonShader](docs/Get-OBSHexagonShader.md) | +|[Get-OBSHotkey](docs/Get-OBSHotkey.md) | +|[Get-OBSHslHsvSaturationShader](docs/Get-OBSHslHsvSaturationShader.md) | +|[Get-OBSHueRotatonShader](docs/Get-OBSHueRotatonShader.md) | +|[Get-OBSInput](docs/Get-OBSInput.md) | +|[Get-OBSInputAudioBalance](docs/Get-OBSInputAudioBalance.md) | +|[Get-OBSInputAudioMonitorType](docs/Get-OBSInputAudioMonitorType.md) | +|[Get-OBSInputAudioSyncOffset](docs/Get-OBSInputAudioSyncOffset.md) | +|[Get-OBSInputAudioTracks](docs/Get-OBSInputAudioTracks.md) | +|[Get-OBSInputDefaultSettings](docs/Get-OBSInputDefaultSettings.md) | +|[Get-OBSInputKind](docs/Get-OBSInputKind.md) | +|[Get-OBSInputMute](docs/Get-OBSInputMute.md) | +|[Get-OBSInputPropertiesListPropertyItems](docs/Get-OBSInputPropertiesListPropertyItems.md) | +|[Get-OBSInputSettings](docs/Get-OBSInputSettings.md) | +|[Get-OBSInputVolume](docs/Get-OBSInputVolume.md) | +|[Get-OBSIntensityScopeShader](docs/Get-OBSIntensityScopeShader.md) | +|[Get-OBSInvertLumaShader](docs/Get-OBSInvertLumaShader.md) | +|[Get-OBSLastReplayBufferReplay](docs/Get-OBSLastReplayBufferReplay.md) | +|[Get-OBSLuminance2Shader](docs/Get-OBSLuminance2Shader.md) | +|[Get-OBSLuminanceAlphaShader](docs/Get-OBSLuminanceAlphaShader.md) | +|[Get-OBSLuminanceShader](docs/Get-OBSLuminanceShader.md) | +|[Get-OBSMatrixShader](docs/Get-OBSMatrixShader.md) | +|[Get-OBSMediaInputStatus](docs/Get-OBSMediaInputStatus.md) | +|[Get-OBSMonitor](docs/Get-OBSMonitor.md) | +|[Get-OBSMotionBlurShader](docs/Get-OBSMotionBlurShader.md) | +|[Get-OBSMultiplyShader](docs/Get-OBSMultiplyShader.md) | +|[Get-OBSNightSkyShader](docs/Get-OBSNightSkyShader.md) | +|[Get-OBSNoiseShader](docs/Get-OBSNoiseShader.md) | +|[Get-OBSNormalMapShader](docs/Get-OBSNormalMapShader.md) | +|[Get-OBSOpacityShader](docs/Get-OBSOpacityShader.md) | +|[Get-OBSOutput](docs/Get-OBSOutput.md) | +|[Get-OBSOutputSettings](docs/Get-OBSOutputSettings.md) | +|[Get-OBSOutputStatus](docs/Get-OBSOutputStatus.md) | +|[Get-OBSPagePeelShader](docs/Get-OBSPagePeelShader.md) | +|[Get-OBSPagePeelTransitionShader](docs/Get-OBSPagePeelTransitionShader.md) | +|[Get-OBSPerlinNoiseShader](docs/Get-OBSPerlinNoiseShader.md) | +|[Get-OBSPersistentData](docs/Get-OBSPersistentData.md) | +|[Get-OBSPerspectiveShader](docs/Get-OBSPerspectiveShader.md) | +|[Get-OBSPieChartShader](docs/Get-OBSPieChartShader.md) | +|[Get-OBSPixelationShader](docs/Get-OBSPixelationShader.md) | +|[Get-OBSPixelationTransitionShader](docs/Get-OBSPixelationTransitionShader.md) | +|[Get-OBSPolarShader](docs/Get-OBSPolarShader.md) | +|[Get-OBSProfile](docs/Get-OBSProfile.md) | +|[Get-OBSProfileParameter](docs/Get-OBSProfileParameter.md) | +|[Get-OBSPulseShader](docs/Get-OBSPulseShader.md) | +|[Get-OBSQuadrilateralCropShader](docs/Get-OBSQuadrilateralCropShader.md) | +|[Get-OBSRainbowShader](docs/Get-OBSRainbowShader.md) | +|[Get-OBSRainWindowShader](docs/Get-OBSRainWindowShader.md) | +|[Get-OBSRecordDirectory](docs/Get-OBSRecordDirectory.md) | +|[Get-OBSRecordStatus](docs/Get-OBSRecordStatus.md) | +|[Get-OBSRectangularDropShadowShader](docs/Get-OBSRectangularDropShadowShader.md) | +|[Get-OBSReflectShader](docs/Get-OBSReflectShader.md) | +|[Get-OBSRemovePartialPixelsShader](docs/Get-OBSRemovePartialPixelsShader.md) | +|[Get-OBSRepeatGridCenterCropShader](docs/Get-OBSRepeatGridCenterCropShader.md) | +|[Get-OBSRepeatShader](docs/Get-OBSRepeatShader.md) | +|[Get-OBSRepeatTextureShader](docs/Get-OBSRepeatTextureShader.md) | +|[Get-OBSReplayBufferStatus](docs/Get-OBSReplayBufferStatus.md) | +|[Get-OBSRGBAPercentShader](docs/Get-OBSRGBAPercentShader.md) | +|[Get-OBSRgbColorWheelShader](docs/Get-OBSRgbColorWheelShader.md) | +|[Get-OBSRgbSplitShader](docs/Get-OBSRgbSplitShader.md) | +|[Get-OBSRgbvisibilityShader](docs/Get-OBSRgbvisibilityShader.md) | +|[Get-OBSRGSSAAShader](docs/Get-OBSRGSSAAShader.md) | +|[Get-OBSRippleShader](docs/Get-OBSRippleShader.md) | +|[Get-OBSRotatingSourceShader](docs/Get-OBSRotatingSourceShader.md) | +|[Get-OBSRotatoeShader](docs/Get-OBSRotatoeShader.md) | +|[Get-OBSRoundedRect2Shader](docs/Get-OBSRoundedRect2Shader.md) | +|[Get-OBSRoundedRectPerCornerShader](docs/Get-OBSRoundedRectPerCornerShader.md) | +|[Get-OBSRoundedRectPerSideShader](docs/Get-OBSRoundedRectPerSideShader.md) | +|[Get-OBSRoundedRectShader](docs/Get-OBSRoundedRectShader.md) | +|[Get-OBSRoundedStrokeGradientShader](docs/Get-OBSRoundedStrokeGradientShader.md) | +|[Get-OBSRoundedStrokeShader](docs/Get-OBSRoundedStrokeShader.md) | +|[Get-OBSScanLineShader](docs/Get-OBSScanLineShader.md) | +|[Get-OBSScene](docs/Get-OBSScene.md) | +|[Get-OBSSceneCollection](docs/Get-OBSSceneCollection.md) | +|[Get-OBSSceneItem](docs/Get-OBSSceneItem.md) | +|[Get-OBSSceneItemBlendMode](docs/Get-OBSSceneItemBlendMode.md) | +|[Get-OBSSceneItemEnabled](docs/Get-OBSSceneItemEnabled.md) | +|[Get-OBSSceneItemId](docs/Get-OBSSceneItemId.md) | +|[Get-OBSSceneItemIndex](docs/Get-OBSSceneItemIndex.md) | +|[Get-OBSSceneItemLocked](docs/Get-OBSSceneItemLocked.md) | +|[Get-OBSSceneItemSource](docs/Get-OBSSceneItemSource.md) | +|[Get-OBSSceneItemTransform](docs/Get-OBSSceneItemTransform.md) | +|[Get-OBSSceneSceneTransitionOverride](docs/Get-OBSSceneSceneTransitionOverride.md) | +|[Get-OBSSceneTransition](docs/Get-OBSSceneTransition.md) | +|[Get-OBSSeascapeShader](docs/Get-OBSSeascapeShader.md) | +|[Get-OBSSeasickShader](docs/Get-OBSSeasickShader.md) | +|[Get-OBSSelectiveColorShader](docs/Get-OBSSelectiveColorShader.md) | +|[Get-OBSShakeShader](docs/Get-OBSShakeShader.md) | +|[Get-OBSShineShader](docs/Get-OBSShineShader.md) | +|[Get-OBSSimpleGradientShader](docs/Get-OBSSimpleGradientShader.md) | +|[Get-OBSSimplexNoiseShader](docs/Get-OBSSimplexNoiseShader.md) | +|[Get-OBSSmartDenoiseShader](docs/Get-OBSSmartDenoiseShader.md) | +|[Get-OBSSourceActive](docs/Get-OBSSourceActive.md) | +|[Get-OBSSourceFilter](docs/Get-OBSSourceFilter.md) | +|[Get-OBSSourceFilterDefaultSettings](docs/Get-OBSSourceFilterDefaultSettings.md) | +|[Get-OBSSourceFilterKind](docs/Get-OBSSourceFilterKind.md) | +|[Get-OBSSourceFilterList](docs/Get-OBSSourceFilterList.md) | +|[Get-OBSSourceScreenshot](docs/Get-OBSSourceScreenshot.md) | +|[Get-OBSSpecialInputs](docs/Get-OBSSpecialInputs.md) | +|[Get-OBSSpecularShineShader](docs/Get-OBSSpecularShineShader.md) | +|[Get-OBSSpotlightShader](docs/Get-OBSSpotlightShader.md) | +|[Get-OBSStats](docs/Get-OBSStats.md) | +|[Get-OBSStreamServiceSettings](docs/Get-OBSStreamServiceSettings.md) | +|[Get-OBSStreamStatus](docs/Get-OBSStreamStatus.md) | +|[Get-OBSStudioModeEnabled](docs/Get-OBSStudioModeEnabled.md) | +|[Get-OBSSwirlShader](docs/Get-OBSSwirlShader.md) | +|[Get-OBSTetraShader](docs/Get-OBSTetraShader.md) | +|[Get-OBSThermalShader](docs/Get-OBSThermalShader.md) | +|[Get-OBSTransitionKind](docs/Get-OBSTransitionKind.md) | +|[Get-OBSTvCrtSubpixelShader](docs/Get-OBSTvCrtSubpixelShader.md) | +|[Get-OBSTwistShader](docs/Get-OBSTwistShader.md) | +|[Get-OBSTwoPassDropShadowShader](docs/Get-OBSTwoPassDropShadowShader.md) | +|[Get-OBSVCRShader](docs/Get-OBSVCRShader.md) | +|[Get-OBSVersion](docs/Get-OBSVersion.md) | +|[Get-OBSVHSShader](docs/Get-OBSVHSShader.md) | +|[Get-OBSVideoSettings](docs/Get-OBSVideoSettings.md) | +|[Get-OBSVignettingShader](docs/Get-OBSVignettingShader.md) | +|[Get-OBSVirtualCamStatus](docs/Get-OBSVirtualCamStatus.md) | +|[Get-OBSVoronoiPixelationShader](docs/Get-OBSVoronoiPixelationShader.md) | +|[Get-OBSWalkingDeadPixelFixerShader](docs/Get-OBSWalkingDeadPixelFixerShader.md) | +|[Get-OBSZigZagShader](docs/Get-OBSZigZagShader.md) | +|[Get-OBSZoomBlurShader](docs/Get-OBSZoomBlurShader.md) | +|[Get-OBSZoomBlurTransitionShader](docs/Get-OBSZoomBlurTransitionShader.md) | +|[Get-OBSZoomShader](docs/Get-OBSZoomShader.md) | +|[Get-OBSZoomXYShader](docs/Get-OBSZoomXYShader.md) | +|[Hide-OBS](docs/Hide-OBS.md) | +|[Import-OBSEffect](docs/Import-OBSEffect.md) | +|[Open-OBSInputFiltersDialog](docs/Open-OBSInputFiltersDialog.md) | +|[Open-OBSInputInteractDialog](docs/Open-OBSInputInteractDialog.md) | +|[Open-OBSInputPropertiesDialog](docs/Open-OBSInputPropertiesDialog.md) | +|[Open-OBSSourceProjector](docs/Open-OBSSourceProjector.md) | +|[Open-OBSVideoMixProjector](docs/Open-OBSVideoMixProjector.md) | +|[Receive-OBS](docs/Receive-OBS.md) | +|[Remove-OBS](docs/Remove-OBS.md) | +|[Remove-OBSEffect](docs/Remove-OBSEffect.md) | +|[Remove-OBSInput](docs/Remove-OBSInput.md) | +|[Remove-OBSProfile](docs/Remove-OBSProfile.md) | +|[Remove-OBSScene](docs/Remove-OBSScene.md) | +|[Remove-OBSSceneItem](docs/Remove-OBSSceneItem.md) | +|[Remove-OBSSourceFilter](docs/Remove-OBSSourceFilter.md) | +|[Resume-OBSRecord](docs/Resume-OBSRecord.md) | +|[Save-OBSReplayBuffer](docs/Save-OBSReplayBuffer.md) | +|[Save-OBSSourceScreenshot](docs/Save-OBSSourceScreenshot.md) | +|[Send-OBS](docs/Send-OBS.md) | +|[Send-OBSCallVendorRequest](docs/Send-OBSCallVendorRequest.md) | +|[Send-OBSCustomEvent](docs/Send-OBSCustomEvent.md) | +|[Send-OBSOffsetMediaInputCursor](docs/Send-OBSOffsetMediaInputCursor.md) | +|[Send-OBSPauseRecord](docs/Send-OBSPauseRecord.md) | +|[Send-OBSPressInputPropertiesButton](docs/Send-OBSPressInputPropertiesButton.md) | +|[Send-OBSSleep](docs/Send-OBSSleep.md) | +|[Send-OBSStreamCaption](docs/Send-OBSStreamCaption.md) | +|[Send-OBSTriggerHotkeyByKeySequence](docs/Send-OBSTriggerHotkeyByKeySequence.md) | +|[Send-OBSTriggerHotkeyByName](docs/Send-OBSTriggerHotkeyByName.md) | +|[Send-OBSTriggerMediaInputAction](docs/Send-OBSTriggerMediaInputAction.md) | +|[Send-OBSTriggerStudioModeTransition](docs/Send-OBSTriggerStudioModeTransition.md) | +|[Set-OBS3DFilter](docs/Set-OBS3DFilter.md) | +|[Set-OBSAudioOutputSource](docs/Set-OBSAudioOutputSource.md) | +|[Set-OBSBrowserSource](docs/Set-OBSBrowserSource.md) | +|[Set-OBSColorFilter](docs/Set-OBSColorFilter.md) | +|[Set-OBSColorSource](docs/Set-OBSColorSource.md) | +|[Set-OBSCurrentPreviewScene](docs/Set-OBSCurrentPreviewScene.md) | +|[Set-OBSCurrentProfile](docs/Set-OBSCurrentProfile.md) | +|[Set-OBSCurrentProgramScene](docs/Set-OBSCurrentProgramScene.md) | +|[Set-OBSCurrentSceneCollection](docs/Set-OBSCurrentSceneCollection.md) | +|[Set-OBSCurrentSceneTransition](docs/Set-OBSCurrentSceneTransition.md) | +|[Set-OBSCurrentSceneTransitionDuration](docs/Set-OBSCurrentSceneTransitionDuration.md) | +|[Set-OBSCurrentSceneTransitionSettings](docs/Set-OBSCurrentSceneTransitionSettings.md) | +|[Set-OBSDisplaySource](docs/Set-OBSDisplaySource.md) | +|[Set-OBSEqualizerFilter](docs/Set-OBSEqualizerFilter.md) | +|[Set-OBSGainFilter](docs/Set-OBSGainFilter.md) | +|[Set-OBSInputAudioBalance](docs/Set-OBSInputAudioBalance.md) | +|[Set-OBSInputAudioMonitorType](docs/Set-OBSInputAudioMonitorType.md) | +|[Set-OBSInputAudioSyncOffset](docs/Set-OBSInputAudioSyncOffset.md) | +|[Set-OBSInputAudioTracks](docs/Set-OBSInputAudioTracks.md) | +|[Set-OBSInputMute](docs/Set-OBSInputMute.md) | +|[Set-OBSInputName](docs/Set-OBSInputName.md) | +|[Set-OBSInputSettings](docs/Set-OBSInputSettings.md) | +|[Set-OBSInputVolume](docs/Set-OBSInputVolume.md) | +|[Set-OBSMarkdownSource](docs/Set-OBSMarkdownSource.md) | +|[Set-OBSMediaInputCursor](docs/Set-OBSMediaInputCursor.md) | +|[Set-OBSMediaSource](docs/Set-OBSMediaSource.md) | +|[Set-OBSOutputSettings](docs/Set-OBSOutputSettings.md) | +|[Set-OBSPersistentData](docs/Set-OBSPersistentData.md) | +|[Set-OBSProfileParameter](docs/Set-OBSProfileParameter.md) | +|[Set-OBSRecordDirectory](docs/Set-OBSRecordDirectory.md) | +|[Set-OBSRenderDelayFilter](docs/Set-OBSRenderDelayFilter.md) | +|[Set-OBSScaleFilter](docs/Set-OBSScaleFilter.md) | +|[Set-OBSSceneItemBlendMode](docs/Set-OBSSceneItemBlendMode.md) | +|[Set-OBSSceneItemEnabled](docs/Set-OBSSceneItemEnabled.md) | +|[Set-OBSSceneItemIndex](docs/Set-OBSSceneItemIndex.md) | +|[Set-OBSSceneItemLocked](docs/Set-OBSSceneItemLocked.md) | +|[Set-OBSSceneItemTransform](docs/Set-OBSSceneItemTransform.md) | +|[Set-OBSSceneName](docs/Set-OBSSceneName.md) | +|[Set-OBSSceneSceneTransitionOverride](docs/Set-OBSSceneSceneTransitionOverride.md) | +|[Set-OBSScrollFilter](docs/Set-OBSScrollFilter.md) | +|[Set-OBSShaderFilter](docs/Set-OBSShaderFilter.md) | +|[Set-OBSSharpnessFilter](docs/Set-OBSSharpnessFilter.md) | +|[Set-OBSSoundCloudSource](docs/Set-OBSSoundCloudSource.md) | +|[Set-OBSSourceFilterEnabled](docs/Set-OBSSourceFilterEnabled.md) | +|[Set-OBSSourceFilterIndex](docs/Set-OBSSourceFilterIndex.md) | +|[Set-OBSSourceFilterName](docs/Set-OBSSourceFilterName.md) | +|[Set-OBSSourceFilterSettings](docs/Set-OBSSourceFilterSettings.md) | +|[Set-OBSStreamServiceSettings](docs/Set-OBSStreamServiceSettings.md) | +|[Set-OBSStudioModeEnabled](docs/Set-OBSStudioModeEnabled.md) | +|[Set-OBSSwitchSource](docs/Set-OBSSwitchSource.md) | +|[Set-OBSTBarPosition](docs/Set-OBSTBarPosition.md) | +|[Set-OBSVideoSettings](docs/Set-OBSVideoSettings.md) | +|[Set-OBSVLCSource](docs/Set-OBSVLCSource.md) | +|[Set-OBSWaveformSource](docs/Set-OBSWaveformSource.md) | +|[Set-OBSWindowSource](docs/Set-OBSWindowSource.md) | +|[Show-OBS](docs/Show-OBS.md) | +|[Start-OBS](docs/Start-OBS.md) | +|[Start-OBSEffect](docs/Start-OBSEffect.md) | +|[Start-OBSOutput](docs/Start-OBSOutput.md) | +|[Start-OBSRecord](docs/Start-OBSRecord.md) | +|[Start-OBSReplayBuffer](docs/Start-OBSReplayBuffer.md) | +|[Start-OBSStream](docs/Start-OBSStream.md) | +|[Start-OBSVirtualCam](docs/Start-OBSVirtualCam.md) | +|[Stop-OBS](docs/Stop-OBS.md) | +|[Stop-OBSEffect](docs/Stop-OBSEffect.md) | +|[Stop-OBSOutput](docs/Stop-OBSOutput.md) | +|[Stop-OBSRecord](docs/Stop-OBSRecord.md) | +|[Stop-OBSReplayBuffer](docs/Stop-OBSReplayBuffer.md) | +|[Stop-OBSStream](docs/Stop-OBSStream.md) | +|[Stop-OBSVirtualCam](docs/Stop-OBSVirtualCam.md) | +|[Switch-OBSInputMute](docs/Switch-OBSInputMute.md) | +|[Switch-OBSOutput](docs/Switch-OBSOutput.md) | +|[Switch-OBSRecord](docs/Switch-OBSRecord.md) | +|[Switch-OBSRecordPause](docs/Switch-OBSRecordPause.md) | +|[Switch-OBSReplayBuffer](docs/Switch-OBSReplayBuffer.md) | +|[Switch-OBSStream](docs/Switch-OBSStream.md) | +|[Switch-OBSVirtualCam](docs/Switch-OBSVirtualCam.md) | +|[Watch-OBS](docs/Watch-OBS.md) | @@ -337,323 +356,342 @@ Functions Aliases ======= -|Name |ResolvedCommand| -|------------------------------------------------------------------------------------------|---------------| -|[Add-OBSInput](docs/Add-OBSInput.md) | -|[Add-OBSProfile](docs/Add-OBSProfile.md) | -|[Add-OBSScene](docs/Add-OBSScene.md) | -|[Add-OBSSceneCollection](docs/Add-OBSSceneCollection.md) | -|[Add-OBSSceneItem](docs/Add-OBSSceneItem.md) | -|[Add-OBSSourceFilter](docs/Add-OBSSourceFilter.md) | -|[Clear-OBSScene](docs/Clear-OBSScene.md) | -|[Connect-OBS](docs/Connect-OBS.md) | -|[Copy-OBSSceneItem](docs/Copy-OBSSceneItem.md) | -|[Disconnect-OBS](docs/Disconnect-OBS.md) | -|[Get-OBS](docs/Get-OBS.md) | -|[Get-OBS3dSwapTransitionShader](docs/Get-OBS3dSwapTransitionShader.md) | -|[Get-OBSAddShader](docs/Get-OBSAddShader.md) | -|[Get-OBSAlphaBorderShader](docs/Get-OBSAlphaBorderShader.md) | -|[Get-OBSAlphaGamingBentCameraShader](docs/Get-OBSAlphaGamingBentCameraShader.md) | -|[Get-OBSAnimatedPathShader](docs/Get-OBSAnimatedPathShader.md) | -|[Get-OBSAnimatedTextureShader](docs/Get-OBSAnimatedTextureShader.md) | -|[Get-OBSAsciiShader](docs/Get-OBSAsciiShader.md) | -|[Get-OBSAspectRatioShader](docs/Get-OBSAspectRatioShader.md) | -|[Get-OBSBackgroundRemovalShader](docs/Get-OBSBackgroundRemovalShader.md) | -|[Get-OBSBlendOpacityShader](docs/Get-OBSBlendOpacityShader.md) | -|[Get-OBSBlinkShader](docs/Get-OBSBlinkShader.md) | -|[Get-OBSBloomShader](docs/Get-OBSBloomShader.md) | -|[Get-OBSBorderShader](docs/Get-OBSBorderShader.md) | -|[Get-OBSBoxBlurShader](docs/Get-OBSBoxBlurShader.md) | -|[Get-OBSBulgePinchShader](docs/Get-OBSBulgePinchShader.md) | -|[Get-OBSBurnShader](docs/Get-OBSBurnShader.md) | -|[Get-OBSCartoonShader](docs/Get-OBSCartoonShader.md) | -|[Get-OBSCellShadedShader](docs/Get-OBSCellShadedShader.md) | -|[Get-OBSChromaticAberrationShader](docs/Get-OBSChromaticAberrationShader.md) | -|[Get-OBSChromaUVDistortionShader](docs/Get-OBSChromaUVDistortionShader.md) | -|[Get-OBSCircleMaskFilterShader](docs/Get-OBSCircleMaskFilterShader.md) | -|[Get-OBSClockAnalogShader](docs/Get-OBSClockAnalogShader.md) | -|[Get-OBSClockDigitalLedShader](docs/Get-OBSClockDigitalLedShader.md) | -|[Get-OBSClockDigitalNixieShader](docs/Get-OBSClockDigitalNixieShader.md) | -|[Get-OBSColorDepthShader](docs/Get-OBSColorDepthShader.md) | -|[Get-OBSColorGradeFilterShader](docs/Get-OBSColorGradeFilterShader.md) | -|[Get-OBSCornerPinShader](docs/Get-OBSCornerPinShader.md) | -|[Get-OBSCrtCurvatureShader](docs/Get-OBSCrtCurvatureShader.md) | -|[Get-OBSCurrentPreviewScene](docs/Get-OBSCurrentPreviewScene.md) | -|[Get-OBSCurrentProgramScene](docs/Get-OBSCurrentProgramScene.md) | -|[Get-OBSCurrentSceneTransition](docs/Get-OBSCurrentSceneTransition.md) | -|[Get-OBSCurrentSceneTransitionCursor](docs/Get-OBSCurrentSceneTransitionCursor.md) | -|[Get-OBSCurveShader](docs/Get-OBSCurveShader.md) | -|[Get-OBSCutRectPerCornerShader](docs/Get-OBSCutRectPerCornerShader.md) | -|[Get-OBSCylinderShader](docs/Get-OBSCylinderShader.md) | -|[Get-OBSDarkenShader](docs/Get-OBSDarkenShader.md) | -|[Get-OBSDeadPixelFixerShader](docs/Get-OBSDeadPixelFixerShader.md) | -|[Get-OBSDensitySatHueShader](docs/Get-OBSDensitySatHueShader.md) | -|[Get-OBSDiffuseTransitionShader](docs/Get-OBSDiffuseTransitionShader.md) | -|[Get-OBSDigitalRainShader](docs/Get-OBSDigitalRainShader.md) | -|[Get-OBSDivideRotateShader](docs/Get-OBSDivideRotateShader.md) | -|[Get-OBSDoodleShader](docs/Get-OBSDoodleShader.md) | -|[Get-OBSDrawingsShader](docs/Get-OBSDrawingsShader.md) | -|[Get-OBSDropShadowShader](docs/Get-OBSDropShadowShader.md) | -|[Get-OBSDrunkShader](docs/Get-OBSDrunkShader.md) | -|[Get-OBSDynamicMaskShader](docs/Get-OBSDynamicMaskShader.md) | -|[Get-OBSEdgeDetectionShader](docs/Get-OBSEdgeDetectionShader.md) | -|[Get-OBSEffect](docs/Get-OBSEffect.md) | -|[Get-OBSEmbersShader](docs/Get-OBSEmbersShader.md) | -|[Get-OBSEmbossColorShader](docs/Get-OBSEmbossColorShader.md) | -|[Get-OBSEmbossShader](docs/Get-OBSEmbossShader.md) | -|[Get-OBSExeldroBentCameraShader](docs/Get-OBSExeldroBentCameraShader.md) | -|[Get-OBSFadeTransitionShader](docs/Get-OBSFadeTransitionShader.md) | -|[Get-OBSFillColorGradientShader](docs/Get-OBSFillColorGradientShader.md) | -|[Get-OBSFillColorLinearShader](docs/Get-OBSFillColorLinearShader.md) | -|[Get-OBSFillColorRadialDegreesShader](docs/Get-OBSFillColorRadialDegreesShader.md) | -|[Get-OBSFillColorRadialPercentageShader](docs/Get-OBSFillColorRadialPercentageShader.md) | -|[Get-OBSFilterTemplateShader](docs/Get-OBSFilterTemplateShader.md) | -|[Get-OBSFire3Shader](docs/Get-OBSFire3Shader.md) | -|[Get-OBSFireShader](docs/Get-OBSFireShader.md) | -|[Get-OBSFireworks2Shader](docs/Get-OBSFireworks2Shader.md) | -|[Get-OBSFireworksShader](docs/Get-OBSFireworksShader.md) | -|[Get-OBSFisheyeShader](docs/Get-OBSFisheyeShader.md) | -|[Get-OBSFisheyeXyShader](docs/Get-OBSFisheyeXyShader.md) | -|[Get-OBSFlipShader](docs/Get-OBSFlipShader.md) | -|[Get-OBSFrostedGlassShader](docs/Get-OBSFrostedGlassShader.md) | -|[Get-OBSGammaCorrectionShader](docs/Get-OBSGammaCorrectionShader.md) | -|[Get-OBSGaussianBlurAdvancedShader](docs/Get-OBSGaussianBlurAdvancedShader.md) | -|[Get-OBSGaussianBlurShader](docs/Get-OBSGaussianBlurShader.md) | -|[Get-OBSGaussianBlurSimpleShader](docs/Get-OBSGaussianBlurSimpleShader.md) | -|[Get-OBSGaussianExampleShader](docs/Get-OBSGaussianExampleShader.md) | -|[Get-OBSGaussianSimpleShader](docs/Get-OBSGaussianSimpleShader.md) | -|[Get-OBSGbCameraShader](docs/Get-OBSGbCameraShader.md) | -|[Get-OBSGlassShader](docs/Get-OBSGlassShader.md) | -|[Get-OBSGlitchAnalogShader](docs/Get-OBSGlitchAnalogShader.md) | -|[Get-OBSGlitchShader](docs/Get-OBSGlitchShader.md) | -|[Get-OBSGlowShader](docs/Get-OBSGlowShader.md) | -|[Get-OBSGradientShader](docs/Get-OBSGradientShader.md) | -|[Get-OBSGroup](docs/Get-OBSGroup.md) | -|[Get-OBSGroupSceneItem](docs/Get-OBSGroupSceneItem.md) | -|[Get-OBSHalftoneShader](docs/Get-OBSHalftoneShader.md) | -|[Get-OBSHeatWaveSimpleShader](docs/Get-OBSHeatWaveSimpleShader.md) | -|[Get-OBSHexagonShader](docs/Get-OBSHexagonShader.md) | -|[Get-OBSHotkey](docs/Get-OBSHotkey.md) | -|[Get-OBSHslHsvSaturationShader](docs/Get-OBSHslHsvSaturationShader.md) | -|[Get-OBSHueRotatonShader](docs/Get-OBSHueRotatonShader.md) | -|[Get-OBSInput](docs/Get-OBSInput.md) | -|[Get-OBSInputAudioBalance](docs/Get-OBSInputAudioBalance.md) | -|[Get-OBSInputAudioMonitorType](docs/Get-OBSInputAudioMonitorType.md) | -|[Get-OBSInputAudioSyncOffset](docs/Get-OBSInputAudioSyncOffset.md) | -|[Get-OBSInputAudioTracks](docs/Get-OBSInputAudioTracks.md) | -|[Get-OBSInputDefaultSettings](docs/Get-OBSInputDefaultSettings.md) | -|[Get-OBSInputKind](docs/Get-OBSInputKind.md) | -|[Get-OBSInputMute](docs/Get-OBSInputMute.md) | -|[Get-OBSInputPropertiesListPropertyItems](docs/Get-OBSInputPropertiesListPropertyItems.md)| -|[Get-OBSInputSettings](docs/Get-OBSInputSettings.md) | -|[Get-OBSInputVolume](docs/Get-OBSInputVolume.md) | -|[Get-OBSIntensityScopeShader](docs/Get-OBSIntensityScopeShader.md) | -|[Get-OBSInvertLumaShader](docs/Get-OBSInvertLumaShader.md) | -|[Get-OBSLastReplayBufferReplay](docs/Get-OBSLastReplayBufferReplay.md) | -|[Get-OBSLuminance2Shader](docs/Get-OBSLuminance2Shader.md) | -|[Get-OBSLuminanceAlphaShader](docs/Get-OBSLuminanceAlphaShader.md) | -|[Get-OBSLuminanceShader](docs/Get-OBSLuminanceShader.md) | -|[Get-OBSMatrixShader](docs/Get-OBSMatrixShader.md) | -|[Get-OBSMediaInputStatus](docs/Get-OBSMediaInputStatus.md) | -|[Get-OBSMonitor](docs/Get-OBSMonitor.md) | -|[Get-OBSMultiplyShader](docs/Get-OBSMultiplyShader.md) | -|[Get-OBSNightSkyShader](docs/Get-OBSNightSkyShader.md) | -|[Get-OBSOpacityShader](docs/Get-OBSOpacityShader.md) | -|[Get-OBSOutput](docs/Get-OBSOutput.md) | -|[Get-OBSOutputSettings](docs/Get-OBSOutputSettings.md) | -|[Get-OBSOutputStatus](docs/Get-OBSOutputStatus.md) | -|[Get-OBSPagePeelShader](docs/Get-OBSPagePeelShader.md) | -|[Get-OBSPagePeelTransitionShader](docs/Get-OBSPagePeelTransitionShader.md) | -|[Get-OBSPerlinNoiseShader](docs/Get-OBSPerlinNoiseShader.md) | -|[Get-OBSPersistentData](docs/Get-OBSPersistentData.md) | -|[Get-OBSPieChartShader](docs/Get-OBSPieChartShader.md) | -|[Get-OBSPixelationShader](docs/Get-OBSPixelationShader.md) | -|[Get-OBSPixelationTransitionShader](docs/Get-OBSPixelationTransitionShader.md) | -|[Get-OBSPolarShader](docs/Get-OBSPolarShader.md) | -|[Get-OBSProfile](docs/Get-OBSProfile.md) | -|[Get-OBSProfileParameter](docs/Get-OBSProfileParameter.md) | -|[Get-OBSPulseShader](docs/Get-OBSPulseShader.md) | -|[Get-OBSRainbowShader](docs/Get-OBSRainbowShader.md) | -|[Get-OBSRainWindowShader](docs/Get-OBSRainWindowShader.md) | -|[Get-OBSRecordDirectory](docs/Get-OBSRecordDirectory.md) | -|[Get-OBSRecordStatus](docs/Get-OBSRecordStatus.md) | -|[Get-OBSRectangularDropShadowShader](docs/Get-OBSRectangularDropShadowShader.md) | -|[Get-OBSReflectShader](docs/Get-OBSReflectShader.md) | -|[Get-OBSRemovePartialPixelsShader](docs/Get-OBSRemovePartialPixelsShader.md) | -|[Get-OBSRepeatShader](docs/Get-OBSRepeatShader.md) | -|[Get-OBSRepeatTextureShader](docs/Get-OBSRepeatTextureShader.md) | -|[Get-OBSReplayBufferStatus](docs/Get-OBSReplayBufferStatus.md) | -|[Get-OBSRGBAPercentShader](docs/Get-OBSRGBAPercentShader.md) | -|[Get-OBSRgbColorWheelShader](docs/Get-OBSRgbColorWheelShader.md) | -|[Get-OBSRgbSplitShader](docs/Get-OBSRgbSplitShader.md) | -|[Get-OBSRgbvisibilityShader](docs/Get-OBSRgbvisibilityShader.md) | -|[Get-OBSRGSSAAShader](docs/Get-OBSRGSSAAShader.md) | -|[Get-OBSRippleShader](docs/Get-OBSRippleShader.md) | -|[Get-OBSRotatingSourceShader](docs/Get-OBSRotatingSourceShader.md) | -|[Get-OBSRotatoeShader](docs/Get-OBSRotatoeShader.md) | -|[Get-OBSRoundedRect2Shader](docs/Get-OBSRoundedRect2Shader.md) | -|[Get-OBSRoundedRectPerCornerShader](docs/Get-OBSRoundedRectPerCornerShader.md) | -|[Get-OBSRoundedRectPerSideShader](docs/Get-OBSRoundedRectPerSideShader.md) | -|[Get-OBSRoundedRectShader](docs/Get-OBSRoundedRectShader.md) | -|[Get-OBSRoundedStrokeGradientShader](docs/Get-OBSRoundedStrokeGradientShader.md) | -|[Get-OBSRoundedStrokeShader](docs/Get-OBSRoundedStrokeShader.md) | -|[Get-OBSScanLineShader](docs/Get-OBSScanLineShader.md) | -|[Get-OBSScene](docs/Get-OBSScene.md) | -|[Get-OBSSceneCollection](docs/Get-OBSSceneCollection.md) | -|[Get-OBSSceneItem](docs/Get-OBSSceneItem.md) | -|[Get-OBSSceneItemBlendMode](docs/Get-OBSSceneItemBlendMode.md) | -|[Get-OBSSceneItemEnabled](docs/Get-OBSSceneItemEnabled.md) | -|[Get-OBSSceneItemId](docs/Get-OBSSceneItemId.md) | -|[Get-OBSSceneItemIndex](docs/Get-OBSSceneItemIndex.md) | -|[Get-OBSSceneItemLocked](docs/Get-OBSSceneItemLocked.md) | -|[Get-OBSSceneItemSource](docs/Get-OBSSceneItemSource.md) | -|[Get-OBSSceneItemTransform](docs/Get-OBSSceneItemTransform.md) | -|[Get-OBSSceneSceneTransitionOverride](docs/Get-OBSSceneSceneTransitionOverride.md) | -|[Get-OBSSceneTransition](docs/Get-OBSSceneTransition.md) | -|[Get-OBSSeascapeShader](docs/Get-OBSSeascapeShader.md) | -|[Get-OBSSeasickShader](docs/Get-OBSSeasickShader.md) | -|[Get-OBSSelectiveColorShader](docs/Get-OBSSelectiveColorShader.md) | -|[Get-OBSShakeShader](docs/Get-OBSShakeShader.md) | -|[Get-OBSShineShader](docs/Get-OBSShineShader.md) | -|[Get-OBSSimpleGradientShader](docs/Get-OBSSimpleGradientShader.md) | -|[Get-OBSSimplexNoiseShader](docs/Get-OBSSimplexNoiseShader.md) | -|[Get-OBSSmartDenoiseShader](docs/Get-OBSSmartDenoiseShader.md) | -|[Get-OBSSourceActive](docs/Get-OBSSourceActive.md) | -|[Get-OBSSourceFilter](docs/Get-OBSSourceFilter.md) | -|[Get-OBSSourceFilterDefaultSettings](docs/Get-OBSSourceFilterDefaultSettings.md) | -|[Get-OBSSourceFilterKind](docs/Get-OBSSourceFilterKind.md) | -|[Get-OBSSourceFilterList](docs/Get-OBSSourceFilterList.md) | -|[Get-OBSSourceScreenshot](docs/Get-OBSSourceScreenshot.md) | -|[Get-OBSSpecialInputs](docs/Get-OBSSpecialInputs.md) | -|[Get-OBSSpecularShineShader](docs/Get-OBSSpecularShineShader.md) | -|[Get-OBSSpotlightShader](docs/Get-OBSSpotlightShader.md) | -|[Get-OBSStats](docs/Get-OBSStats.md) | -|[Get-OBSStreamServiceSettings](docs/Get-OBSStreamServiceSettings.md) | -|[Get-OBSStreamStatus](docs/Get-OBSStreamStatus.md) | -|[Get-OBSStudioModeEnabled](docs/Get-OBSStudioModeEnabled.md) | -|[Get-OBSSwirlShader](docs/Get-OBSSwirlShader.md) | -|[Get-OBSTetraShader](docs/Get-OBSTetraShader.md) | -|[Get-OBSThermalShader](docs/Get-OBSThermalShader.md) | -|[Get-OBSTransitionKind](docs/Get-OBSTransitionKind.md) | -|[Get-OBSTvCrtSubpixelShader](docs/Get-OBSTvCrtSubpixelShader.md) | -|[Get-OBSTwistShader](docs/Get-OBSTwistShader.md) | -|[Get-OBSTwoPassDropShadowShader](docs/Get-OBSTwoPassDropShadowShader.md) | -|[Get-OBSVCRShader](docs/Get-OBSVCRShader.md) | -|[Get-OBSVersion](docs/Get-OBSVersion.md) | -|[Get-OBSVHSShader](docs/Get-OBSVHSShader.md) | -|[Get-OBSVideoSettings](docs/Get-OBSVideoSettings.md) | -|[Get-OBSVignettingShader](docs/Get-OBSVignettingShader.md) | -|[Get-OBSVirtualCamStatus](docs/Get-OBSVirtualCamStatus.md) | -|[Get-OBSVoronoiPixelationShader](docs/Get-OBSVoronoiPixelationShader.md) | -|[Get-OBSZigZagShader](docs/Get-OBSZigZagShader.md) | -|[Get-OBSZoomBlurShader](docs/Get-OBSZoomBlurShader.md) | -|[Get-OBSZoomShader](docs/Get-OBSZoomShader.md) | -|[Get-OBSZoomXYShader](docs/Get-OBSZoomXYShader.md) | -|[Hide-OBS](docs/Hide-OBS.md) | -|[Import-OBSEffect](docs/Import-OBSEffect.md) | -|[Open-OBSInputFiltersDialog](docs/Open-OBSInputFiltersDialog.md) | -|[Open-OBSInputInteractDialog](docs/Open-OBSInputInteractDialog.md) | -|[Open-OBSInputPropertiesDialog](docs/Open-OBSInputPropertiesDialog.md) | -|[Open-OBSSourceProjector](docs/Open-OBSSourceProjector.md) | -|[Open-OBSVideoMixProjector](docs/Open-OBSVideoMixProjector.md) | -|[Receive-OBS](docs/Receive-OBS.md) | -|[Remove-OBS](docs/Remove-OBS.md) | -|[Remove-OBSEffect](docs/Remove-OBSEffect.md) | -|[Remove-OBSInput](docs/Remove-OBSInput.md) | -|[Remove-OBSProfile](docs/Remove-OBSProfile.md) | -|[Remove-OBSScene](docs/Remove-OBSScene.md) | -|[Remove-OBSSceneItem](docs/Remove-OBSSceneItem.md) | -|[Remove-OBSSourceFilter](docs/Remove-OBSSourceFilter.md) | -|[Resume-OBSRecord](docs/Resume-OBSRecord.md) | -|[Save-OBSReplayBuffer](docs/Save-OBSReplayBuffer.md) | -|[Save-OBSSourceScreenshot](docs/Save-OBSSourceScreenshot.md) | -|[Send-OBS](docs/Send-OBS.md) | -|[Send-OBSCallVendorRequest](docs/Send-OBSCallVendorRequest.md) | -|[Send-OBSCustomEvent](docs/Send-OBSCustomEvent.md) | -|[Send-OBSOffsetMediaInputCursor](docs/Send-OBSOffsetMediaInputCursor.md) | -|[Send-OBSPauseRecord](docs/Send-OBSPauseRecord.md) | -|[Send-OBSPressInputPropertiesButton](docs/Send-OBSPressInputPropertiesButton.md) | -|[Send-OBSSleep](docs/Send-OBSSleep.md) | -|[Send-OBSStreamCaption](docs/Send-OBSStreamCaption.md) | -|[Send-OBSTriggerHotkeyByKeySequence](docs/Send-OBSTriggerHotkeyByKeySequence.md) | -|[Send-OBSTriggerHotkeyByName](docs/Send-OBSTriggerHotkeyByName.md) | -|[Send-OBSTriggerMediaInputAction](docs/Send-OBSTriggerMediaInputAction.md) | -|[Send-OBSTriggerStudioModeTransition](docs/Send-OBSTriggerStudioModeTransition.md) | -|[Set-OBS3DFilter](docs/Set-OBS3DFilter.md) | -|[Set-OBSAudioOutputSource](docs/Set-OBSAudioOutputSource.md) | -|[Set-OBSBrowserSource](docs/Set-OBSBrowserSource.md) | -|[Set-OBSColorFilter](docs/Set-OBSColorFilter.md) | -|[Set-OBSColorSource](docs/Set-OBSColorSource.md) | -|[Set-OBSCurrentPreviewScene](docs/Set-OBSCurrentPreviewScene.md) | -|[Set-OBSCurrentProfile](docs/Set-OBSCurrentProfile.md) | -|[Set-OBSCurrentProgramScene](docs/Set-OBSCurrentProgramScene.md) | -|[Set-OBSCurrentSceneCollection](docs/Set-OBSCurrentSceneCollection.md) | -|[Set-OBSCurrentSceneTransition](docs/Set-OBSCurrentSceneTransition.md) | -|[Set-OBSCurrentSceneTransitionDuration](docs/Set-OBSCurrentSceneTransitionDuration.md) | -|[Set-OBSCurrentSceneTransitionSettings](docs/Set-OBSCurrentSceneTransitionSettings.md) | -|[Set-OBSDisplaySource](docs/Set-OBSDisplaySource.md) | -|[Set-OBSEqualizerFilter](docs/Set-OBSEqualizerFilter.md) | -|[Set-OBSGainFilter](docs/Set-OBSGainFilter.md) | -|[Set-OBSInputAudioBalance](docs/Set-OBSInputAudioBalance.md) | -|[Set-OBSInputAudioMonitorType](docs/Set-OBSInputAudioMonitorType.md) | -|[Set-OBSInputAudioSyncOffset](docs/Set-OBSInputAudioSyncOffset.md) | -|[Set-OBSInputAudioTracks](docs/Set-OBSInputAudioTracks.md) | -|[Set-OBSInputMute](docs/Set-OBSInputMute.md) | -|[Set-OBSInputName](docs/Set-OBSInputName.md) | -|[Set-OBSInputSettings](docs/Set-OBSInputSettings.md) | -|[Set-OBSInputVolume](docs/Set-OBSInputVolume.md) | -|[Set-OBSMarkdownSource](docs/Set-OBSMarkdownSource.md) | -|[Set-OBSMediaInputCursor](docs/Set-OBSMediaInputCursor.md) | -|[Set-OBSMediaSource](docs/Set-OBSMediaSource.md) | -|[Set-OBSOutputSettings](docs/Set-OBSOutputSettings.md) | -|[Set-OBSPersistentData](docs/Set-OBSPersistentData.md) | -|[Set-OBSProfileParameter](docs/Set-OBSProfileParameter.md) | -|[Set-OBSRecordDirectory](docs/Set-OBSRecordDirectory.md) | -|[Set-OBSRenderDelayFilter](docs/Set-OBSRenderDelayFilter.md) | -|[Set-OBSScaleFilter](docs/Set-OBSScaleFilter.md) | -|[Set-OBSSceneItemBlendMode](docs/Set-OBSSceneItemBlendMode.md) | -|[Set-OBSSceneItemEnabled](docs/Set-OBSSceneItemEnabled.md) | -|[Set-OBSSceneItemIndex](docs/Set-OBSSceneItemIndex.md) | -|[Set-OBSSceneItemLocked](docs/Set-OBSSceneItemLocked.md) | -|[Set-OBSSceneItemTransform](docs/Set-OBSSceneItemTransform.md) | -|[Set-OBSSceneName](docs/Set-OBSSceneName.md) | -|[Set-OBSSceneSceneTransitionOverride](docs/Set-OBSSceneSceneTransitionOverride.md) | -|[Set-OBSScrollFilter](docs/Set-OBSScrollFilter.md) | -|[Set-OBSShaderFilter](docs/Set-OBSShaderFilter.md) | -|[Set-OBSSharpnessFilter](docs/Set-OBSSharpnessFilter.md) | -|[Set-OBSSoundCloudSource](docs/Set-OBSSoundCloudSource.md) | -|[Set-OBSSourceFilterEnabled](docs/Set-OBSSourceFilterEnabled.md) | -|[Set-OBSSourceFilterIndex](docs/Set-OBSSourceFilterIndex.md) | -|[Set-OBSSourceFilterName](docs/Set-OBSSourceFilterName.md) | -|[Set-OBSSourceFilterSettings](docs/Set-OBSSourceFilterSettings.md) | -|[Set-OBSStreamServiceSettings](docs/Set-OBSStreamServiceSettings.md) | -|[Set-OBSStudioModeEnabled](docs/Set-OBSStudioModeEnabled.md) | -|[Set-OBSSwitchSource](docs/Set-OBSSwitchSource.md) | -|[Set-OBSTBarPosition](docs/Set-OBSTBarPosition.md) | -|[Set-OBSVideoSettings](docs/Set-OBSVideoSettings.md) | -|[Set-OBSVLCSource](docs/Set-OBSVLCSource.md) | -|[Set-OBSWaveformSource](docs/Set-OBSWaveformSource.md) | -|[Set-OBSWindowSource](docs/Set-OBSWindowSource.md) | -|[Show-OBS](docs/Show-OBS.md) | -|[Start-OBSEffect](docs/Start-OBSEffect.md) | -|[Start-OBSOutput](docs/Start-OBSOutput.md) | -|[Start-OBSRecord](docs/Start-OBSRecord.md) | -|[Start-OBSReplayBuffer](docs/Start-OBSReplayBuffer.md) | -|[Start-OBSStream](docs/Start-OBSStream.md) | -|[Start-OBSVirtualCam](docs/Start-OBSVirtualCam.md) | -|[Stop-OBSEffect](docs/Stop-OBSEffect.md) | -|[Stop-OBSOutput](docs/Stop-OBSOutput.md) | -|[Stop-OBSRecord](docs/Stop-OBSRecord.md) | -|[Stop-OBSReplayBuffer](docs/Stop-OBSReplayBuffer.md) | -|[Stop-OBSStream](docs/Stop-OBSStream.md) | -|[Stop-OBSVirtualCam](docs/Stop-OBSVirtualCam.md) | -|[Switch-OBSInputMute](docs/Switch-OBSInputMute.md) | -|[Switch-OBSOutput](docs/Switch-OBSOutput.md) | -|[Switch-OBSRecord](docs/Switch-OBSRecord.md) | -|[Switch-OBSRecordPause](docs/Switch-OBSRecordPause.md) | -|[Switch-OBSReplayBuffer](docs/Switch-OBSReplayBuffer.md) | -|[Switch-OBSStream](docs/Switch-OBSStream.md) | -|[Switch-OBSVirtualCam](docs/Switch-OBSVirtualCam.md) | -|[Watch-OBS](docs/Watch-OBS.md) | +|Name |ResolvedCommand| +|------------------------------------------------------------------------------------------------|---------------| +|[Add-OBSInput](docs/Add-OBSInput.md) | +|[Add-OBSProfile](docs/Add-OBSProfile.md) | +|[Add-OBSScene](docs/Add-OBSScene.md) | +|[Add-OBSSceneCollection](docs/Add-OBSSceneCollection.md) | +|[Add-OBSSceneItem](docs/Add-OBSSceneItem.md) | +|[Add-OBSSourceFilter](docs/Add-OBSSourceFilter.md) | +|[Clear-OBSScene](docs/Clear-OBSScene.md) | +|[Connect-OBS](docs/Connect-OBS.md) | +|[Copy-OBSSceneItem](docs/Copy-OBSSceneItem.md) | +|[Disconnect-OBS](docs/Disconnect-OBS.md) | +|[Get-OBS](docs/Get-OBS.md) | +|[Get-OBS3dPanelShader](docs/Get-OBS3dPanelShader.md) | +|[Get-OBS3dSwapTransitionShader](docs/Get-OBS3dSwapTransitionShader.md) | +|[Get-OBSAddShader](docs/Get-OBSAddShader.md) | +|[Get-OBSAlphaBorderShader](docs/Get-OBSAlphaBorderShader.md) | +|[Get-OBSAlphaGamingBentCameraShader](docs/Get-OBSAlphaGamingBentCameraShader.md) | +|[Get-OBSAnimatedPathShader](docs/Get-OBSAnimatedPathShader.md) | +|[Get-OBSAnimatedTextureShader](docs/Get-OBSAnimatedTextureShader.md) | +|[Get-OBSAsciiShader](docs/Get-OBSAsciiShader.md) | +|[Get-OBSAspectRatioShader](docs/Get-OBSAspectRatioShader.md) | +|[Get-OBSAudioShader](docs/Get-OBSAudioShader.md) | +|[Get-OBSBackgroundRemovalShader](docs/Get-OBSBackgroundRemovalShader.md) | +|[Get-OBSBlendOpacityShader](docs/Get-OBSBlendOpacityShader.md) | +|[Get-OBSBlinkShader](docs/Get-OBSBlinkShader.md) | +|[Get-OBSBloomShader](docs/Get-OBSBloomShader.md) | +|[Get-OBSBorderShader](docs/Get-OBSBorderShader.md) | +|[Get-OBSBoxBlurShader](docs/Get-OBSBoxBlurShader.md) | +|[Get-OBSBulgePinchShader](docs/Get-OBSBulgePinchShader.md) | +|[Get-OBSBurnShader](docs/Get-OBSBurnShader.md) | +|[Get-OBSCartoonShader](docs/Get-OBSCartoonShader.md) | +|[Get-OBSCellShadedShader](docs/Get-OBSCellShadedShader.md) | +|[Get-OBSChromaticAberrationShader](docs/Get-OBSChromaticAberrationShader.md) | +|[Get-OBSChromaUVDistortionShader](docs/Get-OBSChromaUVDistortionShader.md) | +|[Get-OBSCircleMaskFilterShader](docs/Get-OBSCircleMaskFilterShader.md) | +|[Get-OBSClockAnalogShader](docs/Get-OBSClockAnalogShader.md) | +|[Get-OBSClockDigitalLedShader](docs/Get-OBSClockDigitalLedShader.md) | +|[Get-OBSClockDigitalNixieShader](docs/Get-OBSClockDigitalNixieShader.md) | +|[Get-OBSColorDepthShader](docs/Get-OBSColorDepthShader.md) | +|[Get-OBSColorGradeFilterShader](docs/Get-OBSColorGradeFilterShader.md) | +|[Get-OBSCornerPinShader](docs/Get-OBSCornerPinShader.md) | +|[Get-OBSCrtCurvatureShader](docs/Get-OBSCrtCurvatureShader.md) | +|[Get-OBSCubeRotatingShader](docs/Get-OBSCubeRotatingShader.md) | +|[Get-OBSCurrentPreviewScene](docs/Get-OBSCurrentPreviewScene.md) | +|[Get-OBSCurrentProgramScene](docs/Get-OBSCurrentProgramScene.md) | +|[Get-OBSCurrentSceneTransition](docs/Get-OBSCurrentSceneTransition.md) | +|[Get-OBSCurrentSceneTransitionCursor](docs/Get-OBSCurrentSceneTransitionCursor.md) | +|[Get-OBSCurveShader](docs/Get-OBSCurveShader.md) | +|[Get-OBSCutRectPerCornerShader](docs/Get-OBSCutRectPerCornerShader.md) | +|[Get-OBSCylinderShader](docs/Get-OBSCylinderShader.md) | +|[Get-OBSDarkenShader](docs/Get-OBSDarkenShader.md) | +|[Get-OBSDeadPixelFixerShader](docs/Get-OBSDeadPixelFixerShader.md) | +|[Get-OBSDensitySatHueShader](docs/Get-OBSDensitySatHueShader.md) | +|[Get-OBSDiffuseTransitionShader](docs/Get-OBSDiffuseTransitionShader.md) | +|[Get-OBSDigitalRainShader](docs/Get-OBSDigitalRainShader.md) | +|[Get-OBSDisplacementMapAdvancedInvertShader](docs/Get-OBSDisplacementMapAdvancedInvertShader.md)| +|[Get-OBSDisplacementMapAdvancedShader](docs/Get-OBSDisplacementMapAdvancedShader.md) | +|[Get-OBSDisplacementMapInvertShader](docs/Get-OBSDisplacementMapInvertShader.md) | +|[Get-OBSDisplacementMapShader](docs/Get-OBSDisplacementMapShader.md) | +|[Get-OBSDivideRotateShader](docs/Get-OBSDivideRotateShader.md) | +|[Get-OBSDoodleShader](docs/Get-OBSDoodleShader.md) | +|[Get-OBSDrawingsShader](docs/Get-OBSDrawingsShader.md) | +|[Get-OBSDropShadowShader](docs/Get-OBSDropShadowShader.md) | +|[Get-OBSDrunkShader](docs/Get-OBSDrunkShader.md) | +|[Get-OBSDynamicMaskShader](docs/Get-OBSDynamicMaskShader.md) | +|[Get-OBSEdgeDetectionShader](docs/Get-OBSEdgeDetectionShader.md) | +|[Get-OBSEffect](docs/Get-OBSEffect.md) | +|[Get-OBSEmbersShader](docs/Get-OBSEmbersShader.md) | +|[Get-OBSEmbossColorShader](docs/Get-OBSEmbossColorShader.md) | +|[Get-OBSEmbossShader](docs/Get-OBSEmbossShader.md) | +|[Get-OBSExeldroBentCameraShader](docs/Get-OBSExeldroBentCameraShader.md) | +|[Get-OBSFadeTransitionShader](docs/Get-OBSFadeTransitionShader.md) | +|[Get-OBSFillColorGradientShader](docs/Get-OBSFillColorGradientShader.md) | +|[Get-OBSFillColorLinearShader](docs/Get-OBSFillColorLinearShader.md) | +|[Get-OBSFillColorRadialDegreesShader](docs/Get-OBSFillColorRadialDegreesShader.md) | +|[Get-OBSFillColorRadialPercentageShader](docs/Get-OBSFillColorRadialPercentageShader.md) | +|[Get-OBSFilterTemplateShader](docs/Get-OBSFilterTemplateShader.md) | +|[Get-OBSFire3Shader](docs/Get-OBSFire3Shader.md) | +|[Get-OBSFireShader](docs/Get-OBSFireShader.md) | +|[Get-OBSFireworks2Shader](docs/Get-OBSFireworks2Shader.md) | +|[Get-OBSFireworksShader](docs/Get-OBSFireworksShader.md) | +|[Get-OBSFisheyeShader](docs/Get-OBSFisheyeShader.md) | +|[Get-OBSFisheyeXyShader](docs/Get-OBSFisheyeXyShader.md) | +|[Get-OBSFlipShader](docs/Get-OBSFlipShader.md) | +|[Get-OBSFrostedGlassShader](docs/Get-OBSFrostedGlassShader.md) | +|[Get-OBSGammaCorrectionShader](docs/Get-OBSGammaCorrectionShader.md) | +|[Get-OBSGaussianBlurAdvancedShader](docs/Get-OBSGaussianBlurAdvancedShader.md) | +|[Get-OBSGaussianBlurShader](docs/Get-OBSGaussianBlurShader.md) | +|[Get-OBSGaussianBlurSimpleShader](docs/Get-OBSGaussianBlurSimpleShader.md) | +|[Get-OBSGaussianExampleShader](docs/Get-OBSGaussianExampleShader.md) | +|[Get-OBSGaussianSimpleShader](docs/Get-OBSGaussianSimpleShader.md) | +|[Get-OBSGbCameraShader](docs/Get-OBSGbCameraShader.md) | +|[Get-OBSGlassShader](docs/Get-OBSGlassShader.md) | +|[Get-OBSGlitchAnalogShader](docs/Get-OBSGlitchAnalogShader.md) | +|[Get-OBSGlitchPeriodicShader](docs/Get-OBSGlitchPeriodicShader.md) | +|[Get-OBSGlitchShader](docs/Get-OBSGlitchShader.md) | +|[Get-OBSGlowShader](docs/Get-OBSGlowShader.md) | +|[Get-OBSGradientShader](docs/Get-OBSGradientShader.md) | +|[Get-OBSGroup](docs/Get-OBSGroup.md) | +|[Get-OBSGroupSceneItem](docs/Get-OBSGroupSceneItem.md) | +|[Get-OBSHalftoneShader](docs/Get-OBSHalftoneShader.md) | +|[Get-OBSHardBlinkShader](docs/Get-OBSHardBlinkShader.md) | +|[Get-OBSHeatWaveSimpleShader](docs/Get-OBSHeatWaveSimpleShader.md) | +|[Get-OBSHexagonShader](docs/Get-OBSHexagonShader.md) | +|[Get-OBSHotkey](docs/Get-OBSHotkey.md) | +|[Get-OBSHslHsvSaturationShader](docs/Get-OBSHslHsvSaturationShader.md) | +|[Get-OBSHueRotatonShader](docs/Get-OBSHueRotatonShader.md) | +|[Get-OBSInput](docs/Get-OBSInput.md) | +|[Get-OBSInputAudioBalance](docs/Get-OBSInputAudioBalance.md) | +|[Get-OBSInputAudioMonitorType](docs/Get-OBSInputAudioMonitorType.md) | +|[Get-OBSInputAudioSyncOffset](docs/Get-OBSInputAudioSyncOffset.md) | +|[Get-OBSInputAudioTracks](docs/Get-OBSInputAudioTracks.md) | +|[Get-OBSInputDefaultSettings](docs/Get-OBSInputDefaultSettings.md) | +|[Get-OBSInputKind](docs/Get-OBSInputKind.md) | +|[Get-OBSInputMute](docs/Get-OBSInputMute.md) | +|[Get-OBSInputPropertiesListPropertyItems](docs/Get-OBSInputPropertiesListPropertyItems.md) | +|[Get-OBSInputSettings](docs/Get-OBSInputSettings.md) | +|[Get-OBSInputVolume](docs/Get-OBSInputVolume.md) | +|[Get-OBSIntensityScopeShader](docs/Get-OBSIntensityScopeShader.md) | +|[Get-OBSInvertLumaShader](docs/Get-OBSInvertLumaShader.md) | +|[Get-OBSLastReplayBufferReplay](docs/Get-OBSLastReplayBufferReplay.md) | +|[Get-OBSLuminance2Shader](docs/Get-OBSLuminance2Shader.md) | +|[Get-OBSLuminanceAlphaShader](docs/Get-OBSLuminanceAlphaShader.md) | +|[Get-OBSLuminanceShader](docs/Get-OBSLuminanceShader.md) | +|[Get-OBSMatrixShader](docs/Get-OBSMatrixShader.md) | +|[Get-OBSMediaInputStatus](docs/Get-OBSMediaInputStatus.md) | +|[Get-OBSMonitor](docs/Get-OBSMonitor.md) | +|[Get-OBSMotionBlurShader](docs/Get-OBSMotionBlurShader.md) | +|[Get-OBSMultiplyShader](docs/Get-OBSMultiplyShader.md) | +|[Get-OBSNightSkyShader](docs/Get-OBSNightSkyShader.md) | +|[Get-OBSNoiseShader](docs/Get-OBSNoiseShader.md) | +|[Get-OBSNormalMapShader](docs/Get-OBSNormalMapShader.md) | +|[Get-OBSOpacityShader](docs/Get-OBSOpacityShader.md) | +|[Get-OBSOutput](docs/Get-OBSOutput.md) | +|[Get-OBSOutputSettings](docs/Get-OBSOutputSettings.md) | +|[Get-OBSOutputStatus](docs/Get-OBSOutputStatus.md) | +|[Get-OBSPagePeelShader](docs/Get-OBSPagePeelShader.md) | +|[Get-OBSPagePeelTransitionShader](docs/Get-OBSPagePeelTransitionShader.md) | +|[Get-OBSPerlinNoiseShader](docs/Get-OBSPerlinNoiseShader.md) | +|[Get-OBSPersistentData](docs/Get-OBSPersistentData.md) | +|[Get-OBSPerspectiveShader](docs/Get-OBSPerspectiveShader.md) | +|[Get-OBSPieChartShader](docs/Get-OBSPieChartShader.md) | +|[Get-OBSPixelationShader](docs/Get-OBSPixelationShader.md) | +|[Get-OBSPixelationTransitionShader](docs/Get-OBSPixelationTransitionShader.md) | +|[Get-OBSPolarShader](docs/Get-OBSPolarShader.md) | +|[Get-OBSProfile](docs/Get-OBSProfile.md) | +|[Get-OBSProfileParameter](docs/Get-OBSProfileParameter.md) | +|[Get-OBSPulseShader](docs/Get-OBSPulseShader.md) | +|[Get-OBSQuadrilateralCropShader](docs/Get-OBSQuadrilateralCropShader.md) | +|[Get-OBSRainbowShader](docs/Get-OBSRainbowShader.md) | +|[Get-OBSRainWindowShader](docs/Get-OBSRainWindowShader.md) | +|[Get-OBSRecordDirectory](docs/Get-OBSRecordDirectory.md) | +|[Get-OBSRecordStatus](docs/Get-OBSRecordStatus.md) | +|[Get-OBSRectangularDropShadowShader](docs/Get-OBSRectangularDropShadowShader.md) | +|[Get-OBSReflectShader](docs/Get-OBSReflectShader.md) | +|[Get-OBSRemovePartialPixelsShader](docs/Get-OBSRemovePartialPixelsShader.md) | +|[Get-OBSRepeatGridCenterCropShader](docs/Get-OBSRepeatGridCenterCropShader.md) | +|[Get-OBSRepeatShader](docs/Get-OBSRepeatShader.md) | +|[Get-OBSRepeatTextureShader](docs/Get-OBSRepeatTextureShader.md) | +|[Get-OBSReplayBufferStatus](docs/Get-OBSReplayBufferStatus.md) | +|[Get-OBSRGBAPercentShader](docs/Get-OBSRGBAPercentShader.md) | +|[Get-OBSRgbColorWheelShader](docs/Get-OBSRgbColorWheelShader.md) | +|[Get-OBSRgbSplitShader](docs/Get-OBSRgbSplitShader.md) | +|[Get-OBSRgbvisibilityShader](docs/Get-OBSRgbvisibilityShader.md) | +|[Get-OBSRGSSAAShader](docs/Get-OBSRGSSAAShader.md) | +|[Get-OBSRippleShader](docs/Get-OBSRippleShader.md) | +|[Get-OBSRotatingSourceShader](docs/Get-OBSRotatingSourceShader.md) | +|[Get-OBSRotatoeShader](docs/Get-OBSRotatoeShader.md) | +|[Get-OBSRoundedRect2Shader](docs/Get-OBSRoundedRect2Shader.md) | +|[Get-OBSRoundedRectPerCornerShader](docs/Get-OBSRoundedRectPerCornerShader.md) | +|[Get-OBSRoundedRectPerSideShader](docs/Get-OBSRoundedRectPerSideShader.md) | +|[Get-OBSRoundedRectShader](docs/Get-OBSRoundedRectShader.md) | +|[Get-OBSRoundedStrokeGradientShader](docs/Get-OBSRoundedStrokeGradientShader.md) | +|[Get-OBSRoundedStrokeShader](docs/Get-OBSRoundedStrokeShader.md) | +|[Get-OBSScanLineShader](docs/Get-OBSScanLineShader.md) | +|[Get-OBSScene](docs/Get-OBSScene.md) | +|[Get-OBSSceneCollection](docs/Get-OBSSceneCollection.md) | +|[Get-OBSSceneItem](docs/Get-OBSSceneItem.md) | +|[Get-OBSSceneItemBlendMode](docs/Get-OBSSceneItemBlendMode.md) | +|[Get-OBSSceneItemEnabled](docs/Get-OBSSceneItemEnabled.md) | +|[Get-OBSSceneItemId](docs/Get-OBSSceneItemId.md) | +|[Get-OBSSceneItemIndex](docs/Get-OBSSceneItemIndex.md) | +|[Get-OBSSceneItemLocked](docs/Get-OBSSceneItemLocked.md) | +|[Get-OBSSceneItemSource](docs/Get-OBSSceneItemSource.md) | +|[Get-OBSSceneItemTransform](docs/Get-OBSSceneItemTransform.md) | +|[Get-OBSSceneSceneTransitionOverride](docs/Get-OBSSceneSceneTransitionOverride.md) | +|[Get-OBSSceneTransition](docs/Get-OBSSceneTransition.md) | +|[Get-OBSSeascapeShader](docs/Get-OBSSeascapeShader.md) | +|[Get-OBSSeasickShader](docs/Get-OBSSeasickShader.md) | +|[Get-OBSSelectiveColorShader](docs/Get-OBSSelectiveColorShader.md) | +|[Get-OBSShakeShader](docs/Get-OBSShakeShader.md) | +|[Get-OBSShineShader](docs/Get-OBSShineShader.md) | +|[Get-OBSSimpleGradientShader](docs/Get-OBSSimpleGradientShader.md) | +|[Get-OBSSimplexNoiseShader](docs/Get-OBSSimplexNoiseShader.md) | +|[Get-OBSSmartDenoiseShader](docs/Get-OBSSmartDenoiseShader.md) | +|[Get-OBSSourceActive](docs/Get-OBSSourceActive.md) | +|[Get-OBSSourceFilter](docs/Get-OBSSourceFilter.md) | +|[Get-OBSSourceFilterDefaultSettings](docs/Get-OBSSourceFilterDefaultSettings.md) | +|[Get-OBSSourceFilterKind](docs/Get-OBSSourceFilterKind.md) | +|[Get-OBSSourceFilterList](docs/Get-OBSSourceFilterList.md) | +|[Get-OBSSourceScreenshot](docs/Get-OBSSourceScreenshot.md) | +|[Get-OBSSpecialInputs](docs/Get-OBSSpecialInputs.md) | +|[Get-OBSSpecularShineShader](docs/Get-OBSSpecularShineShader.md) | +|[Get-OBSSpotlightShader](docs/Get-OBSSpotlightShader.md) | +|[Get-OBSStats](docs/Get-OBSStats.md) | +|[Get-OBSStreamServiceSettings](docs/Get-OBSStreamServiceSettings.md) | +|[Get-OBSStreamStatus](docs/Get-OBSStreamStatus.md) | +|[Get-OBSStudioModeEnabled](docs/Get-OBSStudioModeEnabled.md) | +|[Get-OBSSwirlShader](docs/Get-OBSSwirlShader.md) | +|[Get-OBSTetraShader](docs/Get-OBSTetraShader.md) | +|[Get-OBSThermalShader](docs/Get-OBSThermalShader.md) | +|[Get-OBSTransitionKind](docs/Get-OBSTransitionKind.md) | +|[Get-OBSTvCrtSubpixelShader](docs/Get-OBSTvCrtSubpixelShader.md) | +|[Get-OBSTwistShader](docs/Get-OBSTwistShader.md) | +|[Get-OBSTwoPassDropShadowShader](docs/Get-OBSTwoPassDropShadowShader.md) | +|[Get-OBSVCRShader](docs/Get-OBSVCRShader.md) | +|[Get-OBSVersion](docs/Get-OBSVersion.md) | +|[Get-OBSVHSShader](docs/Get-OBSVHSShader.md) | +|[Get-OBSVideoSettings](docs/Get-OBSVideoSettings.md) | +|[Get-OBSVignettingShader](docs/Get-OBSVignettingShader.md) | +|[Get-OBSVirtualCamStatus](docs/Get-OBSVirtualCamStatus.md) | +|[Get-OBSVoronoiPixelationShader](docs/Get-OBSVoronoiPixelationShader.md) | +|[Get-OBSWalkingDeadPixelFixerShader](docs/Get-OBSWalkingDeadPixelFixerShader.md) | +|[Get-OBSZigZagShader](docs/Get-OBSZigZagShader.md) | +|[Get-OBSZoomBlurShader](docs/Get-OBSZoomBlurShader.md) | +|[Get-OBSZoomBlurTransitionShader](docs/Get-OBSZoomBlurTransitionShader.md) | +|[Get-OBSZoomShader](docs/Get-OBSZoomShader.md) | +|[Get-OBSZoomXYShader](docs/Get-OBSZoomXYShader.md) | +|[Hide-OBS](docs/Hide-OBS.md) | +|[Import-OBSEffect](docs/Import-OBSEffect.md) | +|[Open-OBSInputFiltersDialog](docs/Open-OBSInputFiltersDialog.md) | +|[Open-OBSInputInteractDialog](docs/Open-OBSInputInteractDialog.md) | +|[Open-OBSInputPropertiesDialog](docs/Open-OBSInputPropertiesDialog.md) | +|[Open-OBSSourceProjector](docs/Open-OBSSourceProjector.md) | +|[Open-OBSVideoMixProjector](docs/Open-OBSVideoMixProjector.md) | +|[Receive-OBS](docs/Receive-OBS.md) | +|[Remove-OBS](docs/Remove-OBS.md) | +|[Remove-OBSEffect](docs/Remove-OBSEffect.md) | +|[Remove-OBSInput](docs/Remove-OBSInput.md) | +|[Remove-OBSProfile](docs/Remove-OBSProfile.md) | +|[Remove-OBSScene](docs/Remove-OBSScene.md) | +|[Remove-OBSSceneItem](docs/Remove-OBSSceneItem.md) | +|[Remove-OBSSourceFilter](docs/Remove-OBSSourceFilter.md) | +|[Resume-OBSRecord](docs/Resume-OBSRecord.md) | +|[Save-OBSReplayBuffer](docs/Save-OBSReplayBuffer.md) | +|[Save-OBSSourceScreenshot](docs/Save-OBSSourceScreenshot.md) | +|[Send-OBS](docs/Send-OBS.md) | +|[Send-OBSCallVendorRequest](docs/Send-OBSCallVendorRequest.md) | +|[Send-OBSCustomEvent](docs/Send-OBSCustomEvent.md) | +|[Send-OBSOffsetMediaInputCursor](docs/Send-OBSOffsetMediaInputCursor.md) | +|[Send-OBSPauseRecord](docs/Send-OBSPauseRecord.md) | +|[Send-OBSPressInputPropertiesButton](docs/Send-OBSPressInputPropertiesButton.md) | +|[Send-OBSSleep](docs/Send-OBSSleep.md) | +|[Send-OBSStreamCaption](docs/Send-OBSStreamCaption.md) | +|[Send-OBSTriggerHotkeyByKeySequence](docs/Send-OBSTriggerHotkeyByKeySequence.md) | +|[Send-OBSTriggerHotkeyByName](docs/Send-OBSTriggerHotkeyByName.md) | +|[Send-OBSTriggerMediaInputAction](docs/Send-OBSTriggerMediaInputAction.md) | +|[Send-OBSTriggerStudioModeTransition](docs/Send-OBSTriggerStudioModeTransition.md) | +|[Set-OBS3DFilter](docs/Set-OBS3DFilter.md) | +|[Set-OBSAudioOutputSource](docs/Set-OBSAudioOutputSource.md) | +|[Set-OBSBrowserSource](docs/Set-OBSBrowserSource.md) | +|[Set-OBSColorFilter](docs/Set-OBSColorFilter.md) | +|[Set-OBSColorSource](docs/Set-OBSColorSource.md) | +|[Set-OBSCurrentPreviewScene](docs/Set-OBSCurrentPreviewScene.md) | +|[Set-OBSCurrentProfile](docs/Set-OBSCurrentProfile.md) | +|[Set-OBSCurrentProgramScene](docs/Set-OBSCurrentProgramScene.md) | +|[Set-OBSCurrentSceneCollection](docs/Set-OBSCurrentSceneCollection.md) | +|[Set-OBSCurrentSceneTransition](docs/Set-OBSCurrentSceneTransition.md) | +|[Set-OBSCurrentSceneTransitionDuration](docs/Set-OBSCurrentSceneTransitionDuration.md) | +|[Set-OBSCurrentSceneTransitionSettings](docs/Set-OBSCurrentSceneTransitionSettings.md) | +|[Set-OBSDisplaySource](docs/Set-OBSDisplaySource.md) | +|[Set-OBSEqualizerFilter](docs/Set-OBSEqualizerFilter.md) | +|[Set-OBSGainFilter](docs/Set-OBSGainFilter.md) | +|[Set-OBSInputAudioBalance](docs/Set-OBSInputAudioBalance.md) | +|[Set-OBSInputAudioMonitorType](docs/Set-OBSInputAudioMonitorType.md) | +|[Set-OBSInputAudioSyncOffset](docs/Set-OBSInputAudioSyncOffset.md) | +|[Set-OBSInputAudioTracks](docs/Set-OBSInputAudioTracks.md) | +|[Set-OBSInputMute](docs/Set-OBSInputMute.md) | +|[Set-OBSInputName](docs/Set-OBSInputName.md) | +|[Set-OBSInputSettings](docs/Set-OBSInputSettings.md) | +|[Set-OBSInputVolume](docs/Set-OBSInputVolume.md) | +|[Set-OBSMarkdownSource](docs/Set-OBSMarkdownSource.md) | +|[Set-OBSMediaInputCursor](docs/Set-OBSMediaInputCursor.md) | +|[Set-OBSMediaSource](docs/Set-OBSMediaSource.md) | +|[Set-OBSOutputSettings](docs/Set-OBSOutputSettings.md) | +|[Set-OBSPersistentData](docs/Set-OBSPersistentData.md) | +|[Set-OBSProfileParameter](docs/Set-OBSProfileParameter.md) | +|[Set-OBSRecordDirectory](docs/Set-OBSRecordDirectory.md) | +|[Set-OBSRenderDelayFilter](docs/Set-OBSRenderDelayFilter.md) | +|[Set-OBSScaleFilter](docs/Set-OBSScaleFilter.md) | +|[Set-OBSSceneItemBlendMode](docs/Set-OBSSceneItemBlendMode.md) | +|[Set-OBSSceneItemEnabled](docs/Set-OBSSceneItemEnabled.md) | +|[Set-OBSSceneItemIndex](docs/Set-OBSSceneItemIndex.md) | +|[Set-OBSSceneItemLocked](docs/Set-OBSSceneItemLocked.md) | +|[Set-OBSSceneItemTransform](docs/Set-OBSSceneItemTransform.md) | +|[Set-OBSSceneName](docs/Set-OBSSceneName.md) | +|[Set-OBSSceneSceneTransitionOverride](docs/Set-OBSSceneSceneTransitionOverride.md) | +|[Set-OBSScrollFilter](docs/Set-OBSScrollFilter.md) | +|[Set-OBSShaderFilter](docs/Set-OBSShaderFilter.md) | +|[Set-OBSSharpnessFilter](docs/Set-OBSSharpnessFilter.md) | +|[Set-OBSSoundCloudSource](docs/Set-OBSSoundCloudSource.md) | +|[Set-OBSSourceFilterEnabled](docs/Set-OBSSourceFilterEnabled.md) | +|[Set-OBSSourceFilterIndex](docs/Set-OBSSourceFilterIndex.md) | +|[Set-OBSSourceFilterName](docs/Set-OBSSourceFilterName.md) | +|[Set-OBSSourceFilterSettings](docs/Set-OBSSourceFilterSettings.md) | +|[Set-OBSStreamServiceSettings](docs/Set-OBSStreamServiceSettings.md) | +|[Set-OBSStudioModeEnabled](docs/Set-OBSStudioModeEnabled.md) | +|[Set-OBSSwitchSource](docs/Set-OBSSwitchSource.md) | +|[Set-OBSTBarPosition](docs/Set-OBSTBarPosition.md) | +|[Set-OBSVideoSettings](docs/Set-OBSVideoSettings.md) | +|[Set-OBSVLCSource](docs/Set-OBSVLCSource.md) | +|[Set-OBSWaveformSource](docs/Set-OBSWaveformSource.md) | +|[Set-OBSWindowSource](docs/Set-OBSWindowSource.md) | +|[Show-OBS](docs/Show-OBS.md) | +|[Start-OBS](docs/Start-OBS.md) | +|[Start-OBSEffect](docs/Start-OBSEffect.md) | +|[Start-OBSOutput](docs/Start-OBSOutput.md) | +|[Start-OBSRecord](docs/Start-OBSRecord.md) | +|[Start-OBSReplayBuffer](docs/Start-OBSReplayBuffer.md) | +|[Start-OBSStream](docs/Start-OBSStream.md) | +|[Start-OBSVirtualCam](docs/Start-OBSVirtualCam.md) | +|[Stop-OBS](docs/Stop-OBS.md) | +|[Stop-OBSEffect](docs/Stop-OBSEffect.md) | +|[Stop-OBSOutput](docs/Stop-OBSOutput.md) | +|[Stop-OBSRecord](docs/Stop-OBSRecord.md) | +|[Stop-OBSReplayBuffer](docs/Stop-OBSReplayBuffer.md) | +|[Stop-OBSStream](docs/Stop-OBSStream.md) | +|[Stop-OBSVirtualCam](docs/Stop-OBSVirtualCam.md) | +|[Switch-OBSInputMute](docs/Switch-OBSInputMute.md) | +|[Switch-OBSOutput](docs/Switch-OBSOutput.md) | +|[Switch-OBSRecord](docs/Switch-OBSRecord.md) | +|[Switch-OBSRecordPause](docs/Switch-OBSRecordPause.md) | +|[Switch-OBSReplayBuffer](docs/Switch-OBSReplayBuffer.md) | +|[Switch-OBSStream](docs/Switch-OBSStream.md) | +|[Switch-OBSVirtualCam](docs/Switch-OBSVirtualCam.md) | +|[Watch-OBS](docs/Watch-OBS.md) | diff --git a/obs-powershell-Help.xml b/obs-powershell-Help.xml index 478fc2fa..75916cfb 100644 --- a/obs-powershell-Help.xml +++ b/obs-powershell-Help.xml @@ -8,7 +8,7 @@ Add-OBSInput : CreateInput - 0.2.0.1 + 0.2.1 Creates a new input, adding it as a scene item to the specified scene. @@ -247,7 +247,7 @@ This can increase performance, and also silently ignore critical errors Add-OBSProfile : CreateProfile - 0.2.0.1 + 0.2.1 Creates a new profile, switching to it in the process @@ -356,7 +356,7 @@ This can increase performance, and also silently ignore critical errors Add-OBSScene : CreateScene - 0.2.0.1 + 0.2.1 Creates a new scene in OBS. @@ -465,7 +465,7 @@ This can increase performance, and also silently ignore critical errors Add-OBSSceneCollection : CreateSceneCollection - 0.2.0.1 + 0.2.1 Creates a new scene collection, switching to it in the process. @@ -575,7 +575,7 @@ This can increase performance, and also silently ignore critical errors Add-OBSSceneItem : CreateSceneItem - 0.2.0.1 + 0.2.1 Creates a new scene item using a source. @@ -789,7 +789,7 @@ This can increase performance, and also silently ignore critical errors Add-OBSSourceFilter : CreateSourceFilter - 0.2.0.1 + 0.2.1 Creates a new filter, adding it to the specified source. @@ -1002,7 +1002,7 @@ This can increase performance, and also silently ignore critical errors Clears a Scene in OBS - 0.2.0.1 + 0.2.1 Clears a Scene in OBS. @@ -1062,7 +1062,7 @@ This can increase performance, and also silently ignore critical errors Connects to Open Broadcast Studio - 0.2.0.1 + 0.2.1 Connects to the obs-websocket. @@ -1159,7 +1159,7 @@ You can see the websocket password in Tools -> obs-websocket settings -> s Copy-OBSSceneItem : DuplicateSceneItem - 0.2.0.1 + 0.2.1 Duplicates a scene item, copying all transform and crop info. @@ -1373,7 +1373,7 @@ This can increase performance, and also silently ignore critical errors Disconnects OBS - 0.2.0.1 + 0.2.1 Disconnects Websockets from OBS. @@ -1413,7 +1413,7 @@ This can increase performance, and also silently ignore critical errors Gets OBS - 0.2.0.1 + 0.2.1 Outputs OBS connection information and state. @@ -1439,21 +1439,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBS3dSwapTransitionShader - OBS3dSwapTransitionShader + Get-OBS3dPanelShader + OBS3dPanelShader Get - Get-OBS3dSwapTransitionShader [[-ImageA] <string>] [[-ImageB] <string>] [[-TransitionTime] <float>] [[-Reflection] <float>] [[-Perspective] <float>] [[-Depth] <float>] [[-BackgroundColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ConvertLinear] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBS3dPanelShader [[-Credits] <string>] [[-Scale] <float>] [[-TiltXDeg] <float>] [[-TiltYDeg] <float>] [[-TiltZDeg] <float>] [[-PosX] <float>] [[-PosY] <float>] [[-Thickness] <float>] [[-RadiusFb] <float>] [[-Brightness] <float>] [[-LightPosition] <int>] [[-Wiggle] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-WiggleRot] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBS3dSwapTransitionShader + Get-OBS3dPanelShader - ImageA + Credits @@ -1467,21 +1467,21 @@ This can increase performance, and also silently ignore critical errors - ImageB + Scale - String + Float - String + Float - TransitionTime + TiltXDeg @@ -1494,22 +1494,22 @@ This can increase performance, and also silently ignore critical errors - - ConvertLinear + + TiltYDeg - Switch + Float - Switch + Float - - Reflection + + TiltZDeg @@ -1522,8 +1522,8 @@ This can increase performance, and also silently ignore critical errors - - Perspective + + PosX @@ -1536,8 +1536,8 @@ This can increase performance, and also silently ignore critical errors - - Depth + + PosY @@ -1550,21 +1550,91 @@ This can increase performance, and also silently ignore critical errors - - BackgroundColor + + Thickness - String + Float - String + Float - + + RadiusFb + + + + + Float + + Float + + + + + + + Brightness + + + + + Float + + Float + + + + + + + LightPosition + + + + + Int + + Int + + + + + + + Wiggle + + + + + Float + + Float + + + + + + + WiggleRot + + + + + Switch + + Switch + + + + + + SourceName @@ -1578,7 +1648,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -1592,7 +1662,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -1666,7 +1736,21 @@ This can increase performance, and also silently ignore critical errors - BackgroundColor + Brightness + + + + + Float + + Float + + + + + + + Credits @@ -1680,7 +1764,21 @@ This can increase performance, and also silently ignore critical errors - ConvertLinear + FilterName + + + + + String + + String + + + + + + + Force @@ -1694,35 +1792,35 @@ This can increase performance, and also silently ignore critical errors - Depth + LightPosition - Float + Int - Float + Int - FilterName + NoResponse - String + Switch - String + Switch - Force + PassThru @@ -1736,21 +1834,63 @@ This can increase performance, and also silently ignore critical errors - ImageA + PosX - String + Float - String + Float - ImageB + PosY + + + + + Float + + Float + + + + + + + RadiusFb + + + + + Float + + Float + + + + + + + Scale + + + + + Float + + Float + + + + + + + ShaderText @@ -1764,35 +1904,35 @@ This can increase performance, and also silently ignore critical errors - NoResponse + SourceName - Switch + String - Switch + String - PassThru + Thickness - Switch + Float - Switch + Float - Perspective + TiltXDeg @@ -1806,7 +1946,7 @@ This can increase performance, and also silently ignore critical errors - Reflection + TiltYDeg @@ -1820,35 +1960,35 @@ This can increase performance, and also silently ignore critical errors - ShaderText + TiltZDeg - String + Float - String + Float - SourceName + UseShaderTime - String + Switch - String + Switch - TransitionTime + Wiggle @@ -1862,7 +2002,7 @@ This can increase performance, and also silently ignore critical errors - UseShaderTime + WiggleRot @@ -1897,21 +2037,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBSAddShader - OBSAddShader + Get-OBS3dSwapTransitionShader + OBS3dSwapTransitionShader Get - Get-OBSAddShader [[-OtherImage] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBS3dSwapTransitionShader [[-ImageA] <string>] [[-ImageB] <string>] [[-TransitionTime] <float>] [[-Reflection] <float>] [[-Perspective] <float>] [[-Depth] <float>] [[-BackgroundColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ConvertLinear] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSAddShader + Get-OBS3dSwapTransitionShader - OtherImage + ImageA @@ -1924,7 +2064,105 @@ This can increase performance, and also silently ignore critical errors - + + ImageB + + + + + String + + String + + + + + + + TransitionTime + + + + + Float + + Float + + + + + + + ConvertLinear + + + + + Switch + + Switch + + + + + + + Reflection + + + + + Float + + Float + + + + + + + Perspective + + + + + Float + + Float + + + + + + + Depth + + + + + Float + + Float + + + + + + + BackgroundColor + + + + + String + + String + + + + + + SourceName @@ -1938,7 +2176,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -1952,7 +2190,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -2026,7 +2264,7 @@ This can increase performance, and also silently ignore critical errors - FilterName + BackgroundColor @@ -2040,7 +2278,7 @@ This can increase performance, and also silently ignore critical errors - Force + ConvertLinear @@ -2054,7 +2292,35 @@ This can increase performance, and also silently ignore critical errors - NoResponse + Depth + + + + + Float + + Float + + + + + + + FilterName + + + + + String + + String + + + + + + + Force @@ -2068,7 +2334,21 @@ This can increase performance, and also silently ignore critical errors - OtherImage + ImageA + + + + + String + + String + + + + + + + ImageB @@ -2081,6 +2361,20 @@ This can increase performance, and also silently ignore critical errors + + NoResponse + + + + + Switch + + Switch + + + + + PassThru @@ -2095,6 +2389,34 @@ This can increase performance, and also silently ignore critical errors + + Perspective + + + + + Float + + Float + + + + + + + Reflection + + + + + Float + + Float + + + + + ShaderText @@ -2123,6 +2445,20 @@ This can increase performance, and also silently ignore critical errors + + TransitionTime + + + + + Float + + Float + + + + + UseShaderTime @@ -2159,21 +2495,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBSAlphaBorderShader - OBSAlphaBorderShader + Get-OBSAddShader + OBSAddShader Get - Get-OBSAlphaBorderShader [[-BorderColor] <string>] [[-BorderThickness] <int>] [[-AlphaCutOff] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSAddShader [[-OtherImage] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSAlphaBorderShader + Get-OBSAddShader - BorderColor + OtherImage @@ -2186,35 +2522,7 @@ This can increase performance, and also silently ignore critical errors - - BorderThickness - - - - - Int - - Int - - - - - - - AlphaCutOff - - - - - Float - - Float - - - - - - + SourceName @@ -2228,7 +2536,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -2242,7 +2550,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -2316,49 +2624,49 @@ This can increase performance, and also silently ignore critical errors - AlphaCutOff + FilterName - Float + String - Float + String - BorderColor + Force - String + Switch - String + Switch - BorderThickness + NoResponse - Int + Switch - Int + Switch - FilterName + OtherImage @@ -2372,7 +2680,7 @@ This can increase performance, and also silently ignore critical errors - Force + PassThru @@ -2386,7 +2694,297 @@ This can increase performance, and also silently ignore critical errors - NoResponse + ShaderText + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + + + + Get-OBSAlphaBorderShader + OBSAlphaBorderShader + Get + + Get-OBSAlphaBorderShader [[-BorderColor] <string>] [[-BorderThickness] <int>] [[-AlphaCutOff] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSAlphaBorderShader + + BorderColor + + + + + String + + String + + + + + + + BorderThickness + + + + + Int + + Int + + + + + + + AlphaCutOff + + + + + Float + + Float + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + AlphaCutOff + + + + + Float + + Float + + + + + + + BorderColor + + + + + String + + String + + + + + + + BorderThickness + + + + + Int + + Int + + + + + + + FilterName + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + NoResponse @@ -2483,7 +3081,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSAlphaGamingBentCameraShader [[-LeftSideWidth] <float>] [[-LeftSideSize] <float>] [[-LeftSideShadow] <float>] [[-LeftFlipWidth] <float>] [[-LeftFlipShadow] <float>] [[-RightSideWidth] <float>] [[-RightSideSize] <float>] [[-RightSideShadow] <float>] [[-RightFlipWidth] <float>] [[-RightFlipShadow] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -2997,7 +3595,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSAnimatedPathShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-RandF] <float>] [[-SpeedPercent] <int>] [[-PathMap] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Reverse] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -3511,7 +4109,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSAnimatedTextureShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-RandF] <float>] [[-UvSize] <float[]>] [[-Notes] <string>] [[-AnimationImage] <string>] [[-ColorizationImage] <string>] [[-PolarAngle] <float>] [[-PolarHeight] <float>] [[-SpeedHorizontalPercent] <float>] [[-SpeedVerticalPercent] <float>] [[-TintSpeedHorizontalPercent] <float>] [[-TintSpeedVerticalPercent] <float>] [[-Alpha] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Reverse] [-Bounce] [-CenterAnimation] [-PolarAnimation] [-UseAnimationImageColor] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -4389,7 +4987,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSAsciiShader [[-Scale] <int>] [[-BaseColor] <string>] [[-CharacterSet] <int>] [[-Note] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Monochrome] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -4763,7 +5361,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSAspectRatioShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-RandF] <float>] [[-UvSize] <float[]>] [[-BorderColor] <string>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -5269,6 +5867,324 @@ This can increase performance, and also silently ignore critical errors + + + Get-OBSAudioShader + OBSAudioShader + Get + + Get-OBSAudioShader [[-AudioPeak] <float>] [[-AudioMagnitude] <float>] [[-Intensity] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSAudioShader + + AudioPeak + + + + + Float + + Float + + + + + + + AudioMagnitude + + + + + Float + + Float + + + + + + + Intensity + + + + + Float + + Float + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + AudioMagnitude + + + + + Float + + Float + + + + + + + AudioPeak + + + + + Float + + Float + + + + + + + FilterName + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + Intensity + + + + + Float + + Float + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + ShaderText + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + Get-OBSBackgroundRemovalShader @@ -5277,7 +6193,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSBackgroundRemovalShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-RandF] <float>] [[-UvSize] <float[]>] [[-Notes] <string>] [[-Target] <string>] [[-Color] <string>] [[-Opacity] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Invert] [-Convert709to601] [-Convert601to709] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -5931,7 +6847,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSBlendOpacityShader [[-RotationOffset] <float>] [[-OpacityStartPercent] <float>] [[-OpacityEndPercent] <float>] [[-Spread] <float>] [[-Speed] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Vertical] [-Rotational] [-ApplyToAlphaLayer] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -6417,7 +7333,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSBlinkShader [[-Speed] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -6679,7 +7595,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSBloomShader [[-AngleSteps] <int>] [[-RadiusSteps] <int>] [[-AmpFactor] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -7025,7 +7941,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSBorderShader [[-BorderColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -7287,7 +8203,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSBoxBlurShader [[-Strength] <int>] [[-MaskLeft] <float>] [[-MaskRight] <float>] [[-MaskTop] <float>] [[-MaskBottom] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -7661,7 +8577,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSBulgePinchShader [[-Radius] <float>] [[-Magnitude] <float>] [[-CenterX] <float>] [[-CenterY] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Animate] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -8063,7 +8979,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSBurnShader [[-BurnGradient] <string>] [[-Speed] <float>] [[-GradientAdjust] <float>] [[-DissolveValue] <float>] [[-SmokeHorizonalSpeed] <float>] [[-SmokeVerticalSpeed] <float>] [[-Iterations] <int>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Animated] [-ApplyToChannel] [-ApplySmoke] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -8605,7 +9521,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSCartoonShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-RandF] <float>] [[-UvSize] <float[]>] [[-Notes] <string>] [[-HueSteps] <int>] [[-ValueSteps] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ApplyToAlphaLayer] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -9175,7 +10091,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSCellShadedShader [[-AngleSteps] <int>] [[-RadiusSteps] <int>] [[-AmpFactor] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -9521,7 +10437,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSChromaticAberrationShader [[-Power] <float>] [[-Gamma] <float>] [[-NumIter] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-DistortRadial] [-DistortBarrel] [-OffsetSpectrumYcgco] [-OffsetSpectrumYuv] [-UseRandom] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -9979,7 +10895,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSChromaUVDistortionShader [[-Distortion] <float>] [[-Amplitude] <float>] [[-Chroma] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -10297,7 +11213,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSCircleMaskFilterShader [[-Radius] <float>] [[-CircleOffsetX] <int>] [[-CircleOffsetY] <int>] [[-SourceOffsetX] <int>] [[-SourceOffsetY] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Antialiasing] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -10699,7 +11615,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSClockAnalogShader [[-CurrentTimeMs] <int>] [[-CurrentTimeSec] <int>] [[-CurrentTimeMin] <int>] [[-CurrentTimeHour] <int>] [[-HourHandleColor] <float[]>] [[-MinuteHandleColor] <float[]>] [[-SecondHandleColor] <float[]>] [[-OutlineColor] <float[]>] [[-TopLineColor] <float[]>] [[-BackgroundColor] <float[]>] [[-TimeOffsetHours] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -11241,7 +12157,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSClockDigitalLedShader [[-CurrentTimeSec] <int>] [[-CurrentTimeMin] <int>] [[-CurrentTimeHour] <int>] [[-TimeMode] <int>] [[-LedColor] <string>] [[-OffsetHours] <int>] [[-OffsetSeconds] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ShowMatrix] [-ShowOff] [-Ampm] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -11755,7 +12671,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSClockDigitalNixieShader [[-CurrentTimeMs] <int>] [[-CurrentTimeSec] <int>] [[-CurrentTimeMin] <int>] [[-CurrentTimeHour] <int>] [[-TimeMode] <int>] [[-OffsetHours] <int>] [[-OffsetSeconds] <int>] [[-Corecolor] <float[]>] [[-Halocolor] <float[]>] [[-Flarecolor] <float[]>] [[-Anodecolor] <float[]>] [[-Anodehighlightscolor] <float[]>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -12325,7 +13241,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSColorDepthShader [[-ColorDepth] <float>] [[-PixelSize] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -12615,7 +13531,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSColorGradeFilterShader [[-Notes] <string>] [[-Lut] <string>] [[-LutAmountPercent] <int>] [[-LutScalePercent] <int>] [[-LutOffsetPercent] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -12989,7 +13905,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSCornerPinShader [[-TopLeftX] <float>] [[-TopLeftY] <float>] [[-TopRightX] <float>] [[-TopRightY] <float>] [[-BottomLeftX] <float>] [[-BottomLeftY] <float>] [[-BottomRightX] <float>] [[-BottomRightY] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-AntialiasEdges] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -13475,7 +14391,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSCrtCurvatureShader [[-Strength] <float>] [[-Border] <string>] [[-Feathering] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -13785,6 +14701,408 @@ This can increase performance, and also silently ignore critical errors + + + Get-OBSCubeRotatingShader + OBSCubeRotatingShader + Get + + Get-OBSCubeRotatingShader [[-Images] <int>] [[-Speed] <float>] [[-Shadow] <float>] [[-OtherImage1] <string>] [[-OtherImage2] <string>] [[-OtherImage3] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSCubeRotatingShader + + Images + + + + + Int + + Int + + + + + + + Speed + + + + + Float + + Float + + + + + + + Shadow + + + + + Float + + Float + + + + + + + OtherImage1 + + + + + String + + String + + + + + + + OtherImage2 + + + + + String + + String + + + + + + + OtherImage3 + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + FilterName + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + Images + + + + + Int + + Int + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + OtherImage1 + + + + + String + + String + + + + + + + OtherImage2 + + + + + String + + String + + + + + + + OtherImage3 + + + + + String + + String + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + ShaderText + + + + + String + + String + + + + + + + Shadow + + + + + Float + + Float + + + + + + + SourceName + + + + + String + + String + + + + + + + Speed + + + + + Float + + Float + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + Get-OBSCurrentPreviewScene @@ -13793,7 +15111,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSCurrentPreviewScene : GetCurrentPreviewScene - 0.2.0.1 + 0.2.1 Gets the current preview scene. @@ -13889,7 +15207,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSCurrentProgramScene : GetCurrentProgramScene - 0.2.0.1 + 0.2.1 Gets the current program scene. @@ -13984,7 +15302,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSCurrentSceneTransition : GetCurrentSceneTransition - 0.2.0.1 + 0.2.1 Gets information about the current scene transition. @@ -14078,7 +15396,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSCurrentSceneTransitionCursor : GetCurrentSceneTransitionCursor - 0.2.0.1 + 0.2.1 Gets the cursor position of the current scene transition. @@ -14173,7 +15491,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSCurveShader [[-Strength] <float>] [[-Scale] <float>] [[-CurveColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -14491,7 +15809,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSCutRectPerCornerShader [[-CornerTl] <int>] [[-CornerTr] <int>] [[-CornerBr] <int>] [[-CornerBl] <int>] [[-BorderThickness] <int>] [[-BorderColor] <string>] [[-BorderAlphaStart] <float>] [[-BorderAlphaEnd] <float>] [[-AlphaCutOff] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -14977,7 +16295,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSCylinderShader [[-CylinderFactor] <float>] [[-BackgroundCut] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -15267,7 +16585,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSDarkenShader [[-OpacityPercentage] <float>] [[-FillPercentage] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -15585,7 +16903,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSDeadPixelFixerShader [[-DeadPixelX] <int>] [[-DeadPixelY] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -15875,7 +17193,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSDensitySatHueShader [[-Notes] <string>] [[-DensityR] <float>] [[-SaturationR] <float>] [[-HueShiftR] <float>] [[-DensityY] <float>] [[-SaturationY] <float>] [[-HueShiftY] <float>] [[-DensityG] <float>] [[-SaturationG] <float>] [[-HueShiftG] <float>] [[-DensityC] <float>] [[-SaturationC] <float>] [[-HueShiftC] <float>] [[-DensityB] <float>] [[-SaturationB] <float>] [[-HueShiftB] <float>] [[-DensityM] <float>] [[-SaturationM] <float>] [[-HueShiftM] <float>] [[-GlobalDensity] <float>] [[-GlobalSaturation] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -16697,7 +18015,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSDiffuseTransitionShader [[-ImageA] <string>] [[-ImageB] <string>] [[-TransitionTime] <float>] [[-NumSamples] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ConvertLinear] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -17071,7 +18389,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSDigitalRainShader [[-Font] <string>] [[-Noise] <string>] [[-BaseColor] <string>] [[-RainSpeed] <float>] [[-CharSpeed] <float>] [[-GlowContrast] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -17467,21 +18785,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBSDivideRotateShader - OBSDivideRotateShader + Get-OBSDisplacementMapAdvancedInvertShader + OBSDisplacementMapAdvancedInvertShader Get - Get-OBSDivideRotateShader [[-IChannel0] <string>] [[-SpeedPercentage] <int>] [[-AlphaPercentage] <int>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ApplyToAlphaLayer] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSDisplacementMapAdvancedInvertShader [[-DisplacementInfo] <string>] [[-DisplacementX] <float>] [[-DisplacementY] <float>] [[-DisplacementCurve] <int>] [[-BlurInfo] <string>] [[-BlurSize] <float>] [[-BlurQuality] <float>] [[-BlurDirections] <float>] [[-BlurAngle] <float>] [[-ChromaticAberrationInfo] <string>] [[-ChromaticAberration] <float>] [[-ColorizeInfo] <string>] [[-ColorizeColor] <string>] [[-FlagsInfo] <string>] [[-BackgroundLayer] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-BlueAffectsStrength] [-BlueAffectsColorize] [-BlueAffectsBlur] [-AlphaAffectsStrength] [-ApplyAlpha] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSDivideRotateShader + Get-OBSDisplacementMapAdvancedInvertShader - IChannel0 + DisplacementInfo @@ -17495,21 +18813,35 @@ This can increase performance, and also silently ignore critical errors - SpeedPercentage + DisplacementX - Int + Float - Int + Float - AlphaPercentage + DisplacementY + + + + + Float + + Float + + + + + + + DisplacementCurve @@ -17522,8 +18854,148 @@ This can increase performance, and also silently ignore critical errors + + BlurInfo + + + + + String + + String + + + + + + + BlurSize + + + + + Float + + Float + + + + + + + BlurQuality + + + + + Float + + Float + + + + + + + BlurDirections + + + + + Float + + Float + + + + + + + BlurAngle + + + + + Float + + Float + + + + + + + ChromaticAberrationInfo + + + + + String + + String + + + + + + + ChromaticAberration + + + + + Float + + Float + + + + + + + ColorizeInfo + + + + + String + + String + + + + + + + ColorizeColor + + + + + String + + String + + + + + + + FlagsInfo + + + + + String + + String + + + + + - ApplyToAlphaLayer + BlueAffectsStrength @@ -17536,8 +19008,64 @@ This can increase performance, and also silently ignore critical errors - - Notes + + BlueAffectsColorize + + + + + Switch + + Switch + + + + + + + BlueAffectsBlur + + + + + Switch + + Switch + + + + + + + AlphaAffectsStrength + + + + + Switch + + Switch + + + + + + + ApplyAlpha + + + + + Switch + + Switch + + + + + + + BackgroundLayer @@ -17550,7 +19078,7 @@ This can increase performance, and also silently ignore critical errors - + SourceName @@ -17564,7 +19092,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -17578,7 +19106,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -17652,21 +19180,21 @@ This can increase performance, and also silently ignore critical errors - AlphaPercentage + AlphaAffectsStrength - Int + Switch - Int + Switch - ApplyToAlphaLayer + ApplyAlpha @@ -17680,7 +19208,7 @@ This can increase performance, and also silently ignore critical errors - FilterName + BackgroundLayer @@ -17694,7 +19222,7 @@ This can increase performance, and also silently ignore critical errors - Force + BlueAffectsBlur @@ -17708,21 +19236,21 @@ This can increase performance, and also silently ignore critical errors - IChannel0 + BlueAffectsColorize - String + Switch - String + Switch - NoResponse + BlueAffectsStrength @@ -17736,7 +19264,35 @@ This can increase performance, and also silently ignore critical errors - Notes + BlurAngle + + + + + Float + + Float + + + + + + + BlurDirections + + + + + Float + + Float + + + + + + + BlurInfo @@ -17750,21 +19306,49 @@ This can increase performance, and also silently ignore critical errors - PassThru + BlurQuality - Switch + Float - Switch + Float - ShaderText + BlurSize + + + + + Float + + Float + + + + + + + ChromaticAberration + + + + + Float + + Float + + + + + + + ChromaticAberrationInfo @@ -17778,7 +19362,7 @@ This can increase performance, and also silently ignore critical errors - SourceName + ColorizeColor @@ -17792,7 +19376,21 @@ This can increase performance, and also silently ignore critical errors - SpeedPercentage + ColorizeInfo + + + + + String + + String + + + + + + + DisplacementCurve @@ -17805,6 +19403,146 @@ This can increase performance, and also silently ignore critical errors + + DisplacementInfo + + + + + String + + String + + + + + + + DisplacementX + + + + + Float + + Float + + + + + + + DisplacementY + + + + + Float + + Float + + + + + + + FilterName + + + + + String + + String + + + + + + + FlagsInfo + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + ShaderText + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + UseShaderTime @@ -17841,49 +19579,49 @@ This can increase performance, and also silently ignore critical errors - Get-OBSDoodleShader - OBSDoodleShader + Get-OBSDisplacementMapAdvancedShader + OBSDisplacementMapAdvancedShader Get - Get-OBSDoodleShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-RandF] <float>] [[-UvSize] <float[]>] [[-DoodleScalePercent] <float>] [[-SnapPercent] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSDisplacementMapAdvancedShader [[-DisplacementInfo] <string>] [[-DisplacementX] <float>] [[-DisplacementY] <float>] [[-DisplacementCurve] <int>] [[-BlurInfo] <string>] [[-BlurSize] <float>] [[-BlurQuality] <float>] [[-BlurDirections] <float>] [[-BlurAngle] <float>] [[-ChromaticAberrationInfo] <string>] [[-ChromaticAberration] <float>] [[-ColorizeInfo] <string>] [[-ColorizeColor] <string>] [[-FlagsInfo] <string>] [[-MaskLayer] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-BlueAffectsStrength] [-BlueAffectsColorize] [-BlueAffectsBlur] [-AlphaAffectsStrength] [-ApplyAlpha] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSDoodleShader + Get-OBSDisplacementMapAdvancedShader - ViewProj + DisplacementInfo - System.Single[][] + String - System.Single[][] + String - Image + DisplacementX - String + Float - String + Float - ElapsedTime + DisplacementY @@ -17897,49 +19635,49 @@ This can increase performance, and also silently ignore critical errors - UvOffset + DisplacementCurve - System.Single[] + Int - System.Single[] + Int - UvScale + BlurInfo - System.Single[] + String - System.Single[] + String - UvPixelInterval + BlurSize - System.Single[] + Float - System.Single[] + Float - RandF + BlurQuality @@ -17953,21 +19691,21 @@ This can increase performance, and also silently ignore critical errors - UvSize + BlurDirections - System.Single[] + Float - System.Single[] + Float - DoodleScalePercent + BlurAngle @@ -17981,35 +19719,35 @@ This can increase performance, and also silently ignore critical errors - SnapPercent + ChromaticAberrationInfo - Float + String - Float + String - Notes + ChromaticAberration - String + Float - String + Float - - SourceName + + ColorizeInfo @@ -18022,8 +19760,8 @@ This can increase performance, and also silently ignore critical errors - - FilterName + + ColorizeColor @@ -18037,7 +19775,7 @@ This can increase performance, and also silently ignore critical errors - ShaderText + FlagsInfo @@ -18051,7 +19789,7 @@ This can increase performance, and also silently ignore critical errors - Force + BlueAffectsStrength @@ -18065,7 +19803,7 @@ This can increase performance, and also silently ignore critical errors - PassThru + BlueAffectsColorize @@ -18079,7 +19817,7 @@ This can increase performance, and also silently ignore critical errors - NoResponse + BlueAffectsBlur @@ -18093,7 +19831,7 @@ This can increase performance, and also silently ignore critical errors - UseShaderTime + AlphaAffectsStrength @@ -18106,17 +19844,213 @@ This can increase performance, and also silently ignore critical errors - - - - - DoodleScalePercent - - - - - Float - + + ApplyAlpha + + + + + Switch + + Switch + + + + + + + MaskLayer + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + AlphaAffectsStrength + + + + + Switch + + Switch + + + + + + + ApplyAlpha + + + + + Switch + + Switch + + + + + + + BlueAffectsBlur + + + + + Switch + + Switch + + + + + + + BlueAffectsColorize + + + + + Switch + + Switch + + + + + + + BlueAffectsStrength + + + + + Switch + + Switch + + + + + + + BlurAngle + + + + + Float + Float @@ -18124,7 +20058,7 @@ This can increase performance, and also silently ignore critical errors - ElapsedTime + BlurDirections @@ -18138,7 +20072,7 @@ This can increase performance, and also silently ignore critical errors - FilterName + BlurInfo @@ -18152,49 +20086,49 @@ This can increase performance, and also silently ignore critical errors - Force + BlurQuality - Switch + Float - Switch + Float - Image + BlurSize - String + Float - String + Float - NoResponse + ChromaticAberration - Switch + Float - Switch + Float - Notes + ChromaticAberrationInfo @@ -18208,35 +20142,49 @@ This can increase performance, and also silently ignore critical errors - PassThru + ColorizeColor - Switch + String - Switch + String - RandF + ColorizeInfo - Float + String - Float + String - ShaderText + DisplacementCurve + + + + + Int + + Int + + + + + + + DisplacementInfo @@ -18250,7 +20198,7 @@ This can increase performance, and also silently ignore critical errors - SnapPercent + DisplacementX @@ -18264,7 +20212,21 @@ This can increase performance, and also silently ignore critical errors - SourceName + DisplacementY + + + + + Float + + Float + + + + + + + FilterName @@ -18278,7 +20240,21 @@ This can increase performance, and also silently ignore critical errors - UseShaderTime + FlagsInfo + + + + + String + + String + + + + + + + Force @@ -18292,70 +20268,84 @@ This can increase performance, and also silently ignore critical errors - UvOffset + MaskLayer - System.Single[] + String - System.Single[] + String - UvPixelInterval + NoResponse - System.Single[] + Switch - System.Single[] + Switch - UvScale + PassThru - System.Single[] + Switch - System.Single[] + Switch - UvSize + ShaderText - System.Single[] + String - System.Single[] + String - ViewProj + SourceName - System.Single[][] + String - System.Single[][] + String + + + + + + + UseShaderTime + + + + + Switch + + Switch @@ -18383,48 +20373,76 @@ This can increase performance, and also silently ignore critical errors - Get-OBSDrawingsShader - OBSDrawingsShader + Get-OBSDisplacementMapInvertShader + OBSDisplacementMapInvertShader Get - Get-OBSDrawingsShader [[-AngleNum] <int>] [[-SampNum] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSDisplacementMapInvertShader [[-DisplacementInfo] <string>] [[-DisplacementX] <float>] [[-DisplacementY] <float>] [[-BackgroundLayer] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSDrawingsShader + Get-OBSDisplacementMapInvertShader - AngleNum + DisplacementInfo - Int + String - Int + String - SampNum + DisplacementX - Int + Float - Int + Float - + + DisplacementY + + + + + Float + + Float + + + + + + + BackgroundLayer + + + + + String + + String + + + + + + SourceName @@ -18438,7 +20456,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -18452,7 +20470,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -18526,21 +20544,21 @@ This can increase performance, and also silently ignore critical errors - AngleNum + BackgroundLayer - Int + String - Int + String - FilterName + DisplacementInfo @@ -18554,21 +20572,49 @@ This can increase performance, and also silently ignore critical errors - Force + DisplacementX - Switch + Float - Switch + Float - NoResponse + DisplacementY + + + + + Float + + Float + + + + + + + FilterName + + + + + String + + String + + + + + + + Force @@ -18582,7 +20628,7 @@ This can increase performance, and also silently ignore critical errors - PassThru + NoResponse @@ -18596,14 +20642,14 @@ This can increase performance, and also silently ignore critical errors - SampNum + PassThru - Int + Switch - Int + Switch @@ -18673,77 +20719,63 @@ This can increase performance, and also silently ignore critical errors - Get-OBSDropShadowShader - OBSDropShadowShader + Get-OBSDisplacementMapShader + OBSDisplacementMapShader Get - Get-OBSDropShadowShader [[-ShadowOffsetX] <int>] [[-ShadowOffsetY] <int>] [[-ShadowBlurSize] <int>] [[-Notes] <string>] [[-ShadowColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-IsAlphaPremultiplied] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSDisplacementMapShader [[-DisplacementInfo] <string>] [[-DisplacementX] <float>] [[-DisplacementY] <float>] [[-MaskLayer] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSDropShadowShader + Get-OBSDisplacementMapShader - ShadowOffsetX + DisplacementInfo - Int + String - Int + String - ShadowOffsetY + DisplacementX - Int + Float - Int + Float - ShadowBlurSize + DisplacementY - Int + Float - Int + Float - Notes - - - - - String - - String - - - - - - - ShadowColor + MaskLayer @@ -18756,21 +20788,7 @@ This can increase performance, and also silently ignore critical errors - - IsAlphaPremultiplied - - - - - Switch - - Switch - - - - - - + SourceName @@ -18784,7 +20802,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -18798,7 +20816,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -18872,7 +20890,7 @@ This can increase performance, and also silently ignore critical errors - FilterName + DisplacementInfo @@ -18886,105 +20904,105 @@ This can increase performance, and also silently ignore critical errors - Force + DisplacementX - Switch + Float - Switch + Float - IsAlphaPremultiplied + DisplacementY - Switch + Float - Switch + Float - NoResponse + FilterName - Switch + String - Switch + String - Notes + Force - String + Switch - String + Switch - PassThru + MaskLayer - Switch + String - Switch + String - ShaderText + NoResponse - String + Switch - String + Switch - ShadowBlurSize + PassThru - Int + Switch - Int + Switch - ShadowColor + ShaderText @@ -18998,42 +21016,14 @@ This can increase performance, and also silently ignore critical errors - ShadowOffsetX + SourceName - Int + String - Int - - - - - - - ShadowOffsetY - - - - - Int - - Int - - - - - - - SourceName - - - - - String - - String + String @@ -19075,35 +21065,35 @@ This can increase performance, and also silently ignore critical errors - Get-OBSDrunkShader - OBSDrunkShader + Get-OBSDivideRotateShader + OBSDivideRotateShader Get - Get-OBSDrunkShader [[-ColorMatrix] <float[][]>] [[-GlowPercent] <int>] [[-Blur] <int>] [[-MinBrightness] <int>] [[-MaxBrightness] <int>] [[-PulseSpeedPercent] <int>] [[-GlowColor] <string>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ApplyToAlphaLayer] [-Ease] [-Glitch] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSDivideRotateShader [[-IChannel0] <string>] [[-SpeedPercentage] <int>] [[-AlphaPercentage] <int>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ApplyToAlphaLayer] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSDrunkShader + Get-OBSDivideRotateShader - ColorMatrix + IChannel0 - System.Single[][] + String - System.Single[][] + String - GlowPercent + SpeedPercentage @@ -19117,49 +21107,7 @@ This can increase performance, and also silently ignore critical errors - Blur - - - - - Int - - Int - - - - - - - MinBrightness - - - - - Int - - Int - - - - - - - MaxBrightness - - - - - Int - - Int - - - - - - - PulseSpeedPercent + AlphaPercentage @@ -19186,49 +21134,7 @@ This can increase performance, and also silently ignore critical errors - - GlowColor - - - - - String - - String - - - - - - - Ease - - - - - Switch - - Switch - - - - - - - Glitch - - - - - Switch - - Switch - - - - - - + Notes @@ -19242,7 +21148,7 @@ This can increase performance, and also silently ignore critical errors - + SourceName @@ -19256,7 +21162,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -19270,7 +21176,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -19344,21 +21250,7 @@ This can increase performance, and also silently ignore critical errors - ApplyToAlphaLayer - - - - - Switch - - Switch - - - - - - - Blur + AlphaPercentage @@ -19372,21 +21264,7 @@ This can increase performance, and also silently ignore critical errors - ColorMatrix - - - - - System.Single[][] - - System.Single[][] - - - - - - - Ease + ApplyToAlphaLayer @@ -19428,21 +21306,7 @@ This can increase performance, and also silently ignore critical errors - Glitch - - - - - Switch - - Switch - - - - - - - GlowColor + IChannel0 @@ -19455,48 +21319,6 @@ This can increase performance, and also silently ignore critical errors - - GlowPercent - - - - - Int - - Int - - - - - - - MaxBrightness - - - - - Int - - Int - - - - - - - MinBrightness - - - - - Int - - Int - - - - - NoResponse @@ -19540,21 +21362,21 @@ This can increase performance, and also silently ignore critical errors - PulseSpeedPercent + ShaderText - Int + String - Int + String - ShaderText + SourceName @@ -19568,14 +21390,14 @@ This can increase performance, and also silently ignore critical errors - SourceName + SpeedPercentage - String + Int - String + Int @@ -19617,49 +21439,49 @@ This can increase performance, and also silently ignore critical errors - Get-OBSDynamicMaskShader - OBSDynamicMaskShader + Get-OBSDoodleShader + OBSDoodleShader Get - Get-OBSDynamicMaskShader [[-InputSource] <string>] [[-RedBaseValue] <float>] [[-RedRedInputValue] <float>] [[-RedGreenInputValue] <float>] [[-RedBlueInputValue] <float>] [[-RedAlphaInputValue] <float>] [[-RedMultiplier] <float>] [[-GreenBaseValue] <float>] [[-GreenRedInputValue] <float>] [[-GreenGreenInputValue] <float>] [[-GreenBlueInputValue] <float>] [[-GreenAlphaInputValue] <float>] [[-GreenMultiplier] <float>] [[-BlueBaseValue] <float>] [[-BlueRedInputValue] <float>] [[-BlueGreenInputValue] <float>] [[-BlueBlueInputValue] <float>] [[-BlueAlphaInputValue] <float>] [[-BlueMultiplier] <float>] [[-AlphaBaseValue] <float>] [[-AlphaRedInputValue] <float>] [[-AlphaGreenInputValue] <float>] [[-AlphaBlueInputValue] <float>] [[-AlphaAlphaInputValue] <float>] [[-AlphaMultiplier] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSDoodleShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-RandF] <float>] [[-UvSize] <float[]>] [[-DoodleScalePercent] <float>] [[-SnapPercent] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSDynamicMaskShader + Get-OBSDoodleShader - InputSource + ViewProj - String + System.Single[][] - String + System.Single[][] - RedBaseValue + Image - Float + String - Float + String - RedRedInputValue + ElapsedTime @@ -19673,49 +21495,49 @@ This can increase performance, and also silently ignore critical errors - RedGreenInputValue + UvOffset - Float + System.Single[] - Float + System.Single[] - RedBlueInputValue + UvScale - Float + System.Single[] - Float + System.Single[] - RedAlphaInputValue + UvPixelInterval - Float + System.Single[] - Float + System.Single[] - RedMultiplier + RandF @@ -19729,21 +21551,21 @@ This can increase performance, and also silently ignore critical errors - GreenBaseValue + UvSize - Float + System.Single[] - Float + System.Single[] - GreenRedInputValue + DoodleScalePercent @@ -19757,7 +21579,7 @@ This can increase performance, and also silently ignore critical errors - GreenGreenInputValue + SnapPercent @@ -19771,216 +21593,20 @@ This can increase performance, and also silently ignore critical errors - GreenBlueInputValue - - - - - Float - - Float - - - - - - - GreenAlphaInputValue - - - - - Float - - Float - - - - - - - GreenMultiplier - - - - - Float - - Float - - - - - - - BlueBaseValue - - - - - Float - - Float - - - - - - - BlueRedInputValue - - - - - Float - - Float - - - - - - - BlueGreenInputValue - - - - - Float - - Float - - - - - - - BlueBlueInputValue - - - - - Float - - Float - - - - - - - BlueAlphaInputValue - - - - - Float - - Float - - - - - - - BlueMultiplier - - - - - Float - - Float - - - - - - - AlphaBaseValue - - - - - Float - - Float - - - - - - - AlphaRedInputValue - - - - - Float - - Float - - - - - - - AlphaGreenInputValue - - - - - Float - - Float - - - - - - - AlphaBlueInputValue - - - - - Float - - Float - - - - - - - AlphaAlphaInputValue - - - - - Float - - Float - - - - - - - AlphaMultiplier + Notes - Float + String - Float + String - + SourceName @@ -19994,7 +21620,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -20008,7 +21634,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -20082,7 +21708,7 @@ This can increase performance, and also silently ignore critical errors - AlphaAlphaInputValue + DoodleScalePercent @@ -20096,7 +21722,7 @@ This can increase performance, and also silently ignore critical errors - AlphaBaseValue + ElapsedTime @@ -20110,105 +21736,91 @@ This can increase performance, and also silently ignore critical errors - AlphaBlueInputValue + FilterName - Float + String - Float + String - AlphaGreenInputValue - - - - - Float - - Float - - - - - - - AlphaMultiplier + Force - Float + Switch - Float + Switch - AlphaRedInputValue + Image - Float + String - Float + String - BlueAlphaInputValue + NoResponse - Float + Switch - Float + Switch - BlueBaseValue + Notes - Float + String - Float + String - BlueBlueInputValue + PassThru - Float + Switch - Float + Switch - BlueGreenInputValue + RandF @@ -20222,21 +21834,21 @@ This can increase performance, and also silently ignore critical errors - BlueMultiplier + ShaderText - Float + String - Float + String - BlueRedInputValue + SnapPercent @@ -20250,7 +21862,7 @@ This can increase performance, and also silently ignore critical errors - FilterName + SourceName @@ -20264,7 +21876,7 @@ This can increase performance, and also silently ignore critical errors - Force + UseShaderTime @@ -20278,210 +21890,318 @@ This can increase performance, and also silently ignore critical errors - GreenAlphaInputValue - - - - - Float - - Float - - - - - - - GreenBaseValue - - - - - Float - - Float - - - - - - - GreenBlueInputValue + UvOffset - Float + System.Single[] - Float + System.Single[] - GreenGreenInputValue + UvPixelInterval - Float + System.Single[] - Float + System.Single[] - GreenMultiplier + UvScale - Float + System.Single[] - Float + System.Single[] - GreenRedInputValue + UvSize - Float + System.Single[] - Float + System.Single[] - InputSource + ViewProj - String + System.Single[][] - String + System.Single[][] - - NoResponse - - - - - Switch + + + - Switch + System.String + - - - - - PassThru - - - - - Switch + + + + - Switch + System.Object + - - - + + + + + + Get-OBSDrawingsShader + OBSDrawingsShader + Get + + Get-OBSDrawingsShader [[-AngleNum] <int>] [[-SampNum] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSDrawingsShader + + AngleNum + + + + + Int + + Int + + + + + + + SampNum + + + + + Int + + Int + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + - RedAlphaInputValue + AngleNum - Float + Int - Float + Int - RedBaseValue + FilterName - Float + String - Float + String - RedBlueInputValue + Force - Float + Switch - Float + Switch - RedGreenInputValue + NoResponse - Float + Switch - Float + Switch - RedMultiplier + PassThru - Float + Switch - Float + Switch - RedRedInputValue + SampNum - Float + Int - Float + Int @@ -20551,77 +22271,63 @@ This can increase performance, and also silently ignore critical errors - Get-OBSEdgeDetectionShader - OBSEdgeDetectionShader + Get-OBSDropShadowShader + OBSDropShadowShader Get - Get-OBSEdgeDetectionShader [[-Sensitivity] <float>] [[-EdgeColor] <string>] [[-NonEdgeColor] <string>] [[-AlphaLevel] <float>] [[-RandF] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-InvertEdge] [-EdgeMultiply] [-NonEdgeMultiply] [-AlphaChannel] [-AlphaInvert] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSDropShadowShader [[-ShadowOffsetX] <int>] [[-ShadowOffsetY] <int>] [[-ShadowBlurSize] <int>] [[-Notes] <string>] [[-ShadowColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-IsAlphaPremultiplied] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSEdgeDetectionShader + Get-OBSDropShadowShader - Sensitivity - - - - - Float - - Float - - - - - - - InvertEdge + ShadowOffsetX - Switch + Int - Switch + Int - EdgeColor + ShadowOffsetY - String + Int - String + Int - - EdgeMultiply + + ShadowBlurSize - Switch + Int - Switch + Int - - NonEdgeColor + + Notes @@ -20634,50 +22340,22 @@ This can increase performance, and also silently ignore critical errors - - NonEdgeMultiply - - - - - Switch - - Switch - - - - - - - AlphaChannel - - - - - Switch - - Switch - - - - - - - AlphaLevel + + ShadowColor - Float + String - Float + String - AlphaInvert + IsAlphaPremultiplied @@ -20690,35 +22368,7 @@ This can increase performance, and also silently ignore critical errors - - RandF - - - - - Float - - Float - - - - - - - Notes - - - - - String - - String - - - - - - + SourceName @@ -20732,7 +22382,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -20746,7 +22396,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -20820,21 +22470,21 @@ This can increase performance, and also silently ignore critical errors - AlphaChannel + FilterName - Switch + String - Switch + String - AlphaInvert + Force @@ -20848,91 +22498,91 @@ This can increase performance, and also silently ignore critical errors - AlphaLevel + IsAlphaPremultiplied - Float + Switch - Float + Switch - EdgeColor + NoResponse - String + Switch - String + Switch - EdgeMultiply + Notes - Switch + String - Switch + String - FilterName + PassThru - String + Switch - String + Switch - Force + ShaderText - Switch + String - Switch + String - InvertEdge + ShadowBlurSize - Switch + Int - Switch + Int - NonEdgeColor + ShadowColor @@ -20946,35 +22596,35 @@ This can increase performance, and also silently ignore critical errors - NonEdgeMultiply + ShadowOffsetX - Switch + Int - Switch + Int - NoResponse + ShadowOffsetY - Switch + Int - Switch + Int - Notes + SourceName @@ -20988,77 +22638,7 @@ This can increase performance, and also silently ignore critical errors - PassThru - - - - - Switch - - Switch - - - - - - - RandF - - - - - Float - - Float - - - - - - - Sensitivity - - - - - Float - - Float - - - - - - - ShaderText - - - - - String - - String - - - - - - - SourceName - - - - - String - - String - - - - - - - UseShaderTime + UseShaderTime @@ -21093,86 +22673,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBSEffect - OBSEffect - Get - - Gets OBS Effects - - 0.2.0.1 - - - Gets effects currently loaded into OBS-PowerShell. - An effect can be thought of as a name with a series of messages to OBS. - Those messages can be defined in a .json file or a script, in any module that tags OBS. - They can also be defined in a function or script named like: - * `*.OBS.FX.*` - * `*.OBS.Effect.*` - * `*.OBS.Effects.*` - - - - Get-OBSEffect - - Name - - The name of the effect. - - String - - String - - - - - - - - - - Name - - The name of the effect. - - String - - String - - - - - - - - - Import-OBSEffect - - - - - Remove-OBSEffect - - - - - - - - Get-OBSEmbersShader - OBSEmbersShader + Get-OBSDrunkShader + OBSDrunkShader Get - Get-OBSEmbersShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvSize] <float[]>] [[-UvPixelInterval] <float[]>] [[-RandF] <float>] [[-RandInstanceF] <float>] [[-RandActivationF] <float>] [[-Loops] <int>] [[-LocalTime] <float>] [[-Notes] <string>] [[-AnimationSpeed] <float>] [[-MovementDirectionHorizontal] <float>] [[-MovementDirectionVertical] <float>] [[-MovementSpeedPercent] <int>] [[-LayersCount] <int>] [[-LumaMin] <float>] [[-LumaMinSmooth] <float>] [[-AlphaPercentage] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ApplyToAlphaLayer] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSDrunkShader [[-ColorMatrix] <float[][]>] [[-GlowPercent] <int>] [[-Blur] <int>] [[-MinBrightness] <int>] [[-MaxBrightness] <int>] [[-PulseSpeedPercent] <int>] [[-GlowColor] <string>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ApplyToAlphaLayer] [-Ease] [-Glitch] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSEmbersShader + Get-OBSDrunkShader - ViewProj + ColorMatrix @@ -21186,133 +22701,63 @@ This can increase performance, and also silently ignore critical errors - Image + GlowPercent - String + Int - String + Int - ElapsedTime + Blur - Float + Int - Float + Int - UvOffset + MinBrightness - System.Single[] + Int - System.Single[] + Int - UvScale + MaxBrightness - System.Single[] + Int - System.Single[] + Int - UvSize - - - - - System.Single[] - - System.Single[] - - - - - - - UvPixelInterval - - - - - System.Single[] - - System.Single[] - - - - - - - RandF - - - - - Float - - Float - - - - - - - RandInstanceF - - - - - Float - - Float - - - - - - - RandActivationF - - - - - Float - - Float - - - - - - - Loops + PulseSpeedPercent @@ -21325,22 +22770,22 @@ This can increase performance, and also silently ignore critical errors - - LocalTime + + ApplyToAlphaLayer - Float + Switch - Float + Switch - - Notes + + GlowColor @@ -21353,133 +22798,49 @@ This can increase performance, and also silently ignore critical errors - - AnimationSpeed - - - - - Float - - Float - - - - - - - MovementDirectionHorizontal - - - - - Float - - Float - - - - - - - MovementDirectionVertical - - - - - Float - - Float - - - - - - - MovementSpeedPercent - - - - - Int - - Int - - - - - - - LayersCount - - - - - Int - - Int - - - - - - - LumaMin - - - - - Float - - Float - - - - - - - LumaMinSmooth + + Ease - Float + Switch - Float + Switch - - AlphaPercentage + + Glitch - Float + Switch - Float + Switch - - ApplyToAlphaLayer + + Notes - Switch + String - Switch + String - + SourceName @@ -21493,7 +22854,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -21507,7 +22868,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -21581,56 +22942,56 @@ This can increase performance, and also silently ignore critical errors - AlphaPercentage + ApplyToAlphaLayer - Float + Switch - Float + Switch - AnimationSpeed + Blur - Float + Int - Float + Int - ApplyToAlphaLayer + ColorMatrix - Switch + System.Single[][] - Switch + System.Single[][] - ElapsedTime + Ease - Float + Switch - Float + Switch @@ -21665,49 +23026,35 @@ This can increase performance, and also silently ignore critical errors - Image - - - - - String - - String - - - - - - - LayersCount + Glitch - Int + Switch - Int + Switch - LocalTime + GlowColor - Float + String - Float + String - Loops + GlowPercent @@ -21721,63 +23068,21 @@ This can increase performance, and also silently ignore critical errors - LumaMin - - - - - Float - - Float - - - - - - - LumaMinSmooth - - - - - Float - - Float - - - - - - - MovementDirectionHorizontal - - - - - Float - - Float - - - - - - - MovementDirectionVertical + MaxBrightness - Float + Int - Float + Int - MovementSpeedPercent + MinBrightness @@ -21833,42 +23138,14 @@ This can increase performance, and also silently ignore critical errors - RandActivationF - - - - - Float - - Float - - - - - - - RandF - - - - - Float - - Float - - - - - - - RandInstanceF + PulseSpeedPercent - Float + Int - Float + Int @@ -21916,79 +23193,9 @@ This can increase performance, and also silently ignore critical errors - - UvOffset - - - - - System.Single[] - - System.Single[] - - - - - - - UvPixelInterval - - - - - System.Single[] - - System.Single[] - - - - - - - UvScale - - - - - System.Single[] - - System.Single[] - - - - - - - UvSize - - - - - System.Single[] - - System.Single[] - - - - - - - ViewProj - - - - - System.Single[][] - - System.Single[][] - - - - - - - - + + + System.String @@ -22008,49 +23215,49 @@ This can increase performance, and also silently ignore critical errors - Get-OBSEmbossColorShader - OBSEmbossColorShader + Get-OBSDynamicMaskShader + OBSDynamicMaskShader Get - Get-OBSEmbossColorShader [[-AngleSteps] <int>] [[-RadiusSteps] <int>] [[-AmpFactor] <float>] [[-UpDownPercent] <int>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ApplyToAlphaLayer] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSDynamicMaskShader [[-InputSource] <string>] [[-RedBaseValue] <float>] [[-RedRedInputValue] <float>] [[-RedGreenInputValue] <float>] [[-RedBlueInputValue] <float>] [[-RedAlphaInputValue] <float>] [[-RedMultiplier] <float>] [[-GreenBaseValue] <float>] [[-GreenRedInputValue] <float>] [[-GreenGreenInputValue] <float>] [[-GreenBlueInputValue] <float>] [[-GreenAlphaInputValue] <float>] [[-GreenMultiplier] <float>] [[-BlueBaseValue] <float>] [[-BlueRedInputValue] <float>] [[-BlueGreenInputValue] <float>] [[-BlueBlueInputValue] <float>] [[-BlueAlphaInputValue] <float>] [[-BlueMultiplier] <float>] [[-AlphaBaseValue] <float>] [[-AlphaRedInputValue] <float>] [[-AlphaGreenInputValue] <float>] [[-AlphaBlueInputValue] <float>] [[-AlphaAlphaInputValue] <float>] [[-AlphaMultiplier] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSEmbossColorShader + Get-OBSDynamicMaskShader - AngleSteps + InputSource - Int + String - Int + String - RadiusSteps + RedBaseValue - Int + Float - Int + Float - AmpFactor + RedRedInputValue @@ -22064,48 +23271,314 @@ This can increase performance, and also silently ignore critical errors - UpDownPercent + RedGreenInputValue - Int + Float - Int + Float - - ApplyToAlphaLayer + + RedBlueInputValue - Switch + Float - Switch + Float - - Notes + + RedAlphaInputValue - String + Float - String + Float - + + RedMultiplier + + + + + Float + + Float + + + + + + + GreenBaseValue + + + + + Float + + Float + + + + + + + GreenRedInputValue + + + + + Float + + Float + + + + + + + GreenGreenInputValue + + + + + Float + + Float + + + + + + + GreenBlueInputValue + + + + + Float + + Float + + + + + + + GreenAlphaInputValue + + + + + Float + + Float + + + + + + + GreenMultiplier + + + + + Float + + Float + + + + + + + BlueBaseValue + + + + + Float + + Float + + + + + + + BlueRedInputValue + + + + + Float + + Float + + + + + + + BlueGreenInputValue + + + + + Float + + Float + + + + + + + BlueBlueInputValue + + + + + Float + + Float + + + + + + + BlueAlphaInputValue + + + + + Float + + Float + + + + + + + BlueMultiplier + + + + + Float + + Float + + + + + + + AlphaBaseValue + + + + + Float + + Float + + + + + + + AlphaRedInputValue + + + + + Float + + Float + + + + + + + AlphaGreenInputValue + + + + + Float + + Float + + + + + + + AlphaBlueInputValue + + + + + Float + + Float + + + + + + + AlphaAlphaInputValue + + + + + Float + + Float + + + + + + + AlphaMultiplier + + + + + Float + + Float + + + + + + SourceName @@ -22119,7 +23592,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -22133,7 +23606,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -22207,7 +23680,7 @@ This can increase performance, and also silently ignore critical errors - AmpFactor + AlphaAlphaInputValue @@ -22221,161 +23694,175 @@ This can increase performance, and also silently ignore critical errors - AngleSteps + AlphaBaseValue - Int + Float - Int + Float - ApplyToAlphaLayer + AlphaBlueInputValue - Switch + Float - Switch + Float - FilterName + AlphaGreenInputValue - String + Float - String + Float - Force + AlphaMultiplier - Switch + Float - Switch + Float - NoResponse + AlphaRedInputValue - Switch + Float - Switch + Float - Notes + BlueAlphaInputValue - String + Float - String + Float - PassThru + BlueBaseValue - Switch + Float - Switch + Float - RadiusSteps + BlueBlueInputValue - Int + Float - Int + Float - ShaderText + BlueGreenInputValue - String + Float - String + Float - SourceName + BlueMultiplier - String + Float - String + Float - UpDownPercent + BlueRedInputValue - Int + Float - Int + Float - UseShaderTime + FilterName + + + + + String + + String + + + + + + + Force @@ -22388,207 +23875,99 @@ This can increase performance, and also silently ignore critical errors - - - + + GreenAlphaInputValue + + + + + Float - System.String + Float - - - - - + + + + + GreenBaseValue + + + + + Float - System.Object + Float - - - - - - - Get-OBSEmbossShader - OBSEmbossShader - Get - - Get-OBSEmbossShader [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-UseColor] [-ApplyToAlphaLayer] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - - 0.2.0.1 - - - - - - Get-OBSEmbossShader - - UseColor - - - - - Switch - - Switch - - - - - - - ApplyToAlphaLayer - - - - - Switch - - Switch - - - - - - - SourceName - - - - - String - - String - - - - - - - FilterName - - - - - String - - String - - - - - - - ShaderText - - - - - String - - String - - - - - - - Force - - - - - Switch - - Switch - - - - - - - PassThru - - - - - Switch - - Switch - - - - - - - NoResponse - - - - - Switch - - Switch - - - - - - - UseShaderTime - - - - - Switch - - Switch - - - - - - - - + + + - ApplyToAlphaLayer + GreenBlueInputValue - Switch + Float - Switch + Float - FilterName + GreenGreenInputValue - String + Float - String + Float - Force + GreenMultiplier - Switch + Float - Switch + Float + + + + + + + GreenRedInputValue + + + + + Float + + Float + + + + + + + InputSource + + + + + String + + String @@ -22623,21 +24002,91 @@ This can increase performance, and also silently ignore critical errors - ShaderText + RedAlphaInputValue - String + Float - String + Float - SourceName + RedBaseValue + + + + + Float + + Float + + + + + + + RedBlueInputValue + + + + + Float + + Float + + + + + + + RedGreenInputValue + + + + + Float + + Float + + + + + + + RedMultiplier + + + + + Float + + Float + + + + + + + RedRedInputValue + + + + + Float + + Float + + + + + + + ShaderText @@ -22651,14 +24100,14 @@ This can increase performance, and also silently ignore critical errors - UseColor + SourceName - Switch + String - Switch + String @@ -22700,21 +24149,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBSExeldroBentCameraShader - OBSExeldroBentCameraShader + Get-OBSEdgeDetectionShader + OBSEdgeDetectionShader Get - Get-OBSExeldroBentCameraShader [[-LeftSideWidth] <float>] [[-LeftSideSize] <float>] [[-LeftSideShadow] <float>] [[-LeftFlipWidth] <float>] [[-LeftFlipShadow] <float>] [[-RightSideWidth] <float>] [[-RightSideSize] <float>] [[-RightSideShadow] <float>] [[-RightFlipWidth] <float>] [[-RightFlipShadow] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSEdgeDetectionShader [[-Sensitivity] <float>] [[-EdgeColor] <string>] [[-NonEdgeColor] <string>] [[-AlphaLevel] <float>] [[-RandF] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-InvertEdge] [-EdgeMultiply] [-NonEdgeMultiply] [-AlphaChannel] [-AlphaInvert] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSExeldroBentCameraShader + Get-OBSEdgeDetectionShader - LeftSideWidth + Sensitivity @@ -22727,78 +24176,92 @@ This can increase performance, and also silently ignore critical errors + + InvertEdge + + + + + Switch + + Switch + + + + + - LeftSideSize + EdgeColor - Float + String - Float + String - - LeftSideShadow + + EdgeMultiply - Float + Switch - Float + Switch - - LeftFlipWidth + + NonEdgeColor - Float + String - Float + String - - LeftFlipShadow + + NonEdgeMultiply - Float + Switch - Float + Switch - - RightSideWidth + + AlphaChannel - Float + Switch - Float + Switch - - RightSideSize + + AlphaLevel @@ -22811,22 +24274,22 @@ This can increase performance, and also silently ignore critical errors - - RightSideShadow + + AlphaInvert - Float + Switch - Float + Switch - - RightFlipWidth + + RandF @@ -22839,21 +24302,21 @@ This can increase performance, and also silently ignore critical errors - - RightFlipShadow + + Notes - Float + String - Float + String - + SourceName @@ -22867,7 +24330,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -22881,7 +24344,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -22955,21 +24418,21 @@ This can increase performance, and also silently ignore critical errors - FilterName + AlphaChannel - String + Switch - String + Switch - Force + AlphaInvert @@ -22983,7 +24446,7 @@ This can increase performance, and also silently ignore critical errors - LeftFlipShadow + AlphaLevel @@ -22997,63 +24460,63 @@ This can increase performance, and also silently ignore critical errors - LeftFlipWidth + EdgeColor - Float + String - Float + String - LeftSideShadow + EdgeMultiply - Float + Switch - Float + Switch - LeftSideSize + FilterName - Float + String - Float + String - LeftSideWidth + Force - Float + Switch - Float + Switch - NoResponse + InvertEdge @@ -23067,7 +24530,21 @@ This can increase performance, and also silently ignore critical errors - PassThru + NonEdgeColor + + + + + String + + String + + + + + + + NonEdgeMultiply @@ -23081,49 +24558,49 @@ This can increase performance, and also silently ignore critical errors - RightFlipShadow + NoResponse - Float + Switch - Float + Switch - RightFlipWidth + Notes - Float + String - Float + String - RightSideShadow + PassThru - Float + Switch - Float + Switch - RightSideSize + RandF @@ -23137,7 +24614,7 @@ This can increase performance, and also silently ignore critical errors - RightSideWidth + Sensitivity @@ -23214,35 +24691,100 @@ This can increase performance, and also silently ignore critical errors - Get-OBSFadeTransitionShader - OBSFadeTransitionShader + Get-OBSEffect + OBSEffect Get - Get-OBSFadeTransitionShader [[-ImageA] <string>] [[-ImageB] <string>] [[-TransitionTime] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ConvertLinear] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Gets OBS Effects - 0.2.0.1 + 0.2.1 + Gets effects currently loaded into OBS-PowerShell. + An effect can be thought of as a name with a series of messages to OBS. + Those messages can be defined in a .json file or a script, in any module that tags OBS. + They can also be defined in a function or script named like: + * `*.OBS.FX.*` + * `*.OBS.Effect.*` + * `*.OBS.Effects.*` - Get-OBSFadeTransitionShader + Get-OBSEffect + + Name + + The name of the effect. + + String + + String + + + + + + + + + + Name + + The name of the effect. + + String + + String + + + + + + + + + Import-OBSEffect + + + + + Remove-OBSEffect + + + + + + + + Get-OBSEmbersShader + OBSEmbersShader + Get + + Get-OBSEmbersShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvSize] <float[]>] [[-UvPixelInterval] <float[]>] [[-RandF] <float>] [[-RandInstanceF] <float>] [[-RandActivationF] <float>] [[-Loops] <int>] [[-LocalTime] <float>] [[-Notes] <string>] [[-AnimationSpeed] <float>] [[-MovementDirectionHorizontal] <float>] [[-MovementDirectionVertical] <float>] [[-MovementSpeedPercent] <int>] [[-LayersCount] <int>] [[-LumaMin] <float>] [[-LumaMinSmooth] <float>] [[-AlphaPercentage] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ApplyToAlphaLayer] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSEmbersShader - ImageA + ViewProj - String + System.Single[][] - String + System.Single[][] - ImageB + Image @@ -23256,7 +24798,7 @@ This can increase performance, and also silently ignore critical errors - TransitionTime + ElapsedTime @@ -23269,312 +24811,120 @@ This can increase performance, and also silently ignore critical errors - - ConvertLinear + + UvOffset - Switch + System.Single[] - Switch + System.Single[] - - SourceName + + UvScale - String + System.Single[] - String + System.Single[] - - FilterName + + UvSize - String + System.Single[] - String + System.Single[] - - ShaderText + + UvPixelInterval - String + System.Single[] - String + System.Single[] - - Force + + RandF - Switch + Float - Switch + Float - - PassThru + + RandInstanceF - Switch + Float - Switch + Float - - NoResponse + + RandActivationF - Switch + Float - Switch + Float - - UseShaderTime + + Loops - Switch + Int - Switch + Int - - - - - ConvertLinear - - - - - Switch - - Switch - - - - - - - FilterName - - - - - String - - String - - - - - - - Force - - - - - Switch - - Switch - - - - - - - ImageA - - - - - String - - String - - - - - - - ImageB - - - - - String - - String - - - - - - - NoResponse - - - - - Switch - - Switch - - - - - - - PassThru - - - - - Switch - - Switch - - - - - - - ShaderText - - - - - String - - String - - - - - - - SourceName - - - - - String - - String - - - - - - - TransitionTime - - - - - Float - - Float - - - - - - - UseShaderTime - - - - - Switch - - Switch - - - - - - - - - - System.String - - - - - - - - - System.Object - - - - - - - - - Get-OBSFillColorGradientShader - OBSFillColorGradientShader - Get - - Get-OBSFillColorGradientShader [[-Fill] <float>] [[-GradientWidth] <float>] [[-GradientOffset] <float>] [[-FillDirection] <int>] [[-FillColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - - 0.2.0.1 - - - - - - Get-OBSFillColorGradientShader - - Fill + + LocalTime @@ -23587,8 +24937,22 @@ This can increase performance, and also silently ignore critical errors - - GradientWidth + + Notes + + + + + String + + String + + + + + + + AnimationSpeed @@ -23601,8 +24965,8 @@ This can increase performance, and also silently ignore critical errors - - GradientOffset + + MovementDirectionHorizontal @@ -23615,8 +24979,22 @@ This can increase performance, and also silently ignore critical errors - - FillDirection + + MovementDirectionVertical + + + + + Float + + Float + + + + + + + MovementSpeedPercent @@ -23629,21 +25007,77 @@ This can increase performance, and also silently ignore critical errors - - FillColor + + LayersCount - String + Int - String + Int - + + LumaMin + + + + + Float + + Float + + + + + + + LumaMinSmooth + + + + + Float + + Float + + + + + + + AlphaPercentage + + + + + Float + + Float + + + + + + + ApplyToAlphaLayer + + + + + Switch + + Switch + + + + + + SourceName @@ -23657,7 +25091,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -23671,7 +25105,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -23745,7 +25179,7 @@ This can increase performance, and also silently ignore critical errors - Fill + AlphaPercentage @@ -23759,28 +25193,42 @@ This can increase performance, and also silently ignore critical errors - FillColor + AnimationSpeed - String + Float - String + Float - FillDirection + ApplyToAlphaLayer - Int + Switch - Int + Switch + + + + + + + ElapsedTime + + + + + Float + + Float @@ -23815,7 +25263,35 @@ This can increase performance, and also silently ignore critical errors - GradientOffset + Image + + + + + String + + String + + + + + + + LayersCount + + + + + Int + + Int + + + + + + + LocalTime @@ -23829,7 +25305,21 @@ This can increase performance, and also silently ignore critical errors - GradientWidth + Loops + + + + + Int + + Int + + + + + + + LumaMin @@ -23843,63 +25333,63 @@ This can increase performance, and also silently ignore critical errors - NoResponse + LumaMinSmooth - Switch + Float - Switch + Float - PassThru + MovementDirectionHorizontal - Switch + Float - Switch + Float - ShaderText + MovementDirectionVertical - String + Float - String + Float - SourceName + MovementSpeedPercent - String + Int - String + Int - UseShaderTime + NoResponse @@ -23912,186 +25402,36 @@ This can increase performance, and also silently ignore critical errors - - - + + Notes + + + + + String - System.String + String - - - - - + + + + + PassThru + + + + + Switch - System.Object + Switch - - - - - - - Get-OBSFillColorLinearShader - OBSFillColorLinearShader - Get - - Get-OBSFillColorLinearShader [[-Fill] <float>] [[-FillDirection] <int>] [[-FillColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - - 0.2.0.1 - - - - - - Get-OBSFillColorLinearShader - - Fill - - - - - Float - - Float - - - - - - - FillDirection - - - - - Int - - Int - - - - - - - FillColor - - - - - String - - String - - - - - - - SourceName - - - - - String - - String - - - - - - - FilterName - - - - - String - - String - - - - - - - ShaderText - - - - - String - - String - - - - - - - Force - - - - - Switch - - Switch - - - - - - - PassThru - - - - - Switch - - Switch - - - - - - - NoResponse - - - - - Switch - - Switch - - - - - - - UseShaderTime - - - - - Switch - - Switch - - - - - - - - + + + - Fill + RandActivationF @@ -24105,35 +25445,35 @@ This can increase performance, and also silently ignore critical errors - FillColor + RandF - String + Float - String + Float - FillDirection + RandInstanceF - Int + Float - Int + Float - FilterName + ShaderText @@ -24147,21 +25487,21 @@ This can increase performance, and also silently ignore critical errors - Force + SourceName - Switch + String - Switch + String - NoResponse + UseShaderTime @@ -24175,56 +25515,70 @@ This can increase performance, and also silently ignore critical errors - PassThru + UvOffset - Switch + System.Single[] - Switch + System.Single[] - ShaderText + UvPixelInterval - String + System.Single[] - String + System.Single[] - SourceName + UvScale - String + System.Single[] - String + System.Single[] - UseShaderTime + UvSize - Switch + System.Single[] - Switch + System.Single[] + + + + + + + ViewProj + + + + + System.Single[][] + + System.Single[][] @@ -24252,21 +25606,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBSFillColorRadialDegreesShader - OBSFillColorRadialDegreesShader + Get-OBSEmbossColorShader + OBSEmbossColorShader Get - Get-OBSFillColorRadialDegreesShader [[-FillDirection] <int>] [[-Fill] <float>] [[-StartAngle] <float>] [[-OffsetX] <float>] [[-OffsetY] <float>] [[-FillColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSEmbossColorShader [[-AngleSteps] <int>] [[-RadiusSteps] <int>] [[-AmpFactor] <float>] [[-UpDownPercent] <int>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ApplyToAlphaLayer] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSFillColorRadialDegreesShader + Get-OBSEmbossColorShader - FillDirection + AngleSteps @@ -24280,21 +25634,21 @@ This can increase performance, and also silently ignore critical errors - Fill + RadiusSteps - Float + Int - Float + Int - StartAngle + AmpFactor @@ -24308,35 +25662,35 @@ This can increase performance, and also silently ignore critical errors - OffsetX + UpDownPercent - Float + Int - Float + Int - - OffsetY + + ApplyToAlphaLayer - Float + Switch - Float + Switch - - FillColor + + Notes @@ -24349,7 +25703,7 @@ This can increase performance, and also silently ignore critical errors - + SourceName @@ -24363,7 +25717,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -24377,7 +25731,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -24451,7 +25805,7 @@ This can increase performance, and also silently ignore critical errors - Fill + AmpFactor @@ -24465,28 +25819,28 @@ This can increase performance, and also silently ignore critical errors - FillColor + AngleSteps - String + Int - String + Int - FillDirection + ApplyToAlphaLayer - Int + Switch - Int + Switch @@ -24535,42 +25889,42 @@ This can increase performance, and also silently ignore critical errors - OffsetX + Notes - Float + String - Float + String - OffsetY + PassThru - Float + Switch - Float + Switch - PassThru + RadiusSteps - Switch + Int - Switch + Int @@ -24605,14 +25959,14 @@ This can increase performance, and also silently ignore critical errors - StartAngle + UpDownPercent - Float + Int - Float + Int @@ -24654,104 +26008,48 @@ This can increase performance, and also silently ignore critical errors - Get-OBSFillColorRadialPercentageShader - OBSFillColorRadialPercentageShader + Get-OBSEmbossShader + OBSEmbossShader Get - Get-OBSFillColorRadialPercentageShader [[-FillDirection] <int>] [[-Fill] <float>] [[-StartAngle] <float>] [[-OffsetX] <float>] [[-OffsetY] <float>] [[-FillColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSEmbossShader [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-UseColor] [-ApplyToAlphaLayer] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSFillColorRadialPercentageShader - - FillDirection - - - - - Int - - Int - - - - - - - Fill - - - - - Float - - Float - - - - - - - StartAngle - - - - - Float - - Float - - - - - - - OffsetX - - - - - Float - - Float - - - - - - - OffsetY + Get-OBSEmbossShader + + UseColor - Float + Switch - Float + Switch - - FillColor + + ApplyToAlphaLayer - String + Switch - String + Switch - + SourceName @@ -24765,7 +26063,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -24779,7 +26077,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -24853,42 +26151,14 @@ This can increase performance, and also silently ignore critical errors - Fill - - - - - Float - - Float - - - - - - - FillColor - - - - - String - - String - - - - - - - FillDirection + ApplyToAlphaLayer - Int + Switch - Int + Switch @@ -24936,34 +26206,6 @@ This can increase performance, and also silently ignore critical errors - - OffsetX - - - - - Float - - Float - - - - - - - OffsetY - - - - - Float - - Float - - - - - PassThru @@ -25007,14 +26249,14 @@ This can increase performance, and also silently ignore critical errors - StartAngle + UseColor - Float + Switch - Float + Switch @@ -25056,49 +26298,49 @@ This can increase performance, and also silently ignore critical errors - Get-OBSFilterTemplateShader - OBSFilterTemplateShader + Get-OBSExeldroBentCameraShader + OBSExeldroBentCameraShader Get - Get-OBSFilterTemplateShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-UvSize] <float[]>] [[-RandF] <float>] [[-RandInstanceF] <float>] [[-RandActivationF] <float>] [[-Loops] <int>] [[-LocalTime] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSExeldroBentCameraShader [[-LeftSideWidth] <float>] [[-LeftSideSize] <float>] [[-LeftSideShadow] <float>] [[-LeftFlipWidth] <float>] [[-LeftFlipShadow] <float>] [[-RightSideWidth] <float>] [[-RightSideSize] <float>] [[-RightSideShadow] <float>] [[-RightFlipWidth] <float>] [[-RightFlipShadow] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSFilterTemplateShader + Get-OBSExeldroBentCameraShader - ViewProj + LeftSideWidth - System.Single[][] + Float - System.Single[][] + Float - Image + LeftSideSize - String + Float - String + Float - ElapsedTime + LeftSideShadow @@ -25112,63 +26354,63 @@ This can increase performance, and also silently ignore critical errors - UvOffset + LeftFlipWidth - System.Single[] + Float - System.Single[] + Float - UvScale + LeftFlipShadow - System.Single[] + Float - System.Single[] + Float - UvPixelInterval + RightSideWidth - System.Single[] + Float - System.Single[] + Float - UvSize + RightSideSize - System.Single[] + Float - System.Single[] + Float - RandF + RightSideShadow @@ -25182,7 +26424,7 @@ This can increase performance, and also silently ignore critical errors - RandInstanceF + RightFlipWidth @@ -25196,7 +26438,7 @@ This can increase performance, and also silently ignore critical errors - RandActivationF + RightFlipShadow @@ -25209,77 +26451,35 @@ This can increase performance, and also silently ignore critical errors - - Loops + + SourceName - Int + String - Int + String - - LocalTime + + FilterName - Float + String - Float + String - Notes - - - - - String - - String - - - - - - - SourceName - - - - - String - - String - - - - - - - FilterName - - - - - String - - String - - - - - - ShaderText @@ -25352,20 +26552,6 @@ This can increase performance, and also silently ignore critical errors - - ElapsedTime - - - - - Float - - Float - - - - - FilterName @@ -25395,21 +26581,21 @@ This can increase performance, and also silently ignore critical errors - Image + LeftFlipShadow - String + Float - String + Float - LocalTime + LeftFlipWidth @@ -25423,49 +26609,49 @@ This can increase performance, and also silently ignore critical errors - Loops + LeftSideShadow - Int + Float - Int + Float - NoResponse + LeftSideSize - Switch + Float - Switch + Float - Notes + LeftSideWidth - String + Float - String + Float - PassThru + NoResponse @@ -25479,21 +26665,21 @@ This can increase performance, and also silently ignore critical errors - RandActivationF + PassThru - Float + Switch - Float + Switch - RandF + RightFlipShadow @@ -25507,7 +26693,7 @@ This can increase performance, and also silently ignore critical errors - RandInstanceF + RightFlipWidth @@ -25521,112 +26707,84 @@ This can increase performance, and also silently ignore critical errors - ShaderText - - - - - String - - String - - - - - - - SourceName - - - - - String - - String - - - - - - - UseShaderTime + RightSideShadow - Switch + Float - Switch + Float - UvOffset + RightSideSize - System.Single[] + Float - System.Single[] + Float - UvPixelInterval + RightSideWidth - System.Single[] + Float - System.Single[] + Float - UvScale + ShaderText - System.Single[] + String - System.Single[] + String - UvSize + SourceName - System.Single[] + String - System.Single[] + String - ViewProj + UseShaderTime - System.Single[][] + Switch - System.Single[][] + Switch @@ -25654,35 +26812,35 @@ This can increase performance, and also silently ignore critical errors - Get-OBSFire3Shader - OBSFire3Shader + Get-OBSFadeTransitionShader + OBSFadeTransitionShader Get - Get-OBSFire3Shader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-UvSize] <float[]>] [[-RandF] <float>] [[-RandInstanceF] <float>] [[-RandActivationF] <float>] [[-Loops] <int>] [[-LocalTime] <float>] [[-MovementDirectionHorizontal] <float>] [[-MovementDirectionVertical] <float>] [[-AlphaPercentage] <int>] [[-Speed] <int>] [[-LumaMin] <float>] [[-LumaMinSmooth] <float>] [[-ColorToReplace] <string>] [[-FlameSize] <float>] [[-SparkGridHeight] <float>] [[-FlameModifier] <float>] [[-FlameTongueSize] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Invert] [-ApplyToImage] [-ReplaceImageColor] [-ApplyToSpecificColor] [-FullWidth] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSFadeTransitionShader [[-ImageA] <string>] [[-ImageB] <string>] [[-TransitionTime] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ConvertLinear] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSFire3Shader + Get-OBSFadeTransitionShader - ViewProj + ImageA - System.Single[][] + String - System.Single[][] + String - Image + ImageB @@ -25696,7 +26854,7 @@ This can increase performance, and also silently ignore critical errors - ElapsedTime + TransitionTime @@ -25709,120 +26867,312 @@ This can increase performance, and also silently ignore critical errors - - UvOffset + + ConvertLinear - System.Single[] + Switch - System.Single[] + Switch - - UvScale + + SourceName - System.Single[] + String - System.Single[] + String - - UvPixelInterval + + FilterName - System.Single[] + String - System.Single[] + String - - UvSize + + ShaderText - System.Single[] + String - System.Single[] + String - - RandF + + Force - Float + Switch - Float + Switch - - RandInstanceF + + PassThru - Float + Switch - Float + Switch - - RandActivationF + + NoResponse - Float + Switch - Float + Switch - - Loops + + UseShaderTime - Int + Switch - Int + Switch - - LocalTime + + + + + ConvertLinear + + + + + Switch + + Switch + + + + + + + FilterName + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + ImageA + + + + + String + + String + + + + + + + ImageB + + + + + String + + String + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + ShaderText + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + TransitionTime + + + + + Float + + Float + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + + + + Get-OBSFillColorGradientShader + OBSFillColorGradientShader + Get + + Get-OBSFillColorGradientShader [[-Fill] <float>] [[-GradientWidth] <float>] [[-GradientOffset] <float>] [[-FillDirection] <int>] [[-FillColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSFillColorGradientShader + + Fill @@ -25835,8 +27185,8 @@ This can increase performance, and also silently ignore critical errors - - MovementDirectionHorizontal + + GradientWidth @@ -25849,8 +27199,8 @@ This can increase performance, and also silently ignore critical errors - - MovementDirectionVertical + + GradientOffset @@ -25863,8 +27213,8 @@ This can increase performance, and also silently ignore critical errors - - AlphaPercentage + + FillDirection @@ -25877,64 +27227,64 @@ This can increase performance, and also silently ignore critical errors - - Speed + + FillColor - Int + String - Int + String - - Invert + + SourceName - Switch + String - Switch + String - - LumaMin + + FilterName - Float + String - Float + String - - LumaMinSmooth + + ShaderText - Float + String - Float + String - ApplyToImage + Force @@ -25948,7 +27298,7 @@ This can increase performance, and also silently ignore critical errors - ReplaceImageColor + PassThru @@ -25961,22 +27311,8 @@ This can increase performance, and also silently ignore critical errors - - ColorToReplace - - - - - String - - String - - - - - - ApplyToSpecificColor + NoResponse @@ -25990,161 +27326,7 @@ This can increase performance, and also silently ignore critical errors - FullWidth - - - - - Switch - - Switch - - - - - - - FlameSize - - - - - Float - - Float - - - - - - - SparkGridHeight - - - - - Float - - Float - - - - - - - FlameModifier - - - - - Float - - Float - - - - - - - FlameTongueSize - - - - - Float - - Float - - - - - - - SourceName - - - - - String - - String - - - - - - - FilterName - - - - - String - - String - - - - - - - ShaderText - - - - - String - - String - - - - - - - Force - - - - - Switch - - Switch - - - - - - - PassThru - - - - - Switch - - Switch - - - - - - - NoResponse - - - - - Switch - - Switch - - - - - - - UseShaderTime + UseShaderTime @@ -26161,49 +27343,21 @@ This can increase performance, and also silently ignore critical errors - AlphaPercentage - - - - - Int - - Int - - - - - - - ApplyToImage - - - - - Switch - - Switch - - - - - - - ApplyToSpecificColor + Fill - Switch + Float - Switch + Float - ColorToReplace + FillColor @@ -26217,14 +27371,14 @@ This can increase performance, and also silently ignore critical errors - ElapsedTime + FillDirection - Float + Int - Float + Int @@ -26245,21 +27399,21 @@ This can increase performance, and also silently ignore critical errors - FlameModifier + Force - Float + Switch - Float + Switch - FlameSize + GradientOffset @@ -26273,7 +27427,7 @@ This can increase performance, and also silently ignore critical errors - FlameTongueSize + GradientWidth @@ -26287,7 +27441,7 @@ This can increase performance, and also silently ignore critical errors - Force + NoResponse @@ -26301,7 +27455,7 @@ This can increase performance, and also silently ignore critical errors - FullWidth + PassThru @@ -26315,7 +27469,7 @@ This can increase performance, and also silently ignore critical errors - Image + ShaderText @@ -26329,63 +27483,213 @@ This can increase performance, and also silently ignore critical errors - Invert + SourceName - Switch + String - Switch + String - LocalTime + UseShaderTime - Float + Switch - Float + Switch - - Loops - - - - - Int + + + - Int + System.String + - - - - - LumaMin - - - - - Float + + + + - Float + System.Object + - - - + + + + + + Get-OBSFillColorLinearShader + OBSFillColorLinearShader + Get + + Get-OBSFillColorLinearShader [[-Fill] <float>] [[-FillDirection] <int>] [[-FillColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSFillColorLinearShader + + Fill + + + + + Float + + Float + + + + + + + FillDirection + + + + + Int + + Int + + + + + + + FillColor + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + - LumaMinSmooth + Fill @@ -26399,49 +27703,49 @@ This can increase performance, and also silently ignore critical errors - MovementDirectionHorizontal + FillColor - Float + String - Float + String - MovementDirectionVertical + FillDirection - Float + Int - Float + Int - NoResponse + FilterName - Switch + String - Switch + String - PassThru + Force @@ -26455,49 +27759,21 @@ This can increase performance, and also silently ignore critical errors - RandActivationF - - - - - Float - - Float - - - - - - - RandF - - - - - Float - - Float - - - - - - - RandInstanceF + NoResponse - Float + Switch - Float + Switch - ReplaceImageColor + PassThru @@ -26538,34 +27814,6 @@ This can increase performance, and also silently ignore critical errors - - SparkGridHeight - - - - - Float - - Float - - - - - - - Speed - - - - - Int - - Int - - - - - UseShaderTime @@ -26580,83 +27828,13 @@ This can increase performance, and also silently ignore critical errors - - UvOffset - - - - - System.Single[] + + + - System.Single[] + System.String - - - - - - UvPixelInterval - - - - - System.Single[] - - System.Single[] - - - - - - - UvScale - - - - - System.Single[] - - System.Single[] - - - - - - - UvSize - - - - - System.Single[] - - System.Single[] - - - - - - - ViewProj - - - - - System.Single[][] - - System.Single[][] - - - - - - - - - - System.String - - + @@ -26672,21 +27850,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBSFireShader - OBSFireShader + Get-OBSFillColorRadialDegreesShader + OBSFillColorRadialDegreesShader Get - Get-OBSFireShader [[-AlphaPercentage] <int>] [[-Speed] <int>] [[-FlameSize] <int>] [[-FireType] <int>] [[-LumaMin] <float>] [[-LumaMinSmooth] <float>] [[-ColorToReplace] <string>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Invert] [-ApplyToImage] [-ReplaceImageColor] [-ApplyToSpecificColor] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSFillColorRadialDegreesShader [[-FillDirection] <int>] [[-Fill] <float>] [[-StartAngle] <float>] [[-OffsetX] <float>] [[-OffsetY] <float>] [[-FillColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSFireShader + Get-OBSFillColorRadialDegreesShader - AlphaPercentage + FillDirection @@ -26700,63 +27878,35 @@ This can increase performance, and also silently ignore critical errors - Speed + Fill - Int + Float - Int + Float - FlameSize + StartAngle - Int + Float - Int + Float - FireType - - - - - Int - - Int - - - - - - - Invert - - - - - Switch - - Switch - - - - - - - LumaMin + OffsetX @@ -26769,8 +27919,8 @@ This can increase performance, and also silently ignore critical errors - - LumaMinSmooth + + OffsetY @@ -26783,64 +27933,8 @@ This can increase performance, and also silently ignore critical errors - - ApplyToImage - - - - - Switch - - Switch - - - - - - - ReplaceImageColor - - - - - Switch - - Switch - - - - - - - ApplyToSpecificColor - - - - - Switch - - Switch - - - - - - - ColorToReplace - - - - - String - - String - - - - - - - Notes + + FillColor @@ -26853,7 +27947,7 @@ This can increase performance, and also silently ignore critical errors - + SourceName @@ -26867,7 +27961,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -26881,7 +27975,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -26955,63 +28049,21 @@ This can increase performance, and also silently ignore critical errors - AlphaPercentage - - - - - Int - - Int - - - - - - - ApplyToImage - - - - - Switch - - Switch - - - - - - - ApplyToSpecificColor - - - - - Switch - - Switch - - - - - - - ColorToReplace + Fill - String + Float - String + Float - FilterName + FillColor @@ -27025,7 +28077,7 @@ This can increase performance, and also silently ignore critical errors - FireType + FillDirection @@ -27039,14 +28091,14 @@ This can increase performance, and also silently ignore critical errors - FlameSize + FilterName - Int + String - Int + String @@ -27067,7 +28119,7 @@ This can increase performance, and also silently ignore critical errors - Invert + NoResponse @@ -27081,7 +28133,7 @@ This can increase performance, and also silently ignore critical errors - LumaMin + OffsetX @@ -27095,7 +28147,7 @@ This can increase performance, and also silently ignore critical errors - LumaMinSmooth + OffsetY @@ -27108,34 +28160,6 @@ This can increase performance, and also silently ignore critical errors - - NoResponse - - - - - Switch - - Switch - - - - - - - Notes - - - - - String - - String - - - - - PassThru @@ -27150,20 +28174,6 @@ This can increase performance, and also silently ignore critical errors - - ReplaceImageColor - - - - - Switch - - Switch - - - - - ShaderText @@ -27193,14 +28203,14 @@ This can increase performance, and also silently ignore critical errors - Speed + StartAngle - Int + Float - Int + Float @@ -27242,21 +28252,35 @@ This can increase performance, and also silently ignore critical errors - Get-OBSFireworks2Shader - OBSFireworks2Shader + Get-OBSFillColorRadialPercentageShader + OBSFillColorRadialPercentageShader Get - Get-OBSFireworks2Shader [[-Speed] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSFillColorRadialPercentageShader [[-FillDirection] <int>] [[-Fill] <float>] [[-StartAngle] <float>] [[-OffsetX] <float>] [[-OffsetY] <float>] [[-FillColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSFireworks2Shader + Get-OBSFillColorRadialPercentageShader - Speed + FillDirection + + + + + Int + + Int + + + + + + + Fill @@ -27269,7 +28293,63 @@ This can increase performance, and also silently ignore critical errors - + + StartAngle + + + + + Float + + Float + + + + + + + OffsetX + + + + + Float + + Float + + + + + + + OffsetY + + + + + Float + + Float + + + + + + + FillColor + + + + + String + + String + + + + + + SourceName @@ -27283,7 +28363,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -27297,7 +28377,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -27370,6 +28450,48 @@ This can increase performance, and also silently ignore critical errors + + Fill + + + + + Float + + Float + + + + + + + FillColor + + + + + String + + String + + + + + + + FillDirection + + + + + Int + + Int + + + + + FilterName @@ -27412,6 +28534,34 @@ This can increase performance, and also silently ignore critical errors + + OffsetX + + + + + Float + + Float + + + + + + + OffsetY + + + + + Float + + Float + + + + + PassThru @@ -27455,7 +28605,7 @@ This can increase performance, and also silently ignore critical errors - Speed + StartAngle @@ -27504,353 +28654,175 @@ This can increase performance, and also silently ignore critical errors - Get-OBSFireworksShader - OBSFireworksShader + Get-OBSFilterTemplateShader + OBSFilterTemplateShader Get - Get-OBSFireworksShader [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ShowFlash] [-ShowStars] [-UseTransparancy] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSFilterTemplateShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-UvSize] <float[]>] [[-RandF] <float>] [[-RandInstanceF] <float>] [[-RandActivationF] <float>] [[-Loops] <int>] [[-LocalTime] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSFireworksShader - - ShowFlash + Get-OBSFilterTemplateShader + + ViewProj - Switch + System.Single[][] - Switch + System.Single[][] - - ShowStars + + Image - Switch + String - Switch + String - - UseTransparancy + + ElapsedTime - Switch + Float - Switch + Float - - SourceName + + UvOffset - String + System.Single[] - String + System.Single[] - - FilterName + + UvScale - String + System.Single[] - String + System.Single[] - - ShaderText + + UvPixelInterval - String + System.Single[] - String + System.Single[] - - Force + + UvSize - Switch + System.Single[] - Switch + System.Single[] - - PassThru + + RandF - Switch + Float - Switch + Float - - NoResponse + + RandInstanceF - Switch + Float - Switch + Float - - UseShaderTime + + RandActivationF - Switch + Float - Switch + Float - - - - - FilterName - - - - - String - - String - - - - - - - Force - - - - - Switch - - Switch - - - - - - - NoResponse - - - - - Switch - - Switch - - - - - - - PassThru - - - - - Switch - - Switch - - - - - - - ShaderText - - - - - String - - String - - - - - - - ShowFlash - - - - - Switch - - Switch - - - - - - - ShowStars - - - - - Switch - - Switch - - - - - - - SourceName - - - - - String - - String - - - - - - - UseShaderTime - - - - - Switch - - Switch - - - - - - - UseTransparancy - - - - - Switch - - Switch - - - - - - - - - - System.String - - - - - - - - - System.Object - - - - - - - - - Get-OBSFisheyeShader - OBSFisheyeShader - Get - - Get-OBSFisheyeShader [[-CenterXPercent] <float>] [[-CenterYPercent] <float>] [[-Power] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - - 0.2.0.1 - - - - - - Get-OBSFisheyeShader - - CenterXPercent + + Loops - Float + Int - Float + Int - - CenterYPercent + + LocalTime @@ -27863,21 +28835,21 @@ This can increase performance, and also silently ignore critical errors - - Power + + Notes - Float + String - Float + String - + SourceName @@ -27891,7 +28863,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -27905,7 +28877,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -27979,7 +28951,7 @@ This can increase performance, and also silently ignore critical errors - CenterXPercent + ElapsedTime @@ -27993,21 +28965,35 @@ This can increase performance, and also silently ignore critical errors - CenterYPercent + FilterName - Float + String - Float + String - FilterName + Force + + + + + Switch + + Switch + + + + + + + Image @@ -28021,14 +29007,28 @@ This can increase performance, and also silently ignore critical errors - Force + LocalTime - Switch + Float - Switch + Float + + + + + + + Loops + + + + + Int + + Int @@ -28048,6 +29048,20 @@ This can increase performance, and also silently ignore critical errors + + Notes + + + + + String + + String + + + + + PassThru @@ -28063,7 +29077,35 @@ This can increase performance, and also silently ignore critical errors - Power + RandActivationF + + + + + Float + + Float + + + + + + + RandF + + + + + Float + + Float + + + + + + + RandInstanceF @@ -28118,6 +29160,76 @@ This can increase performance, and also silently ignore critical errors + + UvOffset + + + + + System.Single[] + + System.Single[] + + + + + + + UvPixelInterval + + + + + System.Single[] + + System.Single[] + + + + + + + UvScale + + + + + System.Single[] + + System.Single[] + + + + + + + UvSize + + + + + System.Single[] + + System.Single[] + + + + + + + ViewProj + + + + + System.Single[][] + + System.Single[][] + + + + + @@ -28140,49 +29252,49 @@ This can increase performance, and also silently ignore critical errors - Get-OBSFisheyeXyShader - OBSFisheyeXyShader + Get-OBSFire3Shader + OBSFire3Shader Get - Get-OBSFisheyeXyShader [[-CenterXPercent] <float>] [[-CenterYPercent] <float>] [[-PowerX] <float>] [[-PowerY] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSFire3Shader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-UvSize] <float[]>] [[-RandF] <float>] [[-RandInstanceF] <float>] [[-RandActivationF] <float>] [[-Loops] <int>] [[-LocalTime] <float>] [[-MovementDirectionHorizontal] <float>] [[-MovementDirectionVertical] <float>] [[-AlphaPercentage] <int>] [[-Speed] <int>] [[-LumaMin] <float>] [[-LumaMinSmooth] <float>] [[-ColorToReplace] <string>] [[-FlameSize] <float>] [[-SparkGridHeight] <float>] [[-FlameModifier] <float>] [[-FlameTongueSize] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Invert] [-ApplyToImage] [-ReplaceImageColor] [-ApplyToSpecificColor] [-FullWidth] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSFisheyeXyShader + Get-OBSFire3Shader - CenterXPercent + ViewProj - Float + System.Single[][] - Float + System.Single[][] - CenterYPercent + Image - Float + String - Float + String - PowerX + ElapsedTime @@ -28196,381 +29308,189 @@ This can increase performance, and also silently ignore critical errors - PowerY + UvOffset - Float + System.Single[] - Float + System.Single[] - - SourceName + + UvScale - String + System.Single[] - String + System.Single[] - - FilterName + + UvPixelInterval - String + System.Single[] - String + System.Single[] - ShaderText + UvSize - String + System.Single[] - String + System.Single[] - - Force + + RandF - Switch + Float - Switch + Float - - PassThru + + RandInstanceF - Switch + Float - Switch + Float - - NoResponse + + RandActivationF - Switch + Float - Switch + Float - - UseShaderTime + + Loops - Switch + Int - Switch + Int - - - - - CenterXPercent - - - - - Float - - Float - - - - - - - CenterYPercent - - - - - Float - - Float - - - - - - - FilterName - - - - - String - - String - - - - - - - Force - - - - - Switch - - Switch - - - - - - - NoResponse - - - - - Switch - - Switch - - - - - - - PassThru - - - - - Switch - - Switch - - - - - - - PowerX - - - - - Float - - Float - - - - - - - PowerY - - - - - Float - - Float - - - - - - - ShaderText - - - - - String - - String - - - - - - - SourceName - - - - - String - - String - - - - - - - UseShaderTime - - - - - Switch - - Switch - - - - - - - - - - System.String - - - - - - - - - System.Object - - - - - - - - - Get-OBSFlipShader - OBSFlipShader - Get - - Get-OBSFlipShader [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Horizontal] [-Vertical] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - - 0.2.0.1 - - - - - - Get-OBSFlipShader - - Horizontal + + LocalTime - Switch + Float - Switch + Float - - Vertical + + MovementDirectionHorizontal - Switch + Float - Switch + Float - - SourceName + + MovementDirectionVertical - String + Float - String + Float - - FilterName + + AlphaPercentage - String + Int - String + Int - - ShaderText + + Speed - String + Int - String + Int - Force + Invert @@ -28583,36 +29503,36 @@ This can increase performance, and also silently ignore critical errors - - PassThru + + LumaMin - Switch + Float - Switch + Float - - NoResponse + + LumaMinSmooth - Switch + Float - Switch + Float - UseShaderTime + ApplyToImage @@ -28625,214 +29545,50 @@ This can increase performance, and also silently ignore critical errors - - - - - FilterName - - - - - String - - String - - - - - - - Force - - - - - Switch - - Switch - - - - - - - Horizontal - - - - - Switch - - Switch - - - - - - - NoResponse - - - - - Switch - - Switch - - - - - - - PassThru - - - - - Switch - - Switch - - - - - - - ShaderText - - - - - String - - String - - - - - - - SourceName - - - - - String - - String - - - - - - - UseShaderTime - - - - - Switch - - Switch - - - - - - - Vertical - - - - - Switch - - Switch - - - - - - - - - - System.String - - - - - - - - - System.Object - - - - - - - - - Get-OBSFrostedGlassShader - OBSFrostedGlassShader - Get - - Get-OBSFrostedGlassShader [[-AlphaPercent] <float>] [[-Amount] <float>] [[-Scale] <float>] [[-BorderOffset] <float>] [[-BorderColor] <string>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Animate] [-HorizontalBorder] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - - 0.2.0.1 - - - - - - Get-OBSFrostedGlassShader - - AlphaPercent + + ReplaceImageColor - Float + Switch - Float + Switch - - Amount + + ColorToReplace - Float + String - Float + String - - Scale + + ApplyToSpecificColor - Float + Switch - Float + Switch - Animate + FullWidth @@ -28845,22 +29601,22 @@ This can increase performance, and also silently ignore critical errors - - HorizontalBorder + + FlameSize - Switch + Float - Switch + Float - - BorderOffset + + SparkGridHeight @@ -28873,35 +29629,35 @@ This can increase performance, and also silently ignore critical errors - - BorderColor + + FlameModifier - String + Float - String + Float - - Notes + + FlameTongueSize - String + Float - String + Float - + SourceName @@ -28915,7 +29671,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -28929,7 +29685,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -29003,35 +29759,35 @@ This can increase performance, and also silently ignore critical errors - AlphaPercent + AlphaPercentage - Float + Int - Float + Int - Amount + ApplyToImage - Float + Switch - Float + Switch - Animate + ApplyToSpecificColor @@ -29045,7 +29801,7 @@ This can increase performance, and also silently ignore critical errors - BorderColor + ColorToReplace @@ -29059,7 +29815,7 @@ This can increase performance, and also silently ignore critical errors - BorderOffset + ElapsedTime @@ -29087,21 +29843,49 @@ This can increase performance, and also silently ignore critical errors - Force + FlameModifier - Switch + Float - Switch + Float - HorizontalBorder + FlameSize + + + + + Float + + Float + + + + + + + FlameTongueSize + + + + + Float + + Float + + + + + + + Force @@ -29115,7 +29899,7 @@ This can increase performance, and also silently ignore critical errors - NoResponse + FullWidth @@ -29129,7 +29913,7 @@ This can increase performance, and also silently ignore critical errors - Notes + Image @@ -29143,7 +29927,7 @@ This can increase performance, and also silently ignore critical errors - PassThru + Invert @@ -29157,7 +29941,7 @@ This can increase performance, and also silently ignore critical errors - Scale + LocalTime @@ -29171,241 +29955,63 @@ This can increase performance, and also silently ignore critical errors - ShaderText + Loops - String + Int - String + Int - SourceName + LumaMin - String + Float - String + Float - UseShaderTime + LumaMinSmooth - Switch + Float - Switch + Float - - - - - System.String - - - - - - - + + MovementDirectionHorizontal + + + + + Float - System.Object + Float - - - - - - - Get-OBSGammaCorrectionShader - OBSGammaCorrectionShader - Get - - Get-OBSGammaCorrectionShader [[-Red] <float>] [[-Green] <float>] [[-Blue] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - - 0.2.0.1 - - - - - - Get-OBSGammaCorrectionShader - - Red - - - - - Float - - Float - - - - - - - Green - - - - - Float - - Float - - - - - - - Blue - - - - - Float - - Float - - - - - - - Notes - - - - - String - - String - - - - - - - SourceName - - - - - String - - String - - - - - - - FilterName - - - - - String - - String - - - - - - - ShaderText - - - - - String - - String - - - - - - - Force - - - - - Switch - - Switch - - - - - - - PassThru - - - - - Switch - - Switch - - - - - - - NoResponse - - - - - Switch - - Switch - - - - - - - UseShaderTime - - - - - Switch - - Switch - - - - - - - - + + + - Blue + MovementDirectionVertical @@ -29419,21 +30025,21 @@ This can increase performance, and also silently ignore critical errors - FilterName + NoResponse - String + Switch - String + Switch - Force + PassThru @@ -29447,7 +30053,7 @@ This can increase performance, and also silently ignore critical errors - Green + RandActivationF @@ -29461,35 +30067,35 @@ This can increase performance, and also silently ignore critical errors - NoResponse + RandF - Switch + Float - Switch + Float - Notes + RandInstanceF - String + Float - String + Float - PassThru + ReplaceImageColor @@ -29503,21 +30109,21 @@ This can increase performance, and also silently ignore critical errors - Red + ShaderText - Float + String - Float + String - ShaderText + SourceName @@ -29531,14 +30137,28 @@ This can increase performance, and also silently ignore critical errors - SourceName + SparkGridHeight - String + Float - String + Float + + + + + + + Speed + + + + + Int + + Int @@ -29558,6 +30178,76 @@ This can increase performance, and also silently ignore critical errors + + UvOffset + + + + + System.Single[] + + System.Single[] + + + + + + + UvPixelInterval + + + + + System.Single[] + + System.Single[] + + + + + + + UvScale + + + + + System.Single[] + + System.Single[] + + + + + + + UvSize + + + + + System.Single[] + + System.Single[] + + + + + + + ViewProj + + + + + System.Single[][] + + System.Single[][] + + + + + @@ -29580,77 +30270,91 @@ This can increase performance, and also silently ignore critical errors - Get-OBSGaussianBlurAdvancedShader - OBSGaussianBlurAdvancedShader + Get-OBSFireShader + OBSFireShader Get - Get-OBSGaussianBlurAdvancedShader [[-Directions] <float>] [[-Quality] <float>] [[-Size] <float>] [[-MaskLeft] <float>] [[-MaskRight] <float>] [[-MaskTop] <float>] [[-MaskBottom] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSFireShader [[-AlphaPercentage] <int>] [[-Speed] <int>] [[-FlameSize] <int>] [[-FireType] <int>] [[-LumaMin] <float>] [[-LumaMinSmooth] <float>] [[-ColorToReplace] <string>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Invert] [-ApplyToImage] [-ReplaceImageColor] [-ApplyToSpecificColor] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSGaussianBlurAdvancedShader + Get-OBSFireShader - Directions + AlphaPercentage - Float + Int - Float + Int - Quality + Speed - Float + Int - Float + Int - Size + FlameSize - Float + Int - Float + Int - MaskLeft + FireType - Float + Int - Float + Int + + + + + + + Invert + + + + + Switch + + Switch - MaskRight + LumaMin @@ -29664,7 +30368,7 @@ This can increase performance, and also silently ignore critical errors - MaskTop + LumaMinSmooth @@ -29677,22 +30381,64 @@ This can increase performance, and also silently ignore critical errors + + ApplyToImage + + + + + Switch + + Switch + + + + + + + ReplaceImageColor + + + + + Switch + + Switch + + + + + + + ApplyToSpecificColor + + + + + Switch + + Switch + + + + + - MaskBottom + ColorToReplace - Float + String - Float + String - - SourceName + + Notes @@ -29706,6 +30452,20 @@ This can increase performance, and also silently ignore critical errors + SourceName + + + + + String + + String + + + + + + FilterName @@ -29719,7 +30479,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -29793,35 +30553,35 @@ This can increase performance, and also silently ignore critical errors - Directions + AlphaPercentage - Float + Int - Float + Int - FilterName + ApplyToImage - String + Switch - String + Switch - Force + ApplyToSpecificColor @@ -29835,63 +30595,63 @@ This can increase performance, and also silently ignore critical errors - MaskBottom + ColorToReplace - Float + String - Float + String - MaskLeft + FilterName - Float + String - Float + String - MaskRight + FireType - Float + Int - Float + Int - MaskTop + FlameSize - Float + Int - Float + Int - NoResponse + Force @@ -29905,7 +30665,7 @@ This can increase performance, and also silently ignore critical errors - PassThru + Invert @@ -29919,7 +30679,7 @@ This can increase performance, and also silently ignore critical errors - Quality + LumaMin @@ -29933,35 +30693,35 @@ This can increase performance, and also silently ignore critical errors - ShaderText + LumaMinSmooth - String + Float - String + Float - Size + NoResponse - Float + Switch - Float + Switch - SourceName + Notes @@ -29975,7 +30735,7 @@ This can increase performance, and also silently ignore critical errors - UseShaderTime + PassThru @@ -29988,9 +30748,79 @@ This can increase performance, and also silently ignore critical errors - - - + + ReplaceImageColor + + + + + Switch + + Switch + + + + + + + ShaderText + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + Speed + + + + + Int + + Int + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + System.String @@ -30010,35 +30840,35 @@ This can increase performance, and also silently ignore critical errors - Get-OBSGaussianBlurShader - OBSGaussianBlurShader + Get-OBSFireworks2Shader + OBSFireworks2Shader Get - Get-OBSGaussianBlurShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ImageSize] <float[]>] [[-ImageTexel] <float[]>] [[-URadius] <int>] [[-UDiameter] <int>] [[-UTexelDelta] <float[]>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-Kernel] <string>] [[-KernelTexel] <float[]>] [[-PixelSize] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSFireworks2Shader [[-Speed] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSGaussianBlurShader + Get-OBSFireworks2Shader - ViewProj + Speed - System.Single[][] + Float - System.Single[][] + Float - - Image + + SourceName @@ -30051,175 +30881,283 @@ This can increase performance, and also silently ignore critical errors - - ImageSize + + FilterName - System.Single[] + String - System.Single[] + String - ImageTexel - - - - - System.Single[] - - System.Single[] - - - - - - - URadius - - - - - Int - - Int - - - - - - - UDiameter - - - - - Int - - Int - - - - - - - UTexelDelta + ShaderText - System.Single[] + String - System.Single[] + String - - ElapsedTime + + Force - Float + Switch - Float + Switch - - UvOffset + + PassThru - System.Single[] + Switch - System.Single[] + Switch - - UvScale + + NoResponse - System.Single[] + Switch - System.Single[] + Switch - - UvPixelInterval + + UseShaderTime - System.Single[] + Switch - System.Single[] + Switch - - Kernel + + + + + FilterName + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + ShaderText + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + Speed + + + + + Float + + Float + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + + + + Get-OBSFireworksShader + OBSFireworksShader + Get + + Get-OBSFireworksShader [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ShowFlash] [-ShowStars] [-UseTransparancy] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSFireworksShader + + ShowFlash - String + Switch - String + Switch - - KernelTexel + + ShowStars - System.Single[] + Switch - System.Single[] + Switch - - PixelSize + + UseTransparancy - Float + Switch - Float + Switch - + SourceName @@ -30233,7 +31171,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -30247,7 +31185,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -30320,20 +31258,6 @@ This can increase performance, and also silently ignore critical errors - - ElapsedTime - - - - - Float - - Float - - - - - FilterName @@ -30362,76 +31286,6 @@ This can increase performance, and also silently ignore critical errors - - Image - - - - - String - - String - - - - - - - ImageSize - - - - - System.Single[] - - System.Single[] - - - - - - - ImageTexel - - - - - System.Single[] - - System.Single[] - - - - - - - Kernel - - - - - String - - String - - - - - - - KernelTexel - - - - - System.Single[] - - System.Single[] - - - - - NoResponse @@ -30460,20 +31314,6 @@ This can increase performance, and also silently ignore critical errors - - PixelSize - - - - - Float - - Float - - - - - ShaderText @@ -30489,42 +31329,42 @@ This can increase performance, and also silently ignore critical errors - SourceName + ShowFlash - String + Switch - String + Switch - UDiameter + ShowStars - Int + Switch - Int + Switch - URadius + SourceName - Int + String - Int + String @@ -30545,140 +31385,56 @@ This can increase performance, and also silently ignore critical errors - UTexelDelta + UseTransparancy - System.Single[] + Switch - System.Single[] + Switch - - UvOffset - - - - - System.Single[] + + + - System.Single[] + System.String + - - - - - UvPixelInterval - - - - - System.Single[] + + + + - System.Single[] + System.Object - - - - - - UvScale - - - - - System.Single[] - - System.Single[] - - - - - - - ViewProj - - - - - System.Single[][] - - System.Single[][] - - - - - - - - - - System.String - - - - - - - - - System.Object - - + - Get-OBSGaussianBlurSimpleShader - OBSGaussianBlurSimpleShader + Get-OBSFisheyeShader + OBSFisheyeShader Get - Get-OBSGaussianBlurSimpleShader [[-Strength] <int>] [[-MaskLeft] <float>] [[-MaskRight] <float>] [[-MaskTop] <float>] [[-MaskBottom] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSFisheyeShader [[-CenterXPercent] <float>] [[-CenterYPercent] <float>] [[-Power] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSGaussianBlurSimpleShader + Get-OBSFisheyeShader - Strength - - - - - Int - - Int - - - - - - - MaskLeft - - - - - Float - - Float - - - - - - - MaskRight + CenterXPercent @@ -30691,8 +31447,8 @@ This can increase performance, and also silently ignore critical errors - - MaskTop + + CenterYPercent @@ -30705,8 +31461,8 @@ This can increase performance, and also silently ignore critical errors - - MaskBottom + + Power @@ -30719,7 +31475,7 @@ This can increase performance, and also silently ignore critical errors - + SourceName @@ -30733,7 +31489,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -30747,7 +31503,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -30821,35 +31577,7 @@ This can increase performance, and also silently ignore critical errors - FilterName - - - - - String - - String - - - - - - - Force - - - - - Switch - - Switch - - - - - - - MaskBottom + CenterXPercent @@ -30863,7 +31591,7 @@ This can increase performance, and also silently ignore critical errors - MaskLeft + CenterYPercent @@ -30877,28 +31605,28 @@ This can increase performance, and also silently ignore critical errors - MaskRight + FilterName - Float + String - Float + String - MaskTop + Force - Float + Switch - Float + Switch @@ -30933,21 +31661,21 @@ This can increase performance, and also silently ignore critical errors - ShaderText + Power - String + Float - String + Float - SourceName + ShaderText @@ -30961,14 +31689,14 @@ This can increase performance, and also silently ignore critical errors - Strength + SourceName - Int + String - Int + String @@ -31010,49 +31738,35 @@ This can increase performance, and also silently ignore critical errors - Get-OBSGaussianExampleShader - OBSGaussianExampleShader + Get-OBSFisheyeXyShader + OBSFisheyeXyShader Get - Get-OBSGaussianExampleShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvSize] <float[]>] [[-UvPixelInterval] <float[]>] [[-InitialImage] <string>] [[-BeforeImage] <string>] [[-AfterImage] <string>] [[-TextColor] <string>] [[-MaxDistance] <float>] [[-Exp] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSFisheyeXyShader [[-CenterXPercent] <float>] [[-CenterYPercent] <float>] [[-PowerX] <float>] [[-PowerY] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSGaussianExampleShader + Get-OBSFisheyeXyShader - ViewProj + CenterXPercent - System.Single[][] + Float - System.Single[][] + Float - Image - - - - - String - - String - - - - - - - ElapsedTime + CenterYPercent @@ -31065,120 +31779,8 @@ This can increase performance, and also silently ignore critical errors - - UvOffset - - - - - System.Single[] - - System.Single[] - - - - - - - UvScale - - - - - System.Single[] - - System.Single[] - - - - - - - UvSize - - - - - System.Single[] - - System.Single[] - - - - - - - UvPixelInterval - - - - - System.Single[] - - System.Single[] - - - - - - - InitialImage - - - - - String - - String - - - - - - - BeforeImage - - - - - String - - String - - - - - - - AfterImage - - - - - String - - String - - - - - - - TextColor - - - - - String - - String - - - - - - - MaxDistance + + PowerX @@ -31191,8 +31793,8 @@ This can increase performance, and also silently ignore critical errors - - Exp + + PowerY @@ -31205,7 +31807,7 @@ This can increase performance, and also silently ignore critical errors - + SourceName @@ -31219,7 +31821,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -31233,7 +31835,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -31307,35 +31909,7 @@ This can increase performance, and also silently ignore critical errors - AfterImage - - - - - String - - String - - - - - - - BeforeImage - - - - - String - - String - - - - - - - ElapsedTime + CenterXPercent @@ -31349,7 +31923,7 @@ This can increase performance, and also silently ignore critical errors - Exp + CenterYPercent @@ -31391,35 +31965,35 @@ This can increase performance, and also silently ignore critical errors - Image + NoResponse - String + Switch - String + Switch - InitialImage + PassThru - String + Switch - String + Switch - MaxDistance + PowerX @@ -31433,28 +32007,14 @@ This can increase performance, and also silently ignore critical errors - NoResponse - - - - - Switch - - Switch - - - - - - - PassThru + PowerY - Switch + Float - Switch + Float @@ -31488,20 +32048,6 @@ This can increase performance, and also silently ignore critical errors - - TextColor - - - - - String - - String - - - - - UseShaderTime @@ -31516,76 +32062,6 @@ This can increase performance, and also silently ignore critical errors - - UvOffset - - - - - System.Single[] - - System.Single[] - - - - - - - UvPixelInterval - - - - - System.Single[] - - System.Single[] - - - - - - - UvScale - - - - - System.Single[] - - System.Single[] - - - - - - - UvSize - - - - - System.Single[] - - System.Single[] - - - - - - - ViewProj - - - - - System.Single[][] - - System.Single[][] - - - - - @@ -31608,266 +32084,98 @@ This can increase performance, and also silently ignore critical errors - Get-OBSGaussianSimpleShader - OBSGaussianSimpleShader + Get-OBSFlipShader + OBSFlipShader Get - Get-OBSGaussianSimpleShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-UvSize] <float[]>] [[-RandF] <float>] [[-RandInstanceF] <float>] [[-RandActivationF] <float>] [[-Loops] <int>] [[-LocalTime] <float>] [[-Samples] <int>] [[-LOD] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSFlipShader [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Horizontal] [-Vertical] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSGaussianSimpleShader - - ViewProj + Get-OBSFlipShader + + Horizontal - System.Single[][] + Switch - System.Single[][] + Switch - - Image + + Vertical - String + Switch - String + Switch - - ElapsedTime + + SourceName - Float + String - Float + String - - UvOffset + + FilterName - System.Single[] + String - System.Single[] + String - - UvScale + + ShaderText - System.Single[] + String - System.Single[] + String - - UvPixelInterval + + Force - System.Single[] + Switch - System.Single[] - - - - - - - UvSize - - - - - System.Single[] - - System.Single[] - - - - - - - RandF - - - - - Float - - Float - - - - - - - RandInstanceF - - - - - Float - - Float - - - - - - - RandActivationF - - - - - Float - - Float - - - - - - - Loops - - - - - Int - - Int - - - - - - - LocalTime - - - - - Float - - Float - - - - - - - Samples - - - - - Int - - Int - - - - - - - LOD - - - - - Int - - Int - - - - - - - SourceName - - - - - String - - String - - - - - - - FilterName - - - - - String - - String - - - - - - - ShaderText - - - - - String - - String - - - - - - - Force - - - - - Switch - - Switch + Switch @@ -31918,20 +32226,6 @@ This can increase performance, and also silently ignore critical errors - - ElapsedTime - - - - - Float - - Float - - - - - FilterName @@ -31961,56 +32255,14 @@ This can increase performance, and also silently ignore critical errors - Image - - - - - String - - String - - - - - - - LocalTime - - - - - Float - - Float - - - - - - - LOD - - - - - Int - - Int - - - - - - - Loops + Horizontal - Int + Switch - Int + Switch @@ -32044,62 +32296,6 @@ This can increase performance, and also silently ignore critical errors - - RandActivationF - - - - - Float - - Float - - - - - - - RandF - - - - - Float - - Float - - - - - - - RandInstanceF - - - - - Float - - Float - - - - - - - Samples - - - - - Int - - Int - - - - - ShaderText @@ -32143,70 +32339,14 @@ This can increase performance, and also silently ignore critical errors - UvOffset - - - - - System.Single[] - - System.Single[] - - - - - - - UvPixelInterval - - - - - System.Single[] - - System.Single[] - - - - - - - UvScale - - - - - System.Single[] - - System.Single[] - - - - - - - UvSize - - - - - System.Single[] - - System.Single[] - - - - - - - ViewProj + Vertical - System.Single[][] + Switch - System.Single[][] + Switch @@ -32234,21 +32374,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBSGbCameraShader - OBSGbCameraShader + Get-OBSFrostedGlassShader + OBSFrostedGlassShader Get - Get-OBSGbCameraShader [[-PixelSize] <float>] [[-DitherFactor] <float>] [[-Brightness] <float>] [[-Contrast] <float>] [[-Gamma] <float>] [[-Color1] <string>] [[-Color2] <string>] [[-Color3] <string>] [[-Color4] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-AlternativeBayer] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSFrostedGlassShader [[-AlphaPercent] <float>] [[-Amount] <float>] [[-Scale] <float>] [[-BorderOffset] <float>] [[-BorderColor] <string>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Animate] [-HorizontalBorder] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSGbCameraShader + Get-OBSFrostedGlassShader - PixelSize + AlphaPercent @@ -32262,7 +32402,7 @@ This can increase performance, and also silently ignore critical errors - DitherFactor + Amount @@ -32275,36 +32415,8 @@ This can increase performance, and also silently ignore critical errors - - AlternativeBayer - - - - - Switch - - Switch - - - - - - Brightness - - - - - Float - - Float - - - - - - - Contrast + Scale @@ -32317,50 +32429,50 @@ This can increase performance, and also silently ignore critical errors - - Gamma + + Animate - Float + Switch - Float + Switch - - Color1 + + HorizontalBorder - String + Switch - String + Switch - - Color2 + + BorderOffset - String + Float - String + Float - - Color3 + + BorderColor @@ -32373,8 +32485,8 @@ This can increase performance, and also silently ignore critical errors - - Color4 + + Notes @@ -32387,7 +32499,7 @@ This can increase performance, and also silently ignore critical errors - + SourceName @@ -32401,7 +32513,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -32415,7 +32527,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -32489,21 +32601,7 @@ This can increase performance, and also silently ignore critical errors - AlternativeBayer - - - - - Switch - - Switch - - - - - - - Brightness + AlphaPercent @@ -32517,49 +32615,35 @@ This can increase performance, and also silently ignore critical errors - Color1 - - - - - String - - String - - - - - - - Color2 + Amount - String + Float - String + Float - Color3 + Animate - String + Switch - String + Switch - Color4 + BorderColor @@ -32573,7 +32657,7 @@ This can increase performance, and also silently ignore critical errors - Contrast + BorderOffset @@ -32587,35 +32671,35 @@ This can increase performance, and also silently ignore critical errors - DitherFactor + FilterName - Float + String - Float + String - FilterName + Force - String + Switch - String + Switch - Force + HorizontalBorder @@ -32629,28 +32713,28 @@ This can increase performance, and also silently ignore critical errors - Gamma + NoResponse - Float + Switch - Float + Switch - NoResponse + Notes - Switch + String - Switch + String @@ -32671,7 +32755,7 @@ This can increase performance, and also silently ignore critical errors - PixelSize + Scale @@ -32748,21 +32832,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBSGlassShader - OBSGlassShader + Get-OBSGammaCorrectionShader + OBSGammaCorrectionShader Get - Get-OBSGlassShader [[-AlphaPercent] <float>] [[-OffsetAmount] <float>] [[-XSize] <int>] [[-YSize] <int>] [[-ReflectionOffset] <int>] [[-BorderOffset] <float>] [[-BorderColor] <string>] [[-GlassColor] <string>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-HorizontalBorder] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSGammaCorrectionShader [[-Red] <float>] [[-Green] <float>] [[-Blue] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSGlassShader + Get-OBSGammaCorrectionShader - AlphaPercent + Red @@ -32776,7 +32860,7 @@ This can increase performance, and also silently ignore critical errors - OffsetAmount + Green @@ -32790,63 +32874,7 @@ This can increase performance, and also silently ignore critical errors - XSize - - - - - Int - - Int - - - - - - - YSize - - - - - Int - - Int - - - - - - - ReflectionOffset - - - - - Int - - Int - - - - - - - HorizontalBorder - - - - - Switch - - Switch - - - - - - - BorderOffset + Blue @@ -32859,35 +32887,7 @@ This can increase performance, and also silently ignore critical errors - - BorderColor - - - - - String - - String - - - - - - - GlassColor - - - - - String - - String - - - - - - + Notes @@ -32901,7 +32901,7 @@ This can increase performance, and also silently ignore critical errors - + SourceName @@ -32915,7 +32915,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -32929,7 +32929,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -33003,35 +33003,7 @@ This can increase performance, and also silently ignore critical errors - AlphaPercent - - - - - Float - - Float - - - - - - - BorderColor - - - - - String - - String - - - - - - - BorderOffset + Blue @@ -33073,28 +33045,14 @@ This can increase performance, and also silently ignore critical errors - GlassColor - - - - - String - - String - - - - - - - HorizontalBorder + Green - Switch + Float - Switch + Float @@ -33128,20 +33086,6 @@ This can increase performance, and also silently ignore critical errors - - OffsetAmount - - - - - Float - - Float - - - - - PassThru @@ -33157,14 +33101,14 @@ This can increase performance, and also silently ignore critical errors - ReflectionOffset + Red - Int + Float - Int + Float @@ -33212,34 +33156,6 @@ This can increase performance, and also silently ignore critical errors - - XSize - - - - - Int - - Int - - - - - - - YSize - - - - - Int - - Int - - - - - @@ -33262,21 +33178,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBSGlitchAnalogShader - OBSGlitchAnalogShader + Get-OBSGaussianBlurAdvancedShader + OBSGaussianBlurAdvancedShader Get - Get-OBSGlitchAnalogShader [[-ScanLineJitterDisplacement] <float>] [[-ScanLineJitterThresholdPercent] <int>] [[-VerticalJumpAmount] <float>] [[-VerticalSpeed] <float>] [[-HorizontalShake] <float>] [[-ColorDriftAmount] <float>] [[-ColorDriftSpeed] <float>] [[-PulseSpeedPercent] <int>] [[-AlphaPercent] <int>] [[-ColorToReplace] <string>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-RotateColors] [-ApplyToAlphaLayer] [-ReplaceImageColor] [-ApplyToSpecificColor] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSGaussianBlurAdvancedShader [[-Directions] <float>] [[-Quality] <float>] [[-Size] <float>] [[-MaskLeft] <float>] [[-MaskRight] <float>] [[-MaskTop] <float>] [[-MaskBottom] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSGlitchAnalogShader + Get-OBSGaussianBlurAdvancedShader - ScanLineJitterDisplacement + Directions @@ -33290,21 +33206,21 @@ This can increase performance, and also silently ignore critical errors - ScanLineJitterThresholdPercent + Quality - Int + Float - Int + Float - VerticalJumpAmount + Size @@ -33318,7 +33234,7 @@ This can increase performance, and also silently ignore critical errors - VerticalSpeed + MaskLeft @@ -33332,7 +33248,7 @@ This can increase performance, and also silently ignore critical errors - HorizontalShake + MaskRight @@ -33346,7 +33262,7 @@ This can increase performance, and also silently ignore critical errors - ColorDriftAmount + MaskTop @@ -33360,7 +33276,7 @@ This can increase performance, and also silently ignore critical errors - ColorDriftSpeed + MaskBottom @@ -33373,119 +33289,7 @@ This can increase performance, and also silently ignore critical errors - - PulseSpeedPercent - - - - - Int - - Int - - - - - - - AlphaPercent - - - - - Int - - Int - - - - - - - RotateColors - - - - - Switch - - Switch - - - - - - - ApplyToAlphaLayer - - - - - Switch - - Switch - - - - - - - ReplaceImageColor - - - - - Switch - - Switch - - - - - - - ApplyToSpecificColor - - - - - Switch - - Switch - - - - - - - ColorToReplace - - - - - String - - String - - - - - - - Notes - - - - - String - - String - - - - - - + SourceName @@ -33499,7 +33303,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -33513,7 +33317,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -33587,63 +33391,7 @@ This can increase performance, and also silently ignore critical errors - AlphaPercent - - - - - Int - - Int - - - - - - - ApplyToAlphaLayer - - - - - Switch - - Switch - - - - - - - ApplyToSpecificColor - - - - - Switch - - Switch - - - - - - - ColorDriftAmount - - - - - Float - - Float - - - - - - - ColorDriftSpeed + Directions @@ -33656,20 +33404,6 @@ This can increase performance, and also silently ignore critical errors - - ColorToReplace - - - - - String - - String - - - - - FilterName @@ -33699,7 +33433,7 @@ This can increase performance, and also silently ignore critical errors - HorizontalShake + MaskBottom @@ -33713,63 +33447,49 @@ This can increase performance, and also silently ignore critical errors - NoResponse - - - - - Switch - - Switch - - - - - - - Notes + MaskLeft - String + Float - String + Float - PassThru + MaskRight - Switch + Float - Switch + Float - PulseSpeedPercent + MaskTop - Int + Float - Int + Float - ReplaceImageColor + NoResponse @@ -33783,7 +33503,7 @@ This can increase performance, and also silently ignore critical errors - RotateColors + PassThru @@ -33797,7 +33517,7 @@ This can increase performance, and also silently ignore critical errors - ScanLineJitterDisplacement + Quality @@ -33811,28 +33531,28 @@ This can increase performance, and also silently ignore critical errors - ScanLineJitterThresholdPercent + ShaderText - Int + String - Int + String - ShaderText + Size - String + Float - String + Float @@ -33866,34 +33586,6 @@ This can increase performance, and also silently ignore critical errors - - VerticalJumpAmount - - - - - Float - - Float - - - - - - - VerticalSpeed - - - - - Float - - Float - - - - - @@ -33916,50 +33608,176 @@ This can increase performance, and also silently ignore critical errors - Get-OBSGlitchShader - OBSGlitchShader + Get-OBSGaussianBlurShader + OBSGaussianBlurShader Get - Get-OBSGlitchShader [[-AMT] <float>] [[-SPEED] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSGaussianBlurShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ImageSize] <float[]>] [[-ImageTexel] <float[]>] [[-URadius] <int>] [[-UDiameter] <int>] [[-UTexelDelta] <float[]>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-Kernel] <string>] [[-KernelTexel] <float[]>] [[-PixelSize] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSGlitchShader + Get-OBSGaussianBlurShader - AMT + ViewProj - Float + System.Single[][] - Float + System.Single[][] - SPEED + Image - Float + String - Float + String - - SourceName - + + ImageSize + + + + + System.Single[] + + System.Single[] + + + + + + + ImageTexel + + + + + System.Single[] + + System.Single[] + + + + + + + URadius + + + + + Int + + Int + + + + + + + UDiameter + + + + + Int + + Int + + + + + + + UTexelDelta + + + + + System.Single[] + + System.Single[] + + + + + + + ElapsedTime + + + + + Float + + Float + + + + + + + UvOffset + + + + + System.Single[] + + System.Single[] + + + + + + + UvScale + + + + + System.Single[] + + System.Single[] + + + + + + + UvPixelInterval + + + + + System.Single[] + + System.Single[] + + + + + + + Kernel + @@ -33971,7 +33789,49 @@ This can increase performance, and also silently ignore critical errors - + + KernelTexel + + + + + System.Single[] + + System.Single[] + + + + + + + PixelSize + + + + + Float + + Float + + + + + + + SourceName + + + + + String + + String + + + + + + FilterName @@ -33985,7 +33845,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -34059,7 +33919,7 @@ This can increase performance, and also silently ignore critical errors - AMT + ElapsedTime @@ -34100,6 +33960,76 @@ This can increase performance, and also silently ignore critical errors + + Image + + + + + String + + String + + + + + + + ImageSize + + + + + System.Single[] + + System.Single[] + + + + + + + ImageTexel + + + + + System.Single[] + + System.Single[] + + + + + + + Kernel + + + + + String + + String + + + + + + + KernelTexel + + + + + System.Single[] + + System.Single[] + + + + + NoResponse @@ -34128,6 +34058,20 @@ This can increase performance, and also silently ignore critical errors + + PixelSize + + + + + Float + + Float + + + + + ShaderText @@ -34157,14 +34101,28 @@ This can increase performance, and also silently ignore critical errors - SPEED + UDiameter - Float + Int - Float + Int + + + + + + + URadius + + + + + Int + + Int @@ -34184,6 +34142,76 @@ This can increase performance, and also silently ignore critical errors + + UTexelDelta + + + + + System.Single[] + + System.Single[] + + + + + + + UvOffset + + + + + System.Single[] + + System.Single[] + + + + + + + UvPixelInterval + + + + + System.Single[] + + System.Single[] + + + + + + + UvScale + + + + + System.Single[] + + System.Single[] + + + + + + + ViewProj + + + + + System.Single[][] + + System.Single[][] + + + + + @@ -34206,21 +34234,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBSGlowShader - OBSGlowShader + Get-OBSGaussianBlurSimpleShader + OBSGaussianBlurSimpleShader Get - Get-OBSGlowShader [[-GlowPercent] <int>] [[-Blur] <int>] [[-MinBrightness] <int>] [[-MaxBrightness] <int>] [[-PulseSpeed] <int>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Ease] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSGaussianBlurSimpleShader [[-Strength] <int>] [[-MaskLeft] <float>] [[-MaskRight] <float>] [[-MaskTop] <float>] [[-MaskBottom] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSGlowShader + Get-OBSGaussianBlurSimpleShader - GlowPercent + Strength @@ -34234,90 +34262,62 @@ This can increase performance, and also silently ignore critical errors - Blur + MaskLeft - Int + Float - Int + Float - MinBrightness + MaskRight - Int + Float - Int + Float - MaxBrightness + MaskTop - Int + Float - Int + Float - PulseSpeed - - - - - Int - - Int - - - - - - - Ease - - - - - Switch - - Switch - - - - - - - Notes + MaskBottom - String + Float - String + Float - + SourceName @@ -34331,7 +34331,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -34345,7 +34345,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -34418,34 +34418,6 @@ This can increase performance, and also silently ignore critical errors - - Blur - - - - - Int - - Int - - - - - - - Ease - - - - - Switch - - Switch - - - - - FilterName @@ -34475,70 +34447,70 @@ This can increase performance, and also silently ignore critical errors - GlowPercent + MaskBottom - Int + Float - Int + Float - MaxBrightness + MaskLeft - Int + Float - Int + Float - MinBrightness + MaskRight - Int + Float - Int + Float - NoResponse + MaskTop - Switch + Float - Switch + Float - Notes + NoResponse - String + Switch - String + Switch @@ -34559,21 +34531,21 @@ This can increase performance, and also silently ignore critical errors - PulseSpeed + ShaderText - Int + String - Int + String - ShaderText + SourceName @@ -34587,14 +34559,14 @@ This can increase performance, and also silently ignore critical errors - SourceName + Strength - String + Int - String + Int @@ -34636,189 +34608,133 @@ This can increase performance, and also silently ignore critical errors - Get-OBSGradientShader - OBSGradientShader + Get-OBSGaussianExampleShader + OBSGaussianExampleShader Get - Get-OBSGradientShader [[-StartColor] <string>] [[-StartStep] <float>] [[-MiddleColor] <string>] [[-MiddleStep] <float>] [[-EndColor] <string>] [[-EndStep] <float>] [[-AlphaPercent] <int>] [[-PulseSpeed] <int>] [[-ColorToReplace] <string>] [[-GradientCenterWidthPercentage] <int>] [[-GradientCenterHeightPercentage] <int>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Ease] [-RotateColors] [-ApplyToAlphaLayer] [-ApplyToSpecificColor] [-Horizontal] [-Vertical] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSGaussianExampleShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvSize] <float[]>] [[-UvPixelInterval] <float[]>] [[-InitialImage] <string>] [[-BeforeImage] <string>] [[-AfterImage] <string>] [[-TextColor] <string>] [[-MaxDistance] <float>] [[-Exp] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSGradientShader + Get-OBSGaussianExampleShader - StartColor + ViewProj - String + System.Single[][] - String + System.Single[][] - StartStep + Image - Float + String - Float + String - MiddleColor + ElapsedTime - String + Float - String + Float - MiddleStep + UvOffset - Float + System.Single[] - Float + System.Single[] - EndColor + UvScale - String + System.Single[] - String + System.Single[] - EndStep + UvSize - Float + System.Single[] - Float + System.Single[] - AlphaPercent + UvPixelInterval - Int + System.Single[] - Int + System.Single[] - PulseSpeed - - - - - Int - - Int - - - - - - - Ease - - - - - Switch - - Switch - - - - - - - RotateColors - - - - - Switch - - Switch - - - - - - - ApplyToAlphaLayer - - - - - Switch - - Switch - - - - - - - ApplyToSpecificColor + InitialImage - Switch + String - Switch + String - ColorToReplace + BeforeImage @@ -34831,77 +34747,63 @@ This can increase performance, and also silently ignore critical errors - - Horizontal - - - - - Switch - - Switch - - - - - - - Vertical + + AfterImage - Switch + String - Switch + String - - GradientCenterWidthPercentage + + TextColor - Int + String - Int + String - - GradientCenterHeightPercentage + + MaxDistance - Int + Float - Int + Float - - Notes + + Exp - String + Float - String + Float - + SourceName @@ -34915,7 +34817,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -34929,7 +34831,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -35003,49 +34905,7 @@ This can increase performance, and also silently ignore critical errors - AlphaPercent - - - - - Int - - Int - - - - - - - ApplyToAlphaLayer - - - - - Switch - - Switch - - - - - - - ApplyToSpecificColor - - - - - Switch - - Switch - - - - - - - ColorToReplace + AfterImage @@ -35059,35 +34919,35 @@ This can increase performance, and also silently ignore critical errors - Ease + BeforeImage - Switch + String - Switch + String - EndColor + ElapsedTime - String + Float - String + Float - EndStep + Exp @@ -35129,49 +34989,21 @@ This can increase performance, and also silently ignore critical errors - GradientCenterHeightPercentage - - - - - Int - - Int - - - - - - - GradientCenterWidthPercentage - - - - - Int - - Int - - - - - - - Horizontal + Image - Switch + String - Switch + String - MiddleColor + InitialImage @@ -35185,7 +35017,7 @@ This can increase performance, and also silently ignore critical errors - MiddleStep + MaxDistance @@ -35213,140 +35045,140 @@ This can increase performance, and also silently ignore critical errors - Notes + PassThru - String + Switch - String + Switch - PassThru + ShaderText - Switch + String - Switch + String - PulseSpeed + SourceName - Int + String - Int + String - RotateColors + TextColor - Switch + String - Switch + String - ShaderText + UseShaderTime - String + Switch - String + Switch - SourceName + UvOffset - String + System.Single[] - String + System.Single[] - StartColor + UvPixelInterval - String + System.Single[] - String + System.Single[] - StartStep + UvScale - Float + System.Single[] - Float + System.Single[] - UseShaderTime + UvSize - Switch + System.Single[] - Switch + System.Single[] - Vertical + ViewProj - Switch + System.Single[][] - Switch + System.Single[][] @@ -35374,253 +35206,119 @@ This can increase performance, and also silently ignore critical errors - Get-OBSGroup - OBSGroup + Get-OBSGaussianSimpleShader + OBSGaussianSimpleShader Get - Get-OBSGroup : GetGroupList + Get-OBSGaussianSimpleShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-UvSize] <float[]>] [[-RandF] <float>] [[-RandInstanceF] <float>] [[-RandActivationF] <float>] [[-Loops] <int>] [[-LocalTime] <float>] [[-Samples] <int>] [[-LOD] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Gets an array of all groups in OBS. - Groups in OBS are actually scenes, but renamed and modified. In obs-websocket, we treat them as scenes where we can. - Get-OBSGroup calls the OBS WebSocket with a request of type GetGroupList. - Get-OBSGroup - - PassThru + Get-OBSGaussianSimpleShader + + ViewProj - If set, will return the information that would otherwise be sent to OBS. + + - Switch + System.Single[][] - Switch + System.Single[][] - - NoResponse + + Image - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + - Switch + String - Switch + String - - - - - NoResponse - - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors - - Switch - - Switch - - - - - - - PassThru - - If set, will return the information that would otherwise be sent to OBS. - - Switch - - Switch - - - - - - - - - -------------------------- EXAMPLE 1 -------------------------- - - PS > - - Get-OBSGroup - - - - - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getgrouplist - - - - - - Get-OBSGroupSceneItem - OBSGroupSceneItem - Get - - Get-OBSGroupSceneItem : GetGroupSceneItemList - - 0.2.0.1 - - - Basically GetSceneItemList, but for groups. - Using groups at all in OBS is discouraged, as they are very broken under the hood. Please use nested scenes instead. - Groups only - Get-OBSGroupSceneItem calls the OBS WebSocket with a request of type GetGroupSceneItemList. - - - - Get-OBSGroupSceneItem - - SceneName + + ElapsedTime - Name of the group to get the items of + + - String + Float - String + Float - - SceneUuid + + UvOffset - UUID of the group to get the items of + + - String + System.Single[] - String + System.Single[] - - PassThru + + UvScale - If set, will return the information that would otherwise be sent to OBS. + + - Switch + System.Single[] - Switch + System.Single[] - - NoResponse + + UvPixelInterval - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + - Switch + System.Single[] - Switch + System.Single[] - - - - - NoResponse - - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors - - Switch - - Switch - - - - - - - PassThru - - If set, will return the information that would otherwise be sent to OBS. - - Switch - - Switch - - - - - - - SceneName - - Name of the group to get the items of - - String - - String - - - - - - - SceneUuid - - UUID of the group to get the items of - - String - - String - - - - - - - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getgroupsceneitemlist - - - - - - Get-OBSHalftoneShader - OBSHalftoneShader - Get - - Get-OBSHalftoneShader [[-Threshold] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - - 0.2.0.1 - - - - - - Get-OBSHalftoneShader - - Threshold + + UvSize + + + + + System.Single[] + + System.Single[] + + + + + + + RandF @@ -35633,7 +35331,91 @@ This can increase performance, and also silently ignore critical errors - + + RandInstanceF + + + + + Float + + Float + + + + + + + RandActivationF + + + + + Float + + Float + + + + + + + Loops + + + + + Int + + Int + + + + + + + LocalTime + + + + + Float + + Float + + + + + + + Samples + + + + + Int + + Int + + + + + + + LOD + + + + + Int + + Int + + + + + + SourceName @@ -35647,7 +35429,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -35661,7 +35443,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -35734,6 +35516,20 @@ This can increase performance, and also silently ignore critical errors + + ElapsedTime + + + + + Float + + Float + + + + + FilterName @@ -35762,6 +35558,62 @@ This can increase performance, and also silently ignore critical errors + + Image + + + + + String + + String + + + + + + + LocalTime + + + + + Float + + Float + + + + + + + LOD + + + + + Int + + Int + + + + + + + Loops + + + + + Int + + Int + + + + + NoResponse @@ -35790,6 +35642,62 @@ This can increase performance, and also silently ignore critical errors + + RandActivationF + + + + + Float + + Float + + + + + + + RandF + + + + + Float + + Float + + + + + + + RandInstanceF + + + + + Float + + Float + + + + + + + Samples + + + + + Int + + Int + + + + + ShaderText @@ -35819,28 +35727,84 @@ This can increase performance, and also silently ignore critical errors - Threshold + UseShaderTime - Float + Switch - Float + Switch - UseShaderTime + UvOffset - Switch + System.Single[] - Switch + System.Single[] + + + + + + + UvPixelInterval + + + + + System.Single[] + + System.Single[] + + + + + + + UvScale + + + + + System.Single[] + + System.Single[] + + + + + + + UvSize + + + + + System.Single[] + + System.Single[] + + + + + + + ViewProj + + + + + System.Single[][] + + System.Single[][] @@ -35868,21 +35832,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBSHeatWaveSimpleShader - OBSHeatWaveSimpleShader + Get-OBSGbCameraShader + OBSGbCameraShader Get - Get-OBSHeatWaveSimpleShader [[-Rate] <float>] [[-Strength] <float>] [[-Distortion] <float>] [[-Opacity] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSGbCameraShader [[-PixelSize] <float>] [[-DitherFactor] <float>] [[-Brightness] <float>] [[-Contrast] <float>] [[-Gamma] <float>] [[-Color1] <string>] [[-Color2] <string>] [[-Color3] <string>] [[-Color4] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-AlternativeBayer] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSHeatWaveSimpleShader + Get-OBSGbCameraShader - Rate + PixelSize @@ -35896,7 +35860,7 @@ This can increase performance, and also silently ignore critical errors - Strength + DitherFactor @@ -35909,8 +35873,22 @@ This can increase performance, and also silently ignore critical errors + + AlternativeBayer + + + + + Switch + + Switch + + + + + - Distortion + Brightness @@ -35924,7 +35902,7 @@ This can increase performance, and also silently ignore critical errors - Opacity + Contrast @@ -35937,7 +35915,77 @@ This can increase performance, and also silently ignore critical errors - + + Gamma + + + + + Float + + Float + + + + + + + Color1 + + + + + String + + String + + + + + + + Color2 + + + + + String + + String + + + + + + + Color3 + + + + + String + + String + + + + + + + Color4 + + + + + String + + String + + + + + + SourceName @@ -35951,7 +35999,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -35965,7 +36013,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -36039,7 +36087,21 @@ This can increase performance, and also silently ignore critical errors - Distortion + AlternativeBayer + + + + + Switch + + Switch + + + + + + + Brightness @@ -36053,7 +36115,7 @@ This can increase performance, and also silently ignore critical errors - FilterName + Color1 @@ -36067,63 +36129,63 @@ This can increase performance, and also silently ignore critical errors - Force + Color2 - Switch + String - Switch + String - NoResponse + Color3 - Switch + String - Switch + String - Opacity + Color4 - Float + String - Float + String - PassThru + Contrast - Switch + Float - Switch + Float - Rate + DitherFactor @@ -36137,7 +36199,7 @@ This can increase performance, and also silently ignore critical errors - ShaderText + FilterName @@ -36151,21 +36213,21 @@ This can increase performance, and also silently ignore critical errors - SourceName + Force - String + Switch - String + Switch - Strength + Gamma @@ -36179,7 +36241,7 @@ This can increase performance, and also silently ignore critical errors - UseShaderTime + NoResponse @@ -36192,71 +36254,127 @@ This can increase performance, and also silently ignore critical errors - - - + + PassThru + + + + + Switch - System.String + Switch - - - - - + + + + + PixelSize + + + + + Float - System.Object + Float - - - - + + + + + ShaderText + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + - Get-OBSHexagonShader - OBSHexagonShader + Get-OBSGlassShader + OBSGlassShader Get - Get-OBSHexagonShader [[-HexColor] <string>] [[-AlphaPercent] <int>] [[-Quantity] <float>] [[-BorderWidth] <int>] [[-SpeedPercent] <int>] [[-DistortX] <float>] [[-DistortY] <float>] [[-OffsetX] <float>] [[-OffsetY] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Blend] [-Equilateral] [-ZoomAnimate] [-Glitch] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSGlassShader [[-AlphaPercent] <float>] [[-OffsetAmount] <float>] [[-XSize] <int>] [[-YSize] <int>] [[-ReflectionOffset] <int>] [[-BorderOffset] <float>] [[-BorderColor] <string>] [[-GlassColor] <string>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-HorizontalBorder] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSHexagonShader + Get-OBSGlassShader - HexColor - - - - - String - - String - - - - - - AlphaPercent - Int + Float - Int + Float - - Quantity + + OffsetAmount @@ -36269,8 +36387,8 @@ This can increase performance, and also silently ignore critical errors - - BorderWidth + + XSize @@ -36283,50 +36401,22 @@ This can increase performance, and also silently ignore critical errors - - Blend - - - - - Switch - - Switch - - - - - - - Equilateral - - - - - Switch - - Switch - - - - - - - ZoomAnimate + + YSize - Switch + Int - Switch + Int - SpeedPercent + ReflectionOffset @@ -36340,7 +36430,7 @@ This can increase performance, and also silently ignore critical errors - Glitch + HorizontalBorder @@ -36354,7 +36444,7 @@ This can increase performance, and also silently ignore critical errors - DistortX + BorderOffset @@ -36368,48 +36458,34 @@ This can increase performance, and also silently ignore critical errors - DistortY + BorderColor - Float + String - Float + String - OffsetX + GlassColor - Float + String - Float + String - OffsetY - - - - - Float - - Float - - - - - - Notes @@ -36423,7 +36499,7 @@ This can increase performance, and also silently ignore critical errors - + SourceName @@ -36437,7 +36513,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -36451,7 +36527,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -36530,48 +36606,6 @@ This can increase performance, and also silently ignore critical errors - Int - - Int - - - - - - - Blend - - - - - Switch - - Switch - - - - - - - BorderWidth - - - - - Int - - Int - - - - - - - DistortX - - - - Float Float @@ -36581,28 +36615,28 @@ This can increase performance, and also silently ignore critical errors - DistortY + BorderColor - Float + String - Float + String - Equilateral + BorderOffset - Switch + Float - Switch + Float @@ -36637,28 +36671,28 @@ This can increase performance, and also silently ignore critical errors - Glitch + GlassColor - Switch + String - Switch + String - HexColor + HorizontalBorder - String + Switch - String + Switch @@ -36693,21 +36727,7 @@ This can increase performance, and also silently ignore critical errors - OffsetX - - - - - Float - - Float - - - - - - - OffsetY + OffsetAmount @@ -36735,14 +36755,14 @@ This can increase performance, and also silently ignore critical errors - Quantity + ReflectionOffset - Float + Int - Float + Int @@ -36777,42 +36797,42 @@ This can increase performance, and also silently ignore critical errors - SpeedPercent + UseShaderTime - Int + Switch - Int + Switch - UseShaderTime + XSize - Switch + Int - Switch + Int - ZoomAnimate + YSize - Switch + Int - Switch + Int @@ -36840,116 +36860,49 @@ This can increase performance, and also silently ignore critical errors - Get-OBSHotkey - OBSHotkey + Get-OBSGlitchAnalogShader + OBSGlitchAnalogShader Get - Get-OBSHotkey : GetHotkeyList + Get-OBSGlitchAnalogShader [[-ScanLineJitterDisplacement] <float>] [[-ScanLineJitterThresholdPercent] <int>] [[-VerticalJumpAmount] <float>] [[-VerticalSpeed] <float>] [[-HorizontalShake] <float>] [[-ColorDriftAmount] <float>] [[-ColorDriftSpeed] <float>] [[-PulseSpeedPercent] <int>] [[-AlphaPercent] <int>] [[-ColorToReplace] <string>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-RotateColors] [-ApplyToAlphaLayer] [-ReplaceImageColor] [-ApplyToSpecificColor] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Gets an array of all hotkey names in OBS. - Note: Hotkey functionality in obs-websocket comes as-is, and we do not guarantee support if things are broken. In 9/10 usages of hotkey requests, there exists a better, more reliable method via other requests. - Get-OBSHotkey calls the OBS WebSocket with a request of type GetHotkeyList. - Get-OBSHotkey - - PassThru + Get-OBSGlitchAnalogShader + + ScanLineJitterDisplacement - If set, will return the information that would otherwise be sent to OBS. + + - Switch + Float - Switch + Float - - NoResponse + + ScanLineJitterThresholdPercent - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + - Switch + Int - Switch + Int - - - - - NoResponse - - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors - - Switch - - Switch - - - - - - - PassThru - - If set, will return the information that would otherwise be sent to OBS. - - Switch - - Switch - - - - - - - - - -------------------------- EXAMPLE 1 -------------------------- - - PS > - - Get-OBSHotkey - - - - - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#gethotkeylist - - - - - - Get-OBSHslHsvSaturationShader - OBSHslHsvSaturationShader - Get - - Get-OBSHslHsvSaturationShader [[-HslSaturationFactor] <float>] [[-HslGamma] <float>] [[-HsvSaturationFactor] <float>] [[-HsvGamma] <float>] [[-AdjustmentOrder] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - - 0.2.0.1 - - - - - - Get-OBSHslHsvSaturationShader - - HslSaturationFactor + + VerticalJumpAmount @@ -36962,8 +36915,8 @@ This can increase performance, and also silently ignore critical errors - - HslGamma + + VerticalSpeed @@ -36976,8 +36929,8 @@ This can increase performance, and also silently ignore critical errors - - HsvSaturationFactor + + HorizontalShake @@ -36990,8 +36943,8 @@ This can increase performance, and also silently ignore critical errors - - HsvGamma + + ColorDriftAmount @@ -37004,8 +36957,22 @@ This can increase performance, and also silently ignore critical errors - - AdjustmentOrder + + ColorDriftSpeed + + + + + Float + + Float + + + + + + + PulseSpeedPercent @@ -37018,7 +36985,105 @@ This can increase performance, and also silently ignore critical errors - + + AlphaPercent + + + + + Int + + Int + + + + + + + RotateColors + + + + + Switch + + Switch + + + + + + + ApplyToAlphaLayer + + + + + Switch + + Switch + + + + + + + ReplaceImageColor + + + + + Switch + + Switch + + + + + + + ApplyToSpecificColor + + + + + Switch + + Switch + + + + + + + ColorToReplace + + + + + String + + String + + + + + + + Notes + + + + + String + + String + + + + + + SourceName @@ -37032,7 +37097,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -37046,7 +37111,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -37120,7 +37185,7 @@ This can increase performance, and also silently ignore critical errors - AdjustmentOrder + AlphaPercent @@ -37134,21 +37199,21 @@ This can increase performance, and also silently ignore critical errors - FilterName + ApplyToAlphaLayer - String + Switch - String + Switch - Force + ApplyToSpecificColor @@ -37162,7 +37227,7 @@ This can increase performance, and also silently ignore critical errors - HslGamma + ColorDriftAmount @@ -37176,7 +37241,7 @@ This can increase performance, and also silently ignore critical errors - HslSaturationFactor + ColorDriftSpeed @@ -37190,21 +37255,49 @@ This can increase performance, and also silently ignore critical errors - HsvGamma + ColorToReplace - Float + String - Float + String - HsvSaturationFactor + FilterName + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + HorizontalShake @@ -37231,6 +37324,20 @@ This can increase performance, and also silently ignore critical errors + + Notes + + + + + String + + String + + + + + PassThru @@ -37245,6 +37352,76 @@ This can increase performance, and also silently ignore critical errors + + PulseSpeedPercent + + + + + Int + + Int + + + + + + + ReplaceImageColor + + + + + Switch + + Switch + + + + + + + RotateColors + + + + + Switch + + Switch + + + + + + + ScanLineJitterDisplacement + + + + + Float + + Float + + + + + + + ScanLineJitterThresholdPercent + + + + + Int + + Int + + + + + ShaderText @@ -37287,6 +37464,34 @@ This can increase performance, and also silently ignore critical errors + + VerticalJumpAmount + + + + + Float + + Float + + + + + + + VerticalSpeed + + + + + Float + + Float + + + + + @@ -37309,21 +37514,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBSHueRotatonShader - OBSHueRotatonShader + Get-OBSGlitchPeriodicShader + OBSGlitchPeriodicShader Get - Get-OBSHueRotatonShader [[-Speed] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-HueOverride] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSGlitchPeriodicShader [[-PERI] <float>] [[-DURA] <float>] [[-AMPL] <float>] [[-SCRA] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSHueRotatonShader + Get-OBSGlitchPeriodicShader - Speed + PERI @@ -37336,21 +37541,49 @@ This can increase performance, and also silently ignore critical errors - - HueOverride + + DURA - Switch + Float - Switch + Float - + + AMPL + + + + + Float + + Float + + + + + + + SCRA + + + + + Float + + Float + + + + + + SourceName @@ -37364,7 +37597,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -37378,7 +37611,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -37451,6 +37684,34 @@ This can increase performance, and also silently ignore critical errors + + AMPL + + + + + Float + + Float + + + + + + + DURA + + + + + Float + + Float + + + + + FilterName @@ -37480,7 +37741,7 @@ This can increase performance, and also silently ignore critical errors - HueOverride + NoResponse @@ -37494,7 +37755,7 @@ This can increase performance, and also silently ignore critical errors - NoResponse + PassThru @@ -37508,35 +37769,35 @@ This can increase performance, and also silently ignore critical errors - PassThru + PERI - Switch + Float - Switch + Float - ShaderText + SCRA - String + Float - String + Float - SourceName + ShaderText @@ -37550,14 +37811,14 @@ This can increase performance, and also silently ignore critical errors - Speed + SourceName - Float + String - Float + String @@ -37599,134 +37860,66 @@ This can increase performance, and also silently ignore critical errors - Get-OBSInput - OBSInput + Get-OBSGlitchShader + OBSGlitchShader Get - Get-OBSInput : GetInputList + Get-OBSGlitchShader [[-AMT] <float>] [[-SPEED] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Gets an array of all inputs in OBS. - Get-OBSInput calls the OBS WebSocket with a request of type GetInputList. - Get-OBSInput - - InputKind + Get-OBSGlitchShader + + AMT - Restrict the array to only inputs of the specified kind + + - String + Float - String + Float - - PassThru + + SPEED - If set, will return the information that would otherwise be sent to OBS. + + - Switch + Float - Switch + Float - - NoResponse + + SourceName - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + - Switch + String - Switch + String - - - - - InputKind - - Restrict the array to only inputs of the specified kind - - String - - String - - - - - - - NoResponse - - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors - - Switch - - Switch - - - - - - - PassThru - - If set, will return the information that would otherwise be sent to OBS. - - Switch - - Switch - - - - - - - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputlist - - - - - - Get-OBSInputAudioBalance - OBSInputAudioBalance - Get - - Get-OBSInputAudioBalance : GetInputAudioBalance - - 0.2.0.1 - - - Gets the audio balance of an input. - Get-OBSInputAudioBalance calls the OBS WebSocket with a request of type GetInputAudioBalance. - - - - Get-OBSInputAudioBalance - - InputName + + FilterName - Name of the input to get the audio balance of + + String @@ -37736,10 +37929,11 @@ This can increase performance, and also silently ignore critical errors - - InputUuid + + ShaderText - UUID of the input to get the audio balance of + + String @@ -37749,10 +37943,25 @@ This can increase performance, and also silently ignore critical errors - + + Force + + + + + Switch + + Switch + + + + + + PassThru - If set, will return the information that would otherwise be sent to OBS. + + Switch @@ -37762,11 +37971,25 @@ This can increase performance, and also silently ignore critical errors - + NoResponse - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + + + Switch + + Switch + + + + + + + UseShaderTime + + + Switch @@ -37780,22 +38003,24 @@ This can increase performance, and also silently ignore critical errors - InputName + AMT - Name of the input to get the audio balance of + + - String + Float - String + Float - InputUuid + FilterName - UUID of the input to get the audio balance of + + String @@ -37805,11 +38030,25 @@ This can increase performance, and also silently ignore critical errors + + Force + + + + + Switch + + Switch + + + + + NoResponse - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + Switch @@ -37822,7 +38061,8 @@ This can increase performance, and also silently ignore critical errors PassThru - If set, will return the information that would otherwise be sent to OBS. + + Switch @@ -37832,96 +38072,11 @@ This can increase performance, and also silently ignore critical errors - - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputaudiobalance - - - - - - Get-OBSInputAudioMonitorType - OBSInputAudioMonitorType - Get - - Get-OBSInputAudioMonitorType : GetInputAudioMonitorType - - 0.2.0.1 - - - Gets the audio monitor type of an input. - The available audio monitor types are: - - `OBS_MONITORING_TYPE_NONE` - - `OBS_MONITORING_TYPE_MONITOR_ONLY` - - `OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT` - Get-OBSInputAudioMonitorType calls the OBS WebSocket with a request of type GetInputAudioMonitorType. - - - - Get-OBSInputAudioMonitorType - - InputName - - Name of the input to get the audio monitor type of - - String - - String - - - - - - - InputUuid - - UUID of the input to get the audio monitor type of - - String - - String - - - - - - - PassThru - - If set, will return the information that would otherwise be sent to OBS. - - Switch - - Switch - - - - - - - NoResponse - - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors - - Switch - - Switch - - - - - - - - - InputName + ShaderText - Name of the input to get the audio monitor type of + + String @@ -37932,9 +38087,10 @@ This can increase performance, and also silently ignore critical errors - InputUuid + SourceName - UUID of the input to get the audio monitor type of + + String @@ -37945,23 +38101,24 @@ This can increase performance, and also silently ignore critical errors - NoResponse + SPEED - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + - Switch + Float - Switch + Float - PassThru + UseShaderTime - If set, will return the information that would otherwise be sent to OBS. + + Switch @@ -37972,76 +38129,115 @@ This can increase performance, and also silently ignore critical errors - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputaudiomonitortype - - + + + + System.String + + + + + + + + + System.Object + + + + + - Get-OBSInputAudioSyncOffset - OBSInputAudioSyncOffset + Get-OBSGlowShader + OBSGlowShader Get - Get-OBSInputAudioSyncOffset : GetInputAudioSyncOffset + Get-OBSGlowShader [[-GlowPercent] <int>] [[-Blur] <int>] [[-MinBrightness] <int>] [[-MaxBrightness] <int>] [[-PulseSpeed] <int>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Ease] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Gets the audio sync offset of an input. - Note: The audio sync offset can be negative too! - Get-OBSInputAudioSyncOffset calls the OBS WebSocket with a request of type GetInputAudioSyncOffset. - Get-OBSInputAudioSyncOffset - - InputName + Get-OBSGlowShader + + GlowPercent - Name of the input to get the audio sync offset of + + - String + Int - String + Int - - InputUuid + + Blur - UUID of the input to get the audio sync offset of + + - String + Int - String + Int - - PassThru + + MinBrightness - If set, will return the information that would otherwise be sent to OBS. + + - Switch + Int - Switch + Int - - NoResponse + + MaxBrightness - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + + + Int + + Int + + + + + + + PulseSpeed + + + + + Int + + Int + + + + + + + Ease + + + Switch @@ -38051,92 +38247,11 @@ This can increase performance, and also silently ignore critical errors - - - - - InputName - - Name of the input to get the audio sync offset of - - String - - String - - - - - - - InputUuid - - UUID of the input to get the audio sync offset of - - String - - String - - - - - - - NoResponse - - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors - - Switch - - Switch - - - - - - - PassThru - - If set, will return the information that would otherwise be sent to OBS. - - Switch - - Switch - - - - - - - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputaudiosyncoffset - - - - - - Get-OBSInputAudioTracks - OBSInputAudioTracks - Get - - Get-OBSInputAudioTracks : GetInputAudioTracks - - 0.2.0.1 - - - Gets the enable state of all audio tracks of an input. - Get-OBSInputAudioTracks calls the OBS WebSocket with a request of type GetInputAudioTracks. - - - - Get-OBSInputAudioTracks - - InputName + + Notes - Name of the input + + String @@ -38146,10 +38261,11 @@ This can increase performance, and also silently ignore critical errors - - InputUuid + + SourceName - UUID of the input + + String @@ -38159,80 +38275,140 @@ This can increase performance, and also silently ignore critical errors - - PassThru + + FilterName - If set, will return the information that would otherwise be sent to OBS. + + - Switch + String - Switch + String - - NoResponse + + ShaderText - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + - Switch + String - Switch + String - + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + - InputName + Blur - Name of the input + + - String + Int - String + Int - InputUuid + Ease - UUID of the input + + - String + Switch - String + Switch - NoResponse + FilterName - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + - Switch + String - Switch + String - PassThru + Force - If set, will return the information that would otherwise be sent to OBS. + + Switch @@ -38242,189 +38418,53 @@ This can increase performance, and also silently ignore critical errors - - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputaudiotracks - - - - - - Get-OBSInputDefaultSettings - OBSInputDefaultSettings - Get - - Get-OBSInputDefaultSettings : GetInputDefaultSettings - - 0.2.0.1 - - - Gets the default settings for an input kind. - Get-OBSInputDefaultSettings calls the OBS WebSocket with a request of type GetInputDefaultSettings. - - - - Get-OBSInputDefaultSettings - - InputKind - - Input kind to get the default settings for - - String - - String - - - - - - - PassThru - - If set, will return the information that would otherwise be sent to OBS. - - Switch - - Switch - - - - - - - NoResponse - - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors - - Switch - - Switch - - - - - - - - - InputKind + GlowPercent - Input kind to get the default settings for + + - String + Int - String + Int - NoResponse + MaxBrightness - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + - Switch + Int - Switch + Int - PassThru + MinBrightness - If set, will return the information that would otherwise be sent to OBS. + + - Switch + Int - Switch + Int - - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputdefaultsettings - - - - - - Get-OBSInputKind - OBSInputKind - Get - - Get-OBSInputKind : GetInputKindList - - 0.2.0.1 - - - Gets an array of all available input kinds in OBS. - Get-OBSInputKind calls the OBS WebSocket with a request of type GetInputKindList. - - - - Get-OBSInputKind - - Unversioned - - True == Return all kinds as unversioned, False == Return with version suffixes (if available) - - Switch - - Switch - - - - - - - PassThru - - If set, will return the information that would otherwise be sent to OBS. - - Switch - - Switch - - - - - - - NoResponse - - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors - - Switch - - Switch - - - - - - - - NoResponse - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + Switch @@ -38435,22 +38475,24 @@ This can increase performance, and also silently ignore critical errors - PassThru + Notes - If set, will return the information that would otherwise be sent to OBS. + + - Switch + String - Switch + String - Unversioned + PassThru - True == Return all kinds as unversioned, False == Return with version suffixes (if available) + + Switch @@ -38460,105 +38502,25 @@ This can increase performance, and also silently ignore critical errors - - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputkindlist - - - - - - Get-OBSInputMute - OBSInputMute - Get - - Get-OBSInputMute : GetInputMute - - 0.2.0.1 - - - Gets the audio mute state of an input. - Get-OBSInputMute calls the OBS WebSocket with a request of type GetInputMute. - - - - Get-OBSInputMute - - InputName - - Name of input to get the mute state of - - String - - String - - - - - - - InputUuid - - UUID of input to get the mute state of - - String - - String - - - - - - - PassThru - - If set, will return the information that would otherwise be sent to OBS. - - Switch - - Switch - - - - - - - NoResponse - - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors - - Switch - - Switch - - - - - - - - - InputName + PulseSpeed - Name of input to get the mute state of + + - String + Int - String + Int - InputUuid + ShaderText - UUID of input to get the mute state of + + String @@ -38569,23 +38531,24 @@ This can increase performance, and also silently ignore critical errors - NoResponse + SourceName - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + - Switch + String - Switch + String - PassThru + UseShaderTime - If set, will return the information that would otherwise be sent to OBS. + + Switch @@ -38596,36 +38559,45 @@ This can increase performance, and also silently ignore critical errors - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputmute - - + + + + System.String + + + + + + + + + System.Object + + + + + - Get-OBSInputPropertiesListPropertyItems - OBSInputPropertiesListPropertyItems + Get-OBSGradientShader + OBSGradientShader Get - Get-OBSInputPropertiesListPropertyItems : GetInputPropertiesListPropertyItems + Get-OBSGradientShader [[-StartColor] <string>] [[-StartStep] <float>] [[-MiddleColor] <string>] [[-MiddleStep] <float>] [[-EndColor] <string>] [[-EndStep] <float>] [[-AlphaPercent] <int>] [[-PulseSpeed] <int>] [[-ColorToReplace] <string>] [[-GradientCenterWidthPercentage] <int>] [[-GradientCenterHeightPercentage] <int>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Ease] [-RotateColors] [-ApplyToAlphaLayer] [-ApplyToSpecificColor] [-Horizontal] [-Vertical] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Gets the items of a list property from an input's properties. - Note: Use this in cases where an input provides a dynamic, selectable list of items. For example, display capture, where it provides a list of available displays. - Get-OBSInputPropertiesListPropertyItems calls the OBS WebSocket with a request of type GetInputPropertiesListPropertyItems. - Get-OBSInputPropertiesListPropertyItems - - InputName + Get-OBSGradientShader + + StartColor - Name of the input + + String @@ -38635,10 +38607,25 @@ This can increase performance, and also silently ignore critical errors - - InputUuid + + StartStep - UUID of the input + + + + Float + + Float + + + + + + + MiddleColor + + + String @@ -38648,12 +38635,27 @@ This can increase performance, and also silently ignore critical errors - - PropertyName + + MiddleStep - Name of the list property to get the items of + + - String + Float + + Float + + + + + + + EndColor + + + + + String String @@ -38661,53 +38663,5081 @@ This can increase performance, and also silently ignore critical errors - - PassThru + + EndStep - If set, will return the information that would otherwise be sent to OBS. + + - Switch + Float - Switch + Float - - NoResponse + + AlphaPercent - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + - Switch + Int - Switch + Int - - - - - InputName - - Name of the input - - String - - String - - - - - - - InputUuid - - UUID of the input + + PulseSpeed + + + + + Int + + Int + + + + + + + Ease + + + + + Switch + + Switch + + + + + + + RotateColors + + + + + Switch + + Switch + + + + + + + ApplyToAlphaLayer + + + + + Switch + + Switch + + + + + + + ApplyToSpecificColor + + + + + Switch + + Switch + + + + + + + ColorToReplace + + + + + String + + String + + + + + + + Horizontal + + + + + Switch + + Switch + + + + + + + Vertical + + + + + Switch + + Switch + + + + + + + GradientCenterWidthPercentage + + + + + Int + + Int + + + + + + + GradientCenterHeightPercentage + + + + + Int + + Int + + + + + + + Notes + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + AlphaPercent + + + + + Int + + Int + + + + + + + ApplyToAlphaLayer + + + + + Switch + + Switch + + + + + + + ApplyToSpecificColor + + + + + Switch + + Switch + + + + + + + ColorToReplace + + + + + String + + String + + + + + + + Ease + + + + + Switch + + Switch + + + + + + + EndColor + + + + + String + + String + + + + + + + EndStep + + + + + Float + + Float + + + + + + + FilterName + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + GradientCenterHeightPercentage + + + + + Int + + Int + + + + + + + GradientCenterWidthPercentage + + + + + Int + + Int + + + + + + + Horizontal + + + + + Switch + + Switch + + + + + + + MiddleColor + + + + + String + + String + + + + + + + MiddleStep + + + + + Float + + Float + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + Notes + + + + + String + + String + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + PulseSpeed + + + + + Int + + Int + + + + + + + RotateColors + + + + + Switch + + Switch + + + + + + + ShaderText + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + StartColor + + + + + String + + String + + + + + + + StartStep + + + + + Float + + Float + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + Vertical + + + + + Switch + + Switch + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + + + + Get-OBSGroup + OBSGroup + Get + + Get-OBSGroup : GetGroupList + + 0.2.1 + + + Gets an array of all groups in OBS. + Groups in OBS are actually scenes, but renamed and modified. In obs-websocket, we treat them as scenes where we can. + Get-OBSGroup calls the OBS WebSocket with a request of type GetGroupList. + + + + Get-OBSGroup + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + + + -------------------------- EXAMPLE 1 -------------------------- + + PS > + + Get-OBSGroup + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getgrouplist + + + + + + Get-OBSGroupSceneItem + OBSGroupSceneItem + Get + + Get-OBSGroupSceneItem : GetGroupSceneItemList + + 0.2.1 + + + Basically GetSceneItemList, but for groups. + Using groups at all in OBS is discouraged, as they are very broken under the hood. Please use nested scenes instead. + Groups only + Get-OBSGroupSceneItem calls the OBS WebSocket with a request of type GetGroupSceneItemList. + + + + Get-OBSGroupSceneItem + + SceneName + + Name of the group to get the items of + + String + + String + + + + + + + SceneUuid + + UUID of the group to get the items of + + String + + String + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + SceneName + + Name of the group to get the items of + + String + + String + + + + + + + SceneUuid + + UUID of the group to get the items of + + String + + String + + + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getgroupsceneitemlist + + + + + + Get-OBSHalftoneShader + OBSHalftoneShader + Get + + Get-OBSHalftoneShader [[-Threshold] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSHalftoneShader + + Threshold + + + + + Float + + Float + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + FilterName + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + ShaderText + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + Threshold + + + + + Float + + Float + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + + + + Get-OBSHardBlinkShader + OBSHardBlinkShader + Get + + Get-OBSHardBlinkShader [[-Timeon] <float>] [[-Timeoff] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSHardBlinkShader + + Timeon + + + + + Float + + Float + + + + + + + Timeoff + + + + + Float + + Float + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + FilterName + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + ShaderText + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + Timeoff + + + + + Float + + Float + + + + + + + Timeon + + + + + Float + + Float + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + + + + Get-OBSHeatWaveSimpleShader + OBSHeatWaveSimpleShader + Get + + Get-OBSHeatWaveSimpleShader [[-Rate] <float>] [[-Strength] <float>] [[-Distortion] <float>] [[-Opacity] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSHeatWaveSimpleShader + + Rate + + + + + Float + + Float + + + + + + + Strength + + + + + Float + + Float + + + + + + + Distortion + + + + + Float + + Float + + + + + + + Opacity + + + + + Float + + Float + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + Distortion + + + + + Float + + Float + + + + + + + FilterName + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + Opacity + + + + + Float + + Float + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + Rate + + + + + Float + + Float + + + + + + + ShaderText + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + Strength + + + + + Float + + Float + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + + + + Get-OBSHexagonShader + OBSHexagonShader + Get + + Get-OBSHexagonShader [[-HexColor] <string>] [[-AlphaPercent] <int>] [[-Quantity] <float>] [[-BorderWidth] <int>] [[-SpeedPercent] <int>] [[-DistortX] <float>] [[-DistortY] <float>] [[-OffsetX] <float>] [[-OffsetY] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Blend] [-Equilateral] [-ZoomAnimate] [-Glitch] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSHexagonShader + + HexColor + + + + + String + + String + + + + + + + AlphaPercent + + + + + Int + + Int + + + + + + + Quantity + + + + + Float + + Float + + + + + + + BorderWidth + + + + + Int + + Int + + + + + + + Blend + + + + + Switch + + Switch + + + + + + + Equilateral + + + + + Switch + + Switch + + + + + + + ZoomAnimate + + + + + Switch + + Switch + + + + + + + SpeedPercent + + + + + Int + + Int + + + + + + + Glitch + + + + + Switch + + Switch + + + + + + + DistortX + + + + + Float + + Float + + + + + + + DistortY + + + + + Float + + Float + + + + + + + OffsetX + + + + + Float + + Float + + + + + + + OffsetY + + + + + Float + + Float + + + + + + + Notes + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + AlphaPercent + + + + + Int + + Int + + + + + + + Blend + + + + + Switch + + Switch + + + + + + + BorderWidth + + + + + Int + + Int + + + + + + + DistortX + + + + + Float + + Float + + + + + + + DistortY + + + + + Float + + Float + + + + + + + Equilateral + + + + + Switch + + Switch + + + + + + + FilterName + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + Glitch + + + + + Switch + + Switch + + + + + + + HexColor + + + + + String + + String + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + Notes + + + + + String + + String + + + + + + + OffsetX + + + + + Float + + Float + + + + + + + OffsetY + + + + + Float + + Float + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + Quantity + + + + + Float + + Float + + + + + + + ShaderText + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + SpeedPercent + + + + + Int + + Int + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + ZoomAnimate + + + + + Switch + + Switch + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + + + + Get-OBSHotkey + OBSHotkey + Get + + Get-OBSHotkey : GetHotkeyList + + 0.2.1 + + + Gets an array of all hotkey names in OBS. + Note: Hotkey functionality in obs-websocket comes as-is, and we do not guarantee support if things are broken. In 9/10 usages of hotkey requests, there exists a better, more reliable method via other requests. + Get-OBSHotkey calls the OBS WebSocket with a request of type GetHotkeyList. + + + + Get-OBSHotkey + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + + + -------------------------- EXAMPLE 1 -------------------------- + + PS > + + Get-OBSHotkey + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#gethotkeylist + + + + + + Get-OBSHslHsvSaturationShader + OBSHslHsvSaturationShader + Get + + Get-OBSHslHsvSaturationShader [[-HslSaturationFactor] <float>] [[-HslGamma] <float>] [[-HsvSaturationFactor] <float>] [[-HsvGamma] <float>] [[-AdjustmentOrder] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSHslHsvSaturationShader + + HslSaturationFactor + + + + + Float + + Float + + + + + + + HslGamma + + + + + Float + + Float + + + + + + + HsvSaturationFactor + + + + + Float + + Float + + + + + + + HsvGamma + + + + + Float + + Float + + + + + + + AdjustmentOrder + + + + + Int + + Int + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + AdjustmentOrder + + + + + Int + + Int + + + + + + + FilterName + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + HslGamma + + + + + Float + + Float + + + + + + + HslSaturationFactor + + + + + Float + + Float + + + + + + + HsvGamma + + + + + Float + + Float + + + + + + + HsvSaturationFactor + + + + + Float + + Float + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + ShaderText + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + + + + Get-OBSHueRotatonShader + OBSHueRotatonShader + Get + + Get-OBSHueRotatonShader [[-Speed] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-HueOverride] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSHueRotatonShader + + Speed + + + + + Float + + Float + + + + + + + HueOverride + + + + + Switch + + Switch + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + FilterName + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + HueOverride + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + ShaderText + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + Speed + + + + + Float + + Float + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + + + + Get-OBSInput + OBSInput + Get + + Get-OBSInput : GetInputList + + 0.2.1 + + + Gets an array of all inputs in OBS. + Get-OBSInput calls the OBS WebSocket with a request of type GetInputList. + + + + Get-OBSInput + + InputKind + + Restrict the array to only inputs of the specified kind + + String + + String + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + + + + InputKind + + Restrict the array to only inputs of the specified kind + + String + + String + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputlist + + + + + + Get-OBSInputAudioBalance + OBSInputAudioBalance + Get + + Get-OBSInputAudioBalance : GetInputAudioBalance + + 0.2.1 + + + Gets the audio balance of an input. + Get-OBSInputAudioBalance calls the OBS WebSocket with a request of type GetInputAudioBalance. + + + + Get-OBSInputAudioBalance + + InputName + + Name of the input to get the audio balance of + + String + + String + + + + + + + InputUuid + + UUID of the input to get the audio balance of + + String + + String + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + + + + InputName + + Name of the input to get the audio balance of + + String + + String + + + + + + + InputUuid + + UUID of the input to get the audio balance of + + String + + String + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputaudiobalance + + + + + + Get-OBSInputAudioMonitorType + OBSInputAudioMonitorType + Get + + Get-OBSInputAudioMonitorType : GetInputAudioMonitorType + + 0.2.1 + + + Gets the audio monitor type of an input. + The available audio monitor types are: + - `OBS_MONITORING_TYPE_NONE` + - `OBS_MONITORING_TYPE_MONITOR_ONLY` + - `OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT` + Get-OBSInputAudioMonitorType calls the OBS WebSocket with a request of type GetInputAudioMonitorType. + + + + Get-OBSInputAudioMonitorType + + InputName + + Name of the input to get the audio monitor type of + + String + + String + + + + + + + InputUuid + + UUID of the input to get the audio monitor type of + + String + + String + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + + + + InputName + + Name of the input to get the audio monitor type of + + String + + String + + + + + + + InputUuid + + UUID of the input to get the audio monitor type of + + String + + String + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputaudiomonitortype + + + + + + Get-OBSInputAudioSyncOffset + OBSInputAudioSyncOffset + Get + + Get-OBSInputAudioSyncOffset : GetInputAudioSyncOffset + + 0.2.1 + + + Gets the audio sync offset of an input. + Note: The audio sync offset can be negative too! + Get-OBSInputAudioSyncOffset calls the OBS WebSocket with a request of type GetInputAudioSyncOffset. + + + + Get-OBSInputAudioSyncOffset + + InputName + + Name of the input to get the audio sync offset of + + String + + String + + + + + + + InputUuid + + UUID of the input to get the audio sync offset of + + String + + String + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + + + + InputName + + Name of the input to get the audio sync offset of + + String + + String + + + + + + + InputUuid + + UUID of the input to get the audio sync offset of + + String + + String + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputaudiosyncoffset + + + + + + Get-OBSInputAudioTracks + OBSInputAudioTracks + Get + + Get-OBSInputAudioTracks : GetInputAudioTracks + + 0.2.1 + + + Gets the enable state of all audio tracks of an input. + Get-OBSInputAudioTracks calls the OBS WebSocket with a request of type GetInputAudioTracks. + + + + Get-OBSInputAudioTracks + + InputName + + Name of the input + + String + + String + + + + + + + InputUuid + + UUID of the input + + String + + String + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + + + + InputName + + Name of the input + + String + + String + + + + + + + InputUuid + + UUID of the input + + String + + String + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputaudiotracks + + + + + + Get-OBSInputDefaultSettings + OBSInputDefaultSettings + Get + + Get-OBSInputDefaultSettings : GetInputDefaultSettings + + 0.2.1 + + + Gets the default settings for an input kind. + Get-OBSInputDefaultSettings calls the OBS WebSocket with a request of type GetInputDefaultSettings. + + + + Get-OBSInputDefaultSettings + + InputKind + + Input kind to get the default settings for + + String + + String + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + + + + InputKind + + Input kind to get the default settings for + + String + + String + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputdefaultsettings + + + + + + Get-OBSInputKind + OBSInputKind + Get + + Get-OBSInputKind : GetInputKindList + + 0.2.1 + + + Gets an array of all available input kinds in OBS. + Get-OBSInputKind calls the OBS WebSocket with a request of type GetInputKindList. + + + + Get-OBSInputKind + + Unversioned + + True == Return all kinds as unversioned, False == Return with version suffixes (if available) + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + Unversioned + + True == Return all kinds as unversioned, False == Return with version suffixes (if available) + + Switch + + Switch + + + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputkindlist + + + + + + Get-OBSInputMute + OBSInputMute + Get + + Get-OBSInputMute : GetInputMute + + 0.2.1 + + + Gets the audio mute state of an input. + Get-OBSInputMute calls the OBS WebSocket with a request of type GetInputMute. + + + + Get-OBSInputMute + + InputName + + Name of input to get the mute state of + + String + + String + + + + + + + InputUuid + + UUID of input to get the mute state of + + String + + String + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + + + + InputName + + Name of input to get the mute state of + + String + + String + + + + + + + InputUuid + + UUID of input to get the mute state of + + String + + String + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputmute + + + + + + Get-OBSInputPropertiesListPropertyItems + OBSInputPropertiesListPropertyItems + Get + + Get-OBSInputPropertiesListPropertyItems : GetInputPropertiesListPropertyItems + + 0.2.1 + + + Gets the items of a list property from an input's properties. + Note: Use this in cases where an input provides a dynamic, selectable list of items. For example, display capture, where it provides a list of available displays. + Get-OBSInputPropertiesListPropertyItems calls the OBS WebSocket with a request of type GetInputPropertiesListPropertyItems. + + + + Get-OBSInputPropertiesListPropertyItems + + InputName + + Name of the input + + String + + String + + + + + + + InputUuid + + UUID of the input + + String + + String + + + + + + + PropertyName + + Name of the list property to get the items of + + String + + String + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + + + + InputName + + Name of the input + + String + + String + + + + + + + InputUuid + + UUID of the input + + String + + String + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + PropertyName + + Name of the list property to get the items of + + String + + String + + + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputpropertieslistpropertyitems + + + + + + Get-OBSInputSettings + OBSInputSettings + Get + + Get-OBSInputSettings : GetInputSettings + + 0.2.1 + + + Gets the settings of an input. + Note: Does not include defaults. To create the entire settings object, overlay `inputSettings` over the `defaultInputSettings` provided by `GetInputDefaultSettings`. + Get-OBSInputSettings calls the OBS WebSocket with a request of type GetInputSettings. + + + + Get-OBSInputSettings + + InputName + + Name of the input to get the settings of + + String + + String + + + + + + + InputUuid + + UUID of the input to get the settings of + + String + + String + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + + + + InputName + + Name of the input to get the settings of + + String + + String + + + + + + + InputUuid + + UUID of the input to get the settings of + + String + + String + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputsettings + + + + + + Get-OBSInputVolume + OBSInputVolume + Get + + Get-OBSInputVolume : GetInputVolume + + 0.2.1 + + + Gets the current volume setting of an input. + Get-OBSInputVolume calls the OBS WebSocket with a request of type GetInputVolume. + + + + Get-OBSInputVolume + + InputName + + Name of the input to get the volume of + + String + + String + + + + + + + InputUuid + + UUID of the input to get the volume of + + String + + String + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + + + + InputName + + Name of the input to get the volume of + + String + + String + + + + + + + InputUuid + + UUID of the input to get the volume of + + String + + String + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputvolume + + + + + + Get-OBSIntensityScopeShader + OBSIntensityScopeShader + Get + + Get-OBSIntensityScopeShader [[-Gain] <float>] [[-Blend] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSIntensityScopeShader + + Gain + + + + + Float + + Float + + + + + + + Blend + + + + + Float + + Float + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + Blend + + + + + Float + + Float + + + + + + + FilterName + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + Gain + + + + + Float + + Float + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + ShaderText + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + + + + Get-OBSInvertLumaShader + OBSInvertLumaShader + Get + + Get-OBSInvertLumaShader [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-InvertColor] [-InvertLuma] [-GammaCorrection] [-TestRamp] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSInvertLumaShader + + InvertColor + + + + + Switch + + Switch + + + + + + + InvertLuma + + + + + Switch + + Switch + + + + + + + GammaCorrection + + + + + Switch + + Switch + + + + + + + TestRamp + + + + + Switch + + Switch + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + FilterName + + + String @@ -38717,11 +43747,67 @@ This can increase performance, and also silently ignore critical errors + + Force + + + + + Switch + + Switch + + + + + + + GammaCorrection + + + + + Switch + + Switch + + + + + + + InvertColor + + + + + Switch + + Switch + + + + + + + InvertLuma + + + + + Switch + + Switch + + + + + NoResponse - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + Switch @@ -38734,7 +43820,8 @@ This can increase performance, and also silently ignore critical errors PassThru - If set, will return the information that would otherwise be sent to OBS. + + Switch @@ -38745,9 +43832,24 @@ This can increase performance, and also silently ignore critical errors - PropertyName + ShaderText - Name of the list property to get the items of + + + + String + + String + + + + + + + SourceName + + + String @@ -38757,37 +43859,168 @@ This can increase performance, and also silently ignore critical errors + + TestRamp + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + + + + Get-OBSLastReplayBufferReplay + OBSLastReplayBufferReplay + Get + + Get-OBSLastReplayBufferReplay : GetLastReplayBufferReplay + + 0.2.1 + + + Gets the filename of the last replay buffer save file. + Get-OBSLastReplayBufferReplay calls the OBS WebSocket with a request of type GetLastReplayBufferReplay. + + + + Get-OBSLastReplayBufferReplay + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + + -------------------------- EXAMPLE 1 -------------------------- + + PS > + + Get-OBSLastReplayBufferReplay + + + + - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputpropertieslistpropertyitems + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getlastreplaybufferreplay - Get-OBSInputSettings - OBSInputSettings + Get-OBSLuminance2Shader + OBSLuminance2Shader Get - Get-OBSInputSettings : GetInputSettings + Get-OBSLuminance2Shader [[-Color] <string>] [[-LumaMax] <float>] [[-LumaMin] <float>] [[-LumaMaxSmooth] <float>] [[-LumaMinSmooth] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-InvertImageColor] [-InvertAlphaChannel] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Gets the settings of an input. - Note: Does not include defaults. To create the entire settings object, overlay `inputSettings` over the `defaultInputSettings` provided by `GetInputDefaultSettings`. - Get-OBSInputSettings calls the OBS WebSocket with a request of type GetInputSettings. - Get-OBSInputSettings - - InputName + Get-OBSLuminance2Shader + + Color - Name of the input to get the settings of + + String @@ -38797,10 +44030,95 @@ This can increase performance, and also silently ignore critical errors - - InputUuid + + LumaMax - UUID of the input to get the settings of + + + + Float + + Float + + + + + + + LumaMin + + + + + Float + + Float + + + + + + + LumaMaxSmooth + + + + + Float + + Float + + + + + + + LumaMinSmooth + + + + + Float + + Float + + + + + + + InvertImageColor + + + + + Switch + + Switch + + + + + + + InvertAlphaChannel + + + + + Switch + + Switch + + + + + + + Notes + + + String @@ -38810,10 +44128,67 @@ This can increase performance, and also silently ignore critical errors - + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + PassThru - If set, will return the information that would otherwise be sent to OBS. + + Switch @@ -38823,11 +44198,25 @@ This can increase performance, and also silently ignore critical errors - + NoResponse - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + + + Switch + + Switch + + + + + + + UseShaderTime + + + Switch @@ -38841,9 +44230,10 @@ This can increase performance, and also silently ignore critical errors - InputName + Color - Name of the input to get the settings of + + String @@ -38854,9 +44244,10 @@ This can increase performance, and also silently ignore critical errors - InputUuid + FilterName - UUID of the input to get the settings of + + String @@ -38866,11 +44257,109 @@ This can increase performance, and also silently ignore critical errors + + Force + + + + + Switch + + Switch + + + + + + + InvertAlphaChannel + + + + + Switch + + Switch + + + + + + + InvertImageColor + + + + + Switch + + Switch + + + + + + + LumaMax + + + + + Float + + Float + + + + + + + LumaMaxSmooth + + + + + Float + + Float + + + + + + + LumaMin + + + + + Float + + Float + + + + + + + LumaMinSmooth + + + + + Float + + Float + + + + + NoResponse - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + Switch @@ -38880,10 +44369,67 @@ This can increase performance, and also silently ignore critical errors + + Notes + + + + + String + + String + + + + + PassThru - If set, will return the information that would otherwise be sent to OBS. + + + + Switch + + Switch + + + + + + + ShaderText + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + UseShaderTime + + + Switch @@ -38894,35 +44440,59 @@ This can increase performance, and also silently ignore critical errors - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputsettings - - + + + + System.String + + + + + + + + + System.Object + + + + + - Get-OBSInputVolume - OBSInputVolume + Get-OBSLuminanceAlphaShader + OBSLuminanceAlphaShader Get - Get-OBSInputVolume : GetInputVolume + Get-OBSLuminanceAlphaShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-RandF] <float>] [[-UvSize] <float[]>] [[-ColorMatrix] <float[][]>] [[-Color] <string>] [[-MulVal] <float>] [[-AddVal] <float>] [[-Level] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-InvertAlphaChannel] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Gets the current volume setting of an input. - Get-OBSInputVolume calls the OBS WebSocket with a request of type GetInputVolume. - Get-OBSInputVolume - - InputName + Get-OBSLuminanceAlphaShader + + ViewProj - Name of the input to get the volume of + + + + System.Single[][] + + System.Single[][] + + + + + + + Image + + + String @@ -38932,10 +44502,109 @@ This can increase performance, and also silently ignore critical errors - - InputUuid + + ElapsedTime + + + + + Float + + Float + + + + + + + UvOffset + + + + + System.Single[] + + System.Single[] + + + + + + + UvScale + + + + + System.Single[] + + System.Single[] + + + + + + + UvPixelInterval + + + + + System.Single[] + + System.Single[] + + + + + + + RandF + + + + + Float + + Float + + + + + + + UvSize + + + + + System.Single[] + + System.Single[] + + + + + + + ColorMatrix + + + + + System.Single[][] + + System.Single[][] + + + + + + + Color - UUID of the input to get the volume of + + String @@ -38945,115 +44614,36 @@ This can increase performance, and also silently ignore critical errors - - PassThru + + MulVal - If set, will return the information that would otherwise be sent to OBS. + + - Switch + Float - Switch + Float - - NoResponse + + AddVal - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + - Switch + Float - Switch + Float - - - - - InputName - - Name of the input to get the volume of - - String - - String - - - - - - - InputUuid - - UUID of the input to get the volume of - - String - - String - - - - - - - NoResponse - - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors - - Switch - - Switch - - - - - - - PassThru - - If set, will return the information that would otherwise be sent to OBS. - - Switch - - Switch - - - - - - - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getinputvolume - - - - - - Get-OBSIntensityScopeShader - OBSIntensityScopeShader - Get - - Get-OBSIntensityScopeShader [[-Gain] <float>] [[-Blend] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - - 0.2.0.1 - - - - - - Get-OBSIntensityScopeShader - - Gain + + Level @@ -39066,21 +44656,21 @@ This can increase performance, and also silently ignore critical errors - - Blend + + InvertAlphaChannel - Float + Switch - Float + Switch - + SourceName @@ -39094,7 +44684,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -39108,7 +44698,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -39182,7 +44772,49 @@ This can increase performance, and also silently ignore critical errors - Blend + AddVal + + + + + Float + + Float + + + + + + + Color + + + + + String + + String + + + + + + + ColorMatrix + + + + + System.Single[][] + + System.Single[][] + + + + + + + ElapsedTime @@ -39224,7 +44856,49 @@ This can increase performance, and also silently ignore critical errors - Gain + Image + + + + + String + + String + + + + + + + InvertAlphaChannel + + + + + Switch + + Switch + + + + + + + Level + + + + + Float + + Float + + + + + + + MulVal @@ -39265,6 +44939,20 @@ This can increase performance, and also silently ignore critical errors + + RandF + + + + + Float + + Float + + + + + ShaderText @@ -39307,6 +44995,76 @@ This can increase performance, and also silently ignore critical errors + + UvOffset + + + + + System.Single[] + + System.Single[] + + + + + + + UvPixelInterval + + + + + System.Single[] + + System.Single[] + + + + + + + UvScale + + + + + System.Single[] + + System.Single[] + + + + + + + UvSize + + + + + System.Single[] + + System.Single[] + + + + + + + ViewProj + + + + + System.Single[][] + + System.Single[][] + + + + + @@ -39329,49 +45087,49 @@ This can increase performance, and also silently ignore critical errors - Get-OBSInvertLumaShader - OBSInvertLumaShader + Get-OBSLuminanceShader + OBSLuminanceShader Get - Get-OBSInvertLumaShader [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-InvertColor] [-InvertLuma] [-GammaCorrection] [-TestRamp] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSLuminanceShader [[-Color] <string>] [[-Level] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-InvertImageColor] [-InvertAlphaChannel] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSInvertLumaShader - - InvertColor + Get-OBSLuminanceShader + + Color - Switch + String - Switch + String - - InvertLuma + + Level - Switch + Float - Switch + Float - GammaCorrection + InvertImageColor @@ -39385,7 +45143,7 @@ This can increase performance, and also silently ignore critical errors - TestRamp + InvertAlphaChannel @@ -39398,7 +45156,21 @@ This can increase performance, and also silently ignore critical errors - + + Notes + + + + + String + + String + + + + + + SourceName @@ -39412,7 +45184,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -39426,7 +45198,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -39499,6 +45271,20 @@ This can increase performance, and also silently ignore critical errors + + Color + + + + + String + + String + + + + + FilterName @@ -39528,7 +45314,7 @@ This can increase performance, and also silently ignore critical errors - GammaCorrection + InvertAlphaChannel @@ -39542,7 +45328,7 @@ This can increase performance, and also silently ignore critical errors - InvertColor + InvertImageColor @@ -39556,14 +45342,14 @@ This can increase performance, and also silently ignore critical errors - InvertLuma + Level - Switch + Float - Switch + Float @@ -39584,35 +45370,35 @@ This can increase performance, and also silently ignore critical errors - PassThru + Notes - Switch + String - Switch + String - ShaderText + PassThru - String + Switch - String + Switch - SourceName + ShaderText @@ -39626,14 +45412,14 @@ This can increase performance, and also silently ignore critical errors - TestRamp + SourceName - Switch + String - Switch + String @@ -39675,129 +45461,175 @@ This can increase performance, and also silently ignore critical errors - Get-OBSLastReplayBufferReplay - OBSLastReplayBufferReplay + Get-OBSMatrixShader + OBSMatrixShader Get - Get-OBSLastReplayBufferReplay : GetLastReplayBufferReplay + Get-OBSMatrixShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvSize] <float[]>] [[-UvPixelInterval] <float[]>] [[-RandF] <float>] [[-RandInstanceF] <float>] [[-RandActivationF] <float>] [[-Loops] <int>] [[-LocalTime] <float>] [[-Mouse] <float[]>] [[-LumaMin] <float>] [[-LumaMinSmooth] <float>] [[-Ratio] <float>] [[-AlphaPercentage] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-InvertDirection] [-ApplyToAlphaLayer] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Gets the filename of the last replay buffer save file. - Get-OBSLastReplayBufferReplay calls the OBS WebSocket with a request of type GetLastReplayBufferReplay. - Get-OBSLastReplayBufferReplay - - PassThru + Get-OBSMatrixShader + + ViewProj + + + + + System.Single[][] + + System.Single[][] + + + + + + + Image + + + + + String + + String + + + + + + + ElapsedTime + + + + + Float + + Float + + + + + + + UvOffset + + + + + System.Single[] + + System.Single[] + + + + + + + UvScale + + + + + System.Single[] + + System.Single[] + + + + + + + UvSize + + + + + System.Single[] + + System.Single[] + + + + + + + UvPixelInterval + + + + + System.Single[] + + System.Single[] + + + + + + + RandF + + + + + Float + + Float + + + + + + + RandInstanceF - If set, will return the information that would otherwise be sent to OBS. + + - Switch + Float - Switch + Float - - NoResponse + + RandActivationF - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + - Switch + Float - Switch + Float - - - - - NoResponse - - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors - - Switch - - Switch - - - - - - - PassThru - - If set, will return the information that would otherwise be sent to OBS. - - Switch - - Switch - - - - - - - - - -------------------------- EXAMPLE 1 -------------------------- - - PS > - - Get-OBSLastReplayBufferReplay - - - - - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getlastreplaybufferreplay - - - - - - Get-OBSLuminance2Shader - OBSLuminance2Shader - Get - - Get-OBSLuminance2Shader [[-Color] <string>] [[-LumaMax] <float>] [[-LumaMin] <float>] [[-LumaMaxSmooth] <float>] [[-LumaMinSmooth] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-InvertImageColor] [-InvertAlphaChannel] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - - 0.2.0.1 - - - - - - Get-OBSLuminance2Shader - - Color + + Loops - String + Int - String + Int - - LumaMax + + LocalTime @@ -39810,22 +45642,36 @@ This can increase performance, and also silently ignore critical errors - - LumaMin + + Mouse - Float + System.Single[] - Float + System.Single[] - - LumaMaxSmooth + + InvertDirection + + + + + Switch + + Switch + + + + + + + LumaMin @@ -39838,7 +45684,7 @@ This can increase performance, and also silently ignore critical errors - + LumaMinSmooth @@ -39852,49 +45698,49 @@ This can increase performance, and also silently ignore critical errors - - InvertImageColor + + Ratio - Switch + Float - Switch + Float - - InvertAlphaChannel + + AlphaPercentage - Switch + Float - Switch + Float - - Notes + + ApplyToAlphaLayer - String + Switch - String + Switch - + SourceName @@ -39908,7 +45754,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -39922,7 +45768,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -39996,14 +45842,42 @@ This can increase performance, and also silently ignore critical errors - Color + AlphaPercentage - String + Float - String + Float + + + + + + + ApplyToAlphaLayer + + + + + Switch + + Switch + + + + + + + ElapsedTime + + + + + Float + + Float @@ -40038,21 +45912,21 @@ This can increase performance, and also silently ignore critical errors - InvertAlphaChannel + Image - Switch + String - Switch + String - InvertImageColor + InvertDirection @@ -40066,7 +45940,7 @@ This can increase performance, and also silently ignore critical errors - LumaMax + LocalTime @@ -40080,14 +45954,14 @@ This can increase performance, and also silently ignore critical errors - LumaMaxSmooth + Loops - Float + Int - Float + Int @@ -40122,28 +45996,28 @@ This can increase performance, and also silently ignore critical errors - NoResponse + Mouse - Switch + System.Single[] - Switch + System.Single[] - Notes + NoResponse - String + Switch - String + Switch @@ -40163,6 +46037,62 @@ This can increase performance, and also silently ignore critical errors + + RandActivationF + + + + + Float + + Float + + + + + + + RandF + + + + + Float + + Float + + + + + + + RandInstanceF + + + + + Float + + Float + + + + + + + Ratio + + + + + Float + + Float + + + + + ShaderText @@ -40205,6 +46135,76 @@ This can increase performance, and also silently ignore critical errors + + UvOffset + + + + + System.Single[] + + System.Single[] + + + + + + + UvPixelInterval + + + + + System.Single[] + + System.Single[] + + + + + + + UvScale + + + + + System.Single[] + + System.Single[] + + + + + + + UvSize + + + + + System.Single[] + + System.Single[] + + + + + + + ViewProj + + + + + System.Single[][] + + System.Single[][] + + + + + @@ -40227,38 +46227,34 @@ This can increase performance, and also silently ignore critical errors - Get-OBSLuminanceAlphaShader - OBSLuminanceAlphaShader + Get-OBSMediaInputStatus + OBSMediaInputStatus Get - Get-OBSLuminanceAlphaShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-RandF] <float>] [[-UvSize] <float[]>] [[-ColorMatrix] <float[][]>] [[-Color] <string>] [[-MulVal] <float>] [[-AddVal] <float>] [[-Level] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-InvertAlphaChannel] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSMediaInputStatus : GetMediaInputStatus - 0.2.0.1 + 0.2.1 + Gets the status of a media input. + Media States: + - `OBS_MEDIA_STATE_NONE` + - `OBS_MEDIA_STATE_PLAYING` + - `OBS_MEDIA_STATE_OPENING` + - `OBS_MEDIA_STATE_BUFFERING` + - `OBS_MEDIA_STATE_PAUSED` + - `OBS_MEDIA_STATE_STOPPED` + - `OBS_MEDIA_STATE_ENDED` + - `OBS_MEDIA_STATE_ERROR` + Get-OBSMediaInputStatus calls the OBS WebSocket with a request of type GetMediaInputStatus. - Get-OBSLuminanceAlphaShader - - ViewProj - - - - - System.Single[][] - - System.Single[][] - - - - - - - Image + Get-OBSMediaInputStatus + + InputName - - + Name of the media input String @@ -40268,106 +46264,222 @@ This can increase performance, and also silently ignore critical errors - - ElapsedTime - - - - - Float - - Float - - - - - - - UvOffset - - - - - System.Single[] - - System.Single[] - - - - - - - UvScale + + InputUuid - - + UUID of the media input - System.Single[] + String - System.Single[] + String - - UvPixelInterval + + PassThru - - + If set, will return the information that would otherwise be sent to OBS. - System.Single[] + Switch - System.Single[] + Switch - - RandF + + NoResponse - - + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors - Float + Switch - Float + Switch - - UvSize + + + + + InputName + + Name of the media input + + String + + String + + + + + + + InputUuid + + UUID of the media input + + String + + String + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getmediainputstatus + + + + + + Get-OBSMonitor + OBSMonitor + Get + + Get-OBSMonitor : GetMonitorList + + 0.2.1 + + + Gets a list of connected monitors and information about them. + Get-OBSMonitor calls the OBS WebSocket with a request of type GetMonitorList. + + + + Get-OBSMonitor + + PassThru - - + If set, will return the information that would otherwise be sent to OBS. - System.Single[] + Switch - System.Single[] + Switch - - ColorMatrix + + NoResponse - - + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors - System.Single[][] + Switch - System.Single[][] + Switch - - Color + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + + + -------------------------- EXAMPLE 1 -------------------------- + + PS > + + Get-OBSMonitor + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getmonitorlist + + + + + + Get-OBSMotionBlurShader + OBSMotionBlurShader + Get + + Get-OBSMotionBlurShader [[-PreviousOutput] <string>] [[-Strength] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSMotionBlurShader + + PreviousOutput @@ -40380,36 +46492,8 @@ This can increase performance, and also silently ignore critical errors - - MulVal - - - - - Float - - Float - - - - - - - AddVal - - - - - Float - - Float - - - - - - - Level + + Strength @@ -40422,21 +46506,7 @@ This can increase performance, and also silently ignore critical errors - - InvertAlphaChannel - - - - - Switch - - Switch - - - - - - + SourceName @@ -40450,7 +46520,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -40464,7 +46534,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -40537,62 +46607,6 @@ This can increase performance, and also silently ignore critical errors - - AddVal - - - - - Float - - Float - - - - - - - Color - - - - - String - - String - - - - - - - ColorMatrix - - - - - System.Single[][] - - System.Single[][] - - - - - - - ElapsedTime - - - - - Float - - Float - - - - - FilterName @@ -40621,62 +46635,6 @@ This can increase performance, and also silently ignore critical errors - - Image - - - - - String - - String - - - - - - - InvertAlphaChannel - - - - - Switch - - Switch - - - - - - - Level - - - - - Float - - Float - - - - - - - MulVal - - - - - Float - - Float - - - - - NoResponse @@ -40706,14 +46664,14 @@ This can increase performance, and also silently ignore critical errors - RandF + PreviousOutput - Float + String - Float + String @@ -40748,84 +46706,28 @@ This can increase performance, and also silently ignore critical errors - UseShaderTime - - - - - Switch - - Switch - - - - - - - UvOffset - - - - - System.Single[] - - System.Single[] - - - - - - - UvPixelInterval - - - - - System.Single[] - - System.Single[] - - - - - - - UvScale - - - - - System.Single[] - - System.Single[] - - - - - - - UvSize + Strength - System.Single[] + Float - System.Single[] + Float - ViewProj + UseShaderTime - System.Single[][] + Switch - System.Single[][] + Switch @@ -40853,77 +46755,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBSLuminanceShader - OBSLuminanceShader + Get-OBSMultiplyShader + OBSMultiplyShader Get - Get-OBSLuminanceShader [[-Color] <string>] [[-Level] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-InvertImageColor] [-InvertAlphaChannel] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSMultiplyShader [[-OtherImage] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSLuminanceShader + Get-OBSMultiplyShader - Color - - - - - String - - String - - - - - - - Level - - - - - Float - - Float - - - - - - - InvertImageColor - - - - - Switch - - Switch - - - - - - - InvertAlphaChannel - - - - - Switch - - Switch - - - - - - - Notes + OtherImage @@ -40936,7 +46782,7 @@ This can increase performance, and also silently ignore critical errors - + SourceName @@ -40950,7 +46796,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -40964,7 +46810,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -41037,20 +46883,6 @@ This can increase performance, and also silently ignore critical errors - - Color - - - - - String - - String - - - - - FilterName @@ -41079,48 +46911,6 @@ This can increase performance, and also silently ignore critical errors - - InvertAlphaChannel - - - - - Switch - - Switch - - - - - - - InvertImageColor - - - - - Switch - - Switch - - - - - - - Level - - - - - Float - - Float - - - - - NoResponse @@ -41136,7 +46926,7 @@ This can increase performance, and also silently ignore critical errors - Notes + OtherImage @@ -41227,49 +47017,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBSMatrixShader - OBSMatrixShader + Get-OBSNightSkyShader + OBSNightSkyShader Get - Get-OBSMatrixShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvSize] <float[]>] [[-UvPixelInterval] <float[]>] [[-RandF] <float>] [[-RandInstanceF] <float>] [[-RandActivationF] <float>] [[-Loops] <int>] [[-LocalTime] <float>] [[-Mouse] <float[]>] [[-LumaMin] <float>] [[-LumaMinSmooth] <float>] [[-Ratio] <float>] [[-AlphaPercentage] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-InvertDirection] [-ApplyToAlphaLayer] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSNightSkyShader [[-Speed] <float>] [[-CenterWidthPercentage] <int>] [[-CenterHeightPercentage] <int>] [[-AlphaPercentage] <float>] [[-NumberStars] <int>] [[-SKYCOLOR] <string>] [[-STARCOLOR] <string>] [[-LIGHTSKY] <string>] [[-SKYLIGHTNESS] <float>] [[-MOONCOLOR] <string>] [[-MoonSize] <float>] [[-MoonBumpSize] <float>] [[-MoonPositionX] <float>] [[-MoonPositionY] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-IncludeClouds] [-IncludeMoon] [-ApplyToImage] [-ReplaceImageColor] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 - - - - - - Get-OBSMatrixShader - - ViewProj - - - - - System.Single[][] - - System.Single[][] - - - - - - - Image - - - - - String - - String - - - - - - - ElapsedTime + 0.2.1 + + + + + + Get-OBSNightSkyShader + + Speed @@ -41282,64 +47044,64 @@ This can increase performance, and also silently ignore critical errors - - UvOffset + + IncludeClouds - System.Single[] + Switch - System.Single[] + Switch - - UvScale + + IncludeMoon - System.Single[] + Switch - System.Single[] + Switch - - UvSize + + CenterWidthPercentage - System.Single[] + Int - System.Single[] + Int - - UvPixelInterval + + CenterHeightPercentage - System.Single[] + Int - System.Single[] + Int - - RandF + + AlphaPercentage @@ -41352,36 +47114,36 @@ This can increase performance, and also silently ignore critical errors - - RandInstanceF + + ApplyToImage - Float + Switch - Float + Switch - - RandActivationF + + ReplaceImageColor - Float + Switch - Float + Switch - - Loops + + NumberStars @@ -41394,50 +47156,50 @@ This can increase performance, and also silently ignore critical errors - - LocalTime + + SKYCOLOR - Float + String - Float + String - - Mouse + + STARCOLOR - System.Single[] + String - System.Single[] + String - - InvertDirection + + LIGHTSKY - Switch + String - Switch + String - - LumaMin + + SKYLIGHTNESS @@ -41450,8 +47212,22 @@ This can increase performance, and also silently ignore critical errors - - LumaMinSmooth + + MOONCOLOR + + + + + String + + String + + + + + + + MoonSize @@ -41464,8 +47240,8 @@ This can increase performance, and also silently ignore critical errors - - Ratio + + MoonBumpSize @@ -41478,8 +47254,8 @@ This can increase performance, and also silently ignore critical errors - - AlphaPercentage + + MoonPositionX @@ -41492,21 +47268,21 @@ This can increase performance, and also silently ignore critical errors - - ApplyToAlphaLayer + + MoonPositionY - Switch + Float - Switch + Float - + SourceName @@ -41520,7 +47296,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -41534,7 +47310,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -41622,7 +47398,7 @@ This can increase performance, and also silently ignore critical errors - ApplyToAlphaLayer + ApplyToImage @@ -41636,49 +47412,35 @@ This can increase performance, and also silently ignore critical errors - ElapsedTime - - - - - Float - - Float - - - - - - - FilterName + CenterHeightPercentage - String + Int - String + Int - Force + CenterWidthPercentage - Switch + Int - Switch + Int - Image + FilterName @@ -41692,7 +47454,7 @@ This can increase performance, and also silently ignore critical errors - InvertDirection + Force @@ -41706,49 +47468,49 @@ This can increase performance, and also silently ignore critical errors - LocalTime + IncludeClouds - Float + Switch - Float + Switch - Loops + IncludeMoon - Int + Switch - Int + Switch - LumaMin + LIGHTSKY - Float + String - Float + String - LumaMinSmooth + MoonBumpSize @@ -41762,49 +47524,49 @@ This can increase performance, and also silently ignore critical errors - Mouse + MOONCOLOR - System.Single[] + String - System.Single[] + String - NoResponse + MoonPositionX - Switch + Float - Switch + Float - PassThru + MoonPositionY - Switch + Float - Switch + Float - RandActivationF + MoonSize @@ -41818,63 +47580,63 @@ This can increase performance, and also silently ignore critical errors - RandF + NoResponse - Float + Switch - Float + Switch - RandInstanceF + NumberStars - Float + Int - Float + Int - Ratio + PassThru - Float + Switch - Float + Switch - ShaderText + ReplaceImageColor - String + Switch - String + Switch - SourceName + ShaderText @@ -41888,84 +47650,84 @@ This can increase performance, and also silently ignore critical errors - UseShaderTime + SKYCOLOR - Switch + String - Switch + String - UvOffset + SKYLIGHTNESS - System.Single[] + Float - System.Single[] + Float - UvPixelInterval + SourceName - System.Single[] + String - System.Single[] + String - UvScale + Speed - System.Single[] + Float - System.Single[] + Float - UvSize + STARCOLOR - System.Single[] + String - System.Single[] + String - ViewProj + UseShaderTime - System.Single[][] + Switch - System.Single[][] + Switch @@ -41980,285 +47742,103 @@ This can increase performance, and also silently ignore critical errors - - - - - System.Object - - - - - - - - - Get-OBSMediaInputStatus - OBSMediaInputStatus - Get - - Get-OBSMediaInputStatus : GetMediaInputStatus - - 0.2.0.1 - - - Gets the status of a media input. - Media States: - - `OBS_MEDIA_STATE_NONE` - - `OBS_MEDIA_STATE_PLAYING` - - `OBS_MEDIA_STATE_OPENING` - - `OBS_MEDIA_STATE_BUFFERING` - - `OBS_MEDIA_STATE_PAUSED` - - `OBS_MEDIA_STATE_STOPPED` - - `OBS_MEDIA_STATE_ENDED` - - `OBS_MEDIA_STATE_ERROR` - Get-OBSMediaInputStatus calls the OBS WebSocket with a request of type GetMediaInputStatus. - - - - Get-OBSMediaInputStatus - - InputName - - Name of the media input - - String - - String - - - - - - - InputUuid - - UUID of the media input - - String - - String - - - - - - - PassThru - - If set, will return the information that would otherwise be sent to OBS. - - Switch - - Switch - - - - - - - NoResponse - - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors - - Switch - - Switch - - - - - - - - - - InputName - - Name of the media input - - String - - String - - - - - - - InputUuid - - UUID of the media input - - String - - String - - - - - - - NoResponse - - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors - - Switch - - Switch - - - - - - - PassThru - - If set, will return the information that would otherwise be sent to OBS. - - Switch - - Switch - - - - - - - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getmediainputstatus - - - - - - Get-OBSMonitor - OBSMonitor - Get - - Get-OBSMonitor : GetMonitorList - - 0.2.0.1 - - - Gets a list of connected monitors and information about them. - Get-OBSMonitor calls the OBS WebSocket with a request of type GetMonitorList. - - - - Get-OBSMonitor - - PassThru - - If set, will return the information that would otherwise be sent to OBS. - - Switch - - Switch - - - - - - - NoResponse - - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors - - Switch - - Switch - - - - - - - - - - NoResponse - - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors - - Switch - - Switch - - - - - - - PassThru - - If set, will return the information that would otherwise be sent to OBS. - - Switch - - Switch - - - - - - - - - -------------------------- EXAMPLE 1 -------------------------- - - PS > - - Get-OBSMonitor - - - - - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getmonitorlist - - + + + + + System.Object + + + + + - Get-OBSMultiplyShader - OBSMultiplyShader + Get-OBSNoiseShader + OBSNoiseShader Get - Get-OBSMultiplyShader [[-OtherImage] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSNoiseShader [[-Speed] <float>] [[-Scale] <float>] [[-NoiseLevel] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Monochromatic] [-UseRand] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSMultiplyShader + Get-OBSNoiseShader - OtherImage + Speed - String + Float - String + Float - + + Scale + + + + + Float + + Float + + + + + + + NoiseLevel + + + + + Float + + Float + + + + + + + Monochromatic + + + + + Switch + + Switch + + + + + + + UseRand + + + + + Switch + + Switch + + + + + + SourceName @@ -42272,7 +47852,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -42286,7 +47866,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -42388,7 +47968,7 @@ This can increase performance, and also silently ignore critical errors - NoResponse + Monochromatic @@ -42402,14 +47982,28 @@ This can increase performance, and also silently ignore critical errors - OtherImage + NoiseLevel - String + Float - String + Float + + + + + + + NoResponse + + + + + Switch + + Switch @@ -42429,6 +48023,20 @@ This can increase performance, and also silently ignore critical errors + + Scale + + + + + Float + + Float + + + + + ShaderText @@ -42457,6 +48065,34 @@ This can increase performance, and also silently ignore critical errors + + Speed + + + + + Float + + Float + + + + + + + UseRand + + + + + Switch + + Switch + + + + + UseShaderTime @@ -42493,21 +48129,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBSNightSkyShader - OBSNightSkyShader + Get-OBSNormalMapShader + OBSNormalMapShader Get - Get-OBSNightSkyShader [[-Speed] <float>] [[-CenterWidthPercentage] <int>] [[-CenterHeightPercentage] <int>] [[-AlphaPercentage] <float>] [[-NumberStars] <int>] [[-SKYCOLOR] <string>] [[-STARCOLOR] <string>] [[-LIGHTSKY] <string>] [[-SKYLIGHTNESS] <float>] [[-MOONCOLOR] <string>] [[-MoonSize] <float>] [[-MoonBumpSize] <float>] [[-MoonPositionX] <float>] [[-MoonPositionY] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-IncludeClouds] [-IncludeMoon] [-ApplyToImage] [-ReplaceImageColor] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSNormalMapShader [[-Strength] <float>] [[-Type] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-OffsetHeight] [-InvertR] [-InvertG] [-InvertH] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSNightSkyShader + Get-OBSNormalMapShader - Speed + Strength @@ -42521,7 +48157,7 @@ This can increase performance, and also silently ignore critical errors - IncludeClouds + OffsetHeight @@ -42535,7 +48171,7 @@ This can increase performance, and also silently ignore critical errors - IncludeMoon + InvertR @@ -42548,50 +48184,8 @@ This can increase performance, and also silently ignore critical errors - - CenterWidthPercentage - - - - - Int - - Int - - - - - - - CenterHeightPercentage - - - - - Int - - Int - - - - - - - AlphaPercentage - - - - - Float - - Float - - - - - - ApplyToImage + InvertG @@ -42605,7 +48199,7 @@ This can increase performance, and also silently ignore critical errors - ReplaceImageColor + InvertH @@ -42618,8 +48212,8 @@ This can increase performance, and also silently ignore critical errors - - NumberStars + + Type @@ -42632,133 +48226,7 @@ This can increase performance, and also silently ignore critical errors - - SKYCOLOR - - - - - String - - String - - - - - - - STARCOLOR - - - - - String - - String - - - - - - - LIGHTSKY - - - - - String - - String - - - - - - - SKYLIGHTNESS - - - - - Float - - Float - - - - - - - MOONCOLOR - - - - - String - - String - - - - - - - MoonSize - - - - - Float - - Float - - - - - - - MoonBumpSize - - - - - Float - - Float - - - - - - - MoonPositionX - - - - - Float - - Float - - - - - - - MoonPositionY - - - - - Float - - Float - - - - - - + SourceName @@ -42772,7 +48240,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -42786,7 +48254,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -42859,62 +48327,6 @@ This can increase performance, and also silently ignore critical errors - - AlphaPercentage - - - - - Float - - Float - - - - - - - ApplyToImage - - - - - Switch - - Switch - - - - - - - CenterHeightPercentage - - - - - Int - - Int - - - - - - - CenterWidthPercentage - - - - - Int - - Int - - - - - FilterName @@ -42944,7 +48356,7 @@ This can increase performance, and also silently ignore critical errors - IncludeClouds + InvertG @@ -42958,7 +48370,7 @@ This can increase performance, and also silently ignore critical errors - IncludeMoon + InvertH @@ -42972,84 +48384,14 @@ This can increase performance, and also silently ignore critical errors - LIGHTSKY - - - - - String - - String - - - - - - - MoonBumpSize - - - - - Float - - Float - - - - - - - MOONCOLOR - - - - - String - - String - - - - - - - MoonPositionX - - - - - Float - - Float - - - - - - - MoonPositionY - - - - - Float - - Float - - - - - - - MoonSize + InvertR - Float + Switch - Float + Switch @@ -43070,21 +48412,7 @@ This can increase performance, and also silently ignore critical errors - NumberStars - - - - - Int - - Int - - - - - - - PassThru + OffsetHeight @@ -43098,7 +48426,7 @@ This can increase performance, and also silently ignore critical errors - ReplaceImageColor + PassThru @@ -43125,34 +48453,6 @@ This can increase performance, and also silently ignore critical errors - - SKYCOLOR - - - - - String - - String - - - - - - - SKYLIGHTNESS - - - - - Float - - Float - - - - - SourceName @@ -43168,7 +48468,7 @@ This can increase performance, and also silently ignore critical errors - Speed + Strength @@ -43182,14 +48482,14 @@ This can increase performance, and also silently ignore critical errors - STARCOLOR + Type - String + Int - String + Int @@ -43237,7 +48537,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSOpacityShader [[-Opacity] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -43499,7 +48799,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSOutput : GetOutputList - 0.2.0.1 + 0.2.1 Gets the list of available outputs. @@ -43593,7 +48893,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSOutputSettings : GetOutputSettings - 0.2.0.1 + 0.2.1 Gets the settings of an output. @@ -43702,7 +49002,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSOutputStatus : GetOutputStatus - 0.2.0.1 + 0.2.1 Gets the status of an output. @@ -43811,7 +49111,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSPagePeelShader [[-Speed] <float>] [[-Position] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -44101,7 +49401,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSPagePeelTransitionShader [[-ImageA] <string>] [[-ImageB] <string>] [[-TransitionTime] <float>] [[-PageColor] <string>] [[-PageTransparency] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ConvertLinear] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -44503,7 +49803,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSPerlinNoiseShader [[-Speed] <float>] [[-SpeedHorizonal] <float>] [[-SpeedVertical] <float>] [[-Iterations] <int>] [[-WhiteNoise] <float>] [[-BlackNoise] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Animated] [-ApplyToChannel] [-Inverted] [-Multiply] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -45045,7 +50345,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSPersistentData : GetPersistentData - 0.2.0.1 + 0.2.1 Gets the value of a "slot" from the selected persistent data realm. @@ -45172,6 +50472,408 @@ This can increase performance, and also silently ignore critical errors + + + Get-OBSPerspectiveShader + OBSPerspectiveShader + Get + + Get-OBSPerspectiveShader [[-AngleX] <float>] [[-AngleY] <float>] [[-AngleZ] <float>] [[-Perspective] <float>] [[-BorderColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ShowBorder] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSPerspectiveShader + + AngleX + + + + + Float + + Float + + + + + + + AngleY + + + + + Float + + Float + + + + + + + AngleZ + + + + + Float + + Float + + + + + + + Perspective + + + + + Float + + Float + + + + + + + BorderColor + + + + + String + + String + + + + + + + ShowBorder + + + + + Switch + + Switch + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + AngleX + + + + + Float + + Float + + + + + + + AngleY + + + + + Float + + Float + + + + + + + AngleZ + + + + + Float + + Float + + + + + + + BorderColor + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + Perspective + + + + + Float + + Float + + + + + + + ShaderText + + + + + String + + String + + + + + + + ShowBorder + + + + + Switch + + Switch + + + + + + + SourceName + + + + + String + + String + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + Get-OBSPieChartShader @@ -45180,7 +50882,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSPieChartShader [[-InnerRadius] <float>] [[-OuterRadius] <float>] [[-StartAngle] <float>] [[-Total] <int>] [[-Part1] <int>] [[-Color1] <string>] [[-Part2] <int>] [[-Color2] <string>] [[-Part3] <int>] [[-Color3] <string>] [[-Part4] <int>] [[-Color4] <string>] [[-Part5] <int>] [[-Color5] <string>] [[-Part6] <int>] [[-Color6] <string>] [[-Part7] <int>] [[-Color7] <string>] [[-Part8] <int>] [[-Color8] <string>] [[-Part9] <int>] [[-Color9] <string>] [[-Part10] <int>] [[-Color10] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -46086,7 +51788,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSPixelationShader [[-TargetWidth] <float>] [[-TargetHeight] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -46404,7 +52106,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSPixelationTransitionShader [[-TransitionTime] <float>] [[-Power] <float>] [[-CenterX] <float>] [[-CenterY] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ConvertLinear] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -46778,7 +52480,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSPolarShader [[-CenterX] <float>] [[-CenterY] <float>] [[-PointY] <float>] [[-Rotate] <float>] [[-Repeat] <float>] [[-Scale] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Flip] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -47208,7 +52910,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSProfile : GetProfileList - 0.2.0.1 + 0.2.1 Gets an array of all profiles @@ -47302,7 +53004,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSProfileParameter : GetProfileParameter - 0.2.0.1 + 0.2.1 Gets a parameter from the current profile's configuration. @@ -47437,7 +53139,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSPulseShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-RandF] <float>] [[-UvSize] <float[]>] [[-Speed] <float>] [[-MinGrowthPixels] <float>] [[-MaxGrowthPixels] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -47971,6 +53673,464 @@ This can increase performance, and also silently ignore critical errors + + + Get-OBSQuadrilateralCropShader + OBSQuadrilateralCropShader + Get + + Get-OBSQuadrilateralCropShader [[-TopLeftX] <float>] [[-TopLeftY] <float>] [[-TopRightX] <float>] [[-TopRightY] <float>] [[-BottomLeftX] <float>] [[-BottomLeftY] <float>] [[-BottomRightX] <float>] [[-BottomRightY] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSQuadrilateralCropShader + + TopLeftX + + + + + Float + + Float + + + + + + + TopLeftY + + + + + Float + + Float + + + + + + + TopRightX + + + + + Float + + Float + + + + + + + TopRightY + + + + + Float + + Float + + + + + + + BottomLeftX + + + + + Float + + Float + + + + + + + BottomLeftY + + + + + Float + + Float + + + + + + + BottomRightX + + + + + Float + + Float + + + + + + + BottomRightY + + + + + Float + + Float + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + BottomLeftX + + + + + Float + + Float + + + + + + + BottomLeftY + + + + + Float + + Float + + + + + + + BottomRightX + + + + + Float + + Float + + + + + + + BottomRightY + + + + + Float + + Float + + + + + + + FilterName + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + ShaderText + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + TopLeftX + + + + + Float + + Float + + + + + + + TopLeftY + + + + + Float + + Float + + + + + + + TopRightX + + + + + Float + + Float + + + + + + + TopRightY + + + + + Float + + Float + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + Get-OBSRainbowShader @@ -47979,7 +54139,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRainbowShader [[-Saturation] <float>] [[-Luminosity] <float>] [[-Spread] <float>] [[-Speed] <float>] [[-AlphaPercentage] <float>] [[-RotationOffset] <float>] [[-ColorToReplace] <string>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Vertical] [-Rotational] [-ApplyToImage] [-ReplaceImageColor] [-ApplyToSpecificColor] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -48577,7 +54737,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRainWindowShader [[-Size] <float>] [[-BlurSize] <float>] [[-TrailStrength] <float>] [[-TrailColor] <float>] [[-Speed] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-DebugShader] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -48979,7 +55139,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRecordDirectory : GetRecordDirectory - 0.2.0.1 + 0.2.1 Gets the current directory that the record output is set to. @@ -49073,7 +55233,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRecordStatus : GetRecordStatus - 0.2.0.1 + 0.2.1 Gets the status of the record output. @@ -49167,7 +55327,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRectangularDropShadowShader [[-ShadowOffsetX] <int>] [[-ShadowOffsetY] <int>] [[-ShadowBlurSize] <int>] [[-ShadowColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -49402,21 +55562,395 @@ This can increase performance, and also silently ignore critical errors - ShadowBlurSize - - - - - Int - - Int - - - - - - - ShadowColor + ShadowBlurSize + + + + + Int + + Int + + + + + + + ShadowColor + + + + + String + + String + + + + + + + ShadowOffsetX + + + + + Int + + Int + + + + + + + ShadowOffsetY + + + + + Int + + Int + + + + + + + SourceName + + + + + String + + String + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + + + + Get-OBSReflectShader + OBSReflectShader + Get + + Get-OBSReflectShader [[-CenterXPercent] <int>] [[-CenterYPercent] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Horizontal] [-Vertical] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSReflectShader + + Horizontal + + + + + Switch + + Switch + + + + + + + Vertical + + + + + Switch + + Switch + + + + + + + CenterXPercent + + + + + Int + + Int + + + + + + + CenterYPercent + + + + + Int + + Int + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + CenterXPercent + + + + + Int + + Int + + + + + + + CenterYPercent + + + + + Int + + Int + + + + + + + FilterName + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + Horizontal + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + ShaderText + + + + + String + + String + + + + + + + SourceName @@ -49430,49 +55964,21 @@ This can increase performance, and also silently ignore critical errors - ShadowOffsetX - - - - - Int - - Int - - - - - - - ShadowOffsetY - - - - - Int - - Int - - - - - - - SourceName + UseShaderTime - String + Switch - String + Switch - UseShaderTime + Vertical @@ -49507,49 +56013,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBSReflectShader - OBSReflectShader + Get-OBSRemovePartialPixelsShader + OBSRemovePartialPixelsShader Get - Get-OBSReflectShader [[-CenterXPercent] <int>] [[-CenterYPercent] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Horizontal] [-Vertical] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSRemovePartialPixelsShader [[-MinimumAlphaPercent] <int>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSReflectShader - - Horizontal - - - - - Switch - - Switch - - - - - - - Vertical - - - - - Switch - - Switch - - - - - + Get-OBSRemovePartialPixelsShader - CenterXPercent + MinimumAlphaPercent @@ -49563,14 +56041,14 @@ This can increase performance, and also silently ignore critical errors - CenterYPercent + Notes - Int + String - Int + String @@ -49678,63 +56156,49 @@ This can increase performance, and also silently ignore critical errors - CenterXPercent - - - - - Int - - Int - - - - - - - CenterYPercent + FilterName - Int + String - Int + String - FilterName + Force - String + Switch - String + Switch - Force + MinimumAlphaPercent - Switch + Int - Switch + Int - Horizontal + NoResponse @@ -49748,14 +56212,14 @@ This can increase performance, and also silently ignore critical errors - NoResponse + Notes - Switch + String - Switch + String @@ -49817,20 +56281,6 @@ This can increase performance, and also silently ignore critical errors - - Vertical - - - - - Switch - - Switch - - - - - @@ -49853,35 +56303,35 @@ This can increase performance, and also silently ignore critical errors - Get-OBSRemovePartialPixelsShader - OBSRemovePartialPixelsShader + Get-OBSRepeatGridCenterCropShader + OBSRepeatGridCenterCropShader Get - Get-OBSRemovePartialPixelsShader [[-MinimumAlphaPercent] <int>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSRepeatGridCenterCropShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-Alpha] <float>] [[-Columns] <float>] [[-Rows] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSRemovePartialPixelsShader + Get-OBSRepeatGridCenterCropShader - MinimumAlphaPercent + ViewProj - Int + System.Single[][] - Int + System.Single[][] - Notes + Image @@ -49894,7 +56344,49 @@ This can increase performance, and also silently ignore critical errors - + + Alpha + + + + + Float + + Float + + + + + + + Columns + + + + + Float + + Float + + + + + + + Rows + + + + + Float + + Float + + + + + + SourceName @@ -49908,7 +56400,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -49922,7 +56414,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -49995,6 +56487,34 @@ This can increase performance, and also silently ignore critical errors + + Alpha + + + + + Float + + Float + + + + + + + Columns + + + + + Float + + Float + + + + + FilterName @@ -50024,14 +56544,14 @@ This can increase performance, and also silently ignore critical errors - MinimumAlphaPercent + Image - Int + String - Int + String @@ -50052,28 +56572,28 @@ This can increase performance, and also silently ignore critical errors - Notes + PassThru - String + Switch - String + Switch - PassThru + Rows - Switch + Float - Switch + Float @@ -50121,6 +56641,20 @@ This can increase performance, and also silently ignore critical errors + + ViewProj + + + + + System.Single[][] + + System.Single[][] + + + + + @@ -50149,7 +56683,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRepeatShader [[-ViewProj] <float[][]>] [[-ColorMatrix] <float[][]>] [[-ColorRangeMin] <float[]>] [[-ColorRangeMax] <float[]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-UvSize] <float[]>] [[-RandF] <float>] [[-Alpha] <float>] [[-Copies] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -50775,7 +57309,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRepeatTextureShader [[-ViewProj] <float[][]>] [[-ColorMatrix] <float[][]>] [[-ColorRangeMin] <float[]>] [[-ColorRangeMax] <float[]>] [[-Image] <string>] [[-TexImage] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-UvSize] <float[]>] [[-RandF] <float>] [[-Blend] <float>] [[-Copies] <float>] [[-Notes] <string>] [[-AlphaPercentage] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -51457,7 +57991,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSReplayBufferStatus : GetReplayBufferStatus - 0.2.0.1 + 0.2.1 Gets the status of the replay buffer output. @@ -51551,7 +58085,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRGBAPercentShader [[-RedPercent] <float>] [[-GreenPercent] <float>] [[-BluePercent] <float>] [[-AlphaPercent] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -51897,7 +58431,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRgbColorWheelShader [[-Speed] <float>] [[-ColorDepth] <float>] [[-ColorToReplace] <string>] [[-AlphaPercentage] <float>] [[-CenterWidthPercentage] <int>] [[-CenterHeightPercentage] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ApplyToImage] [-ReplaceImageColor] [-ApplyToSpecificColor] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -52383,7 +58917,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRgbSplitShader [[-Redx] <float>] [[-Redy] <float>] [[-Greenx] <float>] [[-Greeny] <float>] [[-Bluex] <float>] [[-Bluey] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -52785,7 +59319,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRgbvisibilityShader [[-Red] <float>] [[-Green] <float>] [[-Blue] <float>] [[-RedVisibility] <float>] [[-GreenVisibility] <float>] [[-BlueVisibility] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -53215,7 +59749,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRGSSAAShader [[-ColorSigma] <float>] [[-SpatialSigma] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -53533,7 +60067,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRippleShader [[-DistanceFactor] <float>] [[-TimeFactor] <float>] [[-PowerFactor] <float>] [[-CenterPosX] <float>] [[-CenterPosY] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -53907,7 +60441,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRotatingSourceShader [[-SpinSpeed] <float>] [[-Rotation] <float>] [[-Zoomin] <float>] [[-XCenter] <float>] [[-YCenter] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-KeepAspectratio] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -54309,7 +60843,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRotatoeShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-RandF] <float>] [[-UvSize] <float[]>] [[-SpeedPercent] <int>] [[-AxisX] <float>] [[-AxisY] <float>] [[-AxisZ] <float>] [[-AngleDegrees] <float>] [[-CenterWidthPercentage] <int>] [[-CenterHeightPercentage] <int>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-RotateTransform] [-RotatePixels] [-RotateColors] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -55075,7 +61609,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRoundedRect2Shader [[-CornerRadius] <int>] [[-BorderThickness] <int>] [[-BorderColor] <string>] [[-BorderAlphaStart] <float>] [[-BorderAlphaEnd] <float>] [[-AlphaCutOff] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-FasterScan] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -55505,7 +62039,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRoundedRectPerCornerShader [[-CornerRadiusTl] <int>] [[-CornerRadiusTr] <int>] [[-CornerRadiusBr] <int>] [[-CornerRadiusBl] <int>] [[-BorderThickness] <int>] [[-BorderColor] <string>] [[-BorderAlphaStart] <float>] [[-BorderAlphaEnd] <float>] [[-AlphaCutOff] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -55991,7 +62525,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRoundedRectPerSideShader [[-CornerRadiusBottom] <int>] [[-CornerRadiusLeft] <int>] [[-CornerRadiusTop] <int>] [[-CornerRadiusRight] <int>] [[-BorderThickness] <int>] [[-BorderColor] <string>] [[-BorderAlphaStart] <float>] [[-BorderAlphaEnd] <float>] [[-AlphaCutOff] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -56477,7 +63011,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRoundedRectShader [[-CornerRadius] <int>] [[-BorderThickness] <int>] [[-BorderColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -56795,7 +63329,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRoundedStrokeGradientShader [[-CornerRadius] <int>] [[-BorderThickness] <int>] [[-MinimumAlphaPercent] <int>] [[-RotationSpeed] <int>] [[-BorderColorL] <string>] [[-BorderColorR] <string>] [[-CenterWidth] <int>] [[-CenterHeight] <int>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -57281,7 +63815,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSRoundedStrokeShader [[-CornerRadius] <int>] [[-BorderThickness] <int>] [[-MinimumAlphaPercent] <int>] [[-BorderColor] <string>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -57655,7 +64189,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSScanLineShader [[-Speed] <float>] [[-Angle] <float>] [[-Floor] <float>] [[-Period] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Lengthwise] [-Animate] [-Shift] [-Boost] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -58141,7 +64675,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSScene : GetSceneList - 0.2.0.1 + 0.2.1 Gets an array of all scenes in OBS. @@ -58235,7 +64769,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSceneCollection : GetSceneCollectionList - 0.2.0.1 + 0.2.1 Gets an array of all scene collections @@ -58329,7 +64863,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSceneItem : GetSceneItemList - 0.2.0.1 + 0.2.1 Gets a list of all scene items in a scene. @@ -58465,7 +64999,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSceneItemBlendMode : GetSceneItemBlendMode - 0.2.0.1 + 0.2.1 Gets the blend mode of a scene item. @@ -58635,7 +65169,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSceneItemEnabled : GetSceneItemEnabled - 0.2.0.1 + 0.2.1 Gets the enable state of a scene item. @@ -58797,7 +65331,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSceneItemId : GetSceneItemId - 0.2.0.1 + 0.2.1 Searches a scene for a source, and returns its id. @@ -58985,7 +65519,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSceneItemIndex : GetSceneItemIndex - 0.2.0.1 + 0.2.1 Gets the index position of a scene item in a scene. @@ -59148,7 +65682,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSceneItemLocked : GetSceneItemLocked - 0.2.0.1 + 0.2.1 Gets the lock state of a scene item. @@ -59310,7 +65844,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSceneItemSource : GetSceneItemSource - 0.2.0.1 + 0.2.1 Gets the source associated with a scene item. @@ -59471,7 +66005,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSceneItemTransform : GetSceneItemTransform - 0.2.0.1 + 0.2.1 Gets the transform and crop info of a scene item. @@ -59633,7 +66167,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSceneSceneTransitionOverride : GetSceneSceneTransitionOverride - 0.2.0.1 + 0.2.1 Gets the scene transition overridden for a scene. @@ -59769,7 +66303,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSceneTransition : GetSceneTransitionList - 0.2.0.1 + 0.2.1 Gets an array of all scene transitions in OBS. @@ -59863,7 +66397,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSeascapeShader [[-SEAHEIGHT] <float>] [[-SEACHOPPY] <float>] [[-SEASPEED] <float>] [[-SEAFREQ] <float>] [[-SEABASE] <string>] [[-SEAWATERCOLOR] <string>] [[-CAMERASPEED] <float>] [[-CAMERATURNSPEED] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-AA] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -60349,7 +66883,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSeasickShader [[-Notes] <string>] [[-Amplitude] <float>] [[-Speed] <float>] [[-Frequency] <float>] [[-Opacity] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -60723,7 +67257,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSelectiveColorShader [[-CutoffRed] <float>] [[-CutoffGreen] <float>] [[-CutoffBlue] <float>] [[-CutoffYellow] <float>] [[-AcceptanceAmplifier] <float>] [[-Notes] <string>] [[-BackgroundType] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ShowRed] [-ShowGreen] [-ShowBlue] [-ShowYellow] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -61265,7 +67799,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSShakeShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-RandF] <float>] [[-UvSize] <float[]>] [[-LocalTime] <float>] [[-RandomScale] <float>] [[-Speed] <float>] [[-MinGrowthPixels] <float>] [[-MaxGrowthPixels] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Worble] [-RandomizeMovement] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -61947,7 +68481,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSShineShader [[-LTex] <string>] [[-ShineColor] <string>] [[-SpeedPercent] <int>] [[-GradientPercent] <int>] [[-DelayPercent] <int>] [[-Notes] <string>] [[-StartAdjust] <float>] [[-StopAdjust] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ApplyToAlphaLayer] [-Ease] [-Hide] [-Reverse] [-OneDirection] [-Glitch] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -62573,7 +69107,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSimpleGradientShader [[-SpeedPercentage] <int>] [[-AlphaPercentage] <int>] [[-ColorToReplace] <string>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-LensFlair] [-AnimateLensFlair] [-ApplyToAlphaLayer] [-ApplyToSpecificColor] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -63031,7 +69565,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSimplexNoiseShader [[-SnapPercent] <float>] [[-SpeedPercent] <float>] [[-Resolution] <float>] [[-ForeColor] <string>] [[-BackColor] <string>] [[-AlphaPercent] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Fractal] [-UseAlphaLayer] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -63517,7 +70051,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSmartDenoiseShader [[-USigma] <float>] [[-UKSigma] <float>] [[-UThreshold] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -63835,7 +70369,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSourceActive : GetSourceActive - 0.2.0.1 + 0.2.1 Gets the active and show state of a source. @@ -63971,7 +70505,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSourceFilter : GetSourceFilter - 0.2.0.1 + 0.2.1 Gets the info for a specific source filter. @@ -64132,7 +70666,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSourceFilterDefaultSettings : GetSourceFilterDefaultSettings - 0.2.0.1 + 0.2.1 Gets the default settings for a filter kind. @@ -64241,7 +70775,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSourceFilterKind : GetSourceFilterKindList - 0.2.0.1 + 0.2.1 Gets an array of all available source filter kinds. @@ -64336,7 +70870,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSourceFilterList : GetSourceFilterList - 0.2.0.1 + 0.2.1 Gets an array of all of a source's filters. @@ -64471,7 +71005,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSourceScreenshot : GetSourceScreenshot - 0.2.0.1 + 0.2.1 Gets a Base64-encoded screenshot of a source. @@ -64713,7 +71247,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSpecialInputs : GetSpecialInputs - 0.2.0.1 + 0.2.1 Gets the names of all special inputs. @@ -64807,7 +71341,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSpecularShineShader [[-Hint] <string>] [[-Roughness] <float>] [[-LightStrength] <float>] [[-LightPositionX] <float>] [[-LightPositionY] <float>] [[-FlattenNormal] <float>] [[-StretchNormalX] <float>] [[-StretchNormalY] <float>] [[-LightColor] <float[]>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -65293,7 +71827,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSpotlightShader [[-SpeedPercent] <float>] [[-FocusPercent] <float>] [[-SpotlightColor] <string>] [[-HorizontalOffset] <float>] [[-VerticalOffset] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Glitch] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -65723,7 +72257,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSStats : GetStats - 0.2.0.1 + 0.2.1 Gets statistics about OBS, obs-websocket, and the current session. @@ -65817,7 +72351,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSStreamServiceSettings : GetStreamServiceSettings - 0.2.0.1 + 0.2.1 Gets the current stream service settings (stream destination). @@ -65911,7 +72445,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSStreamStatus : GetStreamStatus - 0.2.0.1 + 0.2.1 Gets the status of the stream output. @@ -66005,7 +72539,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSStudioModeEnabled : GetStudioModeEnabled - 0.2.0.1 + 0.2.1 Gets whether studio is enabled. @@ -66099,7 +72633,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSSwirlShader [[-Radius] <float>] [[-Angle] <float>] [[-CenterX] <float>] [[-CenterY] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Animate] [-Inverse] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -66529,7 +73063,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSTetraShader [[-RedR] <float>] [[-RedG] <float>] [[-RedB] <float>] [[-YelR] <float>] [[-YelG] <float>] [[-YelB] <float>] [[-GrnR] <float>] [[-GrnG] <float>] [[-GrnB] <float>] [[-CynR] <float>] [[-CynG] <float>] [[-CynB] <float>] [[-BluR] <float>] [[-BluG] <float>] [[-BluB] <float>] [[-MagR] <float>] [[-MagG] <float>] [[-MagB] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -66788,7 +73322,507 @@ This can increase performance, and also silently ignore critical errors - + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + + + BluB + + + + + Float + + Float + + + + + + + BluG + + + + + Float + + Float + + + + + + + BluR + + + + + Float + + Float + + + + + + + CynB + + + + + Float + + Float + + + + + + + CynG + + + + + Float + + Float + + + + + + + CynR + + + + + Float + + Float + + + + + + + FilterName + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + GrnB + + + + + Float + + Float + + + + + + + GrnG + + + + + Float + + Float + + + + + + + GrnR + + + + + Float + + Float + + + + + + + MagB + + + + + Float + + Float + + + + + + + MagG + + + + + Float + + Float + + + + + + + MagR + + + + + Float + + Float + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + RedB + + + + + Float + + Float + + + + + + + RedG + + + + + Float + + Float + + + + + + + RedR + + + + + Float + + Float + + + + + + + ShaderText + + + + + String + + String + + + + + + + SourceName + + + + + String + + String + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + YelB + + + + + Float + + Float + + + + + + + YelG + + + + + Float + + Float + + + + + + + YelR + + + + + Float + + Float + + + + + + + + + + System.String + + + + + + + + + System.Object + + + + + + + + + Get-OBSThermalShader + OBSThermalShader + Get + + Get-OBSThermalShader [[-Strength] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSThermalShader + + Strength + + + + + Float + + Float + + + + + + SourceName @@ -66802,7 +73836,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -66816,7 +73850,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -66890,105 +73924,105 @@ This can increase performance, and also silently ignore critical errors - BluB + FilterName - Float + String - Float + String - BluG + Force - Float + Switch - Float + Switch - BluR + NoResponse - Float + Switch - Float + Switch - CynB + PassThru - Float + Switch - Float + Switch - CynG + ShaderText - Float + String - Float + String - CynR + SourceName - Float + String - Float + String - FilterName + Strength - String + Float - String + Float - Force + UseShaderTime @@ -67001,106 +74035,337 @@ This can increase performance, and also silently ignore critical errors - - GrnB - - - - - Float + + + - Float + System.String + - - - - - GrnG - - - - - Float + + + + - Float + System.Object + - - - + + + + + + Get-OBSTransitionKind + OBSTransitionKind + Get + + Get-OBSTransitionKind : GetTransitionKindList + + 0.2.1 + + + Gets an array of all available transition kinds. + Similar to `GetInputKindList` + Get-OBSTransitionKind calls the OBS WebSocket with a request of type GetTransitionKindList. + + + + Get-OBSTransitionKind + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + + - GrnR + NoResponse - - + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors - Float + Switch - Float + Switch - MagB + PassThru - - + If set, will return the information that would otherwise be sent to OBS. - Float + Switch - Float + Switch + + + + -------------------------- EXAMPLE 1 -------------------------- + + PS > + + Get-OBSTransitionKind + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#gettransitionkindlist + + + + + + Get-OBSTvCrtSubpixelShader + OBSTvCrtSubpixelShader + Get + + Get-OBSTvCrtSubpixelShader [[-ChannelWidth] <int>] [[-ChannelHeight] <int>] [[-HGap] <int>] [[-VGap] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSTvCrtSubpixelShader + + ChannelWidth + + + + + Int + + Int + + + + + + + ChannelHeight + + + + + Int + + Int + + + + + + + HGap + + + + + Int + + Int + + + + + + + VGap + + + + + Int + + Int + + + + + + + SourceName + + + + + String + + String + + + + + + + FilterName + + + + + String + + String + + + + + + + ShaderText + + + + + String + + String + + + + + + + Force + + + + + Switch + + Switch + + + + + + + PassThru + + + + + Switch + + Switch + + + + + + + NoResponse + + + + + Switch + + Switch + + + + + + + UseShaderTime + + + + + Switch + + Switch + + + + + + + + - MagG + ChannelHeight - Float + Int - Float + Int - MagR + ChannelWidth - Float + Int - Float + Int - NoResponse + FilterName - Switch + String - Switch + String - PassThru + Force @@ -67114,42 +74379,42 @@ This can increase performance, and also silently ignore critical errors - RedB + HGap - Float + Int - Float + Int - RedG + NoResponse - Float + Switch - Float + Switch - RedR + PassThru - Float + Switch - Float + Switch @@ -67198,42 +74463,14 @@ This can increase performance, and also silently ignore critical errors - YelB - - - - - Float - - Float - - - - - - - YelG - - - - - Float - - Float - - - - - - - YelR + VGap - Float + Int - Float + Int @@ -67261,21 +74498,63 @@ This can increase performance, and also silently ignore critical errors - Get-OBSThermalShader - OBSThermalShader + Get-OBSTwistShader + OBSTwistShader Get - Get-OBSThermalShader [[-Strength] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSTwistShader [[-CenterXPercent] <int>] [[-CenterYPercent] <int>] [[-Power] <float>] [[-Rotation] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSThermalShader + Get-OBSTwistShader - Strength + CenterXPercent + + + + + Int + + Int + + + + + + + CenterYPercent + + + + + Int + + Int + + + + + + + Power + + + + + Float + + Float + + + + + + + Rotation @@ -67288,7 +74567,7 @@ This can increase performance, and also silently ignore critical errors - + SourceName @@ -67302,7 +74581,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -67316,7 +74595,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -67389,6 +74668,34 @@ This can increase performance, and also silently ignore critical errors + + CenterXPercent + + + + + Int + + Int + + + + + + + CenterYPercent + + + + + Int + + Int + + + + + FilterName @@ -67446,21 +74753,35 @@ This can increase performance, and also silently ignore critical errors - ShaderText + Power - String + Float - String + Float - SourceName + Rotation + + + + + Float + + Float + + + + + + + ShaderText @@ -67474,14 +74795,14 @@ This can increase performance, and also silently ignore critical errors - Strength + SourceName - Float + String - Float + String @@ -67523,130 +74844,133 @@ This can increase performance, and also silently ignore critical errors - Get-OBSTransitionKind - OBSTransitionKind + Get-OBSTwoPassDropShadowShader + OBSTwoPassDropShadowShader Get - Get-OBSTransitionKind : GetTransitionKindList + Get-OBSTwoPassDropShadowShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-RandF] <float>] [[-UvSize] <float[]>] [[-ShadowOffsetX] <int>] [[-ShadowOffsetY] <int>] [[-ShadowBlurSize] <int>] [[-ShadowColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-IsAlphaPremultiplied] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Gets an array of all available transition kinds. - Similar to `GetInputKindList` - Get-OBSTransitionKind calls the OBS WebSocket with a request of type GetTransitionKindList. - Get-OBSTransitionKind - - PassThru + Get-OBSTwoPassDropShadowShader + + ViewProj - If set, will return the information that would otherwise be sent to OBS. + + - Switch + System.Single[][] - Switch + System.Single[][] - - NoResponse + + Image - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + - Switch + String - Switch + String - - - - - NoResponse - - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors - - Switch - - Switch - - - - - - - PassThru - - If set, will return the information that would otherwise be sent to OBS. - - Switch - - Switch - - - - - - - - - -------------------------- EXAMPLE 1 -------------------------- - - PS > - - Get-OBSTransitionKind - - - - - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#gettransitionkindlist - - - - - - Get-OBSTvCrtSubpixelShader - OBSTvCrtSubpixelShader - Get - - Get-OBSTvCrtSubpixelShader [[-ChannelWidth] <int>] [[-ChannelHeight] <int>] [[-HGap] <int>] [[-VGap] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - - 0.2.0.1 - - - - - - Get-OBSTvCrtSubpixelShader - - ChannelWidth + + ElapsedTime - Int + Float - Int + Float - - ChannelHeight + + UvOffset + + + + + System.Single[] + + System.Single[] + + + + + + + UvScale + + + + + System.Single[] + + System.Single[] + + + + + + + UvPixelInterval + + + + + System.Single[] + + System.Single[] + + + + + + + RandF + + + + + Float + + Float + + + + + + + UvSize + + + + + System.Single[] + + System.Single[] + + + + + + + ShadowOffsetX @@ -67659,8 +74983,8 @@ This can increase performance, and also silently ignore critical errors - - HGap + + ShadowOffsetY @@ -67673,8 +74997,8 @@ This can increase performance, and also silently ignore critical errors - - VGap + + ShadowBlurSize @@ -67687,7 +75011,35 @@ This can increase performance, and also silently ignore critical errors - + + ShadowColor + + + + + String + + String + + + + + + + IsAlphaPremultiplied + + + + + Switch + + Switch + + + + + + SourceName @@ -67701,7 +75053,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -67715,7 +75067,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -67789,70 +75141,70 @@ This can increase performance, and also silently ignore critical errors - ChannelHeight + ElapsedTime - Int + Float - Int + Float - ChannelWidth + FilterName - Int + String - Int + String - FilterName + Force - String + Switch - String + Switch - Force + Image - Switch + String - Switch + String - HGap + IsAlphaPremultiplied - Int + Switch - Int + Switch @@ -67886,6 +75238,20 @@ This can increase performance, and also silently ignore critical errors + + RandF + + + + + Float + + Float + + + + + ShaderText @@ -67900,6 +75266,62 @@ This can increase performance, and also silently ignore critical errors + + ShadowBlurSize + + + + + Int + + Int + + + + + + + ShadowColor + + + + + String + + String + + + + + + + ShadowOffsetX + + + + + Int + + Int + + + + + + + ShadowOffsetY + + + + + Int + + Int + + + + + SourceName @@ -67929,14 +75351,70 @@ This can increase performance, and also silently ignore critical errors - VGap + UvOffset - Int + System.Single[] - Int + System.Single[] + + + + + + + UvPixelInterval + + + + + System.Single[] + + System.Single[] + + + + + + + UvScale + + + + + System.Single[] + + System.Single[] + + + + + + + UvSize + + + + + System.Single[] + + System.Single[] + + + + + + + ViewProj + + + + + System.Single[][] + + System.Single[][] @@ -67964,49 +75442,49 @@ This can increase performance, and also silently ignore critical errors - Get-OBSTwistShader - OBSTwistShader + Get-OBSVCRShader + OBSVCRShader Get - Get-OBSTwistShader [[-CenterXPercent] <int>] [[-CenterYPercent] <int>] [[-Power] <float>] [[-Rotation] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSVCRShader [[-VerticalShift] <float>] [[-Distort] <float>] [[-Vignet] <float>] [[-Stripe] <float>] [[-VerticalFactor] <float>] [[-VerticalHeight] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSTwistShader + Get-OBSVCRShader - CenterXPercent + VerticalShift - Int + Float - Int + Float - CenterYPercent + Distort - Int + Float - Int + Float - Power + Vignet @@ -68020,7 +75498,7 @@ This can increase performance, and also silently ignore critical errors - Rotation + Stripe @@ -68033,7 +75511,35 @@ This can increase performance, and also silently ignore critical errors - + + VerticalFactor + + + + + Float + + Float + + + + + + + VerticalHeight + + + + + Float + + Float + + + + + + SourceName @@ -68047,7 +75553,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -68061,7 +75567,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -68135,49 +75641,49 @@ This can increase performance, and also silently ignore critical errors - CenterXPercent + Distort - Int + Float - Int + Float - CenterYPercent + FilterName - Int + String - Int + String - FilterName + Force - String + Switch - String + Switch - Force + NoResponse @@ -68191,7 +75697,7 @@ This can increase performance, and also silently ignore critical errors - NoResponse + PassThru @@ -68205,21 +75711,35 @@ This can increase performance, and also silently ignore critical errors - PassThru + ShaderText - Switch + String - Switch + String - Power + SourceName + + + + + String + + String + + + + + + + Stripe @@ -68233,7 +75753,21 @@ This can increase performance, and also silently ignore critical errors - Rotation + UseShaderTime + + + + + Switch + + Switch + + + + + + + VerticalFactor @@ -68247,42 +75781,42 @@ This can increase performance, and also silently ignore critical errors - ShaderText + VerticalHeight - String + Float - String + Float - SourceName + VerticalShift - String + Float - String + Float - UseShaderTime + Vignet - Switch + Float - Switch + Float @@ -68310,49 +75844,115 @@ This can increase performance, and also silently ignore critical errors - Get-OBSTwoPassDropShadowShader - OBSTwoPassDropShadowShader + Get-OBSVersion + OBSVersion Get - Get-OBSTwoPassDropShadowShader [[-ViewProj] <float[][]>] [[-Image] <string>] [[-ElapsedTime] <float>] [[-UvOffset] <float[]>] [[-UvScale] <float[]>] [[-UvPixelInterval] <float[]>] [[-RandF] <float>] [[-UvSize] <float[]>] [[-ShadowOffsetX] <int>] [[-ShadowOffsetY] <int>] [[-ShadowBlurSize] <int>] [[-ShadowColor] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-IsAlphaPremultiplied] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSVersion : GetVersion - 0.2.0.1 + 0.2.1 + Gets data about the current plugin and RPC version. + Get-OBSVersion calls the OBS WebSocket with a request of type GetVersion. - Get-OBSTwoPassDropShadowShader - - ViewProj + Get-OBSVersion + + PassThru - - + If set, will return the information that would otherwise be sent to OBS. - System.Single[][] + Switch - System.Single[][] + Switch - - Image + + NoResponse - - + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors - String + Switch - String + Switch - - ElapsedTime + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + + + -------------------------- EXAMPLE 1 -------------------------- + + PS > + + Get-OBSVersion + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getversion + + + + + + Get-OBSVHSShader + OBSVHSShader + Get + + Get-OBSVHSShader [[-Range] <float>] [[-OffsetIntensity] <float>] [[-NoiseQuality] <float>] [[-NoiseIntensity] <float>] [[-ColorOffsetIntensity] <float>] [[-AlphaPercentage] <float>] [[-ColorToReplace] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ApplyToImage] [-ReplaceImageColor] [-ApplyToSpecificColor] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSVHSShader + + Range @@ -68365,50 +75965,36 @@ This can increase performance, and also silently ignore critical errors - - UvOffset - - - - - System.Single[] - - System.Single[] - - - - - - - UvScale + + OffsetIntensity - System.Single[] + Float - System.Single[] + Float - - UvPixelInterval + + NoiseQuality - System.Single[] + Float - System.Single[] + Float - - RandF + + NoiseIntensity @@ -68421,64 +76007,64 @@ This can increase performance, and also silently ignore critical errors - - UvSize + + ColorOffsetIntensity - System.Single[] + Float - System.Single[] + Float - - ShadowOffsetX + + AlphaPercentage - Int + Float - Int + Float - - ShadowOffsetY + + ApplyToImage - Int + Switch - Int + Switch - - ShadowBlurSize + + ReplaceImageColor - Int + Switch - Int + Switch - - ShadowColor + + ColorToReplace @@ -68492,7 +76078,7 @@ This can increase performance, and also silently ignore critical errors - IsAlphaPremultiplied + ApplyToSpecificColor @@ -68505,7 +76091,7 @@ This can increase performance, and also silently ignore critical errors - + SourceName @@ -68519,7 +76105,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -68533,7 +76119,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -68607,7 +76193,7 @@ This can increase performance, and also silently ignore critical errors - ElapsedTime + AlphaPercentage @@ -68621,49 +76207,7 @@ This can increase performance, and also silently ignore critical errors - FilterName - - - - - String - - String - - - - - - - Force - - - - - Switch - - Switch - - - - - - - Image - - - - - String - - String - - - - - - - IsAlphaPremultiplied + ApplyToImage @@ -68677,7 +76221,7 @@ This can increase performance, and also silently ignore critical errors - NoResponse + ApplyToSpecificColor @@ -68691,35 +76235,35 @@ This can increase performance, and also silently ignore critical errors - PassThru + ColorOffsetIntensity - Switch + Float - Switch + Float - RandF + ColorToReplace - Float + String - Float + String - ShaderText + FilterName @@ -68733,77 +76277,77 @@ This can increase performance, and also silently ignore critical errors - ShadowBlurSize + Force - Int + Switch - Int + Switch - ShadowColor + NoiseIntensity - String + Float - String + Float - ShadowOffsetX + NoiseQuality - Int + Float - Int + Float - ShadowOffsetY + NoResponse - Int + Switch - Int + Switch - SourceName + OffsetIntensity - String + Float - String + Float - UseShaderTime + PassThru @@ -68817,70 +76361,70 @@ This can increase performance, and also silently ignore critical errors - UvOffset + Range - System.Single[] + Float - System.Single[] + Float - UvPixelInterval + ReplaceImageColor - System.Single[] + Switch - System.Single[] + Switch - UvScale + ShaderText - System.Single[] + String - System.Single[] + String - UvSize + SourceName - System.Single[] + String - System.Single[] + String - ViewProj + UseShaderTime - System.Single[][] + Switch - System.Single[][] + Switch @@ -68908,49 +76452,116 @@ This can increase performance, and also silently ignore critical errors - Get-OBSVCRShader - OBSVCRShader + Get-OBSVideoSettings + OBSVideoSettings Get - Get-OBSVCRShader [[-VerticalShift] <float>] [[-Distort] <float>] [[-Vignet] <float>] [[-Stripe] <float>] [[-VerticalFactor] <float>] [[-VerticalHeight] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSVideoSettings : GetVideoSettings - 0.2.0.1 + 0.2.1 + Gets the current video settings. + Note: To get the true FPS value, divide the FPS numerator by the FPS denominator. Example: `60000/1001` + Get-OBSVideoSettings calls the OBS WebSocket with a request of type GetVideoSettings. - Get-OBSVCRShader - - VerticalShift + Get-OBSVideoSettings + + PassThru - - + If set, will return the information that would otherwise be sent to OBS. - Float + Switch - Float + Switch - - Distort + + NoResponse - - + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors - Float + Switch - Float + Switch - - Vignet + + + + + NoResponse + + If set, will not attempt to receive a response from OBS. +This can increase performance, and also silently ignore critical errors + + Switch + + Switch + + + + + + + PassThru + + If set, will return the information that would otherwise be sent to OBS. + + Switch + + Switch + + + + + + + + + -------------------------- EXAMPLE 1 -------------------------- + + PS > + + Get-OBSVideoSettings + + + + + + + + + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getvideosettings + + + + + + Get-OBSVignettingShader + OBSVignettingShader + Get + + Get-OBSVignettingShader [[-InnerRadius] <float>] [[-OuterRadius] <float>] [[-Opacity] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + + 0.2.1 + + + + + + Get-OBSVignettingShader + + InnerRadius @@ -68963,8 +76574,8 @@ This can increase performance, and also silently ignore critical errors - - Stripe + + OuterRadius @@ -68977,8 +76588,8 @@ This can increase performance, and also silently ignore critical errors - - VerticalFactor + + Opacity @@ -68991,21 +76602,21 @@ This can increase performance, and also silently ignore critical errors - - VerticalHeight + + Notes - Float + String - Float + String - + SourceName @@ -69019,7 +76630,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -69033,7 +76644,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -69106,20 +76717,6 @@ This can increase performance, and also silently ignore critical errors - - Distort - - - - - Float - - Float - - - - - FilterName @@ -69149,21 +76746,21 @@ This can increase performance, and also silently ignore critical errors - NoResponse + InnerRadius - Switch + Float - Switch + Float - PassThru + NoResponse @@ -69177,7 +76774,7 @@ This can increase performance, and also silently ignore critical errors - ShaderText + Notes @@ -69191,21 +76788,21 @@ This can increase performance, and also silently ignore critical errors - SourceName + Opacity - String + Float - String + Float - Stripe + OuterRadius @@ -69219,7 +76816,7 @@ This can increase performance, and also silently ignore critical errors - UseShaderTime + PassThru @@ -69233,56 +76830,42 @@ This can increase performance, and also silently ignore critical errors - VerticalFactor - - - - - Float - - Float - - - - - - - VerticalHeight + ShaderText - Float + String - Float + String - VerticalShift + SourceName - Float + String - Float + String - Vignet + UseShaderTime - Float + Switch - Float + Switch @@ -69310,21 +76893,21 @@ This can increase performance, and also silently ignore critical errors - Get-OBSVersion - OBSVersion + Get-OBSVirtualCamStatus + OBSVirtualCamStatus Get - Get-OBSVersion : GetVersion + Get-OBSVirtualCamStatus : GetVirtualCamStatus - 0.2.0.1 + 0.2.1 - Gets data about the current plugin and RPC version. - Get-OBSVersion calls the OBS WebSocket with a request of type GetVersion. + Gets the status of the virtualcam output. + Get-OBSVirtualCamStatus calls the OBS WebSocket with a request of type GetVirtualCamStatus. - Get-OBSVersion + Get-OBSVirtualCamStatus PassThru @@ -69389,7 +76972,7 @@ This can increase performance, and also silently ignore critical errors PS > - Get-OBSVersion + Get-OBSVirtualCamStatus @@ -69398,97 +76981,27 @@ This can increase performance, and also silently ignore critical errors - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getversion + https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getvirtualcamstatus - Get-OBSVHSShader - OBSVHSShader + Get-OBSVoronoiPixelationShader + OBSVoronoiPixelationShader Get - Get-OBSVHSShader [[-Range] <float>] [[-OffsetIntensity] <float>] [[-NoiseQuality] <float>] [[-NoiseIntensity] <float>] [[-ColorOffsetIntensity] <float>] [[-AlphaPercentage] <float>] [[-ColorToReplace] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ApplyToImage] [-ReplaceImageColor] [-ApplyToSpecificColor] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSVoronoiPixelationShader [[-PixH] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Alternative] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSVHSShader + Get-OBSVoronoiPixelationShader - Range - - - - - Float - - Float - - - - - - - OffsetIntensity - - - - - Float - - Float - - - - - - - NoiseQuality - - - - - Float - - Float - - - - - - - NoiseIntensity - - - - - Float - - Float - - - - - - - ColorOffsetIntensity - - - - - Float - - Float - - - - - - - AlphaPercentage + PixH @@ -69502,49 +77015,7 @@ This can increase performance, and also silently ignore critical errors - ApplyToImage - - - - - Switch - - Switch - - - - - - - ReplaceImageColor - - - - - Switch - - Switch - - - - - - - ColorToReplace - - - - - String - - String - - - - - - - ApplyToSpecificColor + Alternative @@ -69557,7 +77028,7 @@ This can increase performance, and also silently ignore critical errors - + SourceName @@ -69571,7 +77042,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -69585,7 +77056,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -69659,35 +77130,7 @@ This can increase performance, and also silently ignore critical errors - AlphaPercentage - - - - - Float - - Float - - - - - - - ApplyToImage - - - - - Switch - - Switch - - - - - - - ApplyToSpecificColor + Alternative @@ -69700,34 +77143,6 @@ This can increase performance, and also silently ignore critical errors - - ColorOffsetIntensity - - - - - Float - - Float - - - - - - - ColorToReplace - - - - - String - - String - - - - - FilterName @@ -69756,34 +77171,6 @@ This can increase performance, and also silently ignore critical errors - - NoiseIntensity - - - - - Float - - Float - - - - - - - NoiseQuality - - - - - Float - - Float - - - - - NoResponse @@ -69798,20 +77185,6 @@ This can increase performance, and also silently ignore critical errors - - OffsetIntensity - - - - - Float - - Float - - - - - PassThru @@ -69827,7 +77200,7 @@ This can increase performance, and also silently ignore critical errors - Range + PixH @@ -69840,20 +77213,6 @@ This can increase performance, and also silently ignore critical errors - - ReplaceImageColor - - - - - Switch - - Switch - - - - - ShaderText @@ -69918,26 +77277,80 @@ This can increase performance, and also silently ignore critical errors - Get-OBSVideoSettings - OBSVideoSettings + Get-OBSWalkingDeadPixelFixerShader + OBSWalkingDeadPixelFixerShader Get - Get-OBSVideoSettings : GetVideoSettings + Get-OBSWalkingDeadPixelFixerShader [[-ScanWidth] <int>] [[-ScanHeight] <int>] [[-ScanOffsetX] <int>] [[-ScanOffsetY] <int>] [[-ContrastThreshold] <float>] [[-MinClusterSize] <int>] [[-MaxClusterSize] <int>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ShowBorder] [-ShowGreen] [-Bypass] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Gets the current video settings. - Note: To get the true FPS value, divide the FPS numerator by the FPS denominator. Example: `60000/1001` - Get-OBSVideoSettings calls the OBS WebSocket with a request of type GetVideoSettings. - Get-OBSVideoSettings - - PassThru + Get-OBSWalkingDeadPixelFixerShader + + ScanWidth + + + + + Int + + Int + + + + + + + ScanHeight + + + + + Int + + Int + + + + + + + ScanOffsetX + + + + + Int + + Int + + + + + + + ScanOffsetY + + + + + Int + + Int + + + + + + + ShowBorder - If set, will return the information that would otherwise be sent to OBS. + + Switch @@ -69947,142 +77360,77 @@ This can increase performance, and also silently ignore critical errors - - NoResponse + + ContrastThreshold - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + - Switch + Float - Switch + Float - - - - - NoResponse - - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors - - Switch - - Switch - - - - - - - PassThru - - If set, will return the information that would otherwise be sent to OBS. - - Switch - - Switch - - - - - - - - - -------------------------- EXAMPLE 1 -------------------------- - - PS > - - Get-OBSVideoSettings - - - - - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getvideosettings - - - - - - Get-OBSVignettingShader - OBSVignettingShader - Get - - Get-OBSVignettingShader [[-InnerRadius] <float>] [[-OuterRadius] <float>] [[-Opacity] <float>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - - 0.2.0.1 - - - - - - Get-OBSVignettingShader - - InnerRadius + + MinClusterSize - Float + Int - Float + Int - - OuterRadius + + MaxClusterSize - Float + Int - Float + Int - - Opacity + + ShowGreen - Float + Switch - Float + Switch - - Notes + + Bypass - String + Switch - String + Switch - + SourceName @@ -70096,7 +77444,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -70110,7 +77458,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -70183,6 +77531,34 @@ This can increase performance, and also silently ignore critical errors + + Bypass + + + + + Switch + + Switch + + + + + + + ContrastThreshold + + + + + Float + + Float + + + + + FilterName @@ -70212,14 +77588,28 @@ This can increase performance, and also silently ignore critical errors - InnerRadius + MaxClusterSize - Float + Int - Float + Int + + + + + + + MinClusterSize + + + + + Int + + Int @@ -70240,56 +77630,70 @@ This can increase performance, and also silently ignore critical errors - Notes + PassThru - String + Switch - String + Switch - Opacity + ScanHeight - Float + Int - Float + Int - OuterRadius + ScanOffsetX - Float + Int - Float + Int - PassThru + ScanOffsetY - Switch + Int - Switch + Int + + + + + + + ScanWidth + + + + + Int + + Int @@ -70309,6 +77713,34 @@ This can increase performance, and also silently ignore critical errors + + ShowBorder + + + + + Switch + + Switch + + + + + + + ShowGreen + + + + + Switch + + Switch + + + + + SourceName @@ -70359,115 +77791,49 @@ This can increase performance, and also silently ignore critical errors - Get-OBSVirtualCamStatus - OBSVirtualCamStatus + Get-OBSZigZagShader + OBSZigZagShader Get - Get-OBSVirtualCamStatus : GetVirtualCamStatus + Get-OBSZigZagShader [[-Radius] <float>] [[-Angle] <float>] [[-Period] <float>] [[-Amplitude] <float>] [[-CenterX] <float>] [[-CenterY] <float>] [[-Phase] <float>] [[-Animate] <int>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Gets the status of the virtualcam output. - Get-OBSVirtualCamStatus calls the OBS WebSocket with a request of type GetVirtualCamStatus. - Get-OBSVirtualCamStatus - - PassThru + Get-OBSZigZagShader + + Radius - If set, will return the information that would otherwise be sent to OBS. + + - Switch + Float - Switch + Float - - NoResponse + + Angle - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors + + - Switch + Float - Switch + Float - - - - - NoResponse - - If set, will not attempt to receive a response from OBS. -This can increase performance, and also silently ignore critical errors - - Switch - - Switch - - - - - - - PassThru - - If set, will return the information that would otherwise be sent to OBS. - - Switch - - Switch - - - - - - - - - -------------------------- EXAMPLE 1 -------------------------- - - PS > - - Get-OBSVirtualCamStatus - - - - - - - - - https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#getvirtualcamstatus - - - - - - Get-OBSVoronoiPixelationShader - OBSVoronoiPixelationShader - Get - - Get-OBSVoronoiPixelationShader [[-PixH] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Alternative] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - - 0.2.0.1 - - - - - - Get-OBSVoronoiPixelationShader - - PixH + + Period @@ -70480,21 +77846,91 @@ This can increase performance, and also silently ignore critical errors - - Alternative + + Amplitude - Switch + Float - Switch + Float - + + CenterX + + + + + Float + + Float + + + + + + + CenterY + + + + + Float + + Float + + + + + + + Phase + + + + + Float + + Float + + + + + + + Animate + + + + + Int + + Int + + + + + + + Notes + + + + + String + + String + + + + + + SourceName @@ -70508,7 +77944,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -70522,7 +77958,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -70596,14 +78032,70 @@ This can increase performance, and also silently ignore critical errors - Alternative + Amplitude - Switch + Float - Switch + Float + + + + + + + Angle + + + + + Float + + Float + + + + + + + Animate + + + + + Int + + Int + + + + + + + CenterX + + + + + Float + + Float + + + + + + + CenterY + + + + + Float + + Float @@ -70651,6 +78143,20 @@ This can increase performance, and also silently ignore critical errors + + Notes + + + + + String + + String + + + + + PassThru @@ -70666,7 +78172,35 @@ This can increase performance, and also silently ignore critical errors - PixH + Period + + + + + Float + + Float + + + + + + + Phase + + + + + Float + + Float + + + + + + + Radius @@ -70743,35 +78277,35 @@ This can increase performance, and also silently ignore critical errors - Get-OBSZigZagShader - OBSZigZagShader + Get-OBSZoomBlurShader + OBSZoomBlurShader Get - Get-OBSZigZagShader [[-Radius] <float>] [[-Angle] <float>] [[-Period] <float>] [[-Amplitude] <float>] [[-CenterX] <float>] [[-CenterY] <float>] [[-Phase] <float>] [[-Animate] <int>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSZoomBlurShader [[-Samples] <int>] [[-Magnitude] <float>] [[-SpeedPercent] <int>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Ease] [-Glitch] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSZigZagShader + Get-OBSZoomBlurShader - Radius + Samples - Float + Int - Float + Int - Angle + Magnitude @@ -70785,90 +78319,48 @@ This can increase performance, and also silently ignore critical errors - Period - - - - - Float - - Float - - - - - - - Amplitude - - - - - Float - - Float - - - - - - - CenterX - - - - - Float - - Float - - - - - - - CenterY + SpeedPercent - Float + Int - Float + Int - - Phase + + Ease - Float + Switch - Float + Switch - - Animate + + Glitch - Int + Switch - Int + Switch - + Notes @@ -70882,7 +78374,7 @@ This can increase performance, and also silently ignore critical errors - + SourceName @@ -70896,7 +78388,7 @@ This can increase performance, and also silently ignore critical errors - + FilterName @@ -70910,7 +78402,7 @@ This can increase performance, and also silently ignore critical errors - + ShaderText @@ -70984,63 +78476,63 @@ This can increase performance, and also silently ignore critical errors - Amplitude + Ease - Float + Switch - Float + Switch - Angle + FilterName - Float + String - Float + String - Animate + Force - Int + Switch - Int + Switch - CenterX + Glitch - Float + Switch - Float + Switch - CenterY + Magnitude @@ -71053,34 +78545,6 @@ This can increase performance, and also silently ignore critical errors - - FilterName - - - - - String - - String - - - - - - - Force - - - - - Switch - - Switch - - - - - NoResponse @@ -71124,49 +78588,35 @@ This can increase performance, and also silently ignore critical errors - Period - - - - - Float - - Float - - - - - - - Phase + Samples - Float + Int - Float + Int - Radius + ShaderText - Float + String - Float + String - ShaderText + SourceName @@ -71180,14 +78630,14 @@ This can increase performance, and also silently ignore critical errors - SourceName + SpeedPercent - String + Int - String + Int @@ -71229,77 +78679,63 @@ This can increase performance, and also silently ignore critical errors - Get-OBSZoomBlurShader - OBSZoomBlurShader + Get-OBSZoomBlurTransitionShader + OBSZoomBlurTransitionShader Get - Get-OBSZoomBlurShader [[-Samples] <int>] [[-Magnitude] <float>] [[-SpeedPercent] <int>] [[-Notes] <string>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Ease] [-Glitch] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] + Get-OBSZoomBlurTransitionShader [[-ImageA] <string>] [[-ImageB] <string>] [[-TransitionTime] <float>] [[-Strength] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-ConvertLinear] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 - Get-OBSZoomBlurShader + Get-OBSZoomBlurTransitionShader - Samples + ImageA - Int + String - Int + String - Magnitude + ImageB - Float + String - Float + String - SpeedPercent - - - - - Int - - Int - - - - - - - Ease + TransitionTime - Switch + Float - Switch + Float - Glitch + ConvertLinear @@ -71313,14 +78749,14 @@ This can increase performance, and also silently ignore critical errors - Notes + Strength - String + Float - String + Float @@ -71428,7 +78864,7 @@ This can increase performance, and also silently ignore critical errors - Ease + ConvertLinear @@ -71470,28 +78906,28 @@ This can increase performance, and also silently ignore critical errors - Glitch + ImageA - Switch + String - Switch + String - Magnitude + ImageB - Float + String - Float + String @@ -71511,20 +78947,6 @@ This can increase performance, and also silently ignore critical errors - - Notes - - - - - String - - String - - - - - PassThru @@ -71540,21 +78962,21 @@ This can increase performance, and also silently ignore critical errors - Samples + ShaderText - Int + String - Int + String - ShaderText + SourceName @@ -71568,28 +78990,28 @@ This can increase performance, and also silently ignore critical errors - SourceName + Strength - String + Float - String + Float - SpeedPercent + TransitionTime - Int + Float - Int + Float @@ -71637,7 +79059,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSZoomShader [[-CenterXPercent] <int>] [[-CenterYPercent] <int>] [[-Power] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -71955,7 +79377,7 @@ This can increase performance, and also silently ignore critical errors Get-OBSZoomXYShader [[-CenterXPercent] <int>] [[-CenterYPercent] <int>] [[-XPower] <float>] [[-YPower] <float>] [[-SourceName] <string>] [[-FilterName] <string>] [[-ShaderText] <string>] [-Force] [-PassThru] [-NoResponse] [-UseShaderTime] [<CommonParameters>] - 0.2.0.1 + 0.2.1 @@ -72301,7 +79723,7 @@ This can increase performance, and also silently ignore critical errors Hide OBS - 0.2.0.1 + 0.2.1 Hides items in OBS @@ -72392,7 +79814,7 @@ This can increase performance, and also silently ignore critical errors Imports Effects - 0.2.0.1 + 0.2.1 Imports obs-powershell effects @@ -72459,7 +79881,7 @@ This can be a string, file, directory, command, or module. Open-OBSInputFiltersDialog : OpenInputFiltersDialog - 0.2.0.1 + 0.2.1 Opens the filters dialog of an input. @@ -72594,7 +80016,7 @@ This can increase performance, and also silently ignore critical errors Open-OBSInputInteractDialog : OpenInputInteractDialog - 0.2.0.1 + 0.2.1 Opens the interact dialog of an input. @@ -72729,7 +80151,7 @@ This can increase performance, and also silently ignore critical errors Open-OBSInputPropertiesDialog : OpenInputPropertiesDialog - 0.2.0.1 + 0.2.1 Opens the properties dialog of an input. @@ -72864,7 +80286,7 @@ This can increase performance, and also silently ignore critical errors Open-OBSSourceProjector : OpenSourceProjector - 0.2.0.1 + 0.2.1 Opens a projector for a source. @@ -73052,7 +80474,7 @@ This can increase performance, and also silently ignore critical errors Open-OBSVideoMixProjector : OpenVideoMixProjector - 0.2.0.1 + 0.2.1 Opens a projector for a specific output video mix. @@ -73218,7 +80640,7 @@ This can increase performance, and also silently ignore critical errors Receives data from OBS - 0.2.0.1 + 0.2.1 Receives responses from the OBS WebSocket @@ -73387,7 +80809,7 @@ You can see the websocket password in Tools -> obs-websocket settings -> s Remove OBS - 0.2.0.1 + 0.2.1 Removes items from OBS @@ -73466,7 +80888,7 @@ You can see the websocket password in Tools -> obs-websocket settings -> s Removes OBS Effects - 0.2.0.1 + 0.2.1 Removes effects currently loaded into OBS-PowerShell. @@ -73527,7 +80949,7 @@ You can see the websocket password in Tools -> obs-websocket settings -> s Remove-OBSInput : RemoveInput - 0.2.0.1 + 0.2.1 Removes an existing input. @@ -73663,7 +81085,7 @@ This can increase performance, and also silently ignore critical errors Remove-OBSProfile : RemoveProfile - 0.2.0.1 + 0.2.1 Removes a profile. If the current profile is chosen, it will change to a different profile first. @@ -73772,7 +81194,7 @@ This can increase performance, and also silently ignore critical errors Remove-OBSScene : RemoveScene - 0.2.0.1 + 0.2.1 Removes a scene from OBS. @@ -73907,7 +81329,7 @@ This can increase performance, and also silently ignore critical errors Remove-OBSSceneItem : RemoveSceneItem - 0.2.0.1 + 0.2.1 Removes a scene item from a scene. @@ -74069,7 +81491,7 @@ This can increase performance, and also silently ignore critical errors Remove-OBSSourceFilter : RemoveSourceFilter - 0.2.0.1 + 0.2.1 Removes a filter from a source. @@ -74230,7 +81652,7 @@ This can increase performance, and also silently ignore critical errors Resume-OBSRecord : ResumeRecord - 0.2.0.1 + 0.2.1 Resumes the record output. @@ -74324,7 +81746,7 @@ This can increase performance, and also silently ignore critical errors Save-OBSReplayBuffer : SaveReplayBuffer - 0.2.0.1 + 0.2.1 Saves the contents of the replay buffer output. @@ -74418,7 +81840,7 @@ This can increase performance, and also silently ignore critical errors Save-OBSSourceScreenshot : SaveSourceScreenshot - 0.2.0.1 + 0.2.1 Saves a screenshot of a source to the filesystem. @@ -74686,7 +82108,7 @@ This can increase performance, and also silently ignore critical errors Sends messages to the OBS websocket. - 0.2.0.1 + 0.2.1 Sends one or more messages to the OBS websocket. @@ -74879,7 +82301,7 @@ If -SerialFrame was provied, -StepTime will be the number of frames to wait. Send-OBSCallVendorRequest : CallVendorRequest - 0.2.0.1 + 0.2.1 Call a request registered to a vendor. @@ -75042,7 +82464,7 @@ This can increase performance, and also silently ignore critical errors Send-OBSCustomEvent : BroadcastCustomEvent - 0.2.0.1 + 0.2.1 Broadcasts a `CustomEvent` to all WebSocket clients. Receivers are clients which are identified and subscribed. @@ -75151,7 +82573,7 @@ This can increase performance, and also silently ignore critical errors Send-OBSOffsetMediaInputCursor : OffsetMediaInputCursor - 0.2.0.1 + 0.2.1 Offsets the current cursor position of a media input by the specified value. @@ -75313,7 +82735,7 @@ This can increase performance, and also silently ignore critical errors Send-OBSPauseRecord : PauseRecord - 0.2.0.1 + 0.2.1 Pauses the record output. @@ -75407,7 +82829,7 @@ This can increase performance, and also silently ignore critical errors Send-OBSPressInputPropertiesButton : PressInputPropertiesButton - 0.2.0.1 + 0.2.1 Presses a button in the properties of an input. @@ -75571,7 +82993,7 @@ This can increase performance, and also silently ignore critical errors Send-OBSSleep : Sleep - 0.2.0.1 + 0.2.1 Sleeps for a time duration or number of frames. Only available in request batches with types `SERIAL_REALTIME` or `SERIAL_FRAME`. @@ -75706,7 +83128,7 @@ This can increase performance, and also silently ignore critical errors Send-OBSStreamCaption : SendStreamCaption - 0.2.0.1 + 0.2.1 Sends CEA-608 caption text over the stream output. @@ -75815,7 +83237,7 @@ This can increase performance, and also silently ignore critical errors Send-OBSTriggerHotkeyByKeySequence : TriggerHotkeyByKeySequence - 0.2.0.1 + 0.2.1 Triggers a hotkey using a sequence of keys. @@ -76055,7 +83477,7 @@ This can increase performance, and also silently ignore critical errors Send-OBSTriggerHotkeyByName : TriggerHotkeyByName - 0.2.0.1 + 0.2.1 Triggers a hotkey using its name. See `GetHotkeyList`. @@ -76191,7 +83613,7 @@ This can increase performance, and also silently ignore critical errors Send-OBSTriggerMediaInputAction : TriggerMediaInputAction - 0.2.0.1 + 0.2.1 Triggers an action on a media input. @@ -76352,7 +83774,7 @@ This can increase performance, and also silently ignore critical errors Send-OBSTriggerStudioModeTransition : TriggerStudioModeTransition - 0.2.0.1 + 0.2.1 Triggers the current scene transition. Same functionality as the `Transition` button in studio mode. @@ -76446,7 +83868,7 @@ This can increase performance, and also silently ignore critical errors Sets an OBS 3D Filter. - 0.2.0.1 + 0.2.1 Adds or Changes a 3D Filter on an OBS Input. @@ -76730,7 +84152,7 @@ If this is not provided and the filter already exists, the settings of the filte Adds or sets an audio output source - 0.2.0.1 + 0.2.1 Adds or sets an audio output source in OBS. This captures the audio that is being sent to an output device. @@ -76891,7 +84313,7 @@ To add support for other operating systems, file an issue or open a pull request Sets a browser source - 0.2.0.1 + 0.2.1 Adds or changes a browser source in OBS. @@ -77221,7 +84643,7 @@ If none is provided, this will be the output width of the video settings. Sets a color filter - 0.2.0.1 + 0.2.1 Adds or Changes a Color Correction Filter on an OBS Input. @@ -77499,7 +84921,7 @@ If this is not provided and the filter already exists, the settings of the filte Adds a color source - 0.2.0.1 + 0.2.1 Adds a color source to OBS. This displays a single 32-bit color (RGBA). @@ -77640,7 +85062,7 @@ If no scene name is provided, the current program scene will be used. Set-OBSCurrentPreviewScene : SetCurrentPreviewScene - 0.2.0.1 + 0.2.1 Sets the current preview scene. @@ -77776,7 +85198,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSCurrentProfile : SetCurrentProfile - 0.2.0.1 + 0.2.1 Switches to a profile. @@ -77885,7 +85307,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSCurrentProgramScene : SetCurrentProgramScene - 0.2.0.1 + 0.2.1 Sets the current program scene. @@ -78020,7 +85442,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSCurrentSceneCollection : SetCurrentSceneCollection - 0.2.0.1 + 0.2.1 Switches to a scene collection. @@ -78130,7 +85552,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSCurrentSceneTransition : SetCurrentSceneTransition - 0.2.0.1 + 0.2.1 Sets the current scene transition. @@ -78240,7 +85662,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSCurrentSceneTransitionDuration : SetCurrentSceneTransitionDuration - 0.2.0.1 + 0.2.1 Sets the duration of the current scene transition, if it is not fixed. @@ -78349,7 +85771,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSCurrentSceneTransitionSettings : SetCurrentSceneTransitionSettings - 0.2.0.1 + 0.2.1 Sets the settings of the current scene transition. @@ -78484,7 +85906,7 @@ This can increase performance, and also silently ignore critical errors Adds a display source - 0.2.0.1 + 0.2.1 Adds a display source to OBS. This captures the contents of the display. @@ -78667,7 +86089,7 @@ If no scene name is provided, the current program scene will be used. Sets a Equalizer filter. - 0.2.0.1 + 0.2.1 Adds or Changes a 3-band Equalizer Filter on an OBS Input. @@ -78794,7 +86216,7 @@ If this is not provided and the filter already exists, the settings of the filte Sets a Gain filter. - 0.2.0.1 + 0.2.1 Adds or Changes a Gain Filter on an OBS Input. @@ -78882,7 +86304,7 @@ If this is not provided and the filter already exists, the settings of the filte Set-OBSInputAudioBalance : SetInputAudioBalance - 0.2.0.1 + 0.2.1 Sets the audio balance of an input. @@ -79043,7 +86465,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSInputAudioMonitorType : SetInputAudioMonitorType - 0.2.0.1 + 0.2.1 Sets the audio monitor type of an input. @@ -79204,7 +86626,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSInputAudioSyncOffset : SetInputAudioSyncOffset - 0.2.0.1 + 0.2.1 Sets the audio sync offset of an input. @@ -79365,7 +86787,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSInputAudioTracks : SetInputAudioTracks - 0.2.0.1 + 0.2.1 Sets the enable state of audio tracks of an input. @@ -79526,7 +86948,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSInputMute : SetInputMute - 0.2.0.1 + 0.2.1 Sets the audio mute state of an input. @@ -79687,7 +87109,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSInputName : SetInputName - 0.2.0.1 + 0.2.1 Sets the name of an input (rename). @@ -79848,7 +87270,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSInputSettings : SetInputSettings - 0.2.0.1 + 0.2.1 Sets the settings of an input. @@ -80035,7 +87457,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSInputVolume : SetInputVolume - 0.2.0.1 + 0.2.1 Sets the volume setting of an input. @@ -80222,7 +87644,7 @@ This can increase performance, and also silently ignore critical errors Sets a markdown source - 0.2.0.1 + 0.2.1 Adds or changes a markdown source in OBS. @@ -80435,7 +87857,7 @@ If none is provided, this will be the output width of the video settings. Set-OBSMediaInputCursor : SetMediaInputCursor - 0.2.0.1 + 0.2.1 Sets the cursor position of a media input. @@ -80597,7 +88019,7 @@ This can increase performance, and also silently ignore critical errors Adds a media source - 0.2.0.1 + 0.2.1 Adds a media source to OBS. @@ -80917,7 +88339,7 @@ If no scene name is provided, the current program scene will be used. Set-OBSOutputSettings : SetOutputSettings - 0.2.0.1 + 0.2.1 Sets the settings of an output. @@ -81052,7 +88474,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSPersistentData : SetPersistentData - 0.2.0.1 + 0.2.1 Sets the value of a "slot" from the selected persistent data realm. @@ -81213,7 +88635,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSProfileParameter : SetProfileParameter - 0.2.0.1 + 0.2.1 Sets the value of a parameter in the current profile's configuration. @@ -81374,7 +88796,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSRecordDirectory : SetRecordDirectory - 0.2.0.1 + 0.2.1 Sets the current directory that the record output writes files to. @@ -81483,7 +88905,7 @@ This can increase performance, and also silently ignore critical errors Sets a RenderDelay filter. - 0.2.0.1 + 0.2.1 Adds or Changes a RenderDelay Filter on an OBS Input. @@ -81571,7 +88993,7 @@ If this is not provided and the filter already exists, the settings of the filte Sets a Scale filter. - 0.2.0.1 + 0.2.1 Adds or Changes a Scale Filter on an OBS Input. @@ -81713,7 +89135,7 @@ This is only valid if the sampling method is set to "lanczos". Set-OBSSceneItemBlendMode : SetSceneItemBlendMode - 0.2.0.1 + 0.2.1 Sets the blend mode of a scene item. @@ -81901,7 +89323,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSSceneItemEnabled : SetSceneItemEnabled - 0.2.0.1 + 0.2.1 Sets the enable state of a scene item. @@ -82089,7 +89511,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSSceneItemIndex : SetSceneItemIndex - 0.2.0.1 + 0.2.1 Sets the index position of a scene item in a scene. @@ -82277,7 +89699,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSSceneItemLocked : SetSceneItemLocked - 0.2.0.1 + 0.2.1 Sets the lock state of a scene item. @@ -82465,7 +89887,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSSceneItemTransform : SetSceneItemTransform - 0.2.0.1 + 0.2.1 Sets the transform and crop info of a scene item. @@ -82652,7 +90074,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSSceneName : SetSceneName - 0.2.0.1 + 0.2.1 Sets the name of a scene (rename). @@ -82813,7 +90235,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSSceneSceneTransitionOverride : SetSceneSceneTransitionOverride - 0.2.0.1 + 0.2.1 Sets the scene transition overridden for a scene. @@ -83000,7 +90422,7 @@ This can increase performance, and also silently ignore critical errors Sets a scroll filter. - 0.2.0.1 + 0.2.1 Adds or Changes a Scroll Filter on an OBS Input. @@ -83192,7 +90614,7 @@ If this is not provided and the filter already exists, the settings of the filte Sets a Shader filter. - 0.2.0.1 + 0.2.1 Adds or Changes a Shader Filter on an OBS Input. @@ -83367,7 +90789,7 @@ To see what the name of a shader setting is, change it in the user interface and Sets a Sharpness filter. - 0.2.0.1 + 0.2.1 Adds or Changes a Sharpness Filter on an OBS Input. @@ -83455,7 +90877,7 @@ If this is not provided and the filter already exists, the settings of the filte Sets a Sound Cloud Source - 0.2.0.1 + 0.2.1 Adds or changes a Sound Cloud source OBS. @@ -84018,7 +91440,7 @@ If none is provided, this will be the output width of the video settings. Set-OBSSourceFilterEnabled : SetSourceFilterEnabled - 0.2.0.1 + 0.2.1 Sets the enable state of a source filter. @@ -84205,7 +91627,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSSourceFilterIndex : SetSourceFilterIndex - 0.2.0.1 + 0.2.1 Sets the index position of a filter on a source. @@ -84392,7 +91814,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSSourceFilterName : SetSourceFilterName - 0.2.0.1 + 0.2.1 Sets the name of a source filter (rename). @@ -84579,7 +92001,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSSourceFilterSettings : SetSourceFilterSettings - 0.2.0.1 + 0.2.1 Sets the settings of a source filter. @@ -84792,7 +92214,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSStreamServiceSettings : SetStreamServiceSettings - 0.2.0.1 + 0.2.1 Sets the current stream service settings (stream destination). @@ -84928,7 +92350,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSStudioModeEnabled : SetStudioModeEnabled - 0.2.0.1 + 0.2.1 Enables or disables studio mode @@ -85037,7 +92459,7 @@ This can increase performance, and also silently ignore critical errors Adds a VLC playlist source - 0.2.0.1 + 0.2.1 Adds or sets VLC playlist sources to OBS. @@ -85626,7 +93048,7 @@ Notice: this current requires confirmation in the UI. Set-OBSTBarPosition : SetTBarPosition - 0.2.0.1 + 0.2.1 Sets the position of the TBar. @@ -85762,7 +93184,7 @@ This can increase performance, and also silently ignore critical errors Set-OBSVideoSettings : SetVideoSettings - 0.2.0.1 + 0.2.1 Sets the current video settings. @@ -86002,7 +93424,7 @@ This can increase performance, and also silently ignore critical errors Adds a VLC playlist source - 0.2.0.1 + 0.2.1 Adds or sets VLC playlist sources to OBS. @@ -86345,7 +93767,7 @@ If an `[IO.FileInfo]` is provided, this will be the exact file. OBS Waveform Source - 0.2.0.1 + 0.2.1 Gets, Sets, or Adds a waveform source in OBS. @@ -87224,7 +94646,7 @@ This is the mathematical function used to determine the current "window" of audi Adds or sets a window capture source - 0.2.0.1 + 0.2.1 Adds or sets a windows capture source in OBS. This captures the contents of a window. @@ -87504,7 +94926,7 @@ This the number of the monitor you would like to capture. Shows content in OBS - 0.2.0.1 + 0.2.1 Shows content in Open Broadcasting Studio @@ -87761,6 +95183,212 @@ Show-OBS -FilePath .\BlueRect.svg + + + Start-OBS + OBS + Start + + Start OBS + + 0.2.1 + + + Starts OBS + Without any parameters, will attempt to start the obs process. + If OBS is already running, will output the current obs process. + * If `-Recording` is passed, will start recording + * If `-Streaming` is passed, will start streaming + * If `-StudioMode` is passed, will start studio mode + * If `-VirtualCamera` is passed, will start the virtual camera + If additional arguments are passed, will pass them thru to a new obs process. + + + + Start-OBS + + ArgumentList + + A list of arguments. These will be passed to a new obs process. + + System.Management.Automation.PSObject[] + + System.Management.Automation.PSObject[] + + + + + + + InputObject + + Any input object. This will currently be ignored. + + System.Management.Automation.PSObject[] + + System.Management.Automation.PSObject[] + + + + + + + Recording + + If set, will start recording. + + Switch + + Switch + + + + + + + Streaming + + If set, will start streaming. + + Switch + + Switch + + + + + + + StudioMode + + If set, will start studio mode. + + Switch + + Switch + + + + + + + VirtualCamera + + If set, will start the virtual camera + + Switch + + Switch + + + + + + + + + + ArgumentList + + A list of arguments. These will be passed to a new obs process. + + System.Management.Automation.PSObject[] + + System.Management.Automation.PSObject[] + + + + + + + InputObject + + Any input object. This will currently be ignored. + + System.Management.Automation.PSObject[] + + System.Management.Automation.PSObject[] + + + + + + + Recording + + If set, will start recording. + + Switch + + Switch + + + + + + + Streaming + + If set, will start streaming. + + Switch + + Switch + + + + + + + StudioMode + + If set, will start studio mode. + + Switch + + Switch + + + + + + + VirtualCamera + + If set, will start the virtual camera + + Switch + + Switch + + + + + + + + + Stop-OBS + + + + + Start-OBSRecord + + + + + Start-OBSStream + + + + + Start-OBSVirtualCam + + + + + Start-OBSEffect @@ -87769,7 +95397,7 @@ Show-OBS -FilePath .\BlueRect.svg Starts obs-powershell effects. - 0.2.0.1 + 0.2.1 Starts an effect in OBS PowerShell. @@ -88140,7 +95768,7 @@ If not provided, each effect should use it's own duration. Start-OBSOutput : StartOutput - 0.2.0.1 + 0.2.1 Starts an output. @@ -88249,7 +95877,7 @@ This can increase performance, and also silently ignore critical errors Start-OBSRecord : StartRecord - 0.2.0.1 + 0.2.1 Starts the record output. @@ -88343,7 +95971,7 @@ This can increase performance, and also silently ignore critical errors Start-OBSReplayBuffer : StartReplayBuffer - 0.2.0.1 + 0.2.1 Starts the replay buffer output. @@ -88437,7 +96065,7 @@ This can increase performance, and also silently ignore critical errors Start-OBSStream : StartStream - 0.2.0.1 + 0.2.1 Starts the stream output. @@ -88531,7 +96159,7 @@ This can increase performance, and also silently ignore critical errors Start-OBSVirtualCam : StartVirtualCam - 0.2.0.1 + 0.2.1 Starts the virtualcam output. @@ -88617,6 +96245,257 @@ This can increase performance, and also silently ignore critical errors + + + Stop-OBS + OBS + Stop + + Stops OBS + + 0.2.1 + + + Stops OBS. + By default, stops recording and streaming. + If -Process is provided, will stop all running OBS processes + If -Recording is provided, will stop recording + If -Streaming if provided, will stop obs streaming + If -VirtualCamera is provided, will stop the virtual camera + + + + Stop-OBS + + Recording + + If set, will stop recording. + + Switch + + Switch + + + + + + + Streaming + + If set, will stop streaming + + Switch + + Switch + + + + + + + VirtualCamera + + If set, will stop the virtual camera. + + Switch + + Switch + + + + + + + Process + + If set, will stop the OBS process. + + Switch + + Switch + + + + + + + StudioMode + + If set, will enable studio mode. + + Switch + + Switch + + + + + + + + + + Process + + If set, will stop the OBS process. + + Switch + + Switch + + + + + + + Recording + + If set, will stop recording. + + Switch + + Switch + + + + + + + Streaming + + If set, will stop streaming + + Switch + + Switch + + + + + + + StudioMode + + If set, will enable studio mode. + + Switch + + Switch + + + + + + + VirtualCamera + + If set, will stop the virtual camera. + + Switch + + Switch + + + + + + + + + + + This command Supports Should Process and has a ConfirmImpact of 'High' + +In an interactive session, this command prompt by default. + +If `-WhatIf` is passed, will output what happen if this ran +If `-Confirm:$false`, confirmation will be skipped. + + + + + -------------------------- EXAMPLE 1 -------------------------- + + PS > + + # Stop Streaming and Recording +Stop-OBS + + + + + -------------------------- EXAMPLE 2 -------------------------- + + PS > + + # Stops obs recording +Stop-OBS -Recording + + + + + -------------------------- EXAMPLE 3 -------------------------- + + PS > + + # Stop Streaming +Stop-OBS -Streaming + + + + + -------------------------- EXAMPLE 4 -------------------------- + + PS > + + # Stop OBS Virtual Camera +Stop-OBS -VirtualCamera + + + + + -------------------------- EXAMPLE 5 -------------------------- + + PS > + + # Stop OBS Virtual Camera without prompting +Stop-OBS -VirtualCamera -Confirm:$false + + + + + -------------------------- EXAMPLE 6 -------------------------- + + PS > + + Stop-OBS -StudioMode + + + + + + + Stop-OBSRecord + + + + + Stop-OBSStream + + + + + Stop-OBSVirtualCam + + + + + Set-OBSStudioModeEnabled + + + + + Stop-OBSEffect @@ -88625,7 +96504,7 @@ This can increase performance, and also silently ignore critical errors Stops obs-powershell effects. - 0.2.0.1 + 0.2.1 Stops an effect in OBS PowerShell. @@ -88687,7 +96566,7 @@ This can increase performance, and also silently ignore critical errors Stop-OBSOutput : StopOutput - 0.2.0.1 + 0.2.1 Stops an output. @@ -88796,7 +96675,7 @@ This can increase performance, and also silently ignore critical errors Stop-OBSRecord : StopRecord - 0.2.0.1 + 0.2.1 Stops the record output. @@ -88890,7 +96769,7 @@ This can increase performance, and also silently ignore critical errors Stop-OBSReplayBuffer : StopReplayBuffer - 0.2.0.1 + 0.2.1 Stops the replay buffer output. @@ -88984,7 +96863,7 @@ This can increase performance, and also silently ignore critical errors Stop-OBSStream : StopStream - 0.2.0.1 + 0.2.1 Stops the stream output. @@ -89078,7 +96957,7 @@ This can increase performance, and also silently ignore critical errors Stop-OBSVirtualCam : StopVirtualCam - 0.2.0.1 + 0.2.1 Stops the virtualcam output. @@ -89172,7 +97051,7 @@ This can increase performance, and also silently ignore critical errors Switch-OBSInputMute : ToggleInputMute - 0.2.0.1 + 0.2.1 Toggles the audio mute state of an input. @@ -89307,7 +97186,7 @@ This can increase performance, and also silently ignore critical errors Switch-OBSOutput : ToggleOutput - 0.2.0.1 + 0.2.1 Toggles the status of an output. @@ -89416,7 +97295,7 @@ This can increase performance, and also silently ignore critical errors Switch-OBSRecord : ToggleRecord - 0.2.0.1 + 0.2.1 Toggles the status of the record output. @@ -89510,7 +97389,7 @@ This can increase performance, and also silently ignore critical errors Switch-OBSRecordPause : ToggleRecordPause - 0.2.0.1 + 0.2.1 Toggles pause on the record output. @@ -89604,7 +97483,7 @@ This can increase performance, and also silently ignore critical errors Switch-OBSReplayBuffer : ToggleReplayBuffer - 0.2.0.1 + 0.2.1 Toggles the state of the replay buffer output. @@ -89698,7 +97577,7 @@ This can increase performance, and also silently ignore critical errors Switch-OBSStream : ToggleStream - 0.2.0.1 + 0.2.1 Toggles the status of the stream output. @@ -89792,7 +97671,7 @@ This can increase performance, and also silently ignore critical errors Switch-OBSVirtualCam : ToggleVirtualCam - 0.2.0.1 + 0.2.1 Toggles the state of the virtualcam output. @@ -89886,7 +97765,7 @@ This can increase performance, and also silently ignore critical errors Watches OBS - 0.2.0.1 + 0.2.1 Watches the OBS websocket for events. diff --git a/obs-powershell.ps.psd1 b/obs-powershell.ps.psd1 index 5f93dac7..176f454f 100644 --- a/obs-powershell.ps.psd1 +++ b/obs-powershell.ps.psd1 @@ -1,11 +1,11 @@ @{ - ModuleVersion = '0.2.0.1' + ModuleVersion = '0.2.1' RootModule = 'obs-powershell.psm1' Description = 'Script your streams' Guid = '1417123e-a932-439f-9b68-a7313cf1e170' Author = 'James Brundage' CompanyName = 'Start-Automating' - Copyright = '2022-2025 Start-Automating' + Copyright = '2022-2026 Start-Automating' FormatsToProcess = 'obs-powershell.format.ps1xml' TypesToProcess = 'obs-powershell.types.ps1xml' PowerShellVersion = '7.0' @@ -15,82 +15,37 @@ ProjectURI = 'https://github.com/StartAutomating/obs-powershell' LicenseURI = 'https://github.com/StartAutomating/obs-powershell/blob/main/LICENSE' ReleaseNotes = @' -> Like It? [Star It](https://github.com/StartAutomating/obs-powershell) -> Love It? [Support It](https://github.com/sponsors/StartAutomating) +## obs-powershell 0.2.1: -## obs-powershell 0.2.0.1: - -* Fixing `Watch-OBS` (Fixes #216) -* Adding `CONTRIBUTING.md` (Fixes #204) -* Adding `CODE_OF_CONDUCT.md` (Fixes #205) +* New General Purpose Commands + * Start-OBS (#220) + * Stop-OBS (#226) +* New Shader Commands: + * Get-OBS3dPanelShader + * Get-OBSAudioShader + * Get-OBSCubeRotatingShader + * Get-OBSDisplacementMapAdvancedInvertShader + * Get-OBSDisplacementMapAdvancedShader + * Get-OBSDisplacementMapInvertShader + * Get-OBSDisplacementMapShader + * Get-OBSGlitchPeriodicShader + * Get-OBSHardBlinkShader + * Get-OBSMotionBlurShader + * Get-OBSNoiseShader + * Get-OBSNormalMapShader + * Get-OBSPerspectiveShader + * Get-OBSQuadrilateralCropShader + * Get-OBSRepeatGridCenterCropShader + * Get-OBSWalkingDeadPixelFixerShader + * Get-OBSZoomBlurTransitionShader --- -## obs-powershell 0.2: - -* So Many Shaders! -* @exeldro makes some excellent obs plugins - * Every PixelShader from [obs-shaderfilter](https://github.com/exeldro/obs-shaderfilter) has an auto-generated function: - * As of this build, there are 142 Shader functions! - * Flip Shader ( #200 ) - * Zoom XY Shader ( #199 ) - * RGBA Percent Shader ( #198 ) - * Reflect Shader ( #197 ) - * Shader Commands now support -Force -* Drastically improved start time on Windows (#214) -* OBS Sources: - * New Sources: - * OBSSoundCloudSource ( #179 ) - * OBSSwitchSource (#142) - * OBSMarkdownSource (#143) - * OBSWaveformSource (#141) - * All existing sources are now implemented in a `Get`, and aliased to `Set`,`Add` - * Making Set also Get-OBSWindowSource (#152) - * Making Set also Get-OBSVLCSource (#151) - * Making Set also Get-OBSMediaSource (#150) - * Making Set also Get-OBSColorSource (#148) - * Making Set also Get-OBSBrowserSource (#147) - * Making Set also Get-OBSAudioOutputSource (#146) -* New Effects: - * Zoom In / Out Effect ( #164 ) - * Start-OBSEffect - Adding -Reverse (Fixes #121) -* Exporting `$obs` (#157, #158, #159) and drastically expanding pseudo types -* Pseudo Types - * GetCurrentProgramScene.ToString() ( Fixes #202, Fixes #166 ) - * OBS.Beat ( #195 ) - * OBS.Beat.Timer - * OBS.Beat.TapBPM ( #191) - * Stopping OBS.Beat.Timer on Unload - * OBS.Beat.get_Sine ( #192 ) - * OBS.Beat.get_Cosine ( #193 ) - * OBS.Beat.Angle ( #194 ) - * OBS.Beat.Duration ( #189 ) - * OBS.Beat.BeatCount ( #190 ) - * OBS.Beat.BeatStart ( #188 ) - * OBS.Beat.BPM ( #187 ) - * $obs.Beat ( #186 ) - * OBS.Input - * OBS.Input.Disable/EnableAllFilter(s) ( #183 ) - * OBS.SceneItem.Animate Permissiveness ( #182 ) - * OBS.Filter.Disable PassThru support ( #181 ) - * OBS.Statistics ( #178 ) - * OBS.Input ( #174 ) - * OBS.Filter ( #175 ) - * OBS.SceneItem ( #173 ) - * OBS.GetSceneItemList.Response.Stretch() ( #172 ) - * OBS.GetSceneItemList.Response.Center() ( #171 ) - * OBS.GetInputList .SourceName alias ( #170 ) - * Adding .SceneItem to OBS.Inputs (Fixes #154) -* Minor Fixes: - * Watch-OBS -BufferSize: Defaulting to 64kb ( Fixes #212, Fixes #213 ) - * Fixing -Scene parameter defaults ( Fixes #210 ) - * Updating Build Conditions - * obs-powershell now mounts itself ( #180 ) - * obs-powershell supporting module profiles (#155) +> Like It? [Star It](https://github.com/StartAutomating/obs-powershell) +> Love It? [Support It](https://github.com/sponsors/StartAutomating) ---- -Previous release notes available in the [CHANGELOG](https://github.com/StartAutomating/obs-powershell/blob/main/CHANGELOG.md) +Additional History available in the [CHANGELOG](https://github.com/StartAutomating/obs-powershell/blob/main/CHANGELOG.md) '@ } } diff --git a/obs-powershell.psd1 b/obs-powershell.psd1 index cc336277..8dfc1f77 100644 --- a/obs-powershell.psd1 +++ b/obs-powershell.psd1 @@ -1,11 +1,11 @@ @{ - ModuleVersion = '0.2.0.1' + ModuleVersion = '0.2.1' RootModule = 'obs-powershell.psm1' Description = 'Script your streams' Guid = '1417123e-a932-439f-9b68-a7313cf1e170' Author = 'James Brundage' CompanyName = 'Start-Automating' - Copyright = '2022-2025 Start-Automating' + Copyright = '2022-2026 Start-Automating' FormatsToProcess = 'obs-powershell.format.ps1xml' TypesToProcess = 'obs-powershell.types.ps1xml' PowerShellVersion = '7.0' @@ -15,82 +15,37 @@ ProjectURI = 'https://github.com/StartAutomating/obs-powershell' LicenseURI = 'https://github.com/StartAutomating/obs-powershell/blob/main/LICENSE' ReleaseNotes = @' -> Like It? [Star It](https://github.com/StartAutomating/obs-powershell) -> Love It? [Support It](https://github.com/sponsors/StartAutomating) - -## obs-powershell 0.2.0.1: +## obs-powershell 0.2.1: -* Fixing `Watch-OBS` (Fixes #216) -* Adding `CONTRIBUTING.md` (Fixes #204) -* Adding `CODE_OF_CONDUCT.md` (Fixes #205) +* New General Purpose Commands + * Start-OBS (#220) + * Stop-OBS (#226) +* New Shader Commands: + * Get-OBS3dPanelShader + * Get-OBSAudioShader + * Get-OBSCubeRotatingShader + * Get-OBSDisplacementMapAdvancedInvertShader + * Get-OBSDisplacementMapAdvancedShader + * Get-OBSDisplacementMapInvertShader + * Get-OBSDisplacementMapShader + * Get-OBSGlitchPeriodicShader + * Get-OBSHardBlinkShader + * Get-OBSMotionBlurShader + * Get-OBSNoiseShader + * Get-OBSNormalMapShader + * Get-OBSPerspectiveShader + * Get-OBSQuadrilateralCropShader + * Get-OBSRepeatGridCenterCropShader + * Get-OBSWalkingDeadPixelFixerShader + * Get-OBSZoomBlurTransitionShader --- -## obs-powershell 0.2: - -* So Many Shaders! -* @exeldro makes some excellent obs plugins - * Every PixelShader from [obs-shaderfilter](https://github.com/exeldro/obs-shaderfilter) has an auto-generated function: - * As of this build, there are 142 Shader functions! - * Flip Shader ( #200 ) - * Zoom XY Shader ( #199 ) - * RGBA Percent Shader ( #198 ) - * Reflect Shader ( #197 ) - * Shader Commands now support -Force -* Drastically improved start time on Windows (#214) -* OBS Sources: - * New Sources: - * OBSSoundCloudSource ( #179 ) - * OBSSwitchSource (#142) - * OBSMarkdownSource (#143) - * OBSWaveformSource (#141) - * All existing sources are now implemented in a `Get`, and aliased to `Set`,`Add` - * Making Set also Get-OBSWindowSource (#152) - * Making Set also Get-OBSVLCSource (#151) - * Making Set also Get-OBSMediaSource (#150) - * Making Set also Get-OBSColorSource (#148) - * Making Set also Get-OBSBrowserSource (#147) - * Making Set also Get-OBSAudioOutputSource (#146) -* New Effects: - * Zoom In / Out Effect ( #164 ) - * Start-OBSEffect - Adding -Reverse (Fixes #121) -* Exporting `$obs` (#157, #158, #159) and drastically expanding pseudo types -* Pseudo Types - * GetCurrentProgramScene.ToString() ( Fixes #202, Fixes #166 ) - * OBS.Beat ( #195 ) - * OBS.Beat.Timer - * OBS.Beat.TapBPM ( #191) - * Stopping OBS.Beat.Timer on Unload - * OBS.Beat.get_Sine ( #192 ) - * OBS.Beat.get_Cosine ( #193 ) - * OBS.Beat.Angle ( #194 ) - * OBS.Beat.Duration ( #189 ) - * OBS.Beat.BeatCount ( #190 ) - * OBS.Beat.BeatStart ( #188 ) - * OBS.Beat.BPM ( #187 ) - * $obs.Beat ( #186 ) - * OBS.Input - * OBS.Input.Disable/EnableAllFilter(s) ( #183 ) - * OBS.SceneItem.Animate Permissiveness ( #182 ) - * OBS.Filter.Disable PassThru support ( #181 ) - * OBS.Statistics ( #178 ) - * OBS.Input ( #174 ) - * OBS.Filter ( #175 ) - * OBS.SceneItem ( #173 ) - * OBS.GetSceneItemList.Response.Stretch() ( #172 ) - * OBS.GetSceneItemList.Response.Center() ( #171 ) - * OBS.GetInputList .SourceName alias ( #170 ) - * Adding .SceneItem to OBS.Inputs (Fixes #154) -* Minor Fixes: - * Watch-OBS -BufferSize: Defaulting to 64kb ( Fixes #212, Fixes #213 ) - * Fixing -Scene parameter defaults ( Fixes #210 ) - * Updating Build Conditions - * obs-powershell now mounts itself ( #180 ) - * obs-powershell supporting module profiles (#155) +> Like It? [Star It](https://github.com/StartAutomating/obs-powershell) +> Love It? [Support It](https://github.com/sponsors/StartAutomating) ---- -Previous release notes available in the [CHANGELOG](https://github.com/StartAutomating/obs-powershell/blob/main/CHANGELOG.md) +Additional History available in the [CHANGELOG](https://github.com/StartAutomating/obs-powershell/blob/main/CHANGELOG.md) '@ } } @@ -103,159 +58,9 @@ Previous release notes available in the [CHANGELOG](https://github.com/StartAuto 'Remove-OBS', 'Send-OBS', 'Show-OBS', +'Start-OBS', +'Stop-OBS', 'Watch-OBS', -'Set-OBSAudioOutputSource', -'Set-OBSBrowserSource', -'Set-OBSColorSource', -'Set-OBSDisplaySource', -'Set-OBSMarkdownSource', -'Set-OBSMediaSource', -'Set-OBSSoundCloudSource', -'Set-OBSSwitchSource', -'Set-OBSVLCSource', -'Set-OBSWaveformSource', -'Set-OBSWindowSource', -'Get-OBS3dSwapTransitionShader', -'Get-OBSAddShader', -'Get-OBSAlphaBorderShader', -'Get-OBSAlphaGamingBentCameraShader', -'Get-OBSAnimatedPathShader', -'Get-OBSAnimatedTextureShader', -'Get-OBSAsciiShader', -'Get-OBSAspectRatioShader', -'Get-OBSBackgroundRemovalShader', -'Get-OBSBlendOpacityShader', -'Get-OBSBlinkShader', -'Get-OBSBloomShader', -'Get-OBSBorderShader', -'Get-OBSBoxBlurShader', -'Get-OBSBulgePinchShader', -'Get-OBSBurnShader', -'Get-OBSCartoonShader', -'Get-OBSCellShadedShader', -'Get-OBSChromaticAberrationShader', -'Get-OBSChromaUVDistortionShader', -'Get-OBSCircleMaskFilterShader', -'Get-OBSClockAnalogShader', -'Get-OBSClockDigitalLedShader', -'Get-OBSClockDigitalNixieShader', -'Get-OBSColorDepthShader', -'Get-OBSColorGradeFilterShader', -'Get-OBSCornerPinShader', -'Get-OBSCrtCurvatureShader', -'Get-OBSCurveShader', -'Get-OBSCutRectPerCornerShader', -'Get-OBSCylinderShader', -'Get-OBSDarkenShader', -'Get-OBSDeadPixelFixerShader', -'Get-OBSDensitySatHueShader', -'Get-OBSDiffuseTransitionShader', -'Get-OBSDigitalRainShader', -'Get-OBSDivideRotateShader', -'Get-OBSDoodleShader', -'Get-OBSDrawingsShader', -'Get-OBSDropShadowShader', -'Get-OBSDrunkShader', -'Get-OBSDynamicMaskShader', -'Get-OBSEdgeDetectionShader', -'Get-OBSEmbersShader', -'Get-OBSEmbossColorShader', -'Get-OBSEmbossShader', -'Get-OBSExeldroBentCameraShader', -'Get-OBSFadeTransitionShader', -'Get-OBSFillColorGradientShader', -'Get-OBSFillColorLinearShader', -'Get-OBSFillColorRadialDegreesShader', -'Get-OBSFillColorRadialPercentageShader', -'Get-OBSFilterTemplateShader', -'Get-OBSFire3Shader', -'Get-OBSFireShader', -'Get-OBSFireworks2Shader', -'Get-OBSFireworksShader', -'Get-OBSFisheyeShader', -'Get-OBSFisheyeXyShader', -'Get-OBSFlipShader', -'Get-OBSFrostedGlassShader', -'Get-OBSGammaCorrectionShader', -'Get-OBSGaussianBlurAdvancedShader', -'Get-OBSGaussianBlurShader', -'Get-OBSGaussianBlurSimpleShader', -'Get-OBSGaussianExampleShader', -'Get-OBSGaussianSimpleShader', -'Get-OBSGbCameraShader', -'Get-OBSGlassShader', -'Get-OBSGlitchAnalogShader', -'Get-OBSGlitchShader', -'Get-OBSGlowShader', -'Get-OBSGradientShader', -'Get-OBSHalftoneShader', -'Get-OBSHeatWaveSimpleShader', -'Get-OBSHexagonShader', -'Get-OBSHslHsvSaturationShader', -'Get-OBSHueRotatonShader', -'Get-OBSIntensityScopeShader', -'Get-OBSInvertLumaShader', -'Get-OBSLuminance2Shader', -'Get-OBSLuminanceAlphaShader', -'Get-OBSLuminanceShader', -'Get-OBSMatrixShader', -'Get-OBSMultiplyShader', -'Get-OBSNightSkyShader', -'Get-OBSOpacityShader', -'Get-OBSPagePeelShader', -'Get-OBSPagePeelTransitionShader', -'Get-OBSPerlinNoiseShader', -'Get-OBSPieChartShader', -'Get-OBSPixelationShader', -'Get-OBSPixelationTransitionShader', -'Get-OBSPolarShader', -'Get-OBSPulseShader', -'Get-OBSRainbowShader', -'Get-OBSRainWindowShader', -'Get-OBSRectangularDropShadowShader', -'Get-OBSReflectShader', -'Get-OBSRemovePartialPixelsShader', -'Get-OBSRepeatShader', -'Get-OBSRepeatTextureShader', -'Get-OBSRGBAPercentShader', -'Get-OBSRgbColorWheelShader', -'Get-OBSRgbSplitShader', -'Get-OBSRgbvisibilityShader', -'Get-OBSRGSSAAShader', -'Get-OBSRippleShader', -'Get-OBSRotatingSourceShader', -'Get-OBSRotatoeShader', -'Get-OBSRoundedRect2Shader', -'Get-OBSRoundedRectPerCornerShader', -'Get-OBSRoundedRectPerSideShader', -'Get-OBSRoundedRectShader', -'Get-OBSRoundedStrokeGradientShader', -'Get-OBSRoundedStrokeShader', -'Get-OBSScanLineShader', -'Get-OBSSeascapeShader', -'Get-OBSSeasickShader', -'Get-OBSSelectiveColorShader', -'Get-OBSShakeShader', -'Get-OBSShineShader', -'Get-OBSSimpleGradientShader', -'Get-OBSSimplexNoiseShader', -'Get-OBSSmartDenoiseShader', -'Get-OBSSpecularShineShader', -'Get-OBSSpotlightShader', -'Get-OBSSwirlShader', -'Get-OBSTetraShader', -'Get-OBSThermalShader', -'Get-OBSTvCrtSubpixelShader', -'Get-OBSTwistShader', -'Get-OBSTwoPassDropShadowShader', -'Get-OBSVCRShader', -'Get-OBSVHSShader', -'Get-OBSVignettingShader', -'Get-OBSVoronoiPixelationShader', -'Get-OBSZigZagShader', -'Get-OBSZoomBlurShader', -'Get-OBSZoomShader', -'Get-OBSZoomXYShader', 'Set-OBS3DFilter', 'Set-OBSColorFilter', 'Set-OBSEqualizerFilter', @@ -265,6 +70,11 @@ Previous release notes available in the [CHANGELOG](https://github.com/StartAuto 'Set-OBSScrollFilter', 'Set-OBSShaderFilter', 'Set-OBSSharpnessFilter', +'Get-OBSEffect', +'Import-OBSEffect', +'Remove-OBSEffect', +'Start-OBSEffect', +'Stop-OBSEffect', 'Add-OBSInput', 'Add-OBSProfile', 'Add-OBSScene', @@ -405,10 +215,174 @@ Previous release notes available in the [CHANGELOG](https://github.com/StartAuto 'Switch-OBSReplayBuffer', 'Switch-OBSStream', 'Switch-OBSVirtualCam', -'Get-OBSEffect', -'Import-OBSEffect', -'Remove-OBSEffect', -'Start-OBSEffect', -'Stop-OBSEffect' +'Get-OBS3dPanelShader', +'Get-OBS3dSwapTransitionShader', +'Get-OBSAddShader', +'Get-OBSAlphaBorderShader', +'Get-OBSAlphaGamingBentCameraShader', +'Get-OBSAnimatedPathShader', +'Get-OBSAnimatedTextureShader', +'Get-OBSAsciiShader', +'Get-OBSAspectRatioShader', +'Get-OBSAudioShader', +'Get-OBSBackgroundRemovalShader', +'Get-OBSBlendOpacityShader', +'Get-OBSBlinkShader', +'Get-OBSBloomShader', +'Get-OBSBorderShader', +'Get-OBSBoxBlurShader', +'Get-OBSBulgePinchShader', +'Get-OBSBurnShader', +'Get-OBSCartoonShader', +'Get-OBSCellShadedShader', +'Get-OBSChromaticAberrationShader', +'Get-OBSChromaUVDistortionShader', +'Get-OBSCircleMaskFilterShader', +'Get-OBSClockAnalogShader', +'Get-OBSClockDigitalLedShader', +'Get-OBSClockDigitalNixieShader', +'Get-OBSColorDepthShader', +'Get-OBSColorGradeFilterShader', +'Get-OBSCornerPinShader', +'Get-OBSCrtCurvatureShader', +'Get-OBSCubeRotatingShader', +'Get-OBSCurveShader', +'Get-OBSCutRectPerCornerShader', +'Get-OBSCylinderShader', +'Get-OBSDarkenShader', +'Get-OBSDeadPixelFixerShader', +'Get-OBSDensitySatHueShader', +'Get-OBSDiffuseTransitionShader', +'Get-OBSDigitalRainShader', +'Get-OBSDisplacementMapAdvancedInvertShader', +'Get-OBSDisplacementMapAdvancedShader', +'Get-OBSDisplacementMapInvertShader', +'Get-OBSDisplacementMapShader', +'Get-OBSDivideRotateShader', +'Get-OBSDoodleShader', +'Get-OBSDrawingsShader', +'Get-OBSDropShadowShader', +'Get-OBSDrunkShader', +'Get-OBSDynamicMaskShader', +'Get-OBSEdgeDetectionShader', +'Get-OBSEmbersShader', +'Get-OBSEmbossColorShader', +'Get-OBSEmbossShader', +'Get-OBSExeldroBentCameraShader', +'Get-OBSFadeTransitionShader', +'Get-OBSFillColorGradientShader', +'Get-OBSFillColorLinearShader', +'Get-OBSFillColorRadialDegreesShader', +'Get-OBSFillColorRadialPercentageShader', +'Get-OBSFilterTemplateShader', +'Get-OBSFire3Shader', +'Get-OBSFireShader', +'Get-OBSFireworks2Shader', +'Get-OBSFireworksShader', +'Get-OBSFisheyeShader', +'Get-OBSFisheyeXyShader', +'Get-OBSFlipShader', +'Get-OBSFrostedGlassShader', +'Get-OBSGammaCorrectionShader', +'Get-OBSGaussianBlurAdvancedShader', +'Get-OBSGaussianBlurShader', +'Get-OBSGaussianBlurSimpleShader', +'Get-OBSGaussianExampleShader', +'Get-OBSGaussianSimpleShader', +'Get-OBSGbCameraShader', +'Get-OBSGlassShader', +'Get-OBSGlitchAnalogShader', +'Get-OBSGlitchPeriodicShader', +'Get-OBSGlitchShader', +'Get-OBSGlowShader', +'Get-OBSGradientShader', +'Get-OBSHalftoneShader', +'Get-OBSHardBlinkShader', +'Get-OBSHeatWaveSimpleShader', +'Get-OBSHexagonShader', +'Get-OBSHslHsvSaturationShader', +'Get-OBSHueRotatonShader', +'Get-OBSIntensityScopeShader', +'Get-OBSInvertLumaShader', +'Get-OBSLuminance2Shader', +'Get-OBSLuminanceAlphaShader', +'Get-OBSLuminanceShader', +'Get-OBSMatrixShader', +'Get-OBSMotionBlurShader', +'Get-OBSMultiplyShader', +'Get-OBSNightSkyShader', +'Get-OBSNoiseShader', +'Get-OBSNormalMapShader', +'Get-OBSOpacityShader', +'Get-OBSPagePeelShader', +'Get-OBSPagePeelTransitionShader', +'Get-OBSPerlinNoiseShader', +'Get-OBSPerspectiveShader', +'Get-OBSPieChartShader', +'Get-OBSPixelationShader', +'Get-OBSPixelationTransitionShader', +'Get-OBSPolarShader', +'Get-OBSPulseShader', +'Get-OBSQuadrilateralCropShader', +'Get-OBSRainbowShader', +'Get-OBSRainWindowShader', +'Get-OBSRectangularDropShadowShader', +'Get-OBSReflectShader', +'Get-OBSRemovePartialPixelsShader', +'Get-OBSRepeatGridCenterCropShader', +'Get-OBSRepeatShader', +'Get-OBSRepeatTextureShader', +'Get-OBSRGBAPercentShader', +'Get-OBSRgbColorWheelShader', +'Get-OBSRgbSplitShader', +'Get-OBSRgbvisibilityShader', +'Get-OBSRGSSAAShader', +'Get-OBSRippleShader', +'Get-OBSRotatingSourceShader', +'Get-OBSRotatoeShader', +'Get-OBSRoundedRect2Shader', +'Get-OBSRoundedRectPerCornerShader', +'Get-OBSRoundedRectPerSideShader', +'Get-OBSRoundedRectShader', +'Get-OBSRoundedStrokeGradientShader', +'Get-OBSRoundedStrokeShader', +'Get-OBSScanLineShader', +'Get-OBSSeascapeShader', +'Get-OBSSeasickShader', +'Get-OBSSelectiveColorShader', +'Get-OBSShakeShader', +'Get-OBSShineShader', +'Get-OBSSimpleGradientShader', +'Get-OBSSimplexNoiseShader', +'Get-OBSSmartDenoiseShader', +'Get-OBSSpecularShineShader', +'Get-OBSSpotlightShader', +'Get-OBSSwirlShader', +'Get-OBSTetraShader', +'Get-OBSThermalShader', +'Get-OBSTvCrtSubpixelShader', +'Get-OBSTwistShader', +'Get-OBSTwoPassDropShadowShader', +'Get-OBSVCRShader', +'Get-OBSVHSShader', +'Get-OBSVignettingShader', +'Get-OBSVoronoiPixelationShader', +'Get-OBSWalkingDeadPixelFixerShader', +'Get-OBSZigZagShader', +'Get-OBSZoomBlurShader', +'Get-OBSZoomBlurTransitionShader', +'Get-OBSZoomShader', +'Get-OBSZoomXYShader', +'Set-OBSAudioOutputSource', +'Set-OBSBrowserSource', +'Set-OBSColorSource', +'Set-OBSDisplaySource', +'Set-OBSMarkdownSource', +'Set-OBSMediaSource', +'Set-OBSSoundCloudSource', +'Set-OBSSwitchSource', +'Set-OBSVLCSource', +'Set-OBSWaveformSource', +'Set-OBSWindowSource' }