Skip to content

Instantly share code, notes, and snippets.

@upgradeQ
Created June 8, 2024 18:50
Show Gist options
  • Save upgradeQ/890913abe3bfd0e4e68f1860e6b97c53 to your computer and use it in GitHub Desktop.
Save upgradeQ/890913abe3bfd0e4e68f1860e6b97c53 to your computer and use it in GitHub Desktop.
frame_blend
S = obslua
local function skip_tick_render(ctx)
local target = S.obs_filter_get_target(ctx.source)
local width, height;
if target == nil then width = 0; height = 0; else
width = S.obs_source_get_base_width(target)
height = S.obs_source_get_base_height(target)
end
ctx.width, ctx.height = width , height
end
local SourceDef = {}
function SourceDef:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function SourceDef:create(source)
local instance = {}
instance.width = 1
instance.height = 1
instance.source = source
instance.current_time = 0
instance.frame_number = 0
instance.strength = 0.001
instance.texture1 = S.gs_texrender_create(S.GS_RGBA, S.GS_ZS_NONE)
instance.texture2 = S.gs_texrender_create(S.GS_RGBA, S.GS_ZS_NONE)
instance.texture3 = S.gs_texrender_create(S.GS_RGBA, S.GS_ZS_NONE)
instance.texture4 = S.gs_texrender_create(S.GS_RGBA, S.GS_ZS_NONE)
instance.texture5 = S.gs_texrender_create(S.GS_RGBA, S.GS_ZS_NONE)
instance.texture6 = S.gs_texrender_create(S.GS_RGBA, S.GS_ZS_NONE)
instance.clear_flags = bit.bor(S.GS_CLEAR_COLOR)
instance.current_texrender = S.gs_texrender_create(S.GS_RGBA, S.GS_ZS_NONE)
instance.texture_clear_color = S.vec4()
instance.clear_flags = bit.bor(S.GS_CLEAR_COLOR)
S.obs_enter_graphics()
instance.effect = S.gs_effect_create(SHADER1, nil, nil)
if instance.effect ~= nil then
instance.params = {}
instance.params.itime = S.gs_effect_get_param_by_name(instance.effect, 'itime')
instance.params.strength = S.gs_effect_get_param_by_name(instance.effect, 'strength')
instance.params.tex1 = S.gs_effect_get_param_by_name(instance.effect, 'tex1')
instance.params.tex2 = S.gs_effect_get_param_by_name(instance.effect, 'tex2')
instance.params.tex3 = S.gs_effect_get_param_by_name(instance.effect, 'tex3')
instance.params.tex4 = S.gs_effect_get_param_by_name(instance.effect, 'tex4')
instance.params.tex5 = S.gs_effect_get_param_by_name(instance.effect, 'tex5')
instance.params.tex6 = S.gs_effect_get_param_by_name(instance.effect, 'tex6')
instance.params.current_frame = S.gs_effect_get_param_by_name(instance.effect, 'current_frame')
end
instance.default_effect = S.obs_get_base_effect(S.OBS_EFFECT_DEFAULT)
instance.params.default_image = S.gs_effect_get_param_by_name(instance.default_effect, 'image')
instance.params.itime = S.gs_effect_get_param_by_name(instance.effect, 'itime')
S.obs_leave_graphics()
if instance.effect == nil then
SourceDef.destroy(instance)
return nil
end
--SourceDef.update(instance,self) -- initialize, self = settings
return instance
end
function SourceDef:destroy()
if self.effect ~= nil then
S.obs_enter_graphics()
S.gs_texrender_destroy(self.texture1)
S.gs_texrender_destroy(self.texture2)
S.gs_texrender_destroy(self.texture3)
S.gs_texrender_destroy(self.texture4)
S.gs_texrender_destroy(self.texture5)
S.gs_texrender_destroy(self.texture6)
S.gs_texrender_destroy(self.current_texrender)
S.gs_effect_destroy(self.effect)
S.obs_leave_graphics()
end
end
function SourceDef:get_name() return "frame blending ?" end
function SourceDef:get_width() return self.width end
function SourceDef:get_height() return self.height end
function SourceDef:video_tick(seconds)
self.current_time = self.current_time + seconds
skip_tick_render(self) -- if source has crop or transform applied to it, this will let it render
end
function texrender_set_texture(self, texrender, texture)
S.gs_texrender_reset(texrender)
if S.gs_texrender_begin(texrender, self.width, self.height) then
S.gs_ortho(0, self.width, 0, self.height, -100.0, 100.0)
S.gs_effect_set_texture(self.params.default_image, texture)
while S.gs_effect_loop(self.default_effect, "Draw") do
S.gs_draw_sprite(nil, 0, self.width, self.height)
end
S.gs_texrender_end(texrender)
end
end
function SourceDef:video_render()
local parent = S.obs_filter_get_parent(self.source)
self.width = S.obs_source_get_base_width(parent)
self.height = S.obs_source_get_base_height(parent)
S.gs_texrender_reset(self.current_texrender)
if S.gs_texrender_begin(self.current_texrender, self.width, self.height) then
S.gs_ortho(0, self.width, 0, self.height, -100.0, 100.0)
--S.gs_clear(self.clear_flags, self.texture_clear_color, 0, 0)
S.gs_effect_set_float(self.params.itime, self.current_time+0.0)
if not S.obs_source_process_filter_begin(self.source, S.GS_RGBA, S.OBS_ALLOW_DIRECT_RENDERING)
then return
end
S.obs_source_process_filter_tech_end(self.source, self.default_effect, self.width, self.height,"Draw")
S.gs_texrender_end(self.current_texrender)
end
local switch = self.frame_number % 6
if (switch == 0) then
texrender_set_texture(self, self.texture1, S.gs_texrender_get_texture(self.current_texrender))
elseif (switch == 1) then
texrender_set_texture(self, self.texture2, S.gs_texrender_get_texture(self.current_texrender))
elseif (switch == 2) then
texrender_set_texture(self, self.texture3, S.gs_texrender_get_texture(self.current_texrender))
elseif (switch == 3) then
texrender_set_texture(self, self.texture4, S.gs_texrender_get_texture(self.current_texrender))
elseif (switch == 4) then
texrender_set_texture(self, self.texture5, S.gs_texrender_get_texture(self.current_texrender))
elseif (switch == 5) then
texrender_set_texture(self, self.texture6, S.gs_texrender_get_texture(self.current_texrender))
end
S.gs_effect_set_texture(self.params.tex1, S.gs_texrender_get_texture(self.texture1))
S.gs_effect_set_texture(self.params.tex2, S.gs_texrender_get_texture(self.texture2))
S.gs_effect_set_texture(self.params.tex3, S.gs_texrender_get_texture(self.texture3))
S.gs_effect_set_texture(self.params.tex4, S.gs_texrender_get_texture(self.texture4))
S.gs_effect_set_texture(self.params.tex5, S.gs_texrender_get_texture(self.texture5))
S.gs_effect_set_texture(self.params.tex6, S.gs_texrender_get_texture(self.texture6))
S.gs_effect_set_texture(self.params.current_frame, S.gs_texrender_get_texture(self.current_texrender))
S.gs_effect_set_float(self.params.strength, self.strength)
while S.gs_effect_loop(self.effect, "DrawFinal") do
S.gs_draw_sprite(nil ,0,self.width,self.height)
end
self.frame_number = self.frame_number + 1
end
function SourceDef:get_properties()
local props = S.obs_properties_create()
S.obs_properties_add_float_slider(props, "_h", "strength", 0, 1, 0.00001)
return props
end
function SourceDef:update(settings)
self.strength = S.obs_data_get_double(settings, "_h")
end
function SourceDef:get_defaults()
S.obs_data_set_default_double(self, "_h", 0.01)
end
function script_properties()
local props = S.obs_properties_create()
S.obs_properties_add_button(props, "button2", "frame blending ? ",
function() end)
return props
end
function script_load(settings)
local my_filter = SourceDef:new({id='frame_blend',type=S.OBS_SOURCE_TYPE_FILTER,
output_flags=bit.bor(S.OBS_SOURCE_VIDEO,S.OBS_SOURCE_CUSTOM_DRAW)})
S.obs_register_source(my_filter)
end
SHADER1 = [==[
// OBS-specific syntax adaptation to HLSL standard to avoid errors reported by the code editor
#define SamplerState sampler_state
#define Texture2D texture2d
uniform float4x4 ViewProj;
uniform Texture2D current_frame;
uniform Texture2D tex1;
uniform Texture2D tex2;
uniform Texture2D tex3;
uniform Texture2D tex4;
uniform Texture2D tex5;
uniform Texture2D tex6;
// Size of the source picture
uniform float itime;
uniform float strength;
SamplerState textureSampler {
Filter = Linear;
AddressU = Clamp;
AddressV = Clamp;
};
struct VertDataIn {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
struct VertDataOut {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
VertDataOut VSDefault(VertDataIn v_in)
{
VertDataOut vert_out;
vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj);
vert_out.uv = v_in.uv;
return vert_out;
}
// https://github.com/libretro/common-shaders/blob/master/motionblur/shaders/motionblur-simple.cg
float4 PassThrough1(VertDataOut v_in) : TARGET
{
float2 uv = v_in.uv;
float4 draw = current_frame.Sample(textureSampler, uv);
float4 color = tex6.Sample(textureSampler, uv);
color = (color + tex5.Sample(textureSampler, uv)) / 2.0;
color = (color + tex4.Sample(textureSampler, uv)) / 2.0;
color = (color + tex3.Sample(textureSampler, uv)) / 2.0;
color = (color + tex2.Sample(textureSampler, uv)) / 2.0;
color = (color + tex1.Sample(textureSampler, uv)) / 2.0;
color = (color + draw) / 2.0;
return color;
}
// https://reshade.me/forum/shader-discussion/2312-who-said-reshade-cant-do-quality-motion-blur
float4 PassThrough(VertDataOut v_in) : TARGET
{
float2 uv = v_in.uv;
float4 draw = current_frame.Sample(textureSampler, uv);
float4 color = tex6.Sample(textureSampler, uv);
color = (color + tex5.Sample(textureSampler, uv));
color = (color + tex4.Sample(textureSampler, uv));
color = (color + tex3.Sample(textureSampler, uv));
color = (color + tex2.Sample(textureSampler, uv));
color = (color + tex1.Sample(textureSampler, uv));
color = (color + draw) / 7;
return lerp(draw,color,strength);
}
technique DrawFinal
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PassThrough(v_in);
}
}
]==]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment