Skip to content

Instantly share code, notes, and snippets.

@upgradeQ
Last active May 2, 2023 16:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save upgradeQ/2bcac29240a7449a80ee26a15936b984 to your computer and use it in GitHub Desktop.
Save upgradeQ/2bcac29240a7449a80ee26a15936b984 to your computer and use it in GitHub Desktop.
Simple multi pass shaders for OBS Studio
S = obslua
local ffi = require"ffi"
local C = ffi.C
local _OR = bit.bor
ffi.cdef[[
typedef struct {int x, y;} Point;
bool GetCursorPos(Point *lpPoint);
]]
RESOLUTION = {2560,1440};
local mouse_pos = ffi.new("Point")
local function norm(val,amin,amax) return (val-amin ) / (amax- amin) end
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.current_time = 0
instance.source = source
S.obs_enter_graphics()
instance.effect = S.gs_effect_create(SHADER, nil, nil)
instance.texture_a = S.gs_texrender_create(S.GS_RGBA,S.GS_ZS_NONE)
if instance.effect ~= nil then
instance.params = {}
instance.params.width = S.gs_effect_get_param_by_name(instance.effect, 'width')
instance.params.itime = S.gs_effect_get_param_by_name(instance.effect, 'itime')
instance.params.height = S.gs_effect_get_param_by_name(instance.effect, 'height')
instance.params.mouse_x = S.gs_effect_get_param_by_name(instance.effect, 'mouse_x')
instance.params.mouse_y = S.gs_effect_get_param_by_name(instance.effect, 'mouse_y')
instance.params.image = S.gs_effect_get_param_by_name(instance.effect, 'image')
end
S.obs_leave_graphics()
if instance.effect == nil then
SourceDef.destroy(instance)
return nil
end
return instance
end
function SourceDef:destroy()
if self.effect ~= nil then
S.obs_enter_graphics()
S.gs_effect_destroy(self.effect)
S.gs_texrender_destroy(self.texture_a)
S.obs_leave_graphics()
end
end
function SourceDef:get_name() return "Cursor Shader by upgradeQ1" 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 SourceDef:video_render()
C.GetCursorPos(mouse_pos)
local norm_x = norm(mouse_pos.x,0,RESOLUTION[1])
local norm_y = norm(mouse_pos.y,0,RESOLUTION[2])
S.gs_texrender_reset(self.texture_a)
S.gs_effect_set_float(self.params.itime, self.current_time+0.0)
S.gs_effect_set_float(self.params.mouse_x, norm_x+0.0)
S.gs_effect_set_float(self.params.mouse_y, norm_y+0.0)
S.gs_effect_set_int(self.params.width, self.width)
S.gs_effect_set_int(self.params.height, self.height)
if S.gs_texrender_begin(self.texture_a, self.width, self.height) then
local tex = S.gs_texrender_get_texture(self.texture_a)
S.gs_effect_set_texture(self.params.image,tex)
while S.gs_effect_loop(self.effect, "Draw") do
S.gs_draw_sprite(tex,0,self.width,self.height)
end
S.gs_texrender_end(self.texture_a)
end
S.gs_effect_set_float(self.params.itime, self.current_time + 0.0)
local tex2 = S.gs_texrender_get_texture(self.texture_a)
S.gs_effect_set_texture(self.params.image, tex2)
while S.gs_effect_loop(self.effect, "Draw2") do
S.gs_draw_sprite(tex2,0,self.width,self.height)
end
end
function script_load(settings) -- OBS_SOURCE_CUSTOM_DRAW
local my_filter = SourceDef:new({id='filter_cursor_shader1',type=S.OBS_SOURCE_TYPE_FILTER,
output_flags=_OR(S.OBS_SOURCE_VIDEO,S.OBS_SOURCE_CUSTOM_DRAW)})
S.obs_register_source(my_filter)
end
SHADER = ([[
// 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 image;
// Size of the source picture
uniform int width;
uniform int height;
uniform float mouse_x;
uniform float mouse_y;
uniform float itime;
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;
}
float4 lerp(float4 a, float4 b, float t) { return (a + t*(b-a)); }
float4 PassThrough(VertDataOut v_in) : TARGET
{
float2 uv = v_in.uv;
float2 mousePos = float2(mouse_x,mouse_y);
float3 col = float3(0.902, 0.297, 0.234);
col = lerp(col, float3(0.898, 0.492, 0.133), smoothstep(0.0, 0.25, uv.x));
col = lerp(col, float3(0.941, 0.766, 0.059), smoothstep(0.25, 0.50, uv.x));
col = lerp(col, float3(0.180, 0.797, 0.441), smoothstep(0.50, 0.75, uv.x));
col = lerp(col, float3(0.102, 0.734, 0.609), smoothstep(0.75, 1.00, uv.x));
return float4(col,1.0);
}
float2 rotate(float2 st, float angle) {
return float2(
st.x * cos(angle) - st.y * sin(angle),
st.x * sin(angle) + st.y * cos(angle)
);
}
float atan_emu(float y, float x)
{
if(x == 0 && y == 0) x = 1;
return atan2(y, x);
}
float4 PassThrough2(VertDataOut v_in) : TARGET
{
float2 uv = v_in.uv;
uv = (2.0 *v_in.pos.xy - float2(2560,1440))/1440;
float ratio = %s.0/%s.0;
uv = rotate(uv - float2(.0,.0),itime);
uv = float2(-atan_emu(uv.y,uv.x) / 3.141459265 * 0.5 +0.5, 0.0);
float4 orig = image.Sample(textureSampler, uv);
return orig;
}
technique Draw
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PassThrough(v_in);
}
}
technique Draw2
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PassThrough2(v_in);
}
}
]]):format(RESOLUTION[1],RESOLUTION[2], RESOLUTION[1],RESOLUTION[2])
S = obslua
local ffi = require"ffi"
local C = ffi.C
local _OR = bit.bor
ffi.cdef[[
typedef struct {int x, y;} Point;
bool GetCursorPos(Point *lpPoint);
]]
RESOLUTION = {2560,1440};
local mouse_pos = ffi.new("Point")
local function norm(val,amin,amax) return (val-amin ) / (amax- amin) end
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.current_time = 0
instance.source = source
S.obs_enter_graphics()
instance.effect = S.gs_effect_create(SHADER, nil, nil)
instance.texture_a = S.gs_texrender_create(S.GS_RGBA,S.GS_ZS_NONE)
instance.texture_b = S.gs_texrender_create(S.GS_RGBA,S.GS_ZS_NONE)
if instance.effect ~= nil then
instance.params = {}
instance.params.width = S.gs_effect_get_param_by_name(instance.effect, 'width')
instance.params.itime = S.gs_effect_get_param_by_name(instance.effect, 'itime')
instance.params.height = S.gs_effect_get_param_by_name(instance.effect, 'height')
instance.params.mouse_x = S.gs_effect_get_param_by_name(instance.effect, 'mouse_x')
instance.params.mouse_y = S.gs_effect_get_param_by_name(instance.effect, 'mouse_y')
instance.params.image = S.gs_effect_get_param_by_name(instance.effect, 'image')
end
S.obs_leave_graphics()
if instance.effect == nil then
SourceDef.destroy(instance)
return nil
end
return instance
end
function SourceDef:destroy()
if self.effect ~= nil then
S.obs_enter_graphics()
S.gs_effect_destroy(self.effect)
S.gs_texrender_destroy(self.texture_a)
S.gs_texrender_destroy(self.texture_b)
S.obs_leave_graphics()
end
end
function SourceDef:get_name() return "Cursor Shader by upgradeQ2" 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 SourceDef:video_render()
C.GetCursorPos(mouse_pos)
local norm_x = norm(mouse_pos.x,0,RESOLUTION[1])
local norm_y = norm(mouse_pos.y,0,RESOLUTION[2])
local target = S.obs_filter_get_target(self.source)
S.gs_texrender_reset(self.texture_a)
S.gs_effect_set_float(self.params.itime, self.current_time+0.0)
S.gs_effect_set_float(self.params.mouse_x, norm_x+0.0)
S.gs_effect_set_float(self.params.mouse_y, norm_y+0.0)
S.gs_effect_set_int(self.params.width, self.width)
S.gs_effect_set_int(self.params.height, self.height)
if S.gs_texrender_begin(self.texture_a, self.width, self.height) then
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.effect, self.width, self.height,"Draw")
S.gs_texrender_end(self.texture_a)
end
S.gs_effect_set_float(self.params.itime, self.current_time + 0.0)
S.gs_effect_set_float(self.params.mouse_x, norm_x+0.0)
S.gs_effect_set_float(self.params.mouse_y, norm_y+0.0)
S.gs_texrender_reset(self.texture_b)
if S.gs_texrender_begin(self.texture_b, self.width, self.height) then
local tex2 = S.gs_texrender_get_texture(self.texture_a)
S.gs_effect_set_texture(self.params.image, tex2)
while S.gs_effect_loop(self.effect, "Draw2") do
S.gs_draw_sprite(tex2,0,self.width,self.height)
end
S.gs_texrender_end(self.texture_b)
end
local tex3 = S.gs_texrender_get_texture(self.texture_b)
S.gs_effect_set_texture(self.params.image, tex3)
while S.gs_effect_loop(self.effect, "Draw3") do
S.gs_draw_sprite(tex3,0,self.width,self.height)
end
end
function script_load(settings) -- OBS_SOURCE_CUSTOM_DRAW
local my_filter = SourceDef:new({id='filter_cursor_shader2',type=S.OBS_SOURCE_TYPE_FILTER,
output_flags=_OR(S.OBS_SOURCE_VIDEO,S.OBS_SOURCE_CUSTOM_DRAW)})
S.obs_register_source(my_filter)
end
SHADER = ([[
// 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 image;
// Size of the source picture
uniform int width;
uniform int height;
uniform float mouse_x;
uniform float mouse_y;
uniform float itime;
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;
}
float4 lerp(float4 a, float4 b, float t) { return (a + t*(b-a)); }
float4 PassThrough(VertDataOut v_in) : TARGET
{
float4 orig = image.Sample(textureSampler, v_in.uv);
//if (v_in.pos.x>0.5){return float4(0.5,0.5,0.5,1.0)} else {return float4(0.5,0.5,0.5,1.0);};
//return float4(1.0,0.5,0.8,1.0);
return float4(1-orig.rgb,1.);
}
float4 PassThrough2(VertDataOut v_in) : TARGET
{
float4 orig = image.Sample(textureSampler, v_in.uv);
if (v_in.uv.x<0.5){
return float4(1.0,1.0,0.0,1.0);} else
{
return float4(orig.rgb,1.);
}
}
float4 PassThrough3(VertDataOut v_in) : TARGET
{
float4 orig = image.Sample(textureSampler, v_in.uv);
if (v_in.uv.y>0.1 && v_in.uv.y<0.5){
return float4(1-orig.rgb,1.0);
}
return orig;
}
technique Draw
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PassThrough(v_in);
}
}
technique Draw2
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PassThrough2(v_in);
}
}
technique Draw3
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PassThrough3(v_in);
}
}
]]):format(RESOLUTION[1],RESOLUTION[2], RESOLUTION[1],RESOLUTION[2])
S = obslua
local ffi = require"ffi"
local C = ffi.C
local _OR = bit.bor
ffi.cdef[[
typedef struct {int x, y;} Point;
bool GetCursorPos(Point *lpPoint);
]]
RESOLUTION = {2560,1440};
local mouse_pos = ffi.new("Point")
local function norm(val,amin,amax) return (val-amin ) / (amax- amin) end
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.current_time = 0
instance.source = source
S.obs_enter_graphics()
instance.effect = S.gs_effect_create(SHADER, nil, nil)
instance.texture_a = S.gs_texrender_create(S.GS_RGBA,S.GS_ZS_NONE)
instance.texture_b = S.gs_texrender_create(S.GS_RGBA,S.GS_ZS_NONE)
if instance.effect ~= nil then
instance.params = {}
instance.params.width = S.gs_effect_get_param_by_name(instance.effect, 'width')
instance.params.itime = S.gs_effect_get_param_by_name(instance.effect, 'itime')
instance.params.height = S.gs_effect_get_param_by_name(instance.effect, 'height')
instance.params.mouse_x = S.gs_effect_get_param_by_name(instance.effect, 'mouse_x')
instance.params.mouse_y = S.gs_effect_get_param_by_name(instance.effect, 'mouse_y')
instance.params.image = S.gs_effect_get_param_by_name(instance.effect, 'image')
end
S.obs_leave_graphics()
if instance.effect == nil then
SourceDef.destroy(instance)
return nil
end
return instance
end
function SourceDef:destroy()
if self.effect ~= nil then
S.obs_enter_graphics()
S.gs_effect_destroy(self.effect)
S.gs_texrender_destroy(self.texture_a)
S.gs_texrender_destroy(self.texture_b)
S.obs_leave_graphics()
end
end
function SourceDef:get_name() return "Cursor Shader by upgradeQ PORT mtSGDy" 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 SourceDef:video_render()
C.GetCursorPos(mouse_pos)
local _x = mouse_pos.x
local _y = mouse_pos.y
S.gs_texrender_reset(self.texture_a)
S.gs_effect_set_float(self.params.itime, self.current_time+0.0)
S.gs_effect_set_float(self.params.mouse_x, _x+0.0)
S.gs_effect_set_float(self.params.mouse_y, _y+0.0)
S.gs_effect_set_int(self.params.width, self.width)
S.gs_effect_set_int(self.params.height, self.height)
if S.gs_texrender_begin(self.texture_a, self.width, self.height) then
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.effect, self.width, self.height,"Draw")
S.gs_effect_set_texture(self.params.image, tex3)
while S.gs_effect_loop(self.effect, "Draw2") do
S.gs_draw_sprite(nil,0,self.width,self.height) -- nil??
end
S.gs_texrender_end(self.texture_a)
end
S.gs_effect_set_float(self.params.itime, self.current_time + 0.0)
S.gs_effect_set_float(self.params.mouse_x, _x+0.0)
S.gs_effect_set_float(self.params.mouse_y, _y+0.0)
S.gs_texrender_reset(self.texture_b)
if S.gs_texrender_begin(self.texture_b, self.width, self.height) then
local tex2 = S.gs_texrender_get_texture(self.texture_a)
S.gs_effect_set_texture(self.params.image, tex2)
while S.gs_effect_loop(self.effect, "Draw") do
S.gs_draw_sprite(tex2,0,self.width,self.height)
end
S.gs_texrender_end(self.texture_b)
end
tex3 = S.gs_texrender_get_texture(self.texture_b)
S.gs_effect_set_texture(self.params.image, tex3)
while S.gs_effect_loop(self.effect, "Draw") do
S.gs_draw_sprite(tex3,0,self.width,self.height)
end
end
function script_load(settings) -- OBS_SOURCE_CUSTOM_DRAW
local my_filter = SourceDef:new({id='filter_cursor_shader_port',type=S.OBS_SOURCE_TYPE_FILTER,
output_flags=_OR(S.OBS_SOURCE_VIDEO,S.OBS_SOURCE_CUSTOM_DRAW)})
S.obs_register_source(my_filter)
end
SHADER = ([[
// 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 image;
// Size of the source picture
uniform int width;
uniform int height;
uniform float mouse_x;
uniform float mouse_y;
uniform float itime;
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;
}
float4 PassThrough(VertDataOut v_in) : TARGET
{
float2 uv = v_in.uv;
float2 mousePos = float2(mouse_x,mouse_y);
float4 draw = image.Sample(textureSampler, uv);
float3 col = draw.xyz;
col = lerp(col, 1.0f.xxx, smoothstep(30.0f, 1.0f, length(v_in.pos.xyz - abs(mousePos.xy))).xxx);
col = clamp(col, 0.0f.xxx, 1.0f.xxx);
float4 fragColor = float4(-0.00999999977648258209228515625f, -0.00999999977648258209228515625f, -0.004999999888241291046142578125f, 1.0f) + float4(col, 1.0f);
return fragColor;
}
float4 PassThrough2(VertDataOut v_in) : TARGET
{
float4 orig = image.Sample(textureSampler, v_in.uv);
return orig;
}
technique Draw
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PassThrough(v_in);
}
}
technique Draw2
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PassThrough2(v_in);
}
}
]]):format(RESOLUTION[1],RESOLUTION[2], RESOLUTION[1],RESOLUTION[2])
S = obslua
local ffi = require"ffi"
local C = ffi.C
local _OR = bit.bor
ffi.cdef[[
typedef struct {int x, y;} Point;
bool GetCursorPos(Point *lpPoint);
]]
RESOLUTION = {2560,1440};
local mouse_pos = ffi.new("Point")
local function norm(val,amin,amax) return (val-amin ) / (amax- amin) end
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.current_time = 0
instance.source = source
S.obs_enter_graphics()
instance.effect = S.gs_effect_create(SHADER, nil, nil)
instance.texture_a = S.gs_texrender_create(S.GS_RGBA,S.GS_ZS_NONE)
instance.texture_b = S.gs_texrender_create(S.GS_RGBA,S.GS_ZS_NONE)
if instance.effect ~= nil then
instance.params = {}
instance.params.width = S.gs_effect_get_param_by_name(instance.effect, 'width')
instance.params.itime = S.gs_effect_get_param_by_name(instance.effect, 'itime')
instance.params.height = S.gs_effect_get_param_by_name(instance.effect, 'height')
instance.params.mouse_x = S.gs_effect_get_param_by_name(instance.effect, 'mouse_x')
instance.params.mouse_y = S.gs_effect_get_param_by_name(instance.effect, 'mouse_y')
instance.params.image = S.gs_effect_get_param_by_name(instance.effect, 'image')
end
S.obs_leave_graphics()
if instance.effect == nil then
SourceDef.destroy(instance)
return nil
end
return instance
end
function SourceDef:destroy()
if self.effect ~= nil then
S.obs_enter_graphics()
S.gs_effect_destroy(self.effect)
S.gs_texrender_destroy(self.texture_a)
S.gs_texrender_destroy(self.texture_b)
S.obs_leave_graphics()
end
end
function SourceDef:get_name() return "Cursor Shader by upgradeQ PORT WlsGRM" 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 SourceDef:video_render()
C.GetCursorPos(mouse_pos)
local _x = mouse_pos.x
local _y = mouse_pos.y
S.gs_texrender_reset(self.texture_a)
S.gs_effect_set_float(self.params.itime, self.current_time+0.0)
S.gs_effect_set_float(self.params.mouse_x, _x+0.0)
S.gs_effect_set_float(self.params.mouse_y, _y+0.0)
S.gs_effect_set_int(self.params.width, self.width)
S.gs_effect_set_int(self.params.height, self.height)
if S.gs_texrender_begin(self.texture_a, self.width, self.height) then
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.effect, self.width, self.height,"Draw")
S.gs_effect_set_texture(self.params.image, tex3)
while S.gs_effect_loop(self.effect, "Draw2") do
S.gs_draw_sprite(nil,0,self.width,self.height) -- nil??
end
S.gs_texrender_end(self.texture_a)
end
S.gs_effect_set_float(self.params.itime, self.current_time + 0.0)
S.gs_effect_set_float(self.params.mouse_x, _x+0.0)
S.gs_effect_set_float(self.params.mouse_y, _y+0.0)
S.gs_texrender_reset(self.texture_b)
if S.gs_texrender_begin(self.texture_b, self.width, self.height) then
local tex2 = S.gs_texrender_get_texture(self.texture_a)
S.gs_effect_set_texture(self.params.image, tex2)
while S.gs_effect_loop(self.effect, "Draw") do
S.gs_draw_sprite(tex2,0,self.width,self.height)
end
S.gs_texrender_end(self.texture_b)
end
tex3 = S.gs_texrender_get_texture(self.texture_b)
S.gs_effect_set_texture(self.params.image, tex3)
while S.gs_effect_loop(self.effect, "Draw") do
S.gs_draw_sprite(tex3,0,self.width,self.height)
end
end
function script_load(settings) -- OBS_SOURCE_CUSTOM_DRAW
local my_filter = SourceDef:new({id='filter_cursor_shader_port',type=S.OBS_SOURCE_TYPE_FILTER,
output_flags=_OR(S.OBS_SOURCE_VIDEO,S.OBS_SOURCE_CUSTOM_DRAW)})
S.obs_register_source(my_filter)
end
SHADER = ([[
// 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 image;
// Size of the source picture
uniform int width;
uniform int height;
uniform float mouse_x;
uniform float mouse_y;
uniform float itime;
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;
}
float4 PassThrough(VertDataOut v_in) : TARGET
{
float2 uv = v_in.uv;
float2 mousePos = float2(mouse_x,mouse_y);
float4 draw = image.Sample(textureSampler, uv);
float3 blob = (0.10999999940395355224609375f - clamp(length((v_in.pos.xyz - mousePos) / width.xx), 0.0f, 0.10999999940395355224609375f)).xxx * 2.0f;
float3 stack = draw.xyz * float3(0.9900000095367431640625f, 0.98199999332427978515625f, 0.930000007152557373046875f);
float4 fragColor = float4(stack + blob, 1.0f);
return fragColor;
}
float4 PassThrough2(VertDataOut v_in) : TARGET
{
float4 orig = image.Sample(textureSampler, v_in.uv);
return orig;
}
technique Draw
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PassThrough(v_in);
}
}
technique Draw2
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PassThrough2(v_in);
}
}
]]):format(RESOLUTION[1],RESOLUTION[2], RESOLUTION[1],RESOLUTION[2])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment