Skip to content

Instantly share code, notes, and snippets.

@magicien
Last active February 14, 2021 11:59
Show Gist options
  • Save magicien/6a2c8cee52302306c8129c058d0184c4 to your computer and use it in GitHub Desktop.
Save magicien/6a2c8cee52302306c8129c058d0184c4 to your computer and use it in GitHub Desktop.
OBS用スクリプト:縁取りフィルタ(簡易版)
obs = obslua
bit = require('bit')
SETTING_ALPHA_THRESHOLD = 'alpha_threshold'
SETTING_LINE_COLOR = 'line_color'
SETTING_LINE_ALPHA = 'line_alpha'
SETTING_LINE_WIDTH = 'line_width'
TEXT_ALPHA_THRESHOLD = '透明度閾値'
TEXT_LINE_COLOR = '線の色'
TEXT_LINE_ALPHA = '線の不透明度'
TEXT_LINE_WIDTH = '線の幅'
SHADER = [[
uniform float4x4 ViewProj;
uniform texture2d image;
uniform float2 pixel_size;
uniform float alpha_threshold;
uniform float4 line_color;
uniform float line_width;
sampler_state textureSampler {
Filter = Linear;
AddressU = Clamp;
AddressV = Clamp;
};
struct VertDataIn {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
struct VertDataOut {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
VertDataOut VShader(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;
}
float diff(float2 uv, float2 diff)
{
float4 col1 = image.Sample(textureSampler, uv - diff);
float4 col2 = image.Sample(textureSampler, uv + diff);
return col2.a - col1.a;
}
float4 PShader(VertDataOut v_in) : TARGET
{
float w = pixel_size.x * line_width / 2;
float h = pixel_size.y * line_width / 2;
float d1 = diff(v_in.uv, float2(w, 0));
float d2 = diff(v_in.uv, float2(0, h));
float d3 = diff(v_in.uv, float2(w * 0.71, h * 0.71));
float d4 = diff(v_in.uv, float2(w * 0.71, -h * 0.71));
float4 color = image.Sample(textureSampler, v_in.uv);
return (abs(d1) > alpha_threshold
|| abs(d2) > alpha_threshold
|| abs(d3) > alpha_threshold
|| abs(d4) > alpha_threshold)
? color + line_color * (1 - color.a)
: color;
}
technique Draw
{
pass
{
vertex_shader = VShader(v_in);
pixel_shader = PShader(v_in);
}
}
]]
source_def = {}
source_def.id = 'draw-outline'
source_def.type = obs.OBS_SOURCE_TYPE_FILTER
source_def.output_flags = bit.bor(obs.OBS_SOURCE_VIDEO)
function set_render_size(filter)
target = obs.obs_filter_get_target(filter.context)
local width, height
if target == nil then
width = 0
height = 0
else
width = obs.obs_source_get_base_width(target)
height = obs.obs_source_get_base_height(target)
end
filter.width = width
filter.height = height
width = width == 0 and 1 or width
height = height == 0 and 1 or height
filter.pixel_size.x = 1.0 / width
filter.pixel_size.y = 1.0 / height
end
source_def.get_name = function()
return '縁取り'
end
source_def.create = function(settings, source)
filter = {}
filter.params = {}
filter.context = source
filter.pixel_size = obs.vec2()
filter.line_color = obs.vec4()
set_render_size(filter)
obs.obs_enter_graphics()
filter.effect = obs.gs_effect_create(SHADER, nil, nil)
if filter.effect ~= nil then
filter.params.pixel_size = obs.gs_effect_get_param_by_name(filter.effect, 'pixel_size')
filter.params.alpha_threshold = obs.gs_effect_get_param_by_name(filter.effect, 'alpha_threshold')
filter.params.line_color = obs.gs_effect_get_param_by_name(filter.effect, 'line_color')
filter.params.line_alpha = obs.gs_effect_get_param_by_name(filter.effect, 'line_alpha')
filter.params.line_width = obs.gs_effect_get_param_by_name(filter.effect, 'line_width')
end
obs.obs_leave_graphics()
if filter.effect == nil then
source_def.destroy(filter)
return nil
end
source_def.update(filter, settings)
return filter
end
source_def.destroy = function(filter)
if filter.effect ~= nil then
obs.obs_enter_graphics()
obs.gs_effect_destroy(filter.effect)
obs.obs_leave_graphics()
end
end
source_def.get_width = function(filter)
return filter.width
end
source_def.get_height = function(filter)
return filter.height
end
source_def.update = function(filter, settings)
filter.alpha_threshold = obs.obs_data_get_double(settings, SETTING_ALPHA_THRESHOLD)
line_color = obs.obs_data_get_int(settings, SETTING_LINE_COLOR)
line_alpha = math.floor(obs.obs_data_get_double(settings, SETTING_LINE_ALPHA) * 255)
obs.vec4_from_rgba(filter.line_color, line_color + line_alpha * 0x1000000)
filter.line_width = obs.obs_data_get_double(settings, SETTING_LINE_WIDTH)
set_render_size(filter)
end
source_def.video_render = function(filter, effect)
obs.obs_source_process_filter_begin(filter.context, obs.GS_RGBA, obs.OBS_NO_DIRECT_RENDERING)
obs.gs_effect_set_vec2(filter.params.pixel_size, filter.pixel_size)
obs.gs_effect_set_float(filter.params.alpha_threshold, filter.alpha_threshold)
obs.gs_effect_set_vec4(filter.params.line_color, filter.line_color)
obs.gs_effect_set_float(filter.params.line_width, filter.line_width)
obs.obs_source_process_filter_end(filter.context, filter.effect, filter.width, filter.height)
end
function script_description()
return '縁取りフィルタ。透明な箇所と不透明な箇所の境目に線を描く'
end
source_def.get_properties = function(settings)
props = obs.obs_properties_create()
obs.obs_properties_add_float_slider(props, SETTING_ALPHA_THRESHOLD, TEXT_ALPHA_THRESHOLD, 0, 1, 0.01)
obs.obs_properties_add_color(props, SETTING_LINE_COLOR, TEXT_LINE_COLOR)
obs.obs_properties_add_float_slider(props, SETTING_LINE_ALPHA, TEXT_LINE_ALPHA, 0, 1, 0.01)
obs.obs_properties_add_float_slider(props, SETTING_LINE_WIDTH, TEXT_LINE_WIDTH, 0, 100, 0.1)
return props
end
source_def.get_defaults = function(settings)
obs.obs_data_set_default_double(settings, SETTING_ALPHA_THRESHOLD, 0.99)
obs.obs_data_set_default_int(settings, SETTING_LINE_COLOR, 0x000000)
obs.obs_data_set_default_double(settings, SETTING_LINE_ALPHA, 1)
obs.obs_data_set_default_double(settings, SETTING_LINE_WIDTH, 1)
end
source_def.video_tick = function(filter, seconds)
set_render_size(filter)
end
obs.obs_register_source(source_def)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment