Commands/Shaders/Get-OBSFireShader.ps1
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 } } } } } |